time_formatter题解
前置知识
简单的说,Use After Free 就是其字面所表达的意思,当一个内存块被释放之后再次被使用。但是其实这里有以下几种情况
- 内存块被释放后,其对应的指针被设置为 NULL , 然后再次使用,自然程序会崩溃。
- 内存块被释放后,其对应的指针没有被设置为 NULL ,然后在它下一次被使用之前,没有代码对这块内存块进行修改,那么程序很有可能可以正常运转。
- 内存块被释放后,其对应的指针没有被设置为 NULL,但是在它下一次使用之前,有代码对这块内存进行了修改,那么当程序再次使用这块内存时,就很有可能会出现奇怪的问题。
而我们一般所指的 Use After Free 漏洞主要是后两种。此外,我们一般称被释放后没有被设置为 NULL 的内存指针为 dangling pointer。
静态分析
运行程序是一个菜单,十有八九是堆题
ida反汇编,开始静态分析,为方便分析,将部分函数,变量重命名
ret_ptr()函数中fgets(str, 1024, stdin);
从标准输入读取字节
str[strcspn(str, "\n")] = 0;
返回第一个”\n”的下标并将其置null
size_t strcspn(const char *str1, const char *str2) 检索字符串 str1 开头连续有几个字符都不含字符串 str2 中的字符。该函数返回 str1 开头连续都不含字符串 str2 中字符的字符数。
1 | __int64 ret_ptr() |
malloc_heap()函数中v1 = strdup(str);
strdup函数类似malloc,可以从堆上分配参数str字符串大小相同的空间
**char *strdup(const char *str)**将字符串复制到新建立的空间,该函数会先用malloc()配置与参数str字符串相同的空间大小,然后将参数str字符串的内容复制到该内存地址,然后把该地址返回。
1 | char *__fastcall malloc_heap(const char *str) |
check_format()函数中strcpy(accept, "%aAbBcCdDeFgGhHIjklmNnNpPrRsStTuUVwWxXyYzZ:-_/0^# ");
将特定字符复制到字符数组中
strspn(str, accept) == strlen(str);
将用户输入的字符串与特定字符比较,如果用户输入的字符全部属于特定字符中,则返回true(1),否则返回false(0)
size_t strspn(const char *str1, const char *str2) 检索字符串 str1 中第一个不在字符串 str2 中出现的字符下标。该函数返回 str1 中第一个不在字符串 str2 中出现的字符下标。
1 | _BOOL8 __fastcall check_format(char *str) |
print()函数中__snprintf_chk(command, 2048LL, 1LL, 2048LL, "/bin/date -d @%d +'%s'", bss, ptr);
是将"/bin/date -d @%d +'%s'",bss,ptr
,%d对应bss,%s对应ptr,写到command数组中
1 | __int64 print() |
漏洞利用
程序流程大概看的差不多,下一步寻找漏洞点
exit()函数内调用free却没有将指针置空,存在uaf
上述print()函数调用system(command);
存在命令注入
1 | void __noreturn exit(int status) |
有了这两个漏洞,我们想一想如何利用
最为直观的想法,就是命令注入执行system(/bin/sh);
我们可以注意到__snprintf_chk(command, 2048LL, 1LL, 2048LL, "/bin/date -d @%d +'%s'", bss, ptr);
参数ptr可以将用户的输入写入command,但是输入参数ptr中的内容会被check_format()函数检查,只有输入的字符全部符合才能通过,直接写是肯定行不通的,这时uaf就派上用场了
首先,我们先进菜单1,执行strdup(str);
分配堆空间后,ptr指向这段堆空间(保证分配的空间free后能进fastbin或tcache)
进菜单5,free(ptr),ptr指向的这段内存空间会放在fastbin(glibc >= 2.27,则会放入tcache),ptr成为悬空指针
进菜单3,执行strdup(str);
尽量保证分配字节数与第一步分配的一致,这样使得malloc的内存是刚刚放入fastbin的内存,现在value和ptr两个指针指向同一块内存,这样修改value指向的内存实际上也是修改ptr指向的内存,这就绕过了只能输入特定字符的限制
当然此程序没有提供edit功能,所以我们在进菜单3时就将payload构造好,"/bin/date -d @%d +'%s'"
在原先的command字符串上,我们可以动手脚的地方就是%s
,显然,直接填/bin/sh是'/bin/sh'
行不通。我们可以用''
闭合,;
分隔command命令,使其可以执行;
前和;
后的命令,同时pwntools中sendline(b’’’’)语法是错的,所以需要\
转义,最后payload应为sendline(b'\';/bin/sh\'')
x32:fastbin中chunk范围0x10-0x40,最小的chunk为0x10
x64:fastbin中chunk范围0x20-0x80,tcache中chunk范围0x20到0x410,一般情况下最小的chunk为0x20
1 | from pwn import * |