填了之前“CTF中的命令执行及Bypass”的坑了属于是
有长度限制的命令执行总结
参考1:p牛博客
参考2:博客
参考3:博客
参考4:挖洞经验
shell的一些tricks
重定向之>与>>
>
:覆盖文件内容
>>
:追加内容
w
w - Show who is logged on and what they are doing.
长度最短的命令
使用w>filename
可以以极短的长度生成名为filename
的文件
sh
sh -c *
:会把*
当作命令执行,若当前目录下有一个名为whoami的文件,则用*
作为文件名通配符,相当于执行sh -c whoami
sh filename
:相当于./filename
ls排序
List information about the FILEs (the current directory by default). Sort entries alphabetically if none of ….
默认排序
ls的默认排序大概有以下特点
数字 > 字母
无视符号
不管加不加符号、加什么符号(包括空格),都会按照字母排序
无视大小写
时间排序
ls -t
可以按时间排序列出
按序生成四个文件,默认排序为first forth second third
(首字母)
ls -t
按时间排序为forth third second first
(最新的排最前)
命令续行 ‘\’
Linux下可以使用\
进行命令续行,实现命令拼接
通配符 ‘*’
可以匹配任意长度的任意字符,最简单的利用:
若单独执行一个*
,则会把第一个文件名当作命令,剩下的文件名当作参数
生成两个文件,其中文件名为echo
的文件在使用通配符时被当作命令执行了
内容反转rev
就是把内容从右到左显示
dir的妙用
参考博客说了两点和ls的区别:
- 一是开头字母是d ,这使得它在 alphabetical 序中靠前
- 按列输出,不换行(这其实是因为ls用换行符分割文件名)
这里主要介绍写文件的一个操作
- 若是
ls>a
,会把a也写入a文件中 - 若是
ls echo hello>c
,c文件里的内容会换行 - 用
dir echo hello>b
,既可以只写入echo hello,又可以避免换行
突破命令长度限制
七长度限制
拥有了上面的一些tricks,就可以把他们结合起来了
思路:
首先准备好要执行的命令(例如
cat /flag
)将命令拆分(这里不能直接使用
cat /flag
拆分,因为文件名中不能含有/
)可以使用之前博客提到过的编码bypass(思考了一下,这可能是唯一可以不出现
/
的bypass了?)- 16进制:
echo hexString|xxd -r -p|bash
- base64:
echo base64String|base64 -d|bash
- 16进制:
将拆分的命令后面加上
\\
- ls文件列表以换行符分割文件
- 第一个
\
是为了伪造命令续行执行的效果,第二个\
是为了转义ls的换行符
按照时间逆序生成文件名,注意空格和
|
需要用一个\
转义,生成后ls -t
可以看到命令已经按序拆分完毕bash下可以直接用
>filename\\
,zsh下就不行,大概也是差异之一,总之长度倒是都能控制在7个字符以内将文件按时间排序后重定向到新文件,并使用
sh filename
命令执行可以看到
0
文件的内容与多行命令拼接执行一样,sh 0
能够成功执行cat /flag
的命令
五长度限制
五长度和七长度最大的区别是ls -t>0
长度为7,如果不能执行ls -t>0
,就没办法让文件名按序排列以达到命令执行的效果,所以需要构造出ls -t>0
的命令执行
其他的命令并不影响五长度和七长度,
w>filename
可以用>filename
,sh 0
也小于五长度
首先先生成文件名后写入
a
文件,ls
看一下可以按默认顺序排的话不是我们想要的效果用
ls>>a
将ls
打印的信息追加到a
文件中在参考博客中,我们使用了同样的方式生成文件名,但是最终的排序效果并不一样
参考博客里的顺序是
\ -t\ >0 l\ s\
,因此可以通过简单的追加变成\ -t\ >0 l\ s\ \ -t\ >0 l\ s\
,形成中间l\ s\ \ -t\ >0
,造成命令执行的效果但是我的(bash和zsh都这样)顺序不一样,不太清楚是什么原因造成的
其实我们达不到上述参考博客效果的主要原因在于
ls
排序方式不同,那我们只要让文件名能按我们想要的顺序排列就行了思考:首先我们得确定什么是我们可以控制的什么是控制不了的,在这些文件名中,
ls -t>filename
这段指令,我们需要让他按顺序排列,ls
和空格
是我们控制不了的,但是-t
(可以添加别的参数)和filename
是可以控制的,以此来构造文件名先放payload:
ls -At>b
原理:
首先是
ls -At
,man ls
查看执行效果
容易看出其实就是有没有显示
.
和..
的区别,加上参数-A
是为了让At
排序排在ls
前面接着是文件名为什么要用
b
:因为我们需要让>filename
排序排在At
后面,若使用>0
,由于数字排序会在字母前面,因此我们让文件名为排在A
后面的字母就可以了
命令执行效果
拆分
echo Y2F0IC9mbGFnCg==|base64 -d|bash
这里不可以直接拆分,因为限制五个字符长度的话
>\需要转义的符号\\
,像这样一个需要转义的符号就要占了5个字符,而我们这里有空格
、|
两个需要转义的符号,空格还好一点,可以用${IFS}
替换,但是管道符我找了好久都没找到有什么替换方式,因此我的想法是先echo Y2F0IC9mbGFnCg==|base64${IFS}-d>0
把cat /flag
写入文件,再cat 0|bash
去执行第一步执行效果
拆分
echo Y2F0IC9mbGFnCg==|base64${IFS}-d>0
第二步执行结果
拆分
cat 0|bash;
五长度流程总结:
拆分
ls -At>b
,通过ls>d
和ls>>d
构造命令执行拆分
echo Y2F0IC9mbGFnCg==|base64${IFS}-d>0
执行第一步的d文件
sh d
,生成b文件(b文件内容为步骤2的命令)执行b文件
sh b
,生成0文件(0文件内容为cat /flag
)拆分
cat 0|bash;
执行第一步的d文件
sh d
,生成b文件(b文件内容为步骤5的命令)执行b文件
sh b
,达到执行命令cat 0|bash
,获取到flag
四长度限制
惯例先说明四长度和五长度的区别,主要在于ls>>d
,追加d文件内容这个命令用不了了,因此构造不出ls -At>b
这条命令
四长度和五长度的区别其实不在于
>\ \\
需要5个长度因为命令行中我们使用
>ab\\
,其中第一个\
是为了转义第二个\
,防止命令行将其识别为命令续行的标志在php中,exec执行的命令则不用在最后转义
\
,因此可以节省一个字符
我们的主要思路还是要放在怎么构造出ls -t>0
这种可以将文件名按时间顺序写入文件的指令,这是限制长度getshell的关键点
先说构造:
先构造
dir 'e>' Ft- sl
这几个文件名,执行*>v
,将dir后面三个文件名写入v文件作为ls的参数,其实和t一起使用的参数只要字母表排序在d之后在s之前的不止一个可以用,参考博客里选用的是h,我们就用个F吧
至于文件名为什么是e也很好理解,因为要比d后比F前,就只有一个e了…
接着生成
rev
文件,执行*v
- 因为通配符的原因,
*v
相当于rev v
,也就是将v文件内容反转了,构造出了ls -tF >e
的命令,可以说是点睛之笔 - 接着只要写入y文件并执行就可以了
- 因为通配符的原因,
到这里生成了y文件就已经可以结束了,剩下的内容就和五字符长度一样,只不过因为命令行需要多一个
\
来转义\
,所以才会需要五个字符,实际上通过php传参的话只要四个字符就够了
其他思路为什么不可行之一
一开始还想着为什么要这么麻烦,因为如果建立如下的几个文件的话,不就可以执行
ls -t >u
了嘛但是执行
*
的时候发现了,当文件名里面存在需要转义的字符时,他会加上单引号,防止被识别为关键字,因此相当于执行ls -t '>u'
,和ls -t>u
是不一样的,因此还是需要将文件名写入文件中再执行其他思路为什么不可行之二
经过之一后,又在想了,可不可以利用一下
dir
呢,如果现在目录下的是dir ls -t '>u'
,我执行*>z
的话,就相当于把ls
、-t
、>u
写入了z文件,再执行z文件就可以构造ls -t>u
了但实际上要注意
*
第一个是命令不假,但是其后均为命令的参数,也就是说实际上等于执行dir -t ls '>u'
,是将ls
和>u
按时间顺序写入了,还是不对
总结
其实通篇的关键点都在于如何构造ls -t>?
的命令,因为只有这样才可以让文件名按我们可以控制的顺序写入文件,然后通过sh ?
去执行命令;对于文件名,因为文件名不能重复,因此当找不到替代时(比如空格可以用${IFS}
替代,>
可以用${PS2}
,+
可以用${PS4}
等,但是管道符|
我就没找到替代方式)就需要拆解命令,将一部分命令写入比如a文件,再构造cat a|bash
之类的命令构造命令执行,总之姿势很多,几乎可以构造任意shell