Pwnable kr asg 题解
花了好几天终于完成了,自己独立完成的,NICE!好吧,有一个思想是被提示的...
这题在自己写 shellcode 基础上增加了点难度,最最主要的就是有一半的 ASCII 码会不让用,这些都是随机产生的,每次执行时会知道。
做完后的思考
所以肯定是要尝试先执行前面代码,然后执行时会修改后面代码
在 ascii 这道题目中,我用的 sub [reg+num], al 这样语句,但是那道题目是要求可打印字符,这道题是尽可能少字符,要求不一样。
但只是看起来不一样,因为都是要尝试先写上,然后执行代码时改掉,所以很有可能是一样的情况!!
PS:这也是我写这总结文章时才发现了这一点
而在 asg 这道题,用的是 add [rax], ok 这条语句(ok 指的是不被过滤器过滤的立即数,后面会提到)。
整体代码为: { 前面代码,改后面的代码 | 后面代码,被前面的代码改完后就是 shellcode }
阶段一: 某条语句绕过过滤器
首先就是有一半 ASCII 不让用,代码怎么绕过?首先前面代码是固定的,听天由命。后面代码是灵活调整的。
下面举例来说明如何布置后面代码:比如 shellcode 假设有一条语句是 0xdeadbeff,我们就会一个字节一个字节来看。
对于第一个字节,0xde 和 0x00 在不在过滤范围内?
只要有一个在,就看 0xdd 和 0x01 在不在?
如果有一个在,就继续再看 0xdc 和 0x02 在不在?一直这样直到不在过滤器范围中
假设我们遍历后,这几个分别是 (0xdc,0x02) (0xad,0x00) (0xbd,0x01) (0xff,0x00)
那么后面代码就是 0xdcadbdff,而前面代码就是 add [rax], 0x02000100,那么如果 rax 指向 0xdcadbdff,那么就会把它改成 0xdeadbeef,这样执行完前面代码,后面代码就是我们要的样子。
阶段二: 整体构想
如果 rax 指向后面代码刚开始那里,然后前面代码每一条语句都是 add [rax], ok; add rax, 0x4,这样就相当于遍历改掉后面代码的每条语句,最终达成效果!
阶段三: 修改寄存器
怎么让 rax 指向后面代码刚刚开始那里?
在 ascii 那道题我们也是需要把 ebx 变成 0x80000000,当时我们利用到了栈,非常推荐去看一下。
但这里我们的地址不是固定的,因此不能用那个套路了。我们这里利用的是 rip 的偏移。
试想一下我们执行第一条代码,rip 是指向它的,而我们要 rax 指向第一条后面语句,所以偏移是固定的。所以刚开始加一条语句就搞定了: lea rax, [rip+len(before_code)],NICE!
Q: 为什么要用 lea 呢
A: 刚开始我是直接打算用 sub [rip+offset], ok,但是它不是四个字节,所以会导致执行下条语句,offset 又不一样,所以用了 rax 来替代,然后发现 rip 赋值其他寄存器非常简单嘛,就用 lea 就可以。