System Hacking - Stage 4 : Shellcode

진주찬·2023년 5월 7일
0

System Hacking

목록 보기
3/6

1. 서론

Exploit : 해킹분야에서 상대 시스템을 공격하는 것

셸코드

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

어셈블리어는 기계어와 거의 일대일 대응되므로 사실상 원하는 모든 명령을 CPU에 내리기 가능

2. orw 셸코드

: 파일을 열고, 읽은 뒤 화면에 출력해주는 셸코드
"/tmp/flag"를 읽는 셸코드는 작성, 구현하려는 셸코드의 동작을 C언어 형식의 의사코드로 표현하면

char buf[0x30];
int fd = open("/tmp/flag", RD_ONLY, NULL);
read(fd, buf, 0x30); 
write(1, buf, 0x30);

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

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

"/tmp/flag"라는 문자열을 메모리에 위치

1) 스택에 0x616c662f706d742f67(/tmp/flag)를 push
2) rdi가 이를 가리키도록 rsp를 rdi로 옮기기
3) O_RDONLY는 0이므로, rsi는 0으로 설정
4) 파일을 읽을 때, mode는 의미를 갖기 않기 때문에 rdx는 0으로 설정
5) rax를 open의 syscall 값인 2로 설정

2. read(fd, buf, 0x30)

/tmp/flag의 fd은 rax에 저장
1) rax를 rdi에 대입
2) rsi에 rsp-0x30을 대입
3) rdx는 파일로부터 읽어낼 데이터의 길이인 0x30으로 설정
4) read 시스템콜을 호출하기 위해 rax를 0으로 설정

3. write(1, buf, 0x30)

1) rdi를 0x1로 설정
2) rsi와 rdx는 read에서 사용한 값을 그대로 사용
3) write 시스템 콜을 호출하기 위해서 rax를 1로 설정

orw 셸코드 컴파일 및 실행

대부분의 운영체제는 실행 가능한 파일의 형식을 규정
ex) 윈도우 - PE, 리눅스 - ELF

컴파일

셸코드를 실행할 수 있는 스켈레톤 코드를 C언어로 작성하고, 거기에 셸코드를 탑재하는 방법을 사용

스켈레톤 코드 : 핵심 내용이 비어있는, 기본 구조만 갖춘 코드

// File name: sh-skeleton.c
// Compile Option: gcc -o sh-skeleton sh-skeleton.c -masm=intel
__asm__(
    ".global run_sh\n"
    "run_sh:\n"
    "Input your shellcode here.\n"
    "Each line of your shellcode should be\n"
    "seperated by '\n'\n"
    "xor rdi, rdi   # rdi = 0\n"
    "mov rax, 0x3c	# rax = sys_exit\n"
    "syscall        # exit(0)");
void run_sh();
int main() { run_sh(); }

실행

셸코드가 실제로 작동함을 확인하기 위해 /tmp/flag 파일 생성

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

orw.c를 컴파일하고, 실행

gcc -o orw orw.c -masm=intel
./orw
flag{this_is_open_read_write_shellcode!}
&��U

공격의 대상의 되는 시스템에서 이 셸코드를 실행할 수 있다면, 상대 서버의 자료를 유출해낼 수 있다.

orw 셸코드 디버깅

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

pwndbg플러그인은 syscall을 호출할 때, 인자를 분석
셸코드를 작성할 때 계획했듯, open(“/tmp/flag”, O_RDONLY, NULL)가 실행됨을 확인 가능
open 시스템 콜을 수행한 결과로 /tmp/flag의 fd(3)가 rax에 저장

2. read(fd, buf, 0x30)

새로 할당한 /tmp/flag의 fd(3)에서 데이터를 0x30바이트만큼 읽어서 0x7fffffffc278에 저장
0x7fffffffc278에 /tmp/flag의 문자열이 성공적으로 저장

3. write(1, buf, 0x30)

데이터를 저장한 0x7fffffffc278에서 48바이트를 출력
/tmp/flag의 데이터 외에 알수없는 문자열이 출력

Appendix. Uninitialized Memory


48바이트 중, 앞의 40바이트만 우리가 저장한 파일의 데이터이고, 뒤의 8바이트는 우리가 저장한 적이 없는 데이터
이 데이터는 나중에 write시스템콜을 수행할 때, 플래그와 함께 출력되는 것

메모리 릭 : 이런 중요한 값을 유출해 내는 것

3. execve 셸코드

셸 : 운영체제에 명령을 내리기 위해 사용되는 사용자의 인터페이스
<-> 커널 : 운영체제의 핵심 기능을 하는 프로그램

execve 셸코드 : 임의의 프로그램을 실행하는 셸코드, 이를 이용하면 서버의 셸을 획득가능

execve(“/bin/sh”, null, null)


argv : 실행파일에 넘겨줄 인자
envp : 환경변수

execve 셸코드 컴파일 및 실행

0개의 댓글