문제를 실행해보면 전형적인 CrackMe 형태인데 Flag 계산시 사용되는 알고리즘이 생각보다 어려워 문제 푸는데 거의 하루가 걸려버렸다.
일단 correct를 띄우는 함수 구조를 보면 아래와 같다.
입력값을 받아서 총 3개의 함수를 거치는데 첫번째 함수는 입력 값을 이진수 형태로 변환해주고 세번째 함수는 두번째 함수로 인해 반환된 결과를 custom base64 인코딩시켜준다.
중요한게 2번째 함수였는데 코드는 아래와 같았다.
코드를 대략적으로 보면 기본적으로는 rand 함수로 구해온 값이랑 현재 버퍼위치의 바이트 값으로 인덱스 값 생성 후 byte_6020A0 위치에 존재하는 테이블에서 해당 인덱스로 값을 가져온다.
이 때 바이트 값이 연속 3개이상 동일할 경우에는 첫번째 값을 !(0x21) 세팅하고 두번째 값은 연속된 바이트 값 개수를 인덱스로해서 테이블에서 값을 구해오며 세번째 값은 이전과 동일하게 rand 함수를 사용해서 구해온다.
위 알고리즘에 맞춰 복호화를 다음과 같이 진행했다.
먼저 비교대상인 base64값을 custom base64 디코딩해서 비교 대상의 hex값을 구해왔다. 해당 코드는 https://github.com/xamiel/custombase64/blob/master/custombase64.py 에서 가져다 썼다.
import base64
import string
import random
cuscharset = "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba9876543210+/"
b64charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
encodedset = string.maketrans(b64charset, cuscharset)
decodedset = string.maketrans(cuscharset, b64charset)
def dataencode(x):
y = base64.b64encode(x)
y = y.translate(encodedset)
return y
def datadecode(x):
y = x.translate(decodedset)
y = base64.b64decode(y)
return y
def randset():
"""Generate a random alphabet for use in base64 encoding"""
x = "".join(random.sample(cuscharset, len(cuscharset)))
global encodedset
global decodedset
encodedset = string.maketrans(b64charset, x)
decodedset = string.maketrans(x, b64charset)
if len(cuscharset) == 64:
print "New random charset: " + x + "="
elif len(cuscharset) == 65:
print "New random charset: " + x
print "Record the above string if you ever want to be able to decode this data again.\n"
# Uncomment the command below to generate a random base64 alphabet.
#randset()
plaintext = "1234"
# Encode the plaintext string
enc = dataencode(plaintext)
#enc = 'WGtECM0UDeq9CGs3eHwGriEFqdYIrjgGvdw5qSEGrTkIrTU4vdrFqcEHpjkIqTC4'
# Decode back into plaintext string
dec = datadecode(enc)
print datadecode("39xs8IzeMEDEsLl/N+ps8yHgRGB9osPSRwD1RwC7QHVdr0xx5qp/fFMCRMFFccMaRGAEcHSEnFVs8w5yI7QlRwDzleMtykO2mbSEqDRvYhfcRwCbi7hsMiJvzbSEebSEzj1yBC9sMomuwHV7K+Zs8ypBUbVdko9oRGzsR+tsMhp8msHV4c2QEP4CGKFsMsps8H7kuclvIBwRRGzRrKyi+akVRwCAIXAAdswNntZ5OIzic1LbHoP/ibd/xdw7FWBsMmfi6VmryjVs8zhSNeZYRGYmRoZmfpskXa8qOrV7IdDQRwCWXL1s8GlpFrSEL/3rRwD0UJCQ6iJs8vG4LDLW2bSEBBeoRwF9eS1sModdQDUnh+cOxBZ8qGts8uhs8CnKKXV7jHSEXFts8yN4RGz7CtJ=").encode("hex")
위 코드를 통해 구해온 hex값을 아래 코드를 통해 복호화하여 다시 이진수 형태로 변환해줬다.
import ctypes
table = [0x52,0x09,0x6A,0xD5,0x30,0x36,0xA5,0x38,0xBF,0x40,0xA3,0x9E,0x81,0xF3,0xD7,0xFB,0x7C,0xE3,0x39,0x82,0x9B,0x2F,0xFF,0x87,0x34,0x8E,0x43,0x44,0xC4,0xDE,0xE9,0xCB,0x54,0x7B,0x94,0x32,0xA6,0xC2,0x23,0x3D,0xEE,0x4C,0x95,0x0B,0x42,0xFA,0xC3,0x4E,0x08,0x2E,0xA1,0x66,0x28,0xD9,0x24,0xB2,0x76,0x5B,0xA2,0x49,0x6D,0x8B,0xD1,0x25,0x72,0xF8,0xF6,0x64,0x86,0x68,0x98,0x16,0xD4,0xA4,0x5C,0xCC,0x5D,0x65,0xB6,0x92,0x6C,0x70,0x48,0x50,0xFD,0xED,0xB9,0xDA,0x5E,0x15,0x46,0x57,0xA7,0x8D,0x9D,0x84,0x90,0xD8,0xAB,0x00,0x8C,0xBC,0xD3,0x0A,0xF7,0xE4,0x58,0x05,0xB8,0xB3,0x45,0x06,0xD0,0x2C,0x1E,0x8F,0xCA,0x3F,0x0F,0x02,0xC1,0xAF,0xBD,0x03,0x01,0x13,0x8A,0x6B,0x3A,0x91,0x11,0x41,0x4F,0x67,0xDC,0xEA,0x97,0xF2,0xCF,0xCE,0xF0,0xB4,0xE6,0x73,0x96,0xAC,0x74,0x22,0xE7,0xAD,0x35,0x85,0xE2,0xF9,0x37,0xE8,0x1C,0x75,0xDF,0x6E,0x47,0xF1,0x1A,0x71,0x1D,0x29,0xC5,0x89,0x6F,0xB7,0x62,0x0E,0xAA,0x18,0xBE,0x1B,0xFC,0x56,0x3E,0x4B,0xC6,0xD2,0x79,0x20,0x9A,0xDB,0xC0,0xFE,0x78,0xCD,0x5A,0xF4,0x1F,0xDD,0xA8,0x33,0x88,0x07,0x21,0x31,0xB1,0x12,0x10,0x59,0x27,0x80,0xEC,0x5F,0x60,0x51,0x7F,0xA9,0x19,0xB5,0x4A,0x0D,0x2D,0xE5,0x7A,0x9F,0x93,0xC9,0x9C,0xEF,0xA0,0xE0,0x3B,0x4D,0xAE,0x2A,0xF5,0xB0,0xC8,0xEB,0xBB,0x3C,0x83,0x53,0x99,0x61,0x17,0x2B,0x04,0x7E,0xBA,0x77,0xD6,0x26,0xE1,0x69,0x14,0x63,0x55,0x7D,0x0C,0xC7]
flag = [0xeb,0x47,0x21,0xd5,0x16,0xaf,0x35,0x55,0x95,0x84,0xea,0x3f,0x33,0xe9,0x21,0xd5,0xb4,0xad,0x21,0x36,0x34,0x96,0x12,0x87,0x21,0xd5,0xbc,0x21,0xd5,0xf6,0x25,0x21,0x30,0x8b,0xd7,0x1c,0xe2,0x39,0x3f,0xb9,0x43,0x57,0x20,0xd5,0x14,0xc7,0x13,0x73,0x21,0x36,0x55,0xc5,0x21,0xd5,0x99,0x41,0x21,0xd5,0xde,0x1b,0x47,0x62,0x68,0x21,0xd5,0x9a,0xa2,0xf3,0x60,0x6e,0x92,0xfb,0x9f,0x21,0xd5,0x8d,0x62,0x1e,0x06,0xcb,0xb1,0x21,0xd5,0xf2,0xaf,0x6b,0x21,0x36,0xb4,0x1e,0x6b,0x21,0xd5,0xbf,0x21,0xd5,0x6a,0xaf,0x1b,0x61,0x7d,0x21,0x36,0x59,0xdf,0x75,0x21,0x36,0x3f,0xe0,0x21,0xd5,0xb9,0x18,0x17,0x21,0x30,0xa6,0x5d,0x25,0x21,0x36,0xa1,0x23,0xe8,0x21,0x36,0xc9,0x35,0x9e,0x14,0x84,0xe7,0x1e,0xc9,0x54,0xae,0x57,0x4c,0xf5,0x21,0x36,0x19,0x21,0xd5,0x2d,0xa9,0x7f,0x1a,0x1e,0x45,0x87,0x48,0x21,0x36,0x88,0x88,0xf6,0xeb,0xfb,0x3a,0x44,0x21,0xd5,0xd9,0x44,0x26,0x59,0xc2,0x17,0x4c,0x9a,0x00,0x38,0x2d,0x16,0xab,0xc7,0xc3,0xb2,0x4a,0x52,0xbf,0xaf,0x2c,0x3f,0x73,0x07,0x76,0x50,0x36,0x21,0x36,0x7b,0xab,0xdc,0x49,0xe2,0x6e,0xa1,0x21,0xd5,0xab,0x07,0x32,0xf0,0x01,0x21,0x30,0x67,0x22,0x50,0x27,0xba,0x48,0x69,0x0b,0x3d,0x63,0x2e,0x21,0x36,0x47,0x05,0x89,0x21,0xd5,0xc3,0x08,0xef,0x21,0xd5,0x3a,0x24,0x52,0x21,0xd5,0x3b,0xfe,0xa2,0x21,0xd5,0xbd,0x15,0x05,0xc9,0xde,0xb4,0x21,0xd5,0xe4,0xf9,0x39,0x63,0x83,0xef,0x21,0xd5,0x61,0x8b,0xe5,0x21,0xd5,0x34,0xbc,0x7f,0x21,0x36,0x5c,0x30,0x25,0x61,0x66,0xb3,0xec,0x4b,0x71,0x80,0x35,0x8d,0x38,0x21,0xd5,0xfb,0x21,0xd5,0x79,0x8f,0x3c,0x21,0x36,0xa9,0x21,0xd5,0x09,0x48,0x21,0xd5,0xb3,0x39,0x21,0x36,0xb6,0x5e,0x04]
def check_index(data):
for i in range(0,len(table)):
if data==table[i]:
print "yo="+str(i)
return i
random_libc = ctypes.CDLL('/lib/x86_64-linux-gnu/libc.so.6')
random_libc.srand(0x7e2)
binary = ""
for i in range(0,len(flag)):
if flag[i]!=0x21 and flag[i-2]==0x21:
tmp = random_libc.random()&0xff
if check_index(flag[i])==tmp:
binary += "0"*check_index(flag[i-1])
else:
binary += "1"*check_index(flag[i-1])
elif flag[i]!=0x21 and flag[i-1]!=0x21 and flag[i-2]!=0x21:
tmp = random_libc.random()&0xff
print tmp
if check_index(flag[i])==tmp:
binary += "0"
else:
binary += "1"
print binary
Result
010001100100110001000001010001110111101101001001010111110111011100110001011011000110110001011111010001110011000001011111011101000011000001011111010110010011000001110101010111110110110001101001011010110011001101011111010101000110100001100101010111110100011000110001011100100111001101110100010111110101001101101110001100000111011101111101
이렇게 구한 이진수 값을 다시 문자열로 변환해주면 플래그가 나온다.
flag = ""
flag_bin = [0b01000110,0b01001100,0b01000001,0b01000111,0b01111011,0b01001001,0b01011111,0b01110111,0b00110001,0b01101100,0b01101100,0b01011111,0b01000111,0b00110000,0b01011111,0b01110100,0b00110000,0b01011111,0b01011001,0b00110000,0b01110101,0b01011111,0b01101100,0b01101001,0b01101011,0b00110011,0b01011111,0b01010100,0b01101000,0b01100101,0b01011111,0b01000110,0b00110001,0b01110010,0b01110011,0b01110100,0b01011111,0b01010011,0b01101110,0b00110000,0b01110111,0b01111101]
for i in range(0,len(flag_bin)):
flag += chr(flag_bin[i])
print flag
Flag = FLAG{I_w1ll_G0_t0_Y0u_lik3_The_F1rst_Sn0w}