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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
8 @( M% I  p' o) e  V漏洞作者:skysheep
4 h1 D8 u2 P) o3 ]) @9 p分析作者:Seay8 z# _! p0 k/ s# o
博客:http://www.cnseay.com/- f+ ?( l5 p4 _' g  s. I
漏洞分析:: r" x1 e$ ?  b/ _9 h* Z6 K
  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。
8 n8 N' L: o6 N* l& @
2 @+ R/ |" A) d
5 \6 {2 l. E7 z" B" A8 k$ ~1 K 8 \1 }. t  i, Z$ Y- M% r
public function account_manage_info() {  ( s# N/ ~; @7 M1 C& w
       if(isset($_POST['dosubmit'])) {  1 o! h0 {$ T: _+ {/ L: V8 B" C
           //更新用户昵称  
( L% c; l6 H2 p4 B2 m           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
9 L* A/ I. q7 |3 l7 a           if($nickname) {  
  h8 Q! Q2 O; k6 m              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
& w: \/ _( v" z              if(!isset($cookietime)) {  
0 I( G+ l( p8 L# T5 X6 Q$ Q                  $get_cookietime = param::get_cookie('cookietime');  & P2 d6 h" g/ m6 S1 e. f7 c
              }  
! X( t4 ~4 u0 t6 R7 u# F( ^5 M* f6 }              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  ' `5 \- k' T( R, B0 H7 x0 ^* L
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  
+ R" C6 w8 X$ L+ Y0 a              param::set_cookie('_nickname', $nickname, $cookietime);  ( }# f5 \4 D3 }
           }  ) n: |! g, p# I' W/ Q
           require_once CACHE_MODEL_PATH.'member_input.class.php';  
+ j6 b+ u0 n  C! Y$ z) f           require_once CACHE_MODEL_PATH.'member_update.class.php';  
8 t, X$ [! V% U/ o           $member_input = new member_input($this->memberinfo['modelid']);  1 h- ^+ v9 J( G, e* Q: p
           $modelinfo = $member_input->get($_POST['info']);  ! w( ]; M4 d5 u' C& Z
           $this->db->set_model($this->memberinfo['modelid']);  
; B3 K5 O) a: X$ ^0 H" L$ e# Q4 M           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  $ n  n9 D( Z7 v; R# o3 h$ M
           if(!empty($membermodelinfo)) {  
# C; Z& W7 h: z2 H              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  - \# ]7 n  ?/ P7 V3 m
           } else {  9 n# i, I: m2 ^, U# U$ x8 M
              $modelinfo['userid'] = $this->memberinfo['userid'];  ( c2 c, D8 Z' L
              $this->db->insert($modelinfo);  
) q" j" z( o/ I           }
4 g3 P( y5 V3 `. p代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,
, t2 N# ?" e$ Y在\caches\caches_model\caches_data\ member_input.class.php 文件中:
+ Q- R" g- L; Y5 q" a  g3 |# ^  k9 g6 c: Z, q
/ V# T! v3 P8 P# s" Y/ u; t; ]
% Q9 v6 R" @( \* m9 b
function get($data) {  
# ^1 {( k8 p/ d" _6 l8 W       $this->data = $data = trim_script($data);  
; l) `6 b: [7 f# J  @! S( a       $model_cache = getcache('member_model', 'commons');  # F) K1 [  }" d
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];  * i' Q1 p/ h: s/ v
       $info = array();  + K4 ^. T6 j- k3 `, T0 W- @
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  
( c8 H! Z* o2 G# s9 P$ w       if(is_array($data)) {  
) r3 `5 ]* b; d+ Y: F. N1 a           foreach($data as $field=>$value) {  - g7 n7 D8 J2 y" e- D
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
3 D5 [. J5 J. f$ q              $name = $this->fields[$field]['name'];  
& b9 U" e/ A3 r5 p5 W) G. P% ~" r              $minlength = $this->fields[$field]['minlength'];  
; O1 B) o6 s* N+ s; l$ M              $maxlength = $this->fields[$field]['maxlength'];  6 `- @; }8 r: r- }
              $pattern = $this->fields[$field]['pattern'];  6 A; z: d$ p4 K1 D. l
              $errortips = $this->fields[$field]['errortips'];  
7 ]8 Z  O1 h! Y) M! C* b  i7 i              if(empty($errortips)) $errortips = "$name 不符合要求!";  
; l: r" U; a* W/ H  b9 N2 [4 W( }+ ~              $length = empty($value) ? 0 : strlen($value);  
: ]! B" p3 o8 f" b0 b/ c' l. u              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  7 n" _( {- M( f2 c6 F' m6 `
              if($maxlength && $length > $maxlength && !$isimport) {  ; E" U7 _9 R9 O
                  showmessage("$name 不得超过 $maxlength 个字符!");  & Y& H! E# ^! \
              } else {  
/ w8 y6 a2 @7 H" G! w" I. S                  str_cut($value, $maxlength);  $ `6 v$ v1 ?0 I3 B
              }  
/ }: X) B$ M6 h              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
: k* j& k' d' ?2 \                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  1 `4 q( V7 c+ a
              $func = $this->fields[$field]['formtype'];  
: h; i: c; U/ T7 P              if(method_exists($this, $func)) $value = $this->$func($field, $value);  ) c+ t# [. v" ~- \
              $info[$field] = $value;  
% e/ p* w: V$ \           }  # Y! B* o  t* a3 u* r+ L
       }  
/ j" B8 r0 }5 k. F       return $info;  6 S  z- J4 N" Z6 Y! x6 U
    } - Q. p, }0 a$ I5 G7 }2 b
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,( j3 d4 p4 u0 D/ r. e/ o

: d* s( m4 j  f; Q6 X再到phpcms\modules\member\index.php 文件account_manage_info函数* T' w, O+ l$ ?" d+ ~
过了get()函数之后。& X0 W. @6 N: C

3 _- `# S" k4 ~8 n 5 ?- T  ?$ }* o3 Q
$modelinfo = $member_input->get($_POST['info']);  
4 a4 F8 z0 \% i; I           $this->db->set_model($this->memberinfo['modelid']);  2 e2 Y5 B! K1 ^1 ?' M
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
8 a; ?. i' D! v- O: c, A: P6 G           if(!empty($membermodelinfo)) {  
; s, G. N+ ^2 l, Q7 q3 i/ I( G              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));    h4 c- f: u. b  S3 w2 f5 u
           } else { . J0 d' M8 {1 U( ^
直接带入数据库,update函数我们跟进看看! i6 R3 k2 G8 x: C% w- V; B7 _1 i

9 Y0 A6 ?5 s2 p5 y2 N
6 L; i7 W6 e& \) d2 mpublic function update($data, $table, $where = '') {  
$ l6 t; _7 A2 I% O       if($table == '' or $where == '') {  
* ]5 h, S- B) K  i5 i6 }( X           return false;  2 e8 g4 v5 r6 u5 x
       }  5 b3 j, P' s3 r  ~5 {
       $where = ' WHERE '.$where;  5 m- z. a! }5 p. \" T: E4 K* i& `
       $field = '';  
* ?% [, ]! g* H, G9 H, O& y( f+ {       if(is_string($data) && $data != '') {  
: `( v: |& D+ h. \/ e( y: m           $field = $data;  - ]' m1 K+ v4 Y9 O
       } elseif (is_array($data) && count($data) > 0) {  
* F& O' k4 D5 ^( Y9 ^* R; y           $fields = array();  
5 U0 b$ b, y/ X1 H( K- y5 c           foreach($data as $k=>$v) {  : e* W& p- H" V; j0 w* Z
              switch (substr($v, 0, 2)) {  
! N5 f) j5 G1 w1 P7 l. L                  case '+=':  
/ {" I# i! E* ?, |" |                     $v = substr($v,2);  
" q4 T. X7 W# T! Z6 O                     if (is_numeric($v)) {  
: t" |  A6 f* |1 q                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  + _' f9 T5 Q' r/ o6 [
                     } else {  / M+ Q# a+ ?8 D. c7 a* V
                         continue;  0 X( p5 J+ U' }  d2 U
                     }  0 u! r* X: H4 k, B, P0 H8 y! ]
                     break;  2 K  l. W7 A  _% ]) O. j( w
                  case '-=':  * R3 A- ]( b# D7 g3 e
                     $v = substr($v,2);  
' L! A" n+ a$ D5 H2 O. I( ~" Z1 e. @                     if (is_numeric($v)) {  ! X! Q8 B# t. r# z$ X1 E5 a: w
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
' G, o8 W+ [. Z  p* b                     } else {  9 S7 _# w# S/ ^$ \- K
                         continue;  * e/ ?1 i0 c; A% {( c9 k
                     }  5 m1 }( q& H& f- }
                     break;  # v3 r- S  u0 H' r
                  default:  ) c" w' @! U2 N. \2 z: k; }/ w
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
0 i; V1 ?4 _( g7 }8 _" a2 B  {              }  ! W& i3 Y. o5 I
           }  - F) x+ l3 I/ E0 ^# I' e
           $field = implode(',', $fields);  
- P  v7 _/ Y) X8 a+ W       } else {  
% W* m5 e( k) a: q# F           return false;  
% d) c1 w# K- e# F( `4 z       }  
% m5 Q4 [0 g3 a       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  * S4 W! A/ {3 C5 D% t# e% D* }
       print_r($sql);  7 t+ M/ c$ X0 {
       return $this->execute($sql);  4 E( e' W# F. P1 ^
    }
  r; X' i1 H6 [( U/ X9 E; X; g8 A- F从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。: e/ H2 P, U" G% C& z. a

# X4 v2 w+ Y2 _攻击测试:) g7 _$ s# P7 U/ c) q8 A) U
测试地址http://localhost+ |  U; Q6 }/ k: x! d! Q9 g( y
  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句
, @/ E0 v- P) A4 C8 `: U& X$ T2 Z5 W( l! s
# ~/ ^/ q4 A$ @! Q$ t) k7 a+ n
4 I% T% j! d4 e2 F! c7 t

7 q5 M6 E# {8 G+ i. w
& w. u+ b, \- a# U* h# a8 e

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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