awdp FIX纸杯
本文最后更新于:2024年7月25日 晚上
awdp fix
非常建议有个keypatch,功能非常强大且有效。不过不要完全依赖keypatch。
通用脚本
如果目标目录非/home/ctf/
可以自行修改。
update.sh
1 |
|
如果check检查上传文件的md5,但我之前上传过相同md5文件(例如说之前环境down了,有需要修复避免一轮结束额外扣分),那么比较合适的方法就是在脚本内部的某些地方加上换行符等等。
首先肯定是格式化字符串
格式化字符串一般是最好修的,我们自己写代码时避免格式化字符串的形式无非两种:一种是"%s", str
,一种是用其他输出函数来输出,例如说puts
。
如果dyn中有puts,那是最方便的,直接从printf(str)
执行成puts(str)
,也就是将call printf
修改为call puts
。
如果dyn中没有puts,那么就需要尝试跳转出去在一个没有使用的可写段去写printf("%s", str)
,我们跳转的位置是从上一个函数执行结束到当前格式化字符串漏洞的call printf
,也就是原本参数修改到执行函数的位置都是自定义的,并不是只有call printf
才能覆写。
跳出去之后就很简单,不需要什么endbr64
,直接写合适的寄存器控制和函数调用就行。
例如说我想写一段printf("%s", str);
,首先把str的地址控制在某个寄存器内(例如说rax),然后找两段地址,一个先写%s
,一个写如下汇编:
1 |
|
keypatch会非常方便。
free后未置空
一般来说后面有错误处理的话是最好的,一般checker不会管错误处理,所以直接在其他函数的错误处理上写mov [rbp+ptr], 0
就可以了,例如说前面写了
1 |
|
那么[rbp+ptr]
就是需要置空的地址,而非rdi或rax寄存器。所以mov [rbp+ptr], 0
就是有效的。
溢出
我们需要注意多种溢出方式,一种是输入溢出,一种是复制溢出。
输入溢出就是通过输入如scanf("%s", buf)
、read(0, buf, a_large_size)
等形式发生的;复制溢出就是通过memcpy(buf1, buf2, a_large_size)
、for i to a_large_size: buf1[i] = buf2[i]
等形式发生的。
memcpy、read这种函数本身存在控制字长的就很简单,可以先试试直接size_t传个0给不给过,然后再看缓冲区长度再去试。
用scanf的话大概率改三参数函数是不够的,一般还是要跳出去再回来,rdi rsi rdx。跳出去的话可以改为read,但其实还有方法,比如说从格式化字符串上下手,找个地方写"%12s"
,百分号和s之间的数字就是scanf即将从stdin读进去的长度。
注意
某道题目可能不会只有一个漏洞点,你要是想到了多种可能的漏洞并且修单个还是exp利用成功那就都修了。
越早修越好,因为是一直得分。