作者:Tangerine@SAINTSEC
0×00 shellcode的使用
在上一篇文章中我们学习了怎么使用栈溢出劫持程序的执行流程。为了减少难度,演示和作业题程序里都带有很明显的后门。然而在现实世界里并不是每个程序都有后门,即使是有,也没有那么好找。因此,我们就需要使用定制的shellcode来执行自己需要的操作。
首先我们把演示程序~/Openctf 2016-tyro_shellcode1/tyro_shellcode1
复制到32位的docker环境中并开启调试器进行调试分析。需要注意的是,由于程序带了一个很简单的反调试,在调试过程中可能会弹出如下窗口:
此时点OK,在弹出的Exception handling窗口中选择No(discard)丢弃掉SIGALRM信号即可。
与上一篇教程不同的是,这次的程序并不存在栈溢出。从F5的结果上看程序使用read函数读取的输入甚至都不在栈上,而是在一片使用mmap分配出来的内存空间上。
通过调试,我们可以发现程序实际上是读取我们的输入,并且使用call指令执行我们的输入。也就是说我们的输入会被当成汇编代码被执行。
显然,我们这里随便输入的“12345678”有点问题,继续执行的话会出错。不过,当程序会把我们的输入当成指令执行,shellcode就有用武之地了。
首先我们需要去找一个shellcode,我们希望shellcode可以打开一个shell以便于远程控制只对我们暴露了一个10001端口的docker环境,而且shellcode的大小不能超过传递给read函数的参数,即0×20=32.我们通过著名的shell-storm.org的shellcode数据库shell-storm.org/shellcode/找到了一段符合条件的shellcode
21个字节的执行sh的shellcode,点开一看里面还有代码和介绍。我们先不管这些介绍,把shellcode取出来使用pwntools库把shellcode作为输入传递给程序,尝试使用io.interactive()与程序进行交互,发现可以执行shell命令。
当然,shell-storm上还有可以执行其他功能如关机,进程炸弹,读取/etc/passwd等的shellcode,大家也可以试一下。总而言之,shellcode是一段可以执行特定功能的神秘代码。那么shellcode是怎么被编写出来,又是怎么执行指定操作的呢?我们继续来深挖下去。链接文字
0×01 shellcode的原理
这次我们直接把断点下在call eax
上,然后F7跟进
可以看到我们的输入变成了如下汇编指令
我们可以选择Options->General,把Number of opcode bytes (non-graph)
的值调大