-1.阿巴阿巴
为什么要写wp?
0.前言
本次PYCC,哦不,ISCC中pwn的难度算是挺友好的了(没有内核,没有沙箱)。
1.create_id
简单的格式化字符串漏洞改写全局变量x,从而执行后门函数。这题有点问题,给的ELF文件是没开PIE保护的,但是在靶机上是开启了PIE保护。所幸也给了x的地址就是。
exp如下:
1 | from pwn import * |
2.sim_treasure
又是格式化字符串漏洞,不过这次是泄露libc地址加改写got。
改写got涉及到格式化字符串改写大数的知识,32位程序的改写在ctf-wiki上有封装好的函数,直接搬过来用即可。
exp如下:
1 | from pwn import * |
3.跳一跳
保护全开的栈溢出,但是只能溢出0x18个字节。
正常情况是要栈迁移的,但是这题能获取靶机使用的libc版本,并且能够利用one_gadget逃课。(这个不是我想出来的,想出来的大佬太强了orz)
exp如下:
1 | from pwn import * |
4.unlink
标题写着unlink,却完全不需要unlink的屑题(bushi)。
主函数:
1 | int __cdecl __noreturn main(int argc, const char **argv, const char **envp) |
然后给了个后门:
1 | void __cdecl sh(char *c) |
这题就是一个很简单的堆溢出漏洞结合tcache attack,将包含cmd的fake_chunk链入tcache bins,从而将cmd这个指针改为指向free@got,进而而改写got表。
exp如下:
1 | from pwn import * |
5.untidy_note
保护全开。
主要的函数如下:
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
1 | int menu() |
1 | unsigned __int64 create_note() |
1 | unsigned __int64 print_note() |
1 | unsigned __int64 delete_note() |
1 | unsigned __int64 edit_note() |
增删查改四个功能都有。但是增加的堆块大小受到限制,不能超过31字节。
漏洞点存在于delete和edit功能的函数,存在UAF漏洞和堆溢出漏洞。
由于无法创建一个unsortedbin大小的堆块,因此我们的思路是先申请一些堆块,保证这些堆块的实际长度大于0xa0。这样我们可以先通过堆溢出漏洞把其中一个堆块的大小改为0xa0,并不断利用double free来使得其填充完整个管理0xa0大小的tcache bin,之后再次free它时就会进入unsorted bin。这里有个注意点是后期的libc2.27版本对直接的double free有检查机制,因此需要绕过,绕过方法是使e->key==tcache不成立。
之后就是普通的tcache attack了。
exp如下:
1 | from pwn import * |
6.h-o-s
hso(bushi)
其实unlink,h-o-s,Huge_Space三题可以看做关联题(,这三题主函数长得很像,只是禁用了不同的功能。并且保护都是一样的。还都给了后门函数。。。
主函数:
1 | int __cdecl __noreturn main(int argc, const char **argv, const char **envp) |
后门:
1 | void __cdecl sh(char *c) |
bss段:
1 | .bss:0000000000601080 ; =========================================================================== |
这题的漏洞是delete时边界检查不严格,导致ptr-1能被解析为堆指针使之指向内存被释放。而通过bss段知道这块内存我们是能够控制的。
因此我们的思路就是在这块附近伪造一个堆块,使得这个堆块包含cmd这个指针,通过释放ptr-1这个指针指向的堆块(也就是我们伪造的堆块),使得其进入tcache bin,进而使得我们能够改写cmd指向got。
exp如下:
1 | from pwn import * |
7.heapheap
保护全开。
存在offbyunll漏洞。由于不存在能打印出堆块内容的功能,因此考虑劫持stdout来leak。
要爆破半个字节,概率为1/16,具体的前面的博客有讲过。
这里提一件我刚开始犯的很nc的错误:我原先是打算改__free_hook为system,后来发现不行———原因是它在释放堆块前清空了堆块的内容……
exp如下:
1 | from pwn import * |
8.Huge_Space
这一题我做了一周(
主函数:
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
后门:
1 | void __cdecl sh(char *c) |
我这一天的解法应该不能算是正常的解法,仅供参考学习使用。(这题是没给libc的,但是通过测试我发现靶机用的libc和我本机的一样)
前面的栈溢出没有用到,后面的堆溢出我先通过House of Orange释放top chunk到unsorted bin,之后再申请一块0x1000的之前的top chunk就能进入large bin,然后我们就能同时泄露libc和堆地址。
之后再利用House of force将新top chunk的大小改成0xffffffffffffffff,然后通过写入一个负数的值,能将top chunk迁移到got附近,然后改写got。
1 | from pwn import * |