0x00 前言
这道题目是在BUU上面看到的,原本是台湾的一个pwn练习平台hackme.inndy的题目,之前做了几道inndy的题目,感觉难度不大但是挺涨知识的。
这道题难度不算大,写这篇博客是为了记录一些骚姿势。
0x01 分析
1 | Arch: amd64-64-little |
主函数如下
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
还有一个很可疑的函数,名字是个下划线,执行的是mprotect函数,不过这次没用到它。
1 | signed __int64 _() |
根据main函数,我们会读入一个16进制的数到v6,然后读入一个10进制的数到v4,然后通过*v6 = v4;
向16进制数的地址中写入这个10进制数,但由于前面是_BYTE *v6;
,所以我们只能写入一个字节。
程序存在任意地址写的漏洞,但是只能使用一次,有什么办法能让这个漏洞多次被使用呢?
可以看到0x400000 - 0x401000 的代码段的权限是rwxp,也就是说这个程序的代码段可写!
接着看main函数的汇编
可以看到程序在判断完v4是否为255以后会有一个jnz跳转,这个在伪代码界面是不显示的,不过可以利用这个修改跳转的目的地来实现多次任意地址写。
有了多次任意地址写
、代码段任意地址跳转
并且代码段可写
,我们就可以像打着patch做题一样了,可以往代码段写入shellcode然后跳转到shellcode来执行了。
0x02 Let’s do it!
首先通过修改跳转的目的地来实现多次利用任意地址写漏洞
在IDA中将这个地方改成4或者5就能看到汇编对应的机器码。
然后来到刚才提到的.text:0000000000400767 75 0A jnz short loc_400773
其中\x75
是jnz
的机器码,\x0A
是跳转地址的偏移。
我们先选定一个跳转目的地。
这里选取了0x40071D mov edi, offset format ; "Where What?"
然后按下N
,给他rename一下,这里就改成loc_40071D
吧。
确定以后可以观察到如下形式
然后来到刚刚那个0x400767
这个地方进行keypatch
将其改成jnz loc_40071D
,就可以看到机器码由原来的75 0A
变成了75 B4
。
这也就说明如果我们通过程序原本的一次任意地址写,将这个0A改成B4就能实现多次任意地址写。
而这个0A
在0x400768
的位置,实现起来就简单了!
1 | c.recvuntil('Where What?') |
向代码段写入shellcode
我选的shellcode_addr = 0x400769
,因为这块地方很容易触发,只需要让输入的十进制数为0XFF就可以。
1 | context(log_level = 'debug',arch = 'amd64',os = 'linux') |
这里有个细节
我们需要保证shellcode里面不存在\xff
,因为程序会有验证输入的十进制数是否等于0xff
!
比较幸运的是,这么生成的shellcode不含有\xff
get shell
1 | c.sendline('0x400000') |
向随便一个地方写入个255就能触发程序走向0x400769,也就是我们的shellcode的位置。
0x03 完整EXP
1 | from pwn import * |
0x04 参考链接
感谢各位师傅们的博客