ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • dreamhack stage 4 - Exploit Tech:Shellcode
    보안/SYSTEM HACKING 2024. 3. 15. 16:05

    0. 서론

    • 익스플로잇(Exploit)

    :해킹 분야에서 상대 시스템을 공격하는 것/ 부당하게 이용하다 라는 의미

    상대 시스템에 침투해 시스템을 악용

    시스템해킹의 익스플로잇과 9가지 공격기법을 소개할 것이다.


    1. 셸코드(Shellcode)

    : 익스플로잇을 위해 제작된 어셈블리 코드 조각

    • 시스템해킹에서의 셸 획득 중요성 - execve 셸코드

    해커가 rip를 자신이 작성한 셸코드로 옮길 수 있으면 해커는 원하는 어셈블리 코드가 실행되게 할 수 있다.

    - -> 어셈블리어는 모든 명령을 CPU에 내릴 수 있다.

    • 셸코드의 구성과 목적

    - 셸코드는 어셈블리어로 구성된다.

    - 공격 수행 대상 아키텍처와 운영체제, 셸코드의 목적에 따라 다르게 작성된다.

    - 공유되는 셸코드는 범용적으로 작성되어 시스템 환경을 완전히 반영할 수 없다

    --> 최적의 셸코드: 직접 작성해야 한다.

     


    2. orw 셸코드

    : 파일을 열고 읽은 후 화면에 출력해주는 셸코드

    • orw 셸코드를 작성하기 위해 알아야 하는 syscall

    • 예제: /tmp/flag 를 읽는 셸코드 작성하기

    구현하려는 셸코드의 동작을 C언어 형식의 의사코드로 표현한다.

     

    예제 풀이 1. /tmp/flag 라는 문자열 메모리에 위치시키기

    -- int fd = open("/tmp/flag", O_RDONLY, NULL) --

    - 스택에 0x616c662f706d742f67(/tmp/flag) 를 push 한다.

    - rdi가 가리키도록 rsp를 rdi로 옮긴다.

    - rsi는 0으로 설정한다. O_RDONLY는 0이기 때문이다.

    - rdx는 0으로 설정한다. 파일을 읽을 때 mode는 의미를 갖지 않기 때문이다.

    - rax를 open의 syscall 값인 2로 설정한다.

    구현모습)

    예제 풀이 2. read(fd, buf, 0x30)

    syscall의 반환값은 rax로 저장된다. open으로 획득한 /tmp/flag의 fd는 rax에 저장된다.

    - rax를 rdi에 대입한다. read의 첫 번째 인자를 이 값으로 설정해야 하기 때문이다.

    - rsi에 rsp-0x30을 대입한다. rsi는 파일에서 읽은 데이터를 저장할 주소를 가리키는데 0x30만큼 읽을 것이기

    때문이다.

    - rdx는 파일로부터 읽어낼 데이터의 길이인 0x30으로 설정한다.

    - rax는 0으로 설정한다. read 시스템콜을 호출하기 위해서이다.

    구현모습)

    + fd(File Descriptor, 파일서술자)

    : 유닉스 계열의 운영체제에서 파일에 접근하는 소프트웨어에 제공하는 가상의 접근 제어자

    - 프로세스마다 고유의 서술자 테이블을 가지고 있고 그 안에 여러 파일 서술자를 저장한다.

    - 서술자는 번호로 구별되는데

    0: 일반 입력

    1: 일반 출력

    2: 일반 오류 이다. 프로세스를 터미널과 연결된다.

     

    예제 풀이 3. write(1, buf, 0x30)

    - rdi 는 0x1로 설정한다. 출력은 stdout으로 할 예정이기 때문이다.

    - rsi와 rdx는 read에서 사용한 값을 그대로 사용한다.

    - rax는 1로 설정한다. write 시스템콜을 호출하기 위해서이다.

    구현모습)

    예제 풀이 요약)

    • orw 셸코드 컴파일 및 실행

    대부분의 운영체제는 실행 가능한 파일의 형식을 규정하고 있다.

    리눅스의 ELF(Executable and Linkable Format)는

    헤더 - 실행에 필요한 여러 정보가 적혀있음,

    코드 - CPU가 이해할 수 있는 기계어 코드가 적혀있음,

    기타데이터로 구성되어있다.

    아까 작성한 셸코드는 어셈블리 코드라서 ELF 형식이 아니다 --> 리눅스에서 실행할 수 없다. gcc 컴파일을 통해 ELF형식으로 변형하자.

    - 컴파일

    방법: 스켈레톤 코드를 C언어로 작성 -> 셸코드 탑재

    + 스켈레톤 코드: 핵심이 비어있고 기본 구조만 갖춘 코드

    - 실행

    셸코드가 실제로 작동하도록 /tmp/flag 파일 생성

    echo "flag{this_is_open_read_write_shellcode!}" > /tmp/flag

     

    orw.c를 컴파일하고 실행한다.

    저장한 문자열 출력

    저장한 문자열 외에도 다른 문자열이 함께 출력되었다.

    • orw 셸코드 디버깅

    - 셸코드 동작을 분석해보자: orw를 gdb로 열고 run_sh)함수에 브레이크 포인트 설정

    - run 명령어로 run_sh()함수의 시작부분까지 코드 실행: rip 위치한 것 확인 가능

    1. int fd = open("/tmp/flag", O_RDONLY, NULL)

    첫번째 syscall전까지 실행하고 syscall에 들어가는 인자를 확인한다.

    pwndbg 플러그인은 syscall을 호출할 때 인자를 분석해준다.

    open("/tmp/flag", O_RDONLY, NULL) 가 실행되는 것을 확인한다.

    open 시스템 콜 수행 결과로 rax에 /tmp/flag의 fd(3)이 저장된다.

    2. read(fd. buf, 0x30)

    - 두번째 syscall 직전까지 실행 후 인자를 본다.

    /tmp/flag의 fd(3)에서 데이터를 0x30바이트만큼 읽어 0x7fffffffc278에 저장한다.

     

    실행 결과를 x/s로 확인해보면 문자열이 성공적으로 저장되었다.

    3. write(1, buf, 0x30)

    - 읽어낸 데이터를 출력하는 write 시스템 콜을 실행한다.

    - 데이터를 저장한 0x7fffffffc278에서 48바이트를 출력한다.

    아까 나온 예제처럼 다른 문자열이 포함되어 출력되었다. 초기화되지 않은 메모리 영역 사용 때문이다.

    + 초기화 되지 않은 메모리 사용(Use of Uninitialized Memory)

    - 스택에서의 해제: rsp와 rbp를 호출한 함수의 것으로 이동한다. 어떤 함수를 해제한 이후 다른 함수가 스택 프레임을 위에 할당하면 이전 스택 프레임의 데이터는 여전히 새로 할당한 스택 프레임에 존재하고 이 값을 쓰레기 값이라고도 한다.

    • Appendix. Uninitialized Memory

    - 파일을 읽어서 스택에 저장했고, 스택의 영역을 다시 확인해보자.

    48바이트 중 40바이트만 저장한 파일의 데이터이고 나머지 8바이트는 저장하지 않은 데이터이다. 나중에 write 시스템콜을 수행할 때 플래그와 함게 출력된다.

    + 메모리 릭(Memory Leak): 어셈블리 코드의 주소와 같은 중요한 값을 유출해내는 것


    3. execve 셸코드

    • 셸과 커널

    - 셸(Shell, 껍질): 운영체제에 명령을 내리기 위해 사용되는 사용자의 인터페이스

    <--> 커널(Kernel, 호두 속 내용물): 운영체제의 핵심 기능을 하는 프로그램

    + 셸 획득 == 시스템해킹의 성공

    • execve 셸코드

    : 임의의 프로그램을 실행하는 셸코드

    execve 셸코드로 서버의 셸을 획득할 수 있다.

    리눅스 계층

    리눅스 대부분 sh, bash를 기본 셸 프로그램으로 탑재하고 있고 zsh, tsh 등을 설치할 수 있다. 우분투에서 execve 셸코드를 작성해보자.

    • execve("/bin/sh", null, null) <- 실행 목표

    execve 셸코드는 execve 시스템 콜만으로 구성된다.

    - argv: 실행파일에 넘겨줄 인자

    - envp: 환경변수

    sh만 실행할 것이기 때문에 나머지는 null로 해도 된다.

    리눅스 기본 실행 프로그램 (sh 포함)이 /bin/ 디렉토리에 저장되어 있다.

    • execve 셸코드 컴파일과 실행

    sh가 실행되는 것을 볼 수 있다.

    • objdump를 이용한 셸코드 추출

    셸코드를 byte code(opcode) 형태로 추출하는 방법의 예시이다.

    shellcode.o (1단계)

    shellcode.bin (2단계)


    '보안 > SYSTEM HACKING' 카테고리의 다른 글

    dreamhack stage 3 - Tool:pwntools  (0) 2024.03.15
    dreamhack stage 3 - Tool:gdb  (0) 2024.03.15
    dreamhack stage 2 - x86 Assembly  (0) 2024.03.15
    dreamhack stage 2 - Computer Architecture  (0) 2024.03.15
    dreamhack stage 2 - Linux Memory Layout  (0) 2024.03.15
Designed by Tistory.