找回密码
 立即注册
欢迎中测联盟老会员回家,1997年注册的域名
查看: 2000|回复: 0
打印 上一主题 下一主题

phpcms v9 2013-02-01 会员中心注入漏洞分析报告

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告# {5 O( d; Z; m* u  U$ [
漏洞作者:skysheep
, u, b5 Q$ O* p' F, i& `分析作者:Seay9 G% ^0 O: l# V; s. p
博客:http://www.cnseay.com/
1 ~7 Z  _9 J  e5 ~6 K3 K& L漏洞分析:
# }) e( y0 J3 L) u  _- h  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
4 V. R& a+ D: o9 Y' {
$ e, I1 a/ B4 Y7 s' L4 [; \  Q- j5 {0 M- b: j( V

2 g  U/ E; Z6 Mpublic function account_manage_info() {    C$ U1 E& g: m3 y$ t& C
       if(isset($_POST['dosubmit'])) {  5 L6 j+ G3 L! Q- g3 I! g
           //更新用户昵称  
6 L1 J. P. Z# r8 [7 c9 A; ~           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  , r3 L3 g0 J' A+ Y5 M# e
           if($nickname) {  
9 {* z; W+ o4 k; `% B              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
+ |5 O: o& k5 }, I9 t              if(!isset($cookietime)) {  
8 j7 ]* v/ G% Z( N# r6 h5 S7 ?) \                  $get_cookietime = param::get_cookie('cookietime');  
/ F9 t, ^, Q3 @) [% W3 q8 A4 U              }  ) j$ _) G8 @# Y, R" W
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
. ^1 I) x" e* D" X              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  # }& e* T/ }/ X0 C
              param::set_cookie('_nickname', $nickname, $cookietime);  
/ G0 N- |9 c3 I) ~* {           }  
3 Z; |0 V' c9 l& z3 ~& O           require_once CACHE_MODEL_PATH.'member_input.class.php';  $ h# `$ L# j5 K& F3 i6 l( R) w
           require_once CACHE_MODEL_PATH.'member_update.class.php';  & p" f( v% h  S% y# I1 q! g2 ?. H
           $member_input = new member_input($this->memberinfo['modelid']);  1 [. U& V- N8 t5 L% _
           $modelinfo = $member_input->get($_POST['info']);  
% C; x2 B1 l$ {           $this->db->set_model($this->memberinfo['modelid']);  0 R# o$ i  r" d5 [9 |, h
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  % ?* L4 D7 L( i% N0 I
           if(!empty($membermodelinfo)) {  / |! @3 j3 e) R$ t5 g
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  2 U6 ~% L; P3 G/ i7 {: O
           } else {  * i5 E' t* r' j  a0 X8 G! Q
              $modelinfo['userid'] = $this->memberinfo['userid'];  7 {6 c! Q$ a) d8 V" i
              $this->db->insert($modelinfo);  $ W, i  ?/ k( R8 n
           } / S# X* D/ b0 ~* }% \
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
: x$ b8 f( C0 J, W; }. P- x/ V在\caches\caches_model\caches_data\ member_input.class.php 文件中:. o/ q* e& X$ f* X9 W, d

7 p0 u/ v% @$ g7 m& @) `" u
$ m  m% S8 {. }1 L4 t1 b8 z
, k1 w1 Q, |- w4 L/ M& _# bfunction get($data) {  
  s$ z* v( S6 b4 \       $this->data = $data = trim_script($data);  
& j( S1 O, p0 [       $model_cache = getcache('member_model', 'commons');  
3 s3 A; n. z! g9 B: s       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
9 c  c. B1 A7 q+ v% H, ~0 z! `       $info = array();  6 _2 r* _3 r+ I0 N# f- y( B* V
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  + d* W6 i2 z/ `! v/ o
       if(is_array($data)) {  
' V  l7 w- ~% _9 N# v# g           foreach($data as $field=>$value) {  
7 |! I1 p: Y* [) }6 w2 C              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  ; }7 e5 j  Y7 a8 B" m) x: Z/ g
              $name = $this->fields[$field]['name'];  
" U9 i! i. Q2 T              $minlength = $this->fields[$field]['minlength'];  - V6 `3 W9 t  I( S3 D" V( ?1 \
              $maxlength = $this->fields[$field]['maxlength'];  
+ B. R8 M# a3 a8 ~              $pattern = $this->fields[$field]['pattern'];  ! |" @3 `0 y! I
              $errortips = $this->fields[$field]['errortips'];  
' ]' M6 Z$ P# V              if(empty($errortips)) $errortips = "$name 不符合要求!";  
* H1 x6 w) K8 W) f/ O  K              $length = empty($value) ? 0 : strlen($value);  8 \1 q& u8 `" t& k9 T
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
% p. U3 s' O, t              if($maxlength && $length > $maxlength && !$isimport) {  
( S/ k  n. ~7 H7 h" E9 V: j                  showmessage("$name 不得超过 $maxlength 个字符!");  : d* M& R( T4 V8 G
              } else {  $ e9 t" D7 i$ Y1 O( a9 T
                  str_cut($value, $maxlength);  6 A! \) @# E5 u8 L- ?% Y6 }
              }  
1 E* t' V! Q9 k/ r              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
: d" t  K" u: W& M9 m9 r6 [                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  + r+ R% m9 d+ x+ Q" Q
              $func = $this->fields[$field]['formtype'];  / T( }) N  c' }) D- C) E$ s9 S" X
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
" X% H9 j2 H) j, Q              $info[$field] = $value;  
. @$ Z0 n7 h; v' c" \           }  - z9 U/ f; _$ G. K; g# p  q
       }  
4 i. n+ \3 m3 N# p' Q       return $info;  ) r! H$ X3 s& c4 t( o
    }
) |/ s9 p- a! w% V  Ptrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,( c% B0 q  r* z* T% K/ H$ U
$ x) }5 Z) b* m  \
再到phpcms\modules\member\index.php 文件account_manage_info函数
6 N0 U6 T' Q( i' l  c7 W过了get()函数之后。! P9 x+ }2 s- L' g3 q3 Y

5 O# v2 b" O3 [1 h7 R* f9 \
+ t: r! g" K+ |; y3 F/ L$modelinfo = $member_input->get($_POST['info']);  
! R& u# ?" A- G$ m/ X& O! Z           $this->db->set_model($this->memberinfo['modelid']);  9 m* ?1 h5 S6 s
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
) V# Q9 |0 R( {& ~           if(!empty($membermodelinfo)) {  
4 X8 |. e1 O; w6 ~5 T- s- F              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  9 a# n* j2 K9 n" N: f# k
           } else {
0 v, m  ~* C7 J- K% }# R直接带入数据库,update函数我们跟进看看
( N8 Y% C4 Z4 d# S1 ]/ Q. l$ I+ ]2 G! `$ Q4 R
: S7 s4 H1 [+ H( E
public function update($data, $table, $where = '') {  2 E/ {. T! |5 i- z. G
       if($table == '' or $where == '') {  
: X7 m1 `$ [0 g" A% K9 |* j) e           return false;  % d' O1 G% g9 x5 k, K% Q
       }  
' z" E* {% U( ~7 F& {       $where = ' WHERE '.$where;  7 F4 D6 C& M, c- e, a
       $field = '';  ) ]3 D6 {2 d: H: Q9 n6 a
       if(is_string($data) && $data != '') {  
% C# f6 M# x4 O           $field = $data;  
% S- S1 @. `$ n       } elseif (is_array($data) && count($data) > 0) {  
/ [; w# u( ~7 m           $fields = array();  8 P7 O, o: p. F2 T7 ?) X
           foreach($data as $k=>$v) {  - l$ |( v' R" L+ b" C; }
              switch (substr($v, 0, 2)) {  
5 ~- g7 |+ D5 ^) n0 g                  case '+=':  
. Y- u3 k1 |# m4 R9 k                     $v = substr($v,2);  2 G8 p5 c9 f2 E. S# T% b3 _$ G# C
                     if (is_numeric($v)) {  
6 {4 \( J8 M+ N- W. G' [3 N! E                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
5 J- E' p& y) J8 {# _                     } else {  3 e' y) [1 [! \3 b' O1 t3 l$ q
                         continue;  
4 ~+ t$ L# f9 x3 x1 ~" l8 c6 p, P- g                     }  - w7 K* b: d5 m) C% z' E: V) L
                     break;  
" t  x3 j7 A1 W8 m+ m8 m1 d                  case '-=':  
! t' \% q! L/ |3 [( _0 }8 S                     $v = substr($v,2);  $ l1 o; B  J; N$ E. ?1 J
                     if (is_numeric($v)) {  
# B/ v$ T8 H  x/ `                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  " c/ N6 e; x/ G! U* l4 C
                     } else {  
6 C5 c5 Q+ ^$ A" m7 G  h$ @                         continue;  * S7 ^7 Z/ q3 `7 R
                     }  ; q. i- J  ^/ v- x
                     break;  
1 n# `' H& }: d- @7 m; {* Z                  default:  
, Y4 N4 W0 L0 x: v- C9 r% x                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  / \9 u5 S- h" N! T6 t5 [% `
              }  / z" e# {! \: G0 `
           }  
' r; o; I+ o. j& A7 z           $field = implode(',', $fields);  4 z7 _/ |, D( r4 e. L- L) |
       } else {  
6 J  E+ a7 v* T           return false;  5 y% S# a8 h1 c" u) [& i
       }  3 Y. }+ }" B4 H# B- i$ D
       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  7 G. ?' I: x8 ]8 ~6 y
       print_r($sql);  
" K! v2 p) h) e7 B, L       return $this->execute($sql);  4 O3 V3 \0 z# |7 A0 j
    } ) g3 V' Y: o( n: c
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。0 ~& t3 ]; Z2 e
9 L6 p  c1 e6 b' n3 i. y5 u, q  i
攻击测试:) G; I0 C1 q! W" i# c7 Y
测试地址http://localhost' G. q, ~0 c) v6 ]" d1 G
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
8 z  }4 Z1 ^# v- e9 h$ u) I
  i# f1 q9 E# E7 f8 e0 i , \# k$ Q' f' e! t3 C
3 R: l+ e6 W6 |6 g. i

. L) ^0 s2 F/ J5 ?0 v4 {
$ p0 X/ A6 F7 f+ U' m

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表