网络通信 频道

透析黑客攻击技术之渗透防火墙的Shellcode


  实现方式简介
  1. 远程shellcode的几种实现方式
  1.1 监听端口
  1.1.1 监听新的端口
  1.1.2 重新使用原端口
  1.1.2.1 端口复用
  1.1.2.2 重新绑定
  1.2 反向连接
  1.3 复用当前连接的SOCKET
  1.3.1 IIS的ECB结构
  1.3.2 getpeername
  1.3.3 fcntl设置socket状态
  1.3.4 ioctl(Linux/Unix)和ioctlsocket(Win32)
  1.3.5 使用OOB特性
  1.3.6 Hook系统的recv调用
  
  复用当前连接技术介绍
  2. 复用当前连接技术的一些问题及优势
  2.1 绑定shell
  Unix下可以直接把SOCKET作为“/bin/sh”的输入输出句柄。在Win32下,socket()函数隐式指定了重叠标志,它创建的SOCKET是重叠套接字(overlapped socket),不能直接将cmd.exe的stdin、stdout、stderr转向到套接字上,只能用管道(pipe)来与cmd.exe进程传输数据。winsock推荐使用重叠套接字,所以实际使用尽可能用管道。WSASocket()创建的SOCKET默认是非重叠套接字,可以直接将cmd.exe的stdin、stdout、stderr转向到套接字上。
  
  复用当前连接技术介绍
  2.2 多线程环境搜索SOCKET
  -=-=-=-=-=- start sample code =-=-=-=-=-=-=
  s = WSASocket(2,1,...)
  bind(s,..)
  listen(s,...)
  s2 = accept(s,....)
  -=-=-=-=-=- end sample code =-=-=-=-=-=-
  当s处于accept状态时,任何对s操作的网络函数都会处于等待状态,直到有连接建立。先用WaitForSingleObjectEx处理句柄,当s处于accept状态时会返回WAIT_TIMEOUT,可用的句柄返回WAIT_OBJECT_0.然后再用ioctlsocket/recv处理判断是否当前连接的socket.
  
  复用当前连接技术介绍
  2.3 优势
  复用当前连接的技术相对较隐蔽,而且对于Win32的用管道绑定cmd.exe后,和服务器交互的数据可以用xor的办法进行编码,进一步躲避IDS的检测。单单查找SOCKET的shellcode可以写的相对比较短,在找到SOCKET后,可以再继续接收一段功能更复杂的shellcode到缓冲区,然后跳入执行。对于该后续shellcode就没有任何字符和长度的限制。甚至接收一个dll文件,实现更复杂的功能。
  
  Win32平台的具体实现
  3. Win32平台的具体实现
  3.1 端口复用具体实现
  端口复用shellcode要求服务重新绑定在0.0.0.0地址,而且不能使用SO_EXCLUSIVEADDRUSE选项。
  客户端攻击的时候需要把服务端的具体IP和端口写入shellcode里面。
  Shellcode里执行:
  setsockopt(s, 0xFFFF, 4, &d, 4);
  bind(s, &sockaddr, 0x10);
  用netstat -na在服务端查看可以看到同一个端口有0.0.0.0和具体IP两个绑定着。如果服务端在NAT环境里,可能会存在问题。
  
  Win32平台的具体实现
  3.2 重新绑定原端口的实现
  CreateProcess()创建一个suspend模式的进程。GetThreadContext()来获得该线程的上下文结构和寄存器信息。用VirtualAllocEx()在该进程里分配内存。把shellcode指令用WriteProcessMemory()来写入该进程刚才分配的空间。SetThreadContext()把GetThreadContext()获得的EIP修改指向VirtualAllocEx()分配的内存地址。ResumeThread()恢复suspend模式的进程。TerminateProcess(-1, 0)终止当前进程。循环绑定原来端口。
  
  Win32平台的具体实现
  3.3 getpeername查找socket
  客户端在发送攻击串之前用getsockname函数获得套接字本地信息,把相应信息写入shellcode.服务端shellcode从1开始递增查找socket,并且用getpeername函数获得套接字远程信息。如果两个信息相符就认为找到socket,跳出递增循环,并且把shell绑定在这个socket上。有很大局限性,如果客户端在NAT网络环境里,客户端getsockname取得的套接字信息和服务端getpeername取得的套接字信息不一定相符,导致查找socket失败。
  
  Win32平台的具体实现
  3.4 字串匹配查找socket
  客户端在发送完攻击数据包后,再发送几个字节的字符串,在服务端的shellcode对一个递增的socket值接收相应字节的字符串,然后匹配是否是当前连接的socket.这种方法避免了getpeername在NAT网络环境里的限制。多线程环境下容易处理到处于accept下的socket,一般的网络函数都会进入等待状态,直到有连接建立。flier提到WaitForSingleObjectEx处理这种处于accept的socket会返回WAIT_TIMEOUT,可用的句柄返回WAIT_OBJECT_0.
  
  Win32平台的具体实现
  3.4 字串匹配查找socket
  查找流程如下:
  while (1)
  {
  i++;
  ret = WaitForSingleObjectEx(i, 10, 1);
  if (ret != 0) continue;
  ret = ioctlsocket(i, FIONREAD, &ul);
  if (ul != 4) continue;
  recv(i, buff, 4, 0);
  if( *(DWORD *)buff == ''Xc0n'') goto shell;
  }
  bkbll测试发现socket()函数创建的句柄在accept用户后有getsockname操作,那么后续WaitForSingleObjectEx返回WAIT_TIMEOUT (0x102)。
  
  Win32平台的具体实现
  3.5 Hook系统的recv调用
  用VirtualProtect设置真实recv函数地址开始的5个字节为可写。把真实recv开始的指令改为跳转到新recv函数。在新的recv函数里先把这5个字节指令改回去。调用真实recv来执行系统本来的操作。再把真实recv函数地址开始的5个字节改为跳转新recv的指令。比较接收的数据是否是约定字串,如果是就绑定一个cmd.exe,否则跳到压栈的返回地址,继续系统原来的流程。这种方法能绕过rpc之类机制,也能够搜索再次连接的socket.
  
  Win32平台的具体实现
  3.6 文件上传下载功能的实现
  必须要客户端和shellcode做紧密配合。上传文件需要客户端打开并读取文件发送给服务端,服务端的shellcode创建并写入该文件。下载文件需要服务端的shellcode打开读取文件发送给客户端,客户端创建并写入该文件。由于是非阻塞的连接,上传文件的时候,服务端的shellcode必须判断socket里是否还有数据可接收,如果没有就关闭句柄,执行后续流程。下载文件的时候,客户端必须判断socket里是否还有数据。select和ioctlsocket都可以实现这个功能。select的汇编实现相对复杂,ioctlsocket需要在发送缓冲块大于接收缓冲块的情况下使用。
  
  Win32平台的具体实现
  3.6 文件上传下载功能的实现
  客户端和服务端shellcode可以使用一个约定的key对传输的数据做xor操作,由于用管道绑定cmd,那么交互的命令也是编码的,进一步增强隐蔽性,躲避IDS的检测。
  
  Linux x86平台的具体实现
  4. Linux x86平台的具体实现
  4.1 fcntl设置socket状态
  scz最早使用这种方法,基本思路如下:
  while (1)
  {
  i++;
  oldflags = fcntl(i, F_GETFL, 0);
  fcntl(i, F_SETFL, oldflags | O_NONBLOCK);
  read(i, buf, 4);
  fcntl( i, F_SETFL, oldflags );
  if (buf == ''Xc0n'') goto shell;
  }
  
  Linux x86平台的具体实现
  4.2 利用OOB特性
  bkbll最先使用该技术。Berkeley套接口的实现OOB数据一般是不会被阻塞的,查找的流程大致如下:
  while (1)
  {
  i++;
  recv(i, buf, 1, 1);
  if (buf == ''I'') goto shell;
  }
  Unix/Linux该方法最是简单易行,而且有效。
  
  Linux x86平台的具体实现
  4.3 利用ioctl函数的一些特性
  ioctl的FIONREAD可以判断句柄有多少数据可读,而且一般情况不会被阻塞。查找socket的流程大致如下:
  while (1)
  {
  i++;
  ioctl(i, FIONREAD, &ul);
  if (ul != 4) continue;
  read(i, buf, 4);
  if (buf == ''Xc0n'') goto shell;
  }
  
  Linux x86平台的具体实现
  4.4 文件上传下载功能的实现
  和Win32实现相似,只是Linux/Unix下似乎没有额外通过管道来绑定/bin/sh,所以shell里交互的数据无法编码处理。隐蔽性可能较差。
  
  AIX PowerPC下具体实现
  5. AIX PowerPC平台的具体实现
  缓存机制
  instruction cache
  data cache
  
  AIX PowerPC下具体实现
  PowerPC自修改的代码按照如下的步骤:
  存储修改的指令。
  执行dcbst指令,强制包含有修改过的指令的高速缓存行进行存储。
  执行sync指令,确保dcbst完成。
  执行icbi指令,使将要存放修改后指令的指令高速缓存行无效。
  执行isync指令,清除所有指令的指令管道,那些指令在高速
  缓存行被设为无效之前可能早已被取走了。
  现在可以运行修改后的指令了。当取这个指令时会发生指令高速缓存失败,结果就会从存储器中取得修改后的指令。
  
  AIX PowerPC下具体实现
  有些AIX是没有高速缓存管理指令。
  简单的解决方法是做完自修改后执行一个系统中断,那么后面就能正确执行自修改后的指令。
  实现解码shellcode,为实现复杂shellcode做好基础。
  
  AIX PowerPC下具体实现
  5.1 利用OOB特性的实现
  和Linux x86的实现类似
  难点:
  各版本AIX的系统调用号都是不相同的,导致exploit不通用。
  本地exploit先用oslevel -r判断系统版本,然后把各不同系

文章转载地址:http://www.cnpaf.net/Class/hack/06101110492280574984.html

0
相关文章