/dev/random: Sleepy

Looks like I’ve got time to write up another recent VM challenge before the memory fades. This time, it’s boot2root challenge Sleepy by Sagi-.

I really like this one because it took me back to my University days of Java development. Then I hated it because it took me back to doing acrobatics with I/O readers, buffers, streams, etc. the Java way. Then when I completed it I loved it.

On with it then!

Initial scanning

Starting off with a full TCP SYN scan produce three open ports.

TCP 21 is FTP, and it allows anonymous login:

Anonymous is rightly jailed and there’s only an image to download:

sleepy

I thought that the image might hold some essential information or clues, but I wasn’t able to find any. Not sure if it’s a motif or a red herring.

Assuming FTP’s a red herring, attention turns to the other two open ports. Running a service scan on the ports might confirm what protocols they’re offering:

So with ajp13 confirmed as Apache Jserv, I guess we’re looking at something Tomcat. Probably my first thing to start work on.

At this stage I had never heard about Java Debug Wire Protocol, but a quick search tells me it’s a remote Java debugger.  This should be great. I still like working with Java, so if I get to play around with a debugger I’ve never seen that’s cool.

Dealing strictly with Apache Jserv first, however…

AJP

As AJP has accidentally been left open to the world, it might be possible to exploit the system, for example by injecting malicious code to the server. In order to control it, though, I need access to some Tomcat management interface to test it.

Exploiting an open AJP is pretty well documented by others so I’ll not go into to much commentary on it. I needed to set up Apache on my machine, and add the Apahce jk modules. Then configuring jk to forward requests – not to my local server, but to the victim – it should be possible to try and get management access.

libapache2-mod-jk provides the following files:

The default Apache website needs to forward all requests to JK, and JK needs to be configured to forward requests to the victim.

After restarting Apache, it’s possible to connect to http://localhost/ and see all of the Tomcat goodies including /manager/ and /host-manager/ on the victim. However, the passwords are not the defaults and attempting a few passwords didn’t prove successful.

Tomcat

Getting access is going to require viewing the administrative passwords – often stored in plaintext – from the server.

The Java debugger

The JDWP port appears to be controlled by the jdb command which provides a remote shell for control. It’s not a shell with the breadth of control that a terminal would provide – everything has to be done via Java execution – but hopefully with enough libraries exposed something can be conjured up.

The help is pretty good for jdb. Command classes outputs a list of all classes that are available to the running program, and classpath shows that we seem to be running Java 7…

Above we’ve got a hell of a lot of Java standard library classes available, plus a class which is named without a long package name – luciddream. This is presumably the author’s work, and given the Sleepy theme, that’s a fair guess.

It’s unfortunately not possible to just execute arbitrary Java from the prompt:

Instead control of execution needs to be seized by the debugger. The main class has only one function other than main and the constructor:

Setting a breakpoint on snore() and waiting eventually gives us control and at that point we can execute any arbitrary Java code we want, using the available classes:

Great! So, with all of the java.io classes we can potentially exfiltrate file data from the victim, or possibly even inject data. Also with java.lang.Runtime we’ve got access to the current thread and can execute arbitrary commands.

The thing is, merely executing a command will merely return the object representing the new process, not the response to the command. For example, running whoami:

To actually get output from the command, some I/O acrobatics is required. Working with what we’ve got (and I probably am not doing it in the most efficient manner), we’ve got the following return values and methods to link up.

  • exec() returns an object of type Process, let’s call it p.
  • p.getInputStream() returns an object of type InputStream, i
  • Ultimately we’re looking to get a String, s, which can be output to the console
  • Out of the many readers available, BufferedReader, r, offers method readLine() which returns a String, s
  • A BufferedReader, r, can be instantiated with an InputStreamReader, ir
  • An InputSteamReader, ir, can be instantiated with an InputStream, i, which we got earlier

Got that? Good.

  • exec() gives us Process p
  • p.getInputStream() gives us InputStream i
  • new InputStreamReader(i) gives us InputStreamReader ir
  • new BufferedReader(ir) gives us BufferedReader r
  • r.readLine() gives us String s

Putting this into practice, we can attempt to run whoami again:

Unfortunately things get a bit more complicated when the result of the command is multiple lines. We only get one call to readLine() on the BufferedReader, so only the first line of output can be retrieved. e.g. ls -la produces a weak result:

To get full output, line feeds need to be replaced with another string – e.g. by using awk ORS=’something’ – and in order to build more complicated commands with pipes and so on, we need a command processor, e.g. bash.

Voila:

Using this methos I did a search for files with tomcat in the name and got the following (edited) list:

Dumping this file gives us the passwords we require (again, edited for reading):

Credentials

TomcatManager

Exploiting Tomcat

Exploiting isn’t the right word here, as we own Tomcat now. We can easily get control as the Tomcat user with Metasploit and the credentials. (Remember that the rhost/target is our own machine as we’re attacking the victim through our Apache server:

We’ve not got a reasonable user shell on the system.

Privilege escalation

It’s getting quite late and I don’t want to make an already verbose walkthrough too much longer. In summary the following items were found in further investigation and are able to lead to privilege escalation.

First of all the machine is vulnerable to shellshock:

This may seem counter intuitive when we already have a shell, but it will come in essential later.

Furthermore there is an executable /usr/bin/nightmare that has SUID bit set and is owned by root. Since this runs as root, if we can get something arbitrary to run from this, then we can gain access as root.

I found the Meterpreter session to be extremely unstable for what happens next – I kept getting disconnected – so I uploaded nc to the victim and opened a reverse shell back to my machine:

And locally on my machine we can get a decent interactive shell:

nightmare needs some better terminal emulation configured, so this can be set up by setting environment variable TERM to ‘linux’ and using Python to spawn a proper tty. (FYI, to enter Ctrl-C in the terminal enter Ctrl-V first; this allows the Ctrl-C to be sent through to the remote host’s control instead of killing the Meterpreter session.)

Here’s what happens when /usr/bin/nightmare is executed normally:

Decompiling nightmare with Hopper, it’s easy to see what it’s doing. main() runs a loop (sub_4008d0()) which repeatedly calls fire(), which executes the command /usr/bin/aafire which is what’s responsible for animating the ASCII-art fire. The option to quit the program at the y/n prompt is ‘broken’ but by pressing Ctrl-C we enter sigHandler() which calls train(), which executes /usr/bin/sl – the executable responsible for the ASCII-art train. However, crucially this call sets the real/effective/saved UIDs and GIDs to root preventing a reduction in privileges if we can explioit Shellshock.

After finding a method to exploit that I hadn’t seen before, it was possible to get a root shell and get the flag.

Done!

Leave a Reply

Your email address will not be published. Required fields are marked *