Hacking/System Hacking

쉘코드 제작(shellcode)

나노콛 2019. 9. 27. 00:01

이전에 만들었던 코드로 계속 진행하겠습니다.

위의 소스 코드는 정적 컴파일을 해야 분석이 용이합니다. (전 게시글 참조)

목적은 write 함수를 쉘코드로 제작하는 게 목적입니다.
그러면 gdb에서 write 함수에 대해 파악하는 것이 필요합니다.

write(1,"hacker\n",7);
이 인자들이 있는 곳을 찾아야 합니다.
mov가 되는 값들을 한번 살펴볼 필요가 있습니다.

7

write(1,"hacker\n",7); 인자들이 여기에 있다는 것을 확인할 수 있습니다.

eax 빼고요

eax는 write의 시스템 콜 넘버입니다.

unistd.h

 

 

http://asm.sourceforge.net/syscall.html

 

Linux/i386 system calls

00 sys_setup [sys_ni_syscall] 01 sys_exit 02 sys_fork 03 sys_read 04 sys_write 05 sys_open 06 sys_close 07 sys_waitpid 08 sys_creat 09 sys_link 10 sys_unlink 11 sys_execve 12 sys_chdir 13 sys_time 14 sys_mknod 15 sys_chmod 16 sys_lchown 17 sys_break [sys_n

asm.sourceforge.net

 

write(1,"hacker\n",7);
  eax ebx ecx           edx

이렇게 구성이 되었다는 것을 파악할 수 있습니다.

 


다음에 int이 붙는 것을 볼 수 있는데요
int는 interrupt의 int이며 함수를 호출하는 명령어인데요
해당 주소로 들어가 보면

값은 0x80입니다.
80번에 해당하는 interrupt를 발생시킵니다.
80번은 system call입니다.

이 내용을 어셈블리어로 만들어 보겠습니다.

syswrite.asm

 

global _start
_start:  는 어셈블리어 시작점입니다.

db는 datebyte이며 메모리에 1byte씩 적재합니다.
0x0a, 0x0d는 \n을 16진수로 표현한 것입니다.

무한 루프

 

무한 루프가 나오게 됩니다.

그 이유는 소스 코드가 그렇기 때문인데요

계속 반복되기 때문입니다.

종료되는 기능을 넣어보겠습니다.
종료할 때는 systemcall에서 exit(0)를 쓰면 되는데요
write가 4였는데 exit는 1입니다.

인자의 순서는 아래처럼 됩니다.
exit(0)
eax ebx
마찬가지로 system call interrupt를 발생시키기 위해
int 0x80을 넣어 줍니다.

syswrite.asm

 

nsam 명령어는 기계어 목적 파일을 만드는 작업입니다. 확장자는 (.o) 파일이 생성됩니다.
ld는 linking 을 하는 작업입니다. 실행파일이 생성됩니다.

이제 문제없이 제대로 동작 됩니다.


쉘코드 추출
앞서 만든 어셈블리어 코드를 가지고 기계어로 추출하는 작업을 하겠습니다.

objdump -d syswrite

 

write(1,"hacker\n",7) 의 기계어가 추출되었습니다.

이 기계어를 다른 실행파일 내용부에 삽입이 된다면
hacker가 출력되게 될 것입니다.

만약에 악성코드를 만들어 기계어로 추출하고
취약점이 있는 실행파일 내용부에 들어간다면 어떻게 될까요

여튼 이 기계어만 가지고 와야 하는데
많은 문자들이 있어서 일일이 적어야 하지만 방법이 있습니다.
grep과 cut를 이용을 해서 원하는 것만 추려낼 수 있습니다.
1.
grep "8048"
주솟값이 동일하게 8048이 달려 나오니 위의 불필요한 영어를 지워 줍니다.

objdump -d syswrite grep "8048"

 


2.
<_start>
<start>
<message>를 안 나오게 합니다.
grep 
-v 하면 제외하고 검색됩니다.
위의 공통적인 부분은 >: 부분이라 판단되니 이것을 가지고 제외하겠습니다.

 


3. 이제 기계어 코드만 가지고 와야 하는데 cut으로 할 수 있습니다.

objdump -d syswrite grep "8048"

 

objdump -d syswrite grep "8048"

 

objdump -d syswrite grep "8048"

 

-f 옵션은 필드 값에 따라 출력됩니다.

기계어 코드만 나오게 했는데 이것을 실제 코드로 사용하려면
\x가 앞에 붙는 식으로 되어야 합니다 
\xb8\x04 이렇게 됩니다.
여기서는 쉘 스크립트 명령어로 해결할 수 있습니다.

for i in $(objdump -d syswrite grep "8048"

 

이제 원하는 코드만 추출을 완료했습니다.

shellcode.c

 

컴파일 후 실행


 

위의 쉘 코드를 보면 00 값이 많이 있는데요

bof (buffer overflow) 공격이나
문자열 함수 작동 관련 일 때는 00을 null 값으로 판단해 오작동이 일어 날 수 있습니다.
이 null 값을 없애주는 작업을 하겠습니다.

 쉘코드 NULL byte 제거

1. short jmp - jmp short는 2바이트만 사용
jmp hacker -> E9 1E 00 00 00
jmp short hacker -> EB 1E

2. 레지스터 수정 8비트 16비트 레지스터로 사용
mov eax,0x04 -> B8 04 00 00 00
mov ax,0x04 -> 66 B8 04 00
mov al,0x04 -> B0 04

3. xor 0값을 넣을 때는 xor을 이용
xor eax,eax

xor eax /ebx / edx 하는 이유는 기존에 값이 들어가 있는 것을 0으로 만들어주기 위함입니다.
eax에 1000이 들어가 있는데 al에 4를 넣어서 1004가 될 수 있기 때문입니다.

ecx는 xor 해줄 필요가 없습니다. 주솟값은 4바이트 사용하기 때문입니다.

하단의 xor ebx, ebx는 exit(0)의 인자의 값은 ebx에 있는 값을 사용하기 때문입니다.
0을 넣으면 null 값이 들어가기 때문에 xor을 해서 0을 넣어주는 모습입니다.

null 값이 제거된 것을 확인할 수 있습니다.

이 쉘코드로 다시 컴파일 하면 됩니다.

 

728x90