找回密码
 立即注册
查看: 2366|回复: 0
打印 上一主题 下一主题

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
9 G; N! V- H: D. B9 ~5 r" u; l& |漏洞作者:skysheep
4 u, ~5 Z. @+ V6 y. t8 h) \分析作者:Seay
$ p* o* [0 |0 P; T) }博客:http://www.cnseay.com/
! U$ B6 \7 Z2 U+ U) F- F9 u( }漏洞分析:  ?  E0 l- o; p$ M& g
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。) h+ n" P7 f& ?8 d% V, J9 N, R

; B4 U' L3 c: q/ n4 j5 L/ ?6 O2 p. E* a" Y2 m0 j! s. H6 \- k

1 B7 g, g& j6 V- \public function account_manage_info() {  
* b/ x) Z0 Y3 T: U0 O9 g2 v       if(isset($_POST['dosubmit'])) {  
$ K! G$ f# n& D/ }           //更新用户昵称  
# l9 h$ @4 K& Z+ y! x8 N1 N           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  " u# H. r  ^: n/ ~: N
           if($nickname) {  
: ~" @3 Y2 ~, r- Z" b+ a* @, Y7 ~              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  / }) w- ?0 ?6 U6 Y$ a* ~& v
              if(!isset($cookietime)) {  
& P* ^) b: `6 }3 b& l9 I- `                  $get_cookietime = param::get_cookie('cookietime');  
5 ], `! W& D$ h  E              }  + c: l5 {3 B2 s, k3 Y' h
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  
& v0 Y; p' h0 [) F              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
3 E/ U' z, r* V  g. X              param::set_cookie('_nickname', $nickname, $cookietime);  
1 ?& V7 T, T) K7 H           }  
6 p+ f* Z8 ~' b. ^- \" T4 Q           require_once CACHE_MODEL_PATH.'member_input.class.php';  
9 m3 I, O; R% @1 C0 V. p  R0 _/ H& ]           require_once CACHE_MODEL_PATH.'member_update.class.php';  5 r2 D9 ]! x' ?3 T
           $member_input = new member_input($this->memberinfo['modelid']);  ) A3 u; Y. b4 o) j
           $modelinfo = $member_input->get($_POST['info']);  % t& A* L/ _. B" e2 S$ v9 g
           $this->db->set_model($this->memberinfo['modelid']);  
" A: e& y4 w4 z- ^) R2 g           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
7 c1 x" H6 F  }           if(!empty($membermodelinfo)) {  
6 b) r# B$ }2 q8 o/ a              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  9 w, v6 F  a3 o
           } else {  
" g5 L$ \7 o" E0 i# o5 n5 e; S              $modelinfo['userid'] = $this->memberinfo['userid'];  / l! _1 ?8 \- Q: @, Z+ y- g
              $this->db->insert($modelinfo);  # l' W9 Y- I& u6 z/ N6 Y9 {0 c
           }
! J" k  J2 L9 T- Y5 S* b9 O代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
/ A( t# X8 z; A# R在\caches\caches_model\caches_data\ member_input.class.php 文件中:8 d  M3 B: S" \2 Q

& ]( w. t: w% d# `3 y5 u! L( w4 O$ I5 M
) j) w7 P; s1 t) w
function get($data) {  : A0 @9 u% j# g3 w" Q
       $this->data = $data = trim_script($data);  
  l; Y1 h8 ?0 e9 p8 o; Q) [       $model_cache = getcache('member_model', 'commons');  9 V# K1 I+ y) k+ i
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];    e2 K6 L& u( K+ T& O
       $info = array();  0 V- l+ ~! g9 f! z- r
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
/ P3 a, i5 t# g+ }1 M4 @/ I       if(is_array($data)) {  4 f8 f0 h" T2 y. e, M, v, s
           foreach($data as $field=>$value) {  * \( U* o; E" x  b6 D; B
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  " I1 J+ I9 H  u: i/ g$ C
              $name = $this->fields[$field]['name'];  
3 e) @* p( g; f. z/ V              $minlength = $this->fields[$field]['minlength'];  
2 V" C8 a' q+ @2 c, s- M              $maxlength = $this->fields[$field]['maxlength'];  
! L! _  I, l2 f, e% ~3 y9 Z0 k9 K9 A              $pattern = $this->fields[$field]['pattern'];  : m7 y/ \4 b: d8 l) p8 }8 [
              $errortips = $this->fields[$field]['errortips'];  
+ J; e2 A! X0 O; H0 i              if(empty($errortips)) $errortips = "$name 不符合要求!";  
9 u  x7 {) \- F4 l6 ]              $length = empty($value) ? 0 : strlen($value);  
* y/ p' \7 Z) o              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
1 ?2 i" E% S& k- G! T              if($maxlength && $length > $maxlength && !$isimport) {  1 N6 Z) X- w. m: ], [
                  showmessage("$name 不得超过 $maxlength 个字符!");  
& c. o# C- c: K2 u              } else {  
2 w3 R& H. C' p) p4 v& G                  str_cut($value, $maxlength);  : B! O  j( r; `) w" B/ l% S" N
              }  ! x* g9 G3 Q, `& @* M$ N
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
- N+ R4 m6 |+ D9 O  M                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  
/ Q4 x. ~& E% C% p6 L' ^2 G              $func = $this->fields[$field]['formtype'];  
+ p1 L' c. T  i% |0 S/ b              if(method_exists($this, $func)) $value = $this->$func($field, $value);  6 A% b+ j4 d9 W, w# k
              $info[$field] = $value;  
8 |# n) V1 k% L3 ~; H           }  
4 I8 {- x  V2 p# |$ G, [! w8 H       }  
" l) H/ ~) X+ a- a4 C- \, Q7 D       return $info;  
: }1 H6 v' ^, C1 G    }
: t1 M1 V5 p% j; j7 Ztrim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,. |' @. H7 v9 [% o
4 m1 b# E( b- ^. H2 F- j. X+ F: P. N
再到phpcms\modules\member\index.php 文件account_manage_info函数3 m7 P. h. Z# p
过了get()函数之后。* x0 \6 d- g; ~: I$ O

# c" r; @% q% t 8 K2 ]- T: F$ `8 G
$modelinfo = $member_input->get($_POST['info']);  + [4 L7 r  Q6 `4 h
           $this->db->set_model($this->memberinfo['modelid']);  
3 i0 |/ I3 \9 p/ r9 F/ D+ U1 F           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  ) s9 E" r8 g! w3 g. u
           if(!empty($membermodelinfo)) {  0 B! V5 {7 d; W$ e
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ' k: ^1 h$ R0 p
           } else { ( A: L. C0 G8 q' }
直接带入数据库,update函数我们跟进看看
  e( ^, @* d) ^/ M3 S, ]' K
$ F" R) C5 l5 {  t7 e ( T1 v$ V9 V) i- z3 _
public function update($data, $table, $where = '') {  9 P, I3 L2 n* B5 V; s0 d  i
       if($table == '' or $where == '') {  
3 H: h$ e  U- m1 H* h           return false;  : k0 O6 ^5 e, h' s' u
       }  ! x, Y& l3 N; }$ m7 k' a2 `; x3 I$ p6 R" ?
       $where = ' WHERE '.$where;  
3 I4 X4 S& h0 Z' j% i! i! z2 _' ]1 W       $field = '';  
. q! h2 F. @; n9 W& [& h5 r2 h' ~       if(is_string($data) && $data != '') {  
, [; H  R2 i3 P           $field = $data;  9 w' E- n2 l8 H4 {  \6 ^
       } elseif (is_array($data) && count($data) > 0) {  * r2 P% n! P! k- [4 P
           $fields = array();  4 s5 ~( ~0 h3 E/ E' ~
           foreach($data as $k=>$v) {  ; z' u! y' I& Y, ?0 |8 J  v
              switch (substr($v, 0, 2)) {  ! x! C# u( d- f( o
                  case '+=':  9 ~5 K) x8 f  ?7 t5 ?
                     $v = substr($v,2);  
7 w1 u* ]7 E+ `0 s                     if (is_numeric($v)) {  3 P7 E# p  u3 J4 m8 w; _
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
3 Q/ d  |7 y3 ^( @2 F                     } else {  ; _5 P4 C" d+ [( v! _. K
                         continue;    s8 i" L8 ~, m2 h
                     }  
9 b. W' @& @( h3 M6 ?5 `4 U                     break;  ; G2 E: I2 S/ i
                  case '-=':  0 V$ W6 n, o) u/ v" ^
                     $v = substr($v,2);  
. F' Q, {0 Z2 K: E( G1 D                     if (is_numeric($v)) {  4 ]7 `- f) M0 {" F: K6 e
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
- T6 d' Y8 v1 f& K0 k) |                     } else {  
6 t) v1 y- i% [' Q& c# o7 S                         continue;  
) Z' q) o) B$ z: C                     }  
. p( {: p9 w( I) u$ J1 _                     break;  0 a) k, a" y6 [+ D9 ?5 E  h6 o0 r
                  default:  
% @+ p! n; E# B8 u9 C                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  ! U" a3 N6 L/ q* ^4 n8 N( G- n
              }  ) ?5 C  |1 ~! ]+ G* F5 @' Q/ E% y
           }  0 Q9 M2 j- ?5 J5 a/ N# E+ ^' ~
           $field = implode(',', $fields);  $ }% C1 m3 e) [4 n% [% w
       } else {  " b. P7 P+ }' a1 e
           return false;  
9 j& t. e2 c! \2 @. [5 A       }  
- B3 v3 @! x& n# q/ c6 p9 b       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  $ d( U% Q, H0 `$ L5 ]9 L. q
       print_r($sql);  5 o7 e: j- q; q8 W& j) I6 q
       return $this->execute($sql);  9 p  B- p, S- V, W. a4 D( ^, L
    }
$ B% v0 {4 w, w2 g) s# o* [从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。
  {3 v3 P% [* U" e) \* u, f2 U9 c. _2 q+ T; k
攻击测试:6 i$ T, p' ^8 V. v
测试地址http://localhost1 h# o5 V; ^( P. A1 i
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句7 V+ \2 x$ r4 p5 U9 q7 M
7 N/ y  D$ x* t$ {. I6 a

; m: [, J7 Y1 X3 i0 a! Z
7 l; i' ~& @3 Q8 |/ D2 k) c) m7 I. V

& s0 q5 r8 d" o5 S$ E+ H

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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