Tags: networking

Rating:

Another cool network challenge!


Homework Help
Could you help me with my homework? I think the professor's solution is broken.

Difficulty: hard


We start with a traditional nmap over the challenge subnet

Starting Nmap 7.60 ( https://nmap.org ) at 2019-03-03 20:34 CET
Nmap scan report for 172.30.0.2
Host is up (0.20s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
80/tcp open http

Nmap scan report for 172.30.0.3
Host is up (0.20s latency).
All 1000 scanned ports on 172.30.0.3 are closed

Nmap scan report for 172.30.0.4
Host is up (0.20s latency).
All 1000 scanned ports on 172.30.0.4 are closed

Nmap scan report for krzysh-laptop (172.30.0.14)
Host is up (0.000076s latency).
[this is my computer]

Nmap done: 16 IP addresses (4 hosts up) scanned in 69.97 seconds


This is the website running on 172.30.0.2:
![image](https://user-images.githubusercontent.com/1517255/53700628-9d301780-3df4-11e9-95ff-84144c61d82e.png)

We seem to have something that runs python, so let's just try os.system()...
![image](https://user-images.githubusercontent.com/1517255/53700697-4840d100-3df5-11e9-88d0-94997f4d9cc1.png)
And there we go, we got the fla... wait, if that was the case this challenge wouldn't be marked as hard, would it?

There is nothing interesting we have access to on the server, but you can notice that the name returned by "whoami" matches the website login in the top-right corner. Perhaps if we could log in as root, things would be different? But if we try to log out we get a message saying "Not important to the challenge; didn't implement it." What now?

Don't forget this is a network challenge and we haven't even looked at the other hosts yet. Let's just arp spoof all the communication between them and see what is happening when we send the code to be executed.

The answer: a lot of SSL traffic going to port 5671, we'll probably have to decrypt it somehow. But first, let's check what we are even dealing with:

[email protected]:~ \$ openssl s_client -connect 172.30.0.4:5671
hello, is anyone there?
AMQP ?closed

Quick googling reveals that AMQP is Advanced Message Queuing Protocol, and the thing that is most likely running on it is RabbitMQ. I have absolutely no experience with RabbitMQ so I have no idea how to set up my own spoofed server, but that turned out to not be necessary.

First, I would like to somehow intercept the encrypted communication and see what information is actually getting exchanged. Getting that to work properly was suprisingly difficult - sslsniff kept segfaulting on startup and I couldn't figure out why. In the end I switched to sslsplit which worked fine:

sudo iptables -t nat -A PREROUTING -p tcp --destination-port 5671 -j REDIRECT --to-ports 1234
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 1826 -key ca.key -out ca.crt
mkdir /tmp/sslsplit logdir
sudo sslsplit -D -l connections.log -j /tmp/sslsplit -S logdir/ -k ca.key -c ca.crt ssl 0.0.0.0 1234
cat logdir/*

![image](https://user-images.githubusercontent.com/1517255/53700985-bb981200-3df8-11e9-9524-304f4f464b88.png)
Looks like our assumptions about RabbitMQ were correct, and BINGO!

{"user": "alice", "assignment": "assignment_one", "code": "import os\nos.system(\"whoami\")\nos.system(\"pwd\")\nos.system(\"ls -la\")"}

It looks like we have to swap out the username here for "root". This turned out to be harder than I would have thought - I couldn't find any tools capable of modifying arbitrary SSL communication on the fly, everything I looked at was tailored specifically for HTTPS. At some point I read that mitmproxy which would be my go-to tool if this was HTTPS has experimental support for raw TCP mode, so I switched to using that...

mitmproxy --mode transparent --listen-port 1234 --ssl-insecure --tcp-hosts 172.30.0.2 --tcp-hosts 172.30.0.4

... but after getting it all set up, I realized that the docs on raw TCP say

* The raw TCP messages are printed to the event log.
* SSL connections will be intercepted.
Please note that message interception or modification are not possible yet. If you are not interested in the raw TCP messages, you should use the ignore domains feature.

Aaaargh, too bad. So what do you do when you can't find a tool that does what you need it to do? You ~write it yourself~ brutally hack the closest thing you have to do what you want. I ended up finding the packet handling code in mitmproxy and hacking it like this:
diff
diff --git a/proxy/protocol/rawtcp.py.bkp b/proxy/protocol/rawtcp.py
index 0ec5059..2ff5f29 100644
--- a/proxy/protocol/rawtcp.py.bkp
+++ b/proxy/protocol/rawtcp.py
@@ -50,7 +50,10 @@ class RawTCPLayer(base.Layer):
return
continue

- tcp_message = tcp.TCPMessage(dst == server, buf[:size].tobytes())
+ x = buf[:size].tobytes()
+ x = x.replace(b'"user": "alice",', b'"user": "root", ')
+ print(x)
+ tcp_message = tcp.TCPMessage(dst == server, x)
if not self.ignore:
f.messages.append(tcp_message)

Now we just click "Run" on the website again and...
![image](https://user-images.githubusercontent.com/1517255/53701134-50e7d600-3dfa-11e9-9d72-a6b44c7ed80d.png)
The rule of thumb on CTFs is "if it looks stupid but it works it's not stupid", and this certainly worked. The flag is gigem{a_chain_is_only_as_strong_as_its_weakest_leporidae}