起因是平台上羽师傅出的一道环境变量截取和linux通配符的题,原题是平台月饼杯的web3_莫负婵娟。
简单介绍一下环境变量截取构造。
我们都知道linux中有个环境变量$PATH
,它决定了shell将到哪些目录中寻找命令或程序,一般是这样

而linux中,我们是可以通过$
和{}
来提取环境变量中某个或者某些字符串的,比如

因此,按照这种构造方式,我们就可以构造出诸如ls,cat之类的命令,从而达到命令执行的目的

当然还有更多的截取方式
${file#*/}:删掉第一个 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt
${file##*/}:删掉最后一个 / 及其左边的字符串:my.file.txt
${file#*.}:删掉第一个 . 及其左边的字符串:file.txt
${file##*.}:删掉最后一个 . 及其左边的字符串:txt
${file%/*}:删掉最后一个 / 及其右边的字符串:/dir1/dir2/dir3
${file%%/*}:删掉第一个 / 及其右边的字符串:(空值)
${file%.*}:删掉最后一个 . 及其右边的字符串:/dir1/dir2/dir3/my.file
${file%%.*}:删掉第一个 . 及其右边的字符串:/dir1/dir2/dir3/my
具体请看参考,这里只讨论其中一两种方式
按照上述方法,可以构造得到payload
?ip=0;${PATH:5:1}${PATH:2:1} //0;ls
ip=0;${PATH:14:1}${PATH:5:1} ????.??? //0;nl ????.??? (通配符匹配)

但这种截取环境变量的方式在做羽师傅续出的web入门题月饼杯web3's revenge出了问题。
首先打开题目直接是到了月饼杯web3的第二关,并且查看源码提示了信息是命令执行

那么有了上道题的经验,有没有可能再次构造出相应的payload呢,不妨试一下
首先fuzz一下题目过滤了哪些字符

发现,除了几个?
,{}
,~
,#
符号之外,只允许输入大写字母,显然之前用数字截取的方式不再适用
那么注意点放到了这几个仅存的字符上,首先是~
,在实际测试中发现当使用取反对变量进行截取,可以输出变量中的最后一位,比如

而有些环境变量比如$SHELL
,$SHLVL
在大多数环境中是通用的,因此我们就多了几个可以利用的字母
再看到#
号,上面的参考文章中已经知道,#
可以用来截取变量,比如说echo ${var#*//}
是删除左边字符,保留右边字符。而当我再把#
号放到变量左边时,有了意外的结果

得到了数字!而且9正是$PATH
中我想要的数字中字母l
的位置,那么如果我们把这个截取字符串作为截取过程中:
的参数,这个截取有没有效呢,答案是肯定的

nice了,那么现在就可以构造了,看着几个固定的环境变量,构造出了下面的payload
${PATH:~A}${PATH:${#SHELL}:${SHLVL:~A}} //nl
${PATH:${#SHELL}:${SHLVL:~A}}${PATH:${#_}:${SHLVL:~A}} //ls
ps:值得提醒的是,有些环境变量在具体的环境中数值是不一样的,所以有可能失效,所有要视自己的环境而定,我这测试了两台虚拟机
在命令行试了下可以看到是有效的

那么问题就来了,把payload传进入打不通(难受。。。。)
后来问了出题人也说payload没问题,docker可以打通,可能就是php的问题,后来在php中试了下,确实有问题

搜了下这个报错,大概是与linux shell使用的是/bin/sh,还是/bin/bash有关系。。。。
那也没办法处理只好到这里了,虽然没做出来,好在也算学到了个新姿势