[Writeup] [UFO CTF 2013] Crypto (100)

Standard

Lời nói đầu

Đề bài

Nội dung chính

Xem file private_encode.py:

import Image

img = Image.open( "img.png" )
width, height = img.size
pix = img.load()
result = ""

def magic( pix ):
	k = 1.158371
	res = (pix[0]&0x1f)*k+(pix[1]&0x3f)*k+(pix[2]&0x7f)*k
	return int( res )

for w in range(width):
	for h in range(height):
		result += chr( magic( pix[w,h] ) )

open("img.encode","wb").write( result )

Như vậy là đọc từng điểm màu của file ảnh, lấy giá trị

res = (red & 0x1F + green & 0x3F + blue & 0x7F) * k

rồi lưu res đó thành từng byte trong file img.encode. Việc ta cần làm là khôi phục lại được file ảnh ban đầu.

Nói chung thì có trời mới lấy lại được đúng đến từng bit (vì a + b + c = x, biết x rồi thì vẫn có vô số bộ a, b, c thỏa mãn), mọi thứ trên đời này chỉ mang tính tương đối thôi. Nhận thức dù sao cũng nên thoáng một chút🙂

Thử code đại theo hướng sau, với tín hiệu khả quan rằng các giá trị red – green – blue sẽ không chồng chéo lẫn nhau khi tham gia vào hàm encode:

import Image

width = height = 300
img = Image.new('RGB', (width, height))
pix = img.load()

encrypted = open('img.encode', 'rb').read()

i = 0
k = 1.158371
for w in range(width):
	for h in range(height):
		byt = int(ord(encrypted[i]) / k)
		r = byt & 0x000FFFFF
		g = byt & 0x00F00000
		b = byt & 0x0F000000
		pix[w, h] = (r, g, b)

		i += 1

img.save('img.png')

Nhận được kết quả:

img

Hừm, Qr thần thánh đây mà =.= Mỗi tội màu không được đẹp lắm. Giờ ta sẽ đổi cái nền đỏ qua trắng, còn các màu khác thì thành đen, như thế nó đúng bài hơn.

Mở file img.encode dưới dạng hex, thấy các byte nền đỏ là 0xFF:

25-07-2013 23-04-28

Sửa code một chút:

import Image

width = height = 300
img = Image.new('RGB', (width, height))
pix = img.load()

encrypted = open('img.encode', 'rb').read()

i = 0
k = 1.158371
for w in range(width):
	for h in range(height):
		byt = int(ord(encrypted[i]) / k)
		if (byt != int(0xFF / k)):
			r = g = b = 0
		else:
			r = g = b = 255

		pix[w, h] = (r, g, b)

		i += 1

img.save('img_.png')

Kết quả rất xinh xắn đây:

img_

Hơi răng cưa, cơ mà không sao. Ráng chọn góc đẹp đẹp rồi quét vài lần, thấy vẫn ra kết quả:

9rypBzr_GB_7sBP6S

Với khả năng suy luận thiên bẩm và vô cùng ảo diệu, nghĩ được như sau:

  • Từ đầu tiên rất giống Cryptor. Đâu tự dưng trùng hợp lại là chữ Cryptor trong một bài thi về Cryptor >”<
  • Nếu từ đầu tiên là Cryptor, thì 9C, Bt, và zo.
  • Thay vào ta được: Cryptor_Gt_7stP6s.
  • Một từ có 2 chữ cái, mà chữ thứ 2 là t, lại ở giữa 2 từ. Nhiều khả năng đó là từ At :”> Vậy tạm coi G là A. Ta có Cryptor_At_7stP6s.
  • Xong, lối tắt đã hiện ra, và chúng ta đâm vào ngõ cụt. Nghĩ cả đêm không xong, chợp mắt chút đã.

Sáng dậy, có điểm sáng khi thím Tý phát hiện rằng nếu tiến hành ROT13 cái 9rypBzr_GB_7sBP6S, ta thu được:

9elcOme_TO_7fOC6F

Quá đẹp! Còn gì phải nghi ngờ nữa? Nó chính là WelcOme_TO_UfOCTF (ai cũng thấy mà, phải hem :-P). Lại thêm một điểm sáng cực kỳ chói lóa, đó là 9 – 7 đúng bằng ‘W’ – ‘U’, và 7 – 6 lại đúng bằng ‘U’ – ‘T’.

Submit luôn, và 100 điểm về tay \m/

Đấy là mình đang tưởng tượng thế😦 Chứ submit nó báo wrong cho tan nát cả từ thể xác cho đến tinh thần T_T.

Mất thêm gần 1 ngày chỉ để hiểu xem ta đã sai ở đâu, ta đã suy luận thiếu ở đâu. Đã thử sang cả ROT18, nhưng cũng chẳng có ý nghĩa gì, vì lời gợi ý từ người ra đề cho ta những điểm quan trọng sau:

  • Không cần đoán các trường hợp của flag, chỉ cần ‘convert’ cẩn thận là ra.
  • Flag không chứa chữ số.

Vâng, từng ấy dữ kiện, nhưng không ra thì… vẫn không ra😥 Suy nghĩ… suy nghĩ… T_T

Chợt thấy trong khung chat irc của cuộc thi có nhắc đến khái niệm extended alphabet. Chỉ thế thôi, chỉ cần thế thôi mà trong đầu đã chợt thấy trăng sao nó kéo đến choán hết cả tầm nhìn xD

s = '9rypBzr_GB_7sBP6S'
extended_alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'

def get_roted_char(original_char, n):
	original_pos = extended_alphabet.find(original_char);
	if (original_pos == -1):
		return original_char

	roted_pos = (original_pos + n) % len(extended_alphabet)
	return extended_alphabet[roted_pos]

# try each value of n and do ROTn with the original string
for n in range(1, len(extended_alphabet)):
	roted_s = ''
	for c in s:
		roted_s += get_roted_char(c, n)

	print roted_s

aszqCAs_HC_8tCQ7T
btArDBt_ID_9uDR8U
cuBsECu_JE_avES9V
dvCtFDv_KF_bwFTaW
ewDuGEw_LG_cxGUbX
fxEvHFx_MH_dyHVcY
gyFwIGy_NI_ezIWdZ
hzGxJHz_OJ_fAJXe0
iAHyKIA_PK_gBKYf1
jBIzLJB_QL_hCLZg2
kCJAMKC_RM_iDM0h3
lDKBNLD_SN_jEN1i4
mELCOME_TO_kFO2j5
nFMDPNF_UP_lGP3k6
oGNEQOG_VQ_mHQ4l7
pHOFRPH_WR_nIR5m8
qIPGSQI_XS_oJS6n9
rJQHTRJ_YT_pKT7oa
sKRIUSK_ZU_qLU8pb
tLSJVTL_0V_rMV9qc
uMTKWUM_1W_sNWard
vNULXVN_2X_tOXbse
wOVMYWO_3Y_uPYctf
xPWNZXP_4Z_vQZdug
yQXO0YQ_50_wR0evh
zRYP1ZR_61_xS1fwi
ASZQ20S_72_yT2gxj
BT0R31T_83_zU3hyk
CU1S42U_94_AV4izl
DV2T53V_a5_BW5jAm
EW3U64W_b6_CX6kBn
FX4V75X_c7_DY7lCo
GY5W86Y_d8_EZ8mDp
HZ6X97Z_e9_F09nEq
I07Ya80_fa_G1aoFr
J18Zb91_gb_H2bpGs
K290ca2_hc_I3cqHt
L3a1db3_id_J4drIu
M4b2ec4_je_K5esJv
N5c3fd5_kf_L6ftKw
O6d4ge6_lg_M7guLx
P7e5hf7_mh_N8hvMy
Q8f6ig8_ni_O9iwNz
R9g7jh9_oj_PajxOA
Sah8kia_pk_QbkyPB
Tbi9ljb_ql_RclzQC
Ucjamkc_rm_SdmARD
Vdkbnld_sn_TenBSE
Welcome_to_UfoCTF
Xfmdpnf_up_VgpDUG
Ygneqog_vq_WhqEVH
Zhofrph_wr_XirFWI
0ipgsqi_xs_YjsGXJ
1jqhtrj_yt_ZktHYK
2kriusk_zu_0luIZL
3lsjvtl_Av_1mvJ0M
4mtkwum_Bw_2nwK1N
5nulxvn_Cx_3oxL2O
6ovmywo_Dy_4pyM3P
7pwnzxp_Ez_5qzN4Q
8qxoAyq_FA_6rAO5R

Ok ok, submit gấp. Lần này thì 100 điểm thật :*

P.S: Gửi tặng mọi người cái hình bản đẹp (còn làm sao mình có được thì, bí mật :”>)

Untitled-11

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s