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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
3 O4 O" F$ y. l1 u) L" K3 E$ g2 y漏洞作者:skysheep1 l' z& c) c+ c$ B- D- [3 ^# [  ?4 l
分析作者:Seay: y/ a; b* P/ w# P
博客:http://www.cnseay.com/
' W+ X& S* C" e* k6 [% H# ^! o* M2 i漏洞分析:) N7 C5 |( n  p4 ?
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
" y+ D& [" G/ K' R1 B
" X8 o. \4 t8 v" i, j3 f; _8 g) S; d
" ?5 t/ G. q& ~
public function account_manage_info() {  * S3 M$ G8 i; ]' q$ o5 Q
       if(isset($_POST['dosubmit'])) {  - u& d! E" @4 j$ Q4 w' E
           //更新用户昵称  ) d) J( ?; @) X" m2 g
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  & G: g4 I  }: G
           if($nickname) {  ' }" _& V; E" F/ X
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  ( ]# S) z7 l2 `
              if(!isset($cookietime)) {  ! u6 X% G. n3 \' W3 @% f
                  $get_cookietime = param::get_cookie('cookietime');  / Q0 v3 L- V+ X8 \9 O8 O
              }  
: A8 r- |* l5 L+ P& `1 q              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  ( H7 Q5 S4 ?: X1 v" o- F) S9 G
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  5 e6 L3 i  j. ]2 i
              param::set_cookie('_nickname', $nickname, $cookietime);  
) H( |* }* M5 J# f           }  
* W' A) z: \/ K. b           require_once CACHE_MODEL_PATH.'member_input.class.php';  ( Y& J3 K. L9 j$ h9 E" G
           require_once CACHE_MODEL_PATH.'member_update.class.php';  7 W0 Z; l; s6 A$ n! f. X
           $member_input = new member_input($this->memberinfo['modelid']);  * \. @: K! P$ U$ M% z# ~/ @% m- |
           $modelinfo = $member_input->get($_POST['info']);  % n( n* ?0 e; A/ e
           $this->db->set_model($this->memberinfo['modelid']);  - \; @8 }# J$ ]8 W6 q: @0 N
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
: F1 y/ x3 B$ Z+ \  f: v! Q6 R           if(!empty($membermodelinfo)) {  
( `5 ?2 W$ W2 s& G, n5 p              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  
5 [) n" k$ M& E& {1 L1 W           } else {  
- P" u+ g# P5 i2 S3 d- F4 |              $modelinfo['userid'] = $this->memberinfo['userid'];  + w: o; c( M: S8 M' M
              $this->db->insert($modelinfo);  " ~& K* u, O9 L7 h: @
           }
" K$ b# U6 P: r* @3 A+ Z& t代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看," i! X* B6 f7 l4 U# ]
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
4 k. q+ S& U$ ^& @: B* Z2 i) j7 C5 ^3 c0 h+ k

) j; l# m4 k+ k$ c4 x
+ B3 `$ R$ V! d9 D; h* D" zfunction get($data) {  + Y3 m. ~: h: v9 L. Y
       $this->data = $data = trim_script($data);  
8 f9 N6 s- @( n4 `% y       $model_cache = getcache('member_model', 'commons');  
- ~& Z" F- X# C' E; |) p9 q2 ^       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  
) G$ w3 E( v# d" A2 N       $info = array();  
( z+ j* M- n3 t       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
' W/ m) I; o5 u. A       if(is_array($data)) {  
, f5 D2 Y( N6 _: |2 U, z           foreach($data as $field=>$value) {  - P+ B  [1 H; U, T# B+ }5 W2 L$ p0 K
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  * u- p$ h# y5 G$ P6 Y0 e
              $name = $this->fields[$field]['name'];  
" b7 `' T/ R- A1 a8 P1 y+ X' E  ]              $minlength = $this->fields[$field]['minlength'];  
$ x" w* D2 p2 m& A8 l              $maxlength = $this->fields[$field]['maxlength'];  " G, C, i9 v8 P4 n
              $pattern = $this->fields[$field]['pattern'];  
' S7 T4 v& V+ f- B! M, R              $errortips = $this->fields[$field]['errortips'];  
( L! g# j% Y" Z& a              if(empty($errortips)) $errortips = "$name 不符合要求!";  
( H' X! C0 a- ?4 S. y. e, _              $length = empty($value) ? 0 : strlen($value);  . e+ G! I/ ^& @- R0 q, P9 ]3 y: j
              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
. k1 p/ ^% \: c9 C              if($maxlength && $length > $maxlength && !$isimport) {  
/ o5 n/ T$ C# y0 ^3 _$ G3 d                  showmessage("$name 不得超过 $maxlength 个字符!");  
' J2 }- k* h- p: f              } else {    A6 M( O' _. u: C% M
                  str_cut($value, $maxlength);  + C, o; l0 i  ~+ e$ Y6 |8 [
              }  
. y1 x* W4 D) P$ m, C              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
$ Y  {; `1 w- `                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  ( U$ n' F) x4 r$ Z0 ]1 Z4 G
              $func = $this->fields[$field]['formtype'];  
+ |( x  ?+ i, H$ W8 N1 w/ P, M              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
6 a) g+ ~( {. e$ m/ [              $info[$field] = $value;  , g) ?4 O7 Q% e3 {& v7 R
           }  
* G$ g: F; L6 `8 ^# w1 d       }  
) l, B9 ~# d6 f" @$ c" c       return $info;  
+ C, R. [% q+ ?4 j2 @' W5 h    } ' U! l% j& B" U5 B( e2 Y/ F% w
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,+ A! s5 o6 X+ P" p; w- R

# n7 Q( o2 H% L; y4 c再到phpcms\modules\member\index.php 文件account_manage_info函数
! b# ^$ w  Q2 Z8 r4 ~9 j过了get()函数之后。5 Q6 |" ^" D3 b; j# Q' [  B4 S

) O/ Z# c6 Y( `7 y6 u
5 H: P. M9 {) F) r$modelinfo = $member_input->get($_POST['info']);  
' i9 p$ W% _2 U1 D- x           $this->db->set_model($this->memberinfo['modelid']);  
; t' o: K3 E' z! W& T           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  " `0 ^8 O" a5 C* I) m# ]7 ?1 L' r
           if(!empty($membermodelinfo)) {  : `+ F0 H( z" Z, N, }
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  * L# u" x; [% _1 P: K) g8 I
           } else {
( A! o1 t0 D9 c1 Y直接带入数据库,update函数我们跟进看看" C, I! y! a& [" [
​
/ S, ]: B% d; i* w  y 2 ^5 C: Y( j8 I7 X4 Z
public function update($data, $table, $where = '') {  * h+ J' b/ Y( V  W
       if($table == '' or $where == '') {  + N- ?0 ~  W) P. y
           return false;  + J# f- ^, Z3 S: ^# D  T  B! z* M
       }  
! S5 z; t0 ?' C9 X( ?       $where = ' WHERE '.$where;  : Q8 d5 |, C. R
       $field = '';  5 }/ L+ o- z5 w$ s0 O% A
       if(is_string($data) && $data != '') {  $ y" t! x, Z6 v8 S4 A
           $field = $data;  # x6 z1 J8 Q' h8 e3 f- L
       } elseif (is_array($data) && count($data) > 0) {  
$ T1 A  S+ u0 T8 {9 X! p           $fields = array();  : N5 }4 [# F2 Y: @5 Q6 d4 ]
           foreach($data as $k=>$v) {  
/ m7 t+ c7 z3 n; P8 f2 A5 u              switch (substr($v, 0, 2)) {  
$ g! g+ C5 d9 M9 u/ S+ x                  case '+=':  
- w; U( U0 Y5 Y5 J$ G' f                     $v = substr($v,2);  9 Q/ h- o6 {! ]/ R* F9 t$ h( F( f
                     if (is_numeric($v)) {  
1 @+ F5 s: j$ d' s7 c                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  
8 R, _2 L, @- R" b3 E; |                     } else {  4 y! y3 ~; O5 N; D; l4 H
                         continue;  , O9 ^- ^/ W  y
                     }  ; M: L2 h$ F( j- V. ]9 D& ?
                     break;  4 M; R% f* w5 C7 \: D
                  case '-=':  ' r6 W$ j) o7 {/ {# j
                     $v = substr($v,2);  
; `& M  b, B3 p2 ^5 y                     if (is_numeric($v)) {  
, C4 ]  V  k! F! X. a                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  # y- G0 g" S; o! V# F
                     } else {  ! Y; T% o& W! ~+ e2 D
                         continue;  . b, P5 q- h7 E- P: k, ^
                     }  
( C+ b; p" ~% [8 m8 ?                     break;  
7 z0 y: y7 C, t; q1 H% H0 r% g                  default:  ( c' b- u% a- I
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
1 b+ _/ _" \3 D5 ]0 n              }  : X; H! X8 N! S: v! r
           }  ) s: `. U/ [2 D8 I7 H
           $field = implode(',', $fields);  
( E, B/ j; r! o# h       } else {  - E: a7 n! K$ y8 X3 a$ w4 P4 J, W
           return false;  ( P( H8 X. _6 E2 l, F7 k! F0 Q1 F% P
       }  
9 S8 ^9 f) h; {& J       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  3 N2 D- U4 H3 ]% w& w
       print_r($sql);  
1 A/ F8 T7 T, C       return $this->execute($sql);  
) B7 [4 n/ _4 |1 T7 B( p    }
# {% m+ V' L- K# G! x从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。# @" a3 T: P, ~; P+ J/ j  q
; l/ }- f& n, ?/ {' c* c& r0 F
攻击测试:2 p% M9 j9 Y8 \* M) W
测试地址http://localhost
/ w: B! A, K1 ]1 @; |1 F  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
5 ^/ m2 z, @( ]+ c
+ U! T& y+ u- g) m& s- h7 r1 X / J6 {, N7 w: G; q
' J8 ~$ E- E7 I0 q6 C$ j6 x( D& @. C
; U9 W, K5 \8 B

3 {6 i* H( N; N/ n# H1 a, z4 b

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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