pwnable刷题笔记一
- 开始认真刷题了嘤嘤嘤…..先从pwnable.tw开始吧
- 做了第一行, 来记个笔记
start
- 纯汇编题, 然后调用基本上查询32位Linux函数调用规则就能写出shellcode
- 但总结起来还是栈题的基本思路之一
- 一. 想办法泄露栈基址
- 二. 写shellcode打过去
orw
- 标题其实已经暗示了, 这是一道沙箱逃逸题
- 具体的沙箱知识我就不贴了, 大佬们写的博客有很多, 我就自己总结一下思路吧
- 用seccomp-tools查看一下可用的函数, 当然在本题中, 用ida也可以查看到.
- 再看ida, 这里有个点提一下, 具体的沙箱内容等我下次写个专题…
- 当option为PR_SET_NO_NEW_PRIVS(38),且arg2为1时,将无法获得特权,当option为PR_SET_SECCOMP(22)时,效果就是seccomp了,如果arg2为SECCOMP_MODE_STRICT(1),则只允许调用read,write,_exit(not exit_group),sigreturn这几个syscall.如果arg2为SECCOMP_MODE_FILTER(2),则为过滤模式,其中对syscall的限制通过arg3用BPF(Berkeley Packet Filter)的形式传进来,是指向struct sock_fprog数组的指针.
- 因为文件有read函数…还提示了写shellcode…那当然是execve打过去 :)
- 这里shellcode的基本写法说一下:
- 先清理环境, 基本上调用的用到的寄存器都需要清理
- push ecx只是单纯的让栈增长一下
- 放进shellcode注意计算机的大端小端
- 向寄存器中放入相应值时尽可能考虑重复性来节省shellcode长度(比如固定的shellcode字符地址…)
- 用nop适当间隔
- 注意最后的add esp, xxx来恢复堆栈平衡,然后ret.
calc
- 重点在calc函数里
- bzero是清零函数, get_expr是获得常规的计算操作符和数字
- parse_expr函数是关键的解析函数, 还好以前实现类似计算器功能的程序, 简单来说就是操作符和操作数分开.
- 虽然分成了两个类似栈的结构来存储, 但这里还是能看出区别, 即存储数据的数组头部是一个类似index作用的数字,这有点意思,其实就是后面的漏洞点
- 然后这里是对操作符的处理和存储. 其中operate[v7]是上一个存储的操作符, 而(char)(i+a1)是当前遇到的操作符,然后进入eval函数操作
- 可以看到eval函数的处理是将结果计算并存储到下标为1的数组单元
- 行吧parser_expr函数逻辑大致清楚了,咱回到calc函数来,这里是输出了v2[v1-1]的内容, 查看一下栈,发现是输出了之前存储数据数组的头部,即index值,好了思路又来了,尝试修改index值来泄露出数组范围外的数.
- 具体的思想历程就不说了, 这里是输入类似 ‘+361’的数据来运用该计算器的规则来使index变为我们想要的值.
- 贴exp
- 这里有些小技巧点, 比如计算栈空间长度, 根据该函数ebp泄露主函数基址,然后在进行偏移计算等. and 老样子execv(‘/bin/sh’)
3x17
已经有大佬讲的很详细了, https://xuanxuanblingbling.github.io/ctf/pwn/2019/09/06/317/
程序很简单,任意地址限定字符写
因为只有一次,而且字符太有限,开了nx保护,且不知道main函数的位置…
那基本上是改变程序流的一个思路, 这里是从libc_fini覆盖fini_array去搞事情
https://github.com/lattera/glibc/blob/895ef79e04a953cac1493863bcae29ad85657ee1/csu/libc-start.c
https://github.com/lattera/glibc/blob/895ef79e04a953cac1493863bcae29ad85657ee1/csu/elf-init.c
__libc_csu_init执行.init和.init_array, __libc_csu_fini执行.fini和.fini_array
1
2
3
4并且执行顺序如下:
__libc_csu_init
main
__libc_csu_fini借个图
1 | +---------------------+ +---------------------+ +---------------------+ +---------------------+ |
- 直接上exp了