pwn1
存在uaf,另外需要在栈上伪造一个chunk头
1 | from pwn import* |
pwn2
这题死活没做出来,主要是不知道怎么leak(如果当时再仔细一点或者去看一下源码也许就能做出来了,我是个憨憨嘤嘤嘤
leak
先看一下函数调用链
1 | #0 __GI___libc_write (fd=1, buf=0x7ffff7dd3708 <_IO_2_1_stderr_+136>, nbytes=219) at ../sysdeps/unix/sysv/linux/write.c:27 |
1 | int |
这里其实就是调用了vtable中的_IO_new_file_xsputn
1 | _IO_new_file_xsputn (_IO_FILE *f, const void *data, _IO_size_t n) |
这里省略了一些代码,最终会调用_IO_OVERFLOW,前面在检查缓冲区还有多少空间
1 | int |
一半情况下flags都为0xfbad2887所以前面的if都可以绕过,最终会调用_IO_do_write
1 | int |
1 | new_do_write (_IO_FILE *fp, const char *data, _IO_size_t to_do) |
为了能绕过else if 有两种方法
- fp->_flags & _IO_IS_APPENDING(0x1000) == 1
或者
- fp->_IO_read_end == fp->_IO_write_base
exp
因为好久没做堆题,exp写的有点烂,看到网上有师傅通过控制tcache_struct来任意地址写,很舒服
1 | from pwn_debug import* |
pwn3
装个ghidra整了两三天,之前一直下载的github上给的release但那个需要自己构建,我还以为是自己java环境的问题,原来是因为我和ghidra官网隔了一堵墙
modify功能会溢出8字节,利用溢出修改下一个chunk的header,构造unlink
大概长这个样子
1 | 0x412000: 0x00000000 0x00000041 0x00000000 0x00000039 |
exp
1 | from pwn import* |
pwn5
这题还是学到很多东西的,当时看到的时候毫无思绪,我妄想通过栈上的libc地址改one_gadget,但是怎么从while中出来我都不知道
看了大师傅们的博客总结了一下大概思路:通过栈链修改栈上_IO_2_1_stdout的fileno为2标准错误,然后就可以泄露地址,因为栈上的_IO_2_1_stdout在低地址处,所以需要将printf函数的返回地址改为start进行抬栈,leak出libc后通过栈上的_libc_start_main将malloc_hook改为one_gadget,最后通过printf大量字符调用malloc实现控制程序流
需要注意的是关闭标准输出后printf最多只能打印0x2000左右个字符
exp
因为程序关闭了标准输出所以需要重定位stdout或者sh flag
1 | from pwn import* |
这题官方wp出来了,但我建议爬
1 | 0x7ffff7a58712 <printf_positional+2482> ret <0x7ffff7a5a4b6; vfprintf+822> |
1 | pwndbg> p /x 0x7ffff7a0d000 + 0x4527a |