pwn
Elden Ring Ⅱ
一个heap manager相关的题目,glibc 2.31,没有pie,包括add edit show delete四个功能,在delete这里有一个uaf
1 | void delete_note() |
通过uaf 去写 tcache 的 next指针为 puts_got的地址,分配到put_got上,用show去泄露libc_base,然后写free_hook为system,去free一块 内容是/bin/sh的堆
1 | from pwn import * |
fastnote
咱好笨,想了好久才做出来,学到新思路了
1 | int __cdecl __noreturn main(int argc, const char **argv, const char **envp) |
1 | unsigned __int64 delete() |
1 | unsigned __int64 add() |
1 | unsigned __int64 show() |
有 add show delete三个功能,delete那存在一个uaf,这个麻烦的地方往堆块写入数据和创建堆块的功能合在一起了,也就是不能直接通过uaf往free掉的堆块里面写数据,但是可以通过double free fastbin构造一个这样的链 main_arena -> A -> B -> A
通过第一次malloc往 A fd位置写入free_hook的地址,这样这个链就变成 main_arena -> A -> B -> A -> free_hook
第二次malloc把B卸下来,第三次malloc把A卸下来,第四次malloc就会分配到free_hook那了
在free_hook中写system的地址,然后去free一个内容为binsh的堆,相当于执行system(binsh)
然后还有个问题就 通过unsortedbin去泄露libc那,如果unsortedbin和top chunk中间没有东西挡着的话,会合并在一起,因为程序有pie,那只能通过unsortedbin去泄露main_arena的地址算libc的基地址,如果没有pie的话,那改fastbin 或者 tcache的fd next为got表然后show就能泄露了,不过这里edit和add合在一起了,tcache bin有一个key的检查,所以通过tcache bin的思路是不行的
exp
1 | from pwn import * |
ShellcodeMaster
好巧妙这一题,没有pie 有一个沙箱 把execve 和 execveat给禁用了
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
有个mprotect() 把写的权限给去掉了,然后在后边有这么一段把mprotect(buf, 0x1000uLL, 4); 残留的寄存器给清空了,还有rbp rsp也改成 2333h,也就是不能通过push pop去修改寄存器,push和pop 指令只占一个字节,0x16字节打orw显然是不够的,思路是用mprotect把mmap出来的段写的权限恢复,然后再read一遍
1 | .text:0000000000401386 49 C7 C7 00 30 33 02 mov r15, 2333000h |
但是搓了很久,最短的汇编都要23个字节,差一个字节
1 | shellcode = asm(''' |
执行完mprotect后 rcx寄存器 有一个地址是能用的,可以用rcx寄存器作为基地址残留下来的rdx作为read的长度再read一次,然后通过输入修改rdx寄存器 再syscall一次read,但是 0x7的长度 算上填充就不够用了,后面发现 mprotect是有四个标志位的,所以 rdx为0xf也是能mprotect成功的,试了一下五个标志位,发现mprotect失败了,所以rdx最多为 0xf。0xf的话长度就够了,这样就通过两次read 间接的修改寄存器绕过了长度限制,然后写orw就好了
exp
1 | from pwn import * |
old_fastnote
和fastnote的代码逻辑一样,但是glibc变成了2.23,没有tcache,fastbin attack的时候会对size位做一个检查,如果不符合fastbin的大小就会报错,在__malloc_hook - 0x23的位置有一个合适的”size”位,通过fastbin attack 在 malloc_hook - 0x23位置分配一个chunk,然后把mallc_hook改成one_gadget就打通了
1 | from pwn import * |