본문 바로가기

Let's Study/Hacking Technique

Alpha-Numeric Shellcode (Ascii Shellcode)

알파뉴메릭 쉘코드 제작방법에 대해 포스팅합니다. 말 그대로 숫자, 영어만으로 쉘코드를 제작할 수 있습니다.


오래된 기법이긴 하지만 이리저리 국내, 해외사이트를 뒤져봐도 정작 제작하는 방법은 안 나와있고 여러가지 툴을 이용한, Alpha3으로 제작하기, 메타스플로잇 alpha_mixed 옵션을 이용해서 만들기 밖에 없네요.


아스키쉘코드를 적용시키려면 우선 환경이 중요합니다. esp컨트롤로 스택포인트를 eip에 위치시켜서 xor한 값을 실행시킬 수 있습니다.


우선, 제일(?) 유명할 거라 생각되는 리눅스 쉘코드를 던져봅니다.


http://shell-storm.org/shellcode/files/shellcode-827.php


#include <stdio.h>
#include <string.h>
 
char *shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69"
		  "\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";

int main(void)
{
fprintf(stdout,"Length: %d\n",strlen(shellcode));
(*(void(*)()) shellcode)();
return 0;
}

xor    %eax,%eax
push   %eax
push   $0x68732f2f
push   $0x6e69622f
mov    %esp,%ebx
push   %eax
push   %ebx
mov    %esp,%ecx
mov    $0xb,%al
int    $0x80

풀이해보자면 eax를 0으로 초기화시켜서 스택에 널값을 올려두고, 푸쉬명령어로 스택에 /bin/sh를 올린 후,


스택포인트 주소를 ebx에 둡니다. ebx = "/bin/sh" 널값을 올린 이유는 /bin/sh 뒤에 쓰레기값이 붙게 하지 않기 위함입니다.


그 후, 0(eax)을 다시 푸쉬하고 ebx값을 푸쉬합니다. 그럼 스택에는 /bin/sh를 가리키는 주소가 푸쉬되겠지요. 


/bin/sh를 가리키는 주소의 주소를 ecx에 옮깁니다. 그렇게 되면, ecx = &ebx 이렇게 표현할 수 있을 것 같네요.


그리고 eax의 하위바이트에 11을 옮기고 인터럽트 80으로 시스템콜을 호출합니다.


이렇게 되면, 시스템콜 넘버 11인 execve 함수가 호출되고 첫번째 인자인 ebx = "/bin/sh" 두번째 인자인 ecx = *["/bin/sh"],


환경변수 edx = ?? 가 되는데, edx는 bad address 만 뜨지 않을정도로만 잡아주면 execve는 잘 작동합니다.




스택 상태를 그림으로 정리해보면 이렇게 됩니다.





중요한 건, xor %eax, %eax를 이용해 초기화된 eax값을 스택에 푸쉬하는 것도 아니고 결과적으로 


eax = 0xb, ebx = "/bin/sh", ecx = *["/bin/sh"], edx = 오류 안 날 정도의 값 (환경변수) 


이렇게 설정해 준 뒤, int $0x80을 불러주는 겁니다.


위의 쉘코드는 


xor %eax,%eax                      \x31\xc0 X push %eax                                \x50 push $0x68732f2f                       \x68\x2f\x2f\x73\x68 push $0x6e69622f                       \x68\x2f\x62\x69\x6e mov %esp,%ebx                        \x89\xe3 X push %eax                                 \x50 push %ebx                                 \x53 mov %esp,%ecx                        \x89\xe1 X mov $0xb,%al                            \xb0\x0b X int $0x80                                   \xcd\x80 X


아스키 범위를 벗어나는 명령어들이 많습니다. 


이걸 아스키쉘코드 테이블을 이용해 적절하게 바꿔주면 됩니다.



Ascii Shellcode Table :

1. https://nets.ec/Ascii_shellcode 

2. http://ninja-sec.org/cyber-security-resources/ascii-shellcode-table/  



일단, 


아스키 쉘코드를 쓸 때에 환경이 중요하다고 했던 건, 결국 esp를 eip가 가리키는 곳으로 컨트롤해서

xor로 cd 80 (int $0x80)을 만들었던 값을 스택에 푸쉬합니다. 그걸 eip가 가리키게 하면 인터럽트 80이 실행됩니다.


예를 들어 로컬환경에서 테스트할 때는 이렇게 짤 수 있습니다.




int $0x80을 제외한 나머지 값들은 전부 아스키 범위 안입니다.


문제가 됬던 값들


xor %eax, %eax

mov %esp, %ebx

mov %esp, %ecx

mov $0xb, %al



xor %eax, %eax -> dec %eax

mov %esp, %ebx -> push %esp, pop %ebx

mov %esp, %ecx -> push %esp, pop %ecx

mov $0xb, %al -> push $0x3b, pop %eax, xor $0x30, %al


로 변경해주었습니다.


int $0x80을 안한 건 (포스팅하려고 만들기엔 너무 귀찮...) 환경에 따라 스택포인트가 달라지기 때문에 만들지 않았습니다.


(근데 사실 int $0x80을 아스키쉘코드로 만드는 부분이 제일 중요합니다.)


어떤 값을 이용하던지 int $0x80을 만들기 전까지는 ebx = "/bin/sh", ecx = *["/bin/sh"] 만 만들어주시면 됩니다.

eax 값은 xor할 때에 쓰이므로 일단 놔두시고 edx나 esi, edi는 쓰이지 않으므로 이 변수들을 이용해서 값들을 저장해뒀다가

스택포인트를 eip에 넣을 때 적절히 사용하시면 되고요.



이렇게 쉘코드를 만들다보면 어느새 값을 다 맞추고 int $0x80 (cd 80) 을 실행해야 될 때가 됩니다.


우선 cd80 아스키쉘코드를 만들기 전에 info reg로 레지스터에 어떤 값들이 있는지 확인을 합니다.


 다른 방법으로도 xor하여 스택에 cd80이 들어갈 수만 있다면 그 값을 미리 만들어두는 것도 좋습니다.


그리고 그걸 따로 다른 안 쓰는 변수에 저장해뒀다가 후에 esp를 어떤식으로든 eip 근처에 갈 수 있게 조작을 해둡니다.


그 이유를 그림으로 설명해봅니다.




 결국 Instruction이 실행되는 건 기계어로 바뀐 코드 cd 80을 eip가 만나게 되어 실행을 하는 구조로 되어있습니다.


값을 다 셋팅한 후 cd 80을 만나기 전까지 의미없는 명령어 \x47로 다 채웠는데 (\x47 = inc edi) 지금 eip와 esp의 거리는


 0x5e정도로 멀찍이 떨어져있습니다. 좀 더 가깝게 하고 싶으면 push(esp - 4)를 이용해서 가깝게 붙일 수 있습니다.


그림의 register가 eip를 가리키는 그림은 eip가 저기에 있을 때의 레지스터 상태를 나타내고 있습니다.


이걸로 알파뉴메릭 쉘코드 제작방법 포스팅을 마칩니다. (_ _)