본문 바로가기

해킹/System

[Windows_System] Shellcoding 쉘코딩법 #2 널바이트(\x00) 제거

반응형

이 포스팅은 "윈도우 시스템 해킹 가이드-버그헌팅과 익스플로잇"을 참조하며 만들었습니다.

#1

2019/08/21 - [해킹/System] - [Windows_System] Shellcoding 쉘코딩법 #1

 

[Windows_System] Shellcoding 쉘코딩법

============================================================================ 사진날아가서 재작성 합니다~ 실행 환경이 달라져서 일부 수정되었습니다! 윈도우7+VS2018 => 윈도우10+VS2017 =================..

r3dzone.tistory.com

============================================================================

\xC6\x45\xF8\x63\xC6\x45\xF9\x61\xC6\x45\xFA\x6C\xC6\x45\xFB\x63\xC6\x45\xFC\x00\x6A\x01\x8D\x45\xF8\x50\xB8\x10\x3A\x64\x76\xFF\xD0\x6A\x01\xB8\x20\x2D\x85\x75\xFF\xD0

지난번에 만든 쉘코드에는 널바이트(\x00)가 들어있었습니다. 

널바이트는 보통 문자열의 마지막을 의미하기때문에 이 널바이트가 쉘코드에 포함되어있다면 그 쉘코드를 읽어오는 도중에 끊어질 수가 있습니다. 그렇게 되면 애써만든 쉘코드를 사용할 수 없게 됩니다.

그렇다면 이 널바이트를 제거하려면 어떻게 해야하나? 

여러 가지 방식이 존재할 수 있습니다. 어셈블리를 약간만 배웠다면 다양한 방식으로 이 널바이트를 없앨 수 있습니다.

다시한번 쉘코딩한것을 디버깅해서 코드바이트를 봐줍니다.

문제가 되는 부분은 빨간색으로 표시한 부분에서의 00입니다. 저의 쉘코드에는 한부분이 문제가 되는 군요.

C6 45 F8 63          mov         byte ptr [ebp-8],63h  
C6 45 F9 61          mov         byte ptr [ebp-7],61h  
C6 45 FA 6C          mov         byte ptr [ebp-6],6Ch  
C6 45 FB 63          mov         byte ptr [ebp-5],63h  
C6 45 FC 00          mov         byte ptr [ebp-4],0  
6A 01                push        1  
8D 45 F8             lea         eax,[ebp-8]  
50                   push        eax  
B8 10 3A 64 76       mov         eax,76643A10h  
FF D0                call        eax 

지난번 처럼 어셈을 한번 정리해봤습니다. 이때 널바이트를 만들어 내는 부분은 "mov byte ptr [ebp-4],0"이네요

이 어셈은 ebp-4영역에 0을 집어넣으라는 의미입니다.

0 즉 널(NULL)을 넣으니 당연히 널바이트가 생성될수밖에 없습니다.

그럼 이 0을 어떻게 넣어주면 될까요?

방법1. 0이 필요없는 다른 명령어로 대체

방법2. 32비트 레지스터가 아닌 16비트,8비트 레지스터 사용하기

방법3. 연산 명령을 사용해서 0을 결과로 나타냄 (포스팅 맨 위에 표기한 책을 참조하였습니다.)

이외에도 창의적으로 어셈블리를 조합해서 원하는 방식으로 널바이트를 없앨 수 있습니다.

위 나열한 방식중 방법2번은 저희가 없애야할 널바이트가 16비트나 8비트로 끊기지 않아 사용할 수 없으니 패스합니다.

그럼 방법1로 가봅시다.

널바이트 제거

#include <stdio.h>
#include <windows.h>

int main() {

	__asm {
		//char buf[5] = { 'c','a','l','c','\x0' };
			mov         byte ptr[ebp - 8], 63h   //buf에 calc0 차곡차곡 저장~ ebp 기준으로
			mov         byte ptr[ebp - 7], 61h
			mov         byte ptr[ebp - 6], 6Ch
			mov         byte ptr[ebp - 5], 63h
			//mov         byte ptr[ebp - 4], 0
			xor			ebx , ebx
			mov			byte ptr[ebp - 4], bl
		//WinExec(buf, 1);
			push        1 			//스택에 인자인 1 넣기
			lea         eax, [ebp - 8]  //인자로 buf 주기
			push        eax 		//스택에 buf주소 쌓기
			mov		 eax, 0x73B43A10 //WinExec() 주소
			call        eax  //함수 실행!
		//exit(1);
			push        1  		//스택에 1 쌓기!
			mov		 eax, 0x762D2D20 //exit() 주소!
			call        eax  //함수 실행!
	};
}
//r3dzone
//shellcode.c

xor 연산을 통해 ebx레지스터의 값을 0으로 만들어주고 그 ebx의 하위 8비트(bl)를 ebp-4영역에 넣어줬습니다.

(bl을 사용한 이유는 ebp -4를 byte로 선언했기 때문! dword로 선언시에는 그냥 ebx로 가능!)

(xor연산은 두개의 값을 비교해서 다르면 1, 같으면 0을 목표레지스터에 저장합니다.)

결국 ebp-4에는 저희가 원하는 것과 똑같이 0이라는 값이 저장되게 되서 정상적으로 동작합니다.

정상 동작!
바이트 코드

디스어셈블리를 통해 다시 바이트 코드를 확인해봐도 널바이트가 없습니다! 성공!

\xC6\x45\xF8\x63\xC6\x45\xF9\x61\xC6\x45\xFA\x6C\xC6\x45\xFB\x63\x33\xDB\x88\x5D\xFC\x6A\x01\x8D\x45\xF8\x50\xB8\x10\x3A\xB4\x73\xFF\xD0\x6A\x01\xB8\x20\x2D\x2D\x76\xFF\xD0

 

이제 방법3을 사용해 볼까요?

방법 3 : 계산시켜서 결과값으로 0 얻기!

mov 연산을 통해 ebp-4에 1을 넣어주고 sub연산으로 1을 빼주었습니다. 

역시 ebp-4에는 똑같이 0이라는 값이 저장되게 되서 정상적으로 동작합니다.

코드가 약간 길어졌긴 했지만 역시나 널바이트는 제거되었습니다!

\xC6\x45\xF8\x63\xC6\x45\xF9\x61\xC6\x45\xFA\x6C\xC6\x45\xFB\x63\xC6\x45\xFC\x01\x80\x6D\xFC\x01\x6A\x01\x8D\x45\xF8\x50\xB8\x10\x3A\xB4\x73\xFF\xD0