[CSAW CTF 2013] onlythisprogram (Crypto300)
onlythisprogram – 300 Points
Solved by 127 teams.
File dự phòng:
Nội dung chính
Có cảm giác như CSAW có liên kết với Apple, vì mình nghĩ bài này chỉ nên là Crypto100, thay vì 300 như họ báo giá
Chúng ta có một file dùng để mã hóa, và 9 file đã được mã hóa (tên từ file0.enc đến file8.enc). Thuật toán vô cùng đơn giản: XOR huyền thoại, sử dụng XOR_KEY có kích thước 256 byte. Nhiệm vụ vẫn như mọi lần, đó là giải mã cái mớ file nhảm nhảm xxx.enc kia.
Xem thử nội dung các file, ta thấy ở file5.enc và file7.enc có biến. Cụ thể ở file5.enc, ngay đầu file ta đã thấy có các phần dữ liệu trùng lặp, và kỳ lạ là kích thước của chúng đúng bằng 256 byte.
file7.enc cũng tương tự, nhưng khác về vị trí:
Thật khó mà nghĩ rằng đối với một file dạng nhị phân mà lại có thể chứa những dữ liệu kỳ dị như vậy, một đoạn văn bản lặp lại dài đúng 256 byte? Một tiếng rên với 256 âm tiết? A a a a a? Ớ ớ ớ ớ ớ? Ui ui, bậy quá bậy quá
Nếu 256 byte đó ở file gốc là một dãy các byte khác nhau, chẳng có gì để nói cả, thậm chí bài toán có thể trở nên không giải được, vì liệu có thần tiên tỉ tỉ nào lại có thể đoán trúng một lượng dữ liệu khổng lồ như vậy? Theo Toán học mà nói, mỗi byte có 256 trường hợp, nên một dãy 256 byte thì số trường hợp là 256^256, xác suất đoán đúng là:
[sh]1 / 32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638215525166389437335543602135433229604645318478604952148193555853611059596230656[/sh]
Tuy nhiên nếu đưa ngay flag ra thì sẽ không thể hiện được sự lãng tử và tài hoa của người viết, nên chúng ta sẽ đi vòng thêm một vài bước nữa
Giả sử chúng ta chưa biết đến sự lặp lại của các byte này, hoặc chưa hiểu nó là gì, thì việc đầu tiên cần làm chính là xác định định dạng của từng file gốc. Bằng cách nào? Bằng cách thử các chữ ký của một vài định dạng file phổ biến, xét với từng trường hợp, mỗi trường hợp ứng với chữ ký đó dành cho 1 trong 9 file .enc. Code minh họa:
[python]file_names = [‘file0.enc’, ‘file1.enc’, ‘file2.enc’, ‘file3.enc’,
‘file4.enc’, ‘file5.enc’, ‘file6.enc’, ‘file7.enc’, ‘file8.enc’]
file_datas = {}
for file_name in file_names:
file_datas[file_name] = open(‘output/’ + file_name, ‘rb’).read()
def solve(sign):
print ‘solving with sign:’, sign.encode(‘hex’)
for file_name2 in file_names:
key = ”
for i in range(len(sign)):
key += chr(ord(sign[i]) ^ ord(file_datas[file_name2][i]))
print ‘nnnn===> key if provided sign is for file %s:’ % file_name2, key.encode(‘hex’)
for file_name in file_names:
decoded_data = ”
for i in range(len(key)):
decoded_data += chr(ord(key[i]) ^ ord(file_datas[file_name][i]))
print ‘decoded data for %s:’ % file_name, decoded_data, decoded_data.encode(‘hex’)
def decode(secret):
for file_name in file_names:
outfile = open(‘decoded/’ + file_name, ‘wb’)
for i in range(len(file_datas[file_name])):
outfile.write(chr(ord(file_datas[file_name][i]) ^ ord(secret[i % len(secret)])))
sign = ’89 50 4E 47 0D 0A 1A 0A’
sign = sign.replace(‘ ‘, ”).decode(‘hex’)
solve(sign)[/python]
Khi xét đến sign = “89 50 4E 47 0D 0A 1A 0A” (.png), ta thấy kết quả:
[sh]…
===> key if provided sign is for file file2.enc: 40503ac82d69f7d3
decoded data for file0.enc: MThd ♠ 4d54686400000006
decoded data for file1.enc: ╪ α ►JF ffd8ffe000104a46
decoded data for file2.enc: ëPNG→ 89504e470d0a1a0a
decoded data for file3.enc: ╪ α ►JF ffd8ffe000104a46
decoded data for file4.enc: ▼ ÷}&R 1f8b0800f67d2652
decoded data for file5.enc: BM>~♦ 424d3e7e04000000
decoded data for file6.enc: GIF89aç 4749463839618700
decoded data for file7.enc: ╨╧◄αí▒→ß d0cf11e0a1b11ae1
decoded data for file8.enc: %PDF-1.2 255044462d312e32
…[/sh]
Hoàn hảo! Vì tất cả các chữ ký đều trùng khớp với một định dạng file nào đó, cụ thể:
[sh]file0: MID
file1: JPEG
file2: PNG
file3: JPEG
file4: GZIP
file5: BMP
file6: GIF
file7: DOC
file8: PDF[/sh]
file5 là BMP – một định dạng rất thú vị, vì các byte màu được lưu theo phong cách hoàn toàn mộc mạc và giản dị
Đọc qua về cấu trúc của nó, ta thấy sau khoảng hơn 100 byte đầu dành cho header và những thứ linh tinh, các byte sau đó lần lượt là giá trị R, G, B, Alpha của từng pixel (kiểu kiểu vậy). Như thế có nghĩa là?…
…
Là sẽ rất hợp theo lẽ tự nhiên, nếu những byte đầu là 0x00, 0x00, 0x00 rồi lại 0x00 – ứng với màu đen (màu nền). Tất nhiên nó có thể là một màu khác, nhưng tóm lại cái quan trọng là, các byte đó dù có giống nhau thì cũng không có gì phi logic cả. Chúng ta buộc phải xét rằng các byte đó giống nhau (vì nếu khác thì không thể làm được), và khi đã giống nhau, cùng lắm là nó có tối đa 256 trường hợp cần xét, quá nhỏ!
Trước tiên xét mặc định là màu đen cái đã, ok, là 0x00, tức là các byte trong file5.enc chính là XOR_KEY luôn (a XOR 0 = a). Lấy 256 byte tính từ offset 256 (vì những byte đầu có chứa header):
thử decrypt:
[python]def get_original_file():
secret = ‘40503AC82D69F7D3023AF4AC67DE4D3B81443E4DEDE1D5437456A8D29FA02329126D0BCEA40FC7F6BE9FF7C66D74DCBAD2D40EA3D5290C31F108532EB10C796A29BCE1E4B3BB40BF69777D2155EA80457E43036093B498B3268E35A16CCC6ED4CA8F10EE61297FAB882408B53023A61BC89C10A0181EAC9E62A1B66A48469C608587CB63A87F2BD630531D657CAC220D3A41E164DCF778E3F8DE04439C6EEC5AD4A6D17FA96CDF63DFD5712EC1D65E555F8E704BB853F28DF7162B3AB9A175749BE03EE7FC68CB8D9A954500E4A4EC15F41E8083E436817A4512006C5AA4D30B8B89B99139F7E2B7985939B3864D5DAF589E30EFCD2BBC0C9FDCE6C69E71AAE8’.decode(‘hex’)
for file_name in file_names:
outFile = open(‘decoded/’ + file_name, ‘wb’)
for i in range(len(file_datas[file_name])):
outFile.write(chr(ord(secret[i % len(secret)]) ^ ord(file_datas[file_name][i])))
outFile.close()
get_original_file()[/python]
Kết quả không ngoài dự đoán:
Unzip file4, mở bằng text editor bất kỳ, bỏ word-wrap:
[sh] _____ _ __ _ _ _ _ _ _ __ _ _ _ ___ _ _ _ _ _ _ _ _ _ __ _ _ _ _ _ _ _ _ _ _ _____ _ _ ___ _ _ _ _ _ _ _ _ _ _ _ _ ____ _ _ ___ __ ___ ____ _ ____ ___ _ _ _ _ _ _ ____ _ _
| ___|__ _ __ ___ ___ _ __ ___ ___ _ __ ___ __ _ ___ ___ _ __ _ __ ___(_)/ _| ___ _ __| |_ _____ __ _ __ ___ __ _| | |_ _ | (_) | _____ ___ / _(_) __ _| | ___| |_ ___ |_ _|_ __ | |_| |__ (_)___ ___ __ _ ___ ___ (_) |_( )___ _ __ ___ ___ ___ ___ ___ __ _ _ __ _ _ | |__ ___ ___ __ _ _ _ ___ ___ | |_| |__ ___ / _(_) | ___ ___(_)_______ ___| |__ ___ _ _| | __| | _ __ ___ | |_ | |__ ___ __ _ | |__ _ _ __ _ ___ __ _(_)_ _____ __ ___ ____ _ _ _ |_ _| |__ ___ _ _ __ _| |__ |_ _| ___ _ _ _ __ _ __ ___ ___ ___ (_)_ __ ___ __ _ __ _ ___ ___ __ _____ _ _| | __| | | |__ __ ___ _____ __ _____ _ __| | _____ __| | | |_ ___ ___ / _ __ _ ___ ____ _ _ _ | |_| |__ ___ | | _____ _ _ (_)___ _ | __ ) _ _(_) | __| / /__ _ _ _ __ / _ __ ___ __ / ___|_ __ _ _ _ __ | |_ ___/ ___| ___ / _ | |_| |__ ___ _ __ ___| | | | __ ___ _____ | | ___ | |__/ ___| ___ ___ _ _ _ __(_) |_ _ _
| |_ / _ | ‘__| / __|/ _ | ‘_ _ / _ | '__/ _ / _
/ __|/ _ | ‘_ | ‘_ / __| | |_ / _ ‘__| __/ _ / / | ‘__/ _ / _ | | | | | | | | | |/ / _ / __| | |_| |/ _
| |/ _ __/ __| | || ‘_ | __| ‘_ | / __| / __/ _ / __|/ _ | | __|// __| | '_ / _ / __/ _ / __/ __|/ _
| ‘__| | | | | ‘_ / _ / __/ _ | | | / __|/ _ | __| '_ / _ | |_| | |/ _ / __| |_ / _ / __| '_ / _ | | | | |/ _
| | ‘_ / _ | __| | ‘_ / _ / _ | | '_ | | | |/ _
|/ _ / _ | / / _ / _
/ / / _ | | | | | | | '_ / _ | | | |/ _
| ‘_ | | / __| | | | ‘_ | ‘_ / _ / __|/ _ | | ‘_ _ / _
|/ _ |/ _ / __| / / / _ | | | | |/ _
| | ‘_ / _ / / _ / / / _ | '__| |/ / _ / _
| | __/ _ / _ / _ | ‘_ | | | / / / _ | | | | | __| '_ / _ | |/ / _ | | | | / __(_) | _ | | | | | |/ _
| V / _ | | | | ‘__| | | / / / ‘_ | | | ‘__| | | | ‘_ | __/ _ ___ / _ | | | | __| ‘_ / _ ‘__/ __| |_| |/ _` / / _ _ | |/ _ | ‘_ ___ / _ / __| | | | ‘__| | __| | | |
| _| (_) | | __ (_) | | | | | | __/ | | | __/ (_| __ (_) | | | | | |_) __ | _| __/ | | || __/> < | | | __/ (_| | | | |_| | | | | < __/__ | _| | (_| | | __/ |___ _ | || | | | | |_| | | | __ | (_| (_| __ __/ | | |_ __ | | | | __/ (_| __/__ __ (_| | | | |_| | | |_) | __/ (_| (_| | |_| __ __/ | |_| | | | __/ | _| | | __/ __ |/ / __/ __ | | | (_) | |_| | | (_| | | | | | (_) | |_ | |_) | __/ | (_| | | | | | |_| | (_| | __/ | (_| | | V / __/ (_| | V V / (_| | |_| |_ | | | | | | (_) | |_| | (_| | | | | | | __ |_| | |_) | |_) | (_) __ __/ | | | | | | | (_| | (_| | __/__ V V / (_) | |_| | | (_| | | | | | (_| | V / __/ V V / (_) | | | < __/ (_| | | || (_) | (_) | / ___ | | | | |_| | V V / (_| | |_| |_ | |_| | | | __/ | < __/ |_| | | __ _ | |_) | |_| | | | (_| | | | (_) | |_| | | | |_| | V V /| | | | |___| | | |_| | |_) | || (_) |__) | (_) | |_| | |_| | | | __/ | __ _ | (_| | V / __/ |_| | (_) | |_) |__) | __/ (__| |_| | | | | |_| |_| |
|_| ___/|_| |___/___/|_| |_| |_|___| |_| ___|__,_|___/___/|_| |_| | .__/|___/_|_| ___|_| _____/_/_ |_| ___|__,_|_|_|__, | |_|_|_|____||___/ |_| |_|__, |_|___|__|___(_) |___|_| |_| __|_| |_|_|___/ _____,_|___/___| |_|__| |___/ |_| |_|___|______||___/___/__,_|_| __, | |_.__/ ___|_____,_|__,_|___/___| __|_| |_|___| |_| |_|_|___| |___/_/______| |___/_| |_|___/ __,_|_|__,_| |_| |_|___/ __| |_.__/ ___| __,_| |_| |_|__,_|__, |___| __, |_| _/ ___|__,_| _/_/ __,_|__, (_) |_| |_| |_|___/ __,_|__, |_| |_| |___| |___/__,_| .__/| .__/ ___/|___/___| |_|_| |_| |_|__,_|__, |___||___/ _/_/ ___/ __,_|_|__,_| |_| |_|__,_| _/ ___| _/_/ ___/|_| |_|____|__,_| _____/ ___(_) /_/ __| |_|__, | _/_/ __,_|__, ( ) __|_| |_|___| |_|____|__, | |_|___(_) |____/ __,_|_|_|__,_| |_|___/ __,_|_| ___/ _/_/ |_| |_|____|_| __, | .__/ _____/____/ ___/ ___/ __|_| |_|___|_| |___/_| |_|__,_| _/ ___|___/ ___/|_.__/____/ ___|___|__,_|_| |_|__|__, |
|_| |___/ |___/ |___/ |___/ |___/ |___/ |___/ |_| |_| |___/ |___/ |___/|/ |___/ |___/|_| |___/
[/sh]
flag = BuildYourOwnCryptoSoOthersHaveJobSecurity
Recent comments