[write-up] Insomni'hack Teaser - Smartcat 1 & 2

This years Insomni'hack teaser, an internet-of-things themed capture-the-flag contest, lasted 36 hours and started on Jan 16 at around 10 am local (Berlin) time. I decided to participate together with a couple of guys from the workgroup for computer security of TU Berlin, the AGRS. So I woke up in time and made my way through the snow covered city of Berlin to arrive at an still empty room of the TU just before 9 o'clock.
I always try to arrive early as that gives me some time to set up all scripts, the proxy, folders and files and have a read thorugh some old tasks of the upcoming CTF. I lurked in the IRC channel for a while to pick up some hints and other information that might flow around and when the task descriptions appeared at 10am I was ready to go.

Smartcat 1 Challenge

The first thing I normally do is looking through all the challenges and make note of the ones that list web as a category.
"Smartcat" was one of them so I picked this one to start.

The description talked about a cat litter that was controllable through a web interface. The task was to receive the contract-number from the service that seemed only capable of doing a simple ping-request.

Damn it, that stupid smart cat litter is broken again
Now only the debug interface is available here and this stupid thing only permits one ping to be sent!
I know my contract number is stored somewhere on that interface but I can't find it and this is the only available page! Please have a look and get this info for me !
FYI No need to bruteforce anything there. If you do you'll be banned permanently

And provided a link to the challenge site:

The smartcat web application

The link lead us to a cgi-script that sits in the cgi-bin directory. The source was not available to us although I later managed to download it from the site using the vulnerability.
Visiting this page showed the following:

I entered a few IP addresses to see if this thing worked (it did) and started thinking what could be wrong here.
The output that you can see above looks similar to the output of the ping command that you run from the command line. So I figured that the script probably passed the entered ip-address to a shell command.
This screams command injection.

Command Injection

I got to work by trying the usual way of exploiting command injections which is injecting a new command by appending it to the current command in some way. That could be by using a pipe "|" to pipe the output of a command to another command, a semicolon ";" to separate two commands and "&&" to execute two commands together. None of these seemed to work.
Whenever I entered one of several characters like a whitespace, or one of ";$&({" I recieved an error that an invalid character was submitted.

By injecting a newline "%0A" together with a command like "ls" (including none of the forbidden characters):
I reveived some new output:

PING ( 56(84) bytes of data.
 64 bytes from icmp_seq=1 ttl=64 time=0.015 ms

 --- ping statistics ---
 1 packets transmitted, 1 received, 0% packet loss, time 0ms
 rtt min/avg/max/mdev = 0.015/0.015/0.015/0.000 ms

We can see that the current directory is home to the script that we currently access and a folder: "there".
Submitting<index.cgi yielded us the source code of the script:

 #!/usr/bin/env python
 import cgi, subprocess, os
 headers = ["mod_cassette_is_back/0.1","format-me-i-im-famous","dirbuster.will.not.help.you","solve_me_already"]

 print "X-Powered-By: %s" % headers[os.getpid()%4]
 print "Content-type: text/html"

 print """
 <head><title>Can I haz Smart Cat ???</title></head>
  <h3> Smart Cat debugging interface </h3>

 blacklist = " $;&|({`\t"
 results = ""
 form = cgi.FieldStorage()
 dest = form.getvalue("dest", "")
 for badchar in blacklist:
  if badchar in dest:
   results = "Bad character %s in dest" % badchar

 if "%n" in dest:
  results = "Segmentation fault"

 if not results:
   results = subprocess.check_output("ping -c 1 "+dest, shell=True)
   results = "Error running " + "ping -c 1 "+dest

 print """

  <form method="post" action="index.cgi">
  <p>Ping destination: <input type="text" name="dest"/></p>
  <p>Ping results:</p><br/>
  <img src="../img/cat.jpg"/>
 """ % cgi.escape(results) 

Since no flag can be found here I tried to figure out what was in that "there" directory that I found with the "ls" command.
I could however not just submit "ls there" as there is a whitespace in that.
After a while I ended up going with the "find" command without any parameters:
That resulted in the following output:

The file was not accessible through the web interface so I used the "cat" command like before to receive the flag:<there/is/your/flag/or/maybe/not/what/do/you/think/really/please/tell/me/seriously/though/here/is/the/flag



Just as I finished this task the door opened and another team member appeared. It was Sebastian from Internetwache.org.

The second part was a bit harder but together with him I finsihed the second part as well. How we did it?
Have a look at his blogpost about the smartcat 2 challenge.

Denis Werner