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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-4 16:17:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
报告名称:phpcms v9 2013-02-01 会员中心注入漏洞分析报告
$ L0 H* c$ F. g8 S7 {漏洞作者:skysheep
8 H1 r% Y8 w  v! y0 B9 ]! V( }2 e分析作者:Seay
/ l# y- q3 W* A* R! I博客:http://www.cnseay.com/$ ~; k; H% s" H8 i
漏洞分析:
0 a3 o- ?" ^! e# |! f$ Q! s1 O; W  漏洞存在于 phpcms\modules\member\index.php 文件account_manage_info函数,其功能是更新会员信息。8 c* L  C" `6 u' f; o' {
* y$ _- d" x2 C& `% }8 w) f
" e" Q" C1 a7 S

( H. o- M8 S) `# v2 T8 i5 }public function account_manage_info() {  
! Y3 x$ n+ E4 ~3 W+ L2 ?4 S0 q8 X       if(isset($_POST['dosubmit'])) {  6 B! J" t/ e: Y. S7 }) [
           //更新用户昵称  9 ^' e3 F  _7 k% C; X
           $nickname = isset($_POST['nickname']) && trim($_POST['nickname']) ? trim($_POST['nickname']) : '';  
9 E# I: ]7 c$ y% E$ e  J  q           if($nickname) {  " W7 c1 m  F1 r4 C
              $this->db->update(array('nickname'=>$nickname), array('userid'=>$this->memberinfo['userid']));  
! c% B8 P6 V9 n7 `# D3 d8 q* V              if(!isset($cookietime)) {  
! m4 d& O+ ^; r" G4 Z                  $get_cookietime = param::get_cookie('cookietime');  * W3 k$ |# g9 _4 v4 e  |" i# ]8 Y5 `1 d
              }  ' A: @" O$ N! ^# x
              $_cookietime = $cookietime ? intval($cookietime) : ($get_cookietime ? $get_cookietime : 0);  5 y" L! G5 J7 _+ E/ J, s& w' ^( k
              $cookietime = $_cookietime ? TIME + $_cookietime : 0;  ( x! a" Z1 `1 W
              param::set_cookie('_nickname', $nickname, $cookietime);  
& e3 {% p6 {! _; j+ @           }  
3 M3 Y  g, [% v2 H- o           require_once CACHE_MODEL_PATH.'member_input.class.php';  8 X* u5 A, \7 t5 p3 T; `
           require_once CACHE_MODEL_PATH.'member_update.class.php';  
- {6 I  Q) Y$ H% ~' o! o           $member_input = new member_input($this->memberinfo['modelid']);  
+ I/ o0 |9 k0 O  H$ s2 F8 D! R" n, j' A           $modelinfo = $member_input->get($_POST['info']);  
9 u7 [- J) i2 b' g           $this->db->set_model($this->memberinfo['modelid']);  5 u- r/ c, d: M
           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  
1 A8 _" O4 f) d0 i, o3 H           if(!empty($membermodelinfo)) {  9 g  ]1 f  U0 N7 i+ z
              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  ; M- |$ e  [( l  Y$ T/ p* F$ W
           } else {  7 M; \/ y- S  e0 r: R
              $modelinfo['userid'] = $this->memberinfo['userid'];  
$ P5 H: }1 a7 r" q) p& b- S1 v              $this->db->insert($modelinfo);  
# I9 R6 P, R0 I; @5 ]           } / w) R4 ^6 p$ o: ]/ ~
代码中:$modelinfo = $member_input->get($_POST['info']);取得提交上来的会员模型中的字段,我们跟进member_input类中的get()函数看看,: ?* {( Z+ L1 i7 i
在\caches\caches_model\caches_data\ member_input.class.php 文件中:
. s6 v1 Z! O- A( @3 x7 ^  z  J" C6 C
$ C& ]3 `' z$ [' T
' W) r+ y3 m3 R% k& x; J
function get($data) {  + s+ P- v  a5 e( k4 D- [
       $this->data = $data = trim_script($data);  1 A3 O* q0 ?( v( g* m, Q
       $model_cache = getcache('member_model', 'commons');  ( f% X4 O8 d- I6 M2 }
       $this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];    s) i. r0 q3 i( r; b
       $info = array();  2 R. X) ~( H0 p1 ~7 Y
       $debar_filed = array('catid','title','style','thumb','status','islink','description');  1 f1 K% L0 D3 y6 J6 L" p% f' o- ]
       if(is_array($data)) {  ) ]1 t) A4 N7 k6 g' u& H1 V
           foreach($data as $field=>$value) {  2 q' m" X# ]4 t. f" V- C
              if($data['islink']==1 && !in_array($field,$debar_filed)) continue;  
, L/ G5 \* T$ s/ O- H              $name = $this->fields[$field]['name'];  
7 p, \# s9 |, a2 V7 k9 _              $minlength = $this->fields[$field]['minlength'];  5 v8 [8 \, U* h
              $maxlength = $this->fields[$field]['maxlength'];  
8 e/ n+ }' Q! H1 S              $pattern = $this->fields[$field]['pattern'];  5 d7 I7 p, g+ \2 B% A. h  J
              $errortips = $this->fields[$field]['errortips'];  5 A+ {$ i1 }4 m, `- \0 f
              if(empty($errortips)) $errortips = "$name 不符合要求!";  
+ N/ C; T( w  Y, B. Z0 n              $length = empty($value) ? 0 : strlen($value);  
# ^# `5 u* o) @0 {- y              if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");  
9 c! g' V4 B& k. D- w              if($maxlength && $length > $maxlength && !$isimport) {  ) P% c3 Y! |7 E( N+ m5 c
                  showmessage("$name 不得超过 $maxlength 个字符!");  ) ~, U& ^7 |! r; w
              } else {  * H/ D4 K! z' x0 I# _1 m
                  str_cut($value, $maxlength);  3 X" k" H+ @( h& |* I
              }  - R1 S; l4 y" Z- H
              if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);  
2 N& P, D: P) S                if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");  ! F/ v$ Z& @2 m$ {/ Z' H
              $func = $this->fields[$field]['formtype'];  % r( i' s# r1 Y( m& W
              if(method_exists($this, $func)) $value = $this->$func($field, $value);  
6 i1 s. l6 D1 N2 E3 F              $info[$field] = $value;  
5 r( w6 l- ~8 z6 F           }  % a- y7 L8 @5 Q( ?& v- ~9 t
       }  
2 o! L# U5 Q  E: X       return $info;  
2 I5 K( W5 u0 R  ~' n    } $ X2 ?2 e; [# n6 p; i
trim_script函数是过滤XSS的,上面get函数一段代码干的事就是取提交上来的字段和值重新赋值到数组,2 w9 u+ {7 z% c- |: D
! k. s# N9 |4 S
再到phpcms\modules\member\index.php 文件account_manage_info函数$ \1 A" l* N% H% x% o6 f+ u
过了get()函数之后。
3 t7 e- u: o4 h. x% g$ ?
+ {: u3 x1 P# l5 I0 y; ^ ) G6 F0 W5 T1 T6 ]+ R6 u
$modelinfo = $member_input->get($_POST['info']);  
: x9 d. y! X" ?7 b& D4 [7 @           $this->db->set_model($this->memberinfo['modelid']);  
+ C" e/ w. j" m4 _$ ~2 G( K7 v& |           $membermodelinfo = $this->db->get_one(array('userid'=>$this->memberinfo['userid']));  ( M! W) a0 Z# V# H% q
           if(!empty($membermodelinfo)) {  
9 p8 U3 W* Y* _. [* I/ M, S5 m              $this->db->update($modelinfo, array('userid'=>$this->memberinfo['userid']));  3 Z. e  J6 Y% M: X- b- V
           } else { + K( o. U0 S( m9 C
直接带入数据库,update函数我们跟进看看
& Q7 g" y6 k, X6 @: N5 T% f# F5 p, |7 @3 e& E
5 o6 o, ^8 B: z
public function update($data, $table, $where = '') {  
9 u9 h5 W5 y, Y       if($table == '' or $where == '') {  % [8 m0 Q* C/ G
           return false;  
: Z. g* n) T' L) b4 l/ t+ ]3 W       }  7 n- b9 @4 S* Y: u! Y) p# y* y
       $where = ' WHERE '.$where;  5 S2 E8 y* Q. k3 }
       $field = '';  8 e. R. b4 Y6 Q' _! U3 O* O
       if(is_string($data) && $data != '') {  
6 \7 x4 i  Q- ?' M( i2 S; h           $field = $data;  9 R. b% v: A9 C8 W  g4 Z
       } elseif (is_array($data) && count($data) > 0) {  - ]  v) [! |6 M5 L5 j3 F' y
           $fields = array();  * l* v9 x6 X( q: y
           foreach($data as $k=>$v) {  " r7 ]/ \4 l$ Z
              switch (substr($v, 0, 2)) {  
+ J5 \6 F$ p7 T( j5 G! g                  case '+=':  
, L+ Z  h* \7 ]7 R# W. }. [# Q                     $v = substr($v,2);  2 X# L" {6 D: M, f- X' G& B
                     if (is_numeric($v)) {  & X6 ?: t" l; ^! B! [
                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);  / G# f7 B) S( K+ C) p
                     } else {  ; \1 r& n, ]. a- A. M- C! R& D; Q1 A
                         continue;  0 w6 b+ u' Q6 j( k
                     }  
, P" d) m% h6 F% r6 |( R, g, t                     break;  & i- d8 `" K( ^' N. l* w
                  case '-=':  
7 f5 u; R: G" \. f                     $v = substr($v,2);  : R) A9 U% X" ^% E, h! P" ^% L$ b! j
                     if (is_numeric($v)) {  
: X6 G9 S* K1 \9 q                         $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);  
  ?% |6 p* _' s9 k1 A                     } else {  , X  A$ Z( G4 j3 D6 ]$ T, M
                         continue;  
4 d% p; Y! G9 F/ A7 l                     }  7 B" p8 E- Y  z
                     break;  
5 a& Y; T( L. q! y% J/ E0 u/ x                  default:  3 n9 b( ]9 ^1 I
                     $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);  
* F$ l, u2 p1 g9 M& P' I              }  2 X& H, i2 F& v) h* P" A
           }  5 Z& P5 e3 P$ s. _
           $field = implode(',', $fields);  ' j/ G9 f7 ~" `3 u! t! I7 B0 Y
       } else {  * y# X8 P! V* L! N
           return false;  
* `1 [0 z' {% G# s3 y" W       }  
6 d; J' ]+ Y/ S2 ]       $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;  * y# t5 t9 s; }" l) p* p* [1 @' H
       print_r($sql);  
. Q' ?6 M9 y: F% h: v4 ]5 i$ X; Z3 n       return $this->execute($sql);  
7 y3 m- V1 r( w( T    } , o$ A, d* c, Q5 l; A
从头到尾也是没有验证数据库是否存在数组中的字段,然后直接执行SQL语句。也就是说SQL语句中的字段我们可控,导致注入。, Z$ E/ _0 s/ m2 B% k- t

3 }  h8 P7 u# G' |+ ]攻击测试:
: z$ M' Z3 D! X, k0 B5 q测试地址http://localhost
6 G- q/ v# y; z  {  注册会员seay并登陆。打开firebug工具HTML选项。修改birthday的name值为注入语句7 j2 C# e1 i, j" `. s2 f( z* E

+ M5 h, x6 e5 v5 ?0 c* \ 3 J% n" j; O, D$ e( p9 s
/ R0 ^  r2 [6 Q& k/ G& j" l% [' h: @

/ q  r' j" R- W6 s7 i6 f- g1 j3 J' j: _3 X0 D7 Q" W. {& B/ t

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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