この大会は2021/5/15 0:00(JST)~2021/5/17 7:00(JST)に開催されました。
今回もチームで参戦。結果は7350.点で1084チーム中13位でした。
自分で解けた問題をWriteupとして書いておきます。
Sanity Check (Welcome 50)
トップページのSANITY CHECKのエリアにフラグが書いてあった。
dctf{welc0m3_t0_dCTF}
Dragon (Misc 100)
StegSolveで開き、Blue plane 0を見ると、フラグが書いてあった。
dctf{N0w_Y0u_s3e_m3}
Don't let it run (Misc 100)
PDF Stream Dumperで開くと、Object 3にJavaScriptが書いてある。
<< /Type /Action /S /JavaScript /JS var _0x4ac9=['663aCYhYK','9qwaGGO','log','1PtCftm','1068uRYmqT','dctf{pdf_1nj3ct3d}','768577jhhsbr','717342hAzOOQ','722513PAXCbh','833989PQKiti','1447863RVcnTo','125353VtkXUG'];(function(_0x3b1f6b,_0x1ad8b7){var _0x566ee2=_0x5347;while(!![]){try{var _0x2750a5=parseInt(_0x566ee2(0x16e))+-parseInt(_0x566ee2(0x16d))+parseInt(_0x566ee2(0x16c))+-parseInt(_0x566ee2(0x173))*-parseInt(_0x566ee2(0x171))+parseInt(_0x566ee2(0x172))*-parseInt(_0x566ee2(0x16a))+parseInt(_0x566ee2(0x16f))*parseInt(_0x566ee2(0x175))+-parseInt(_0x566ee2(0x170));if(_0x2750a5===_0x1ad8b7)break;else _0x3b1f6b['push'](_0x3b1f6b['shift']());}catch(_0x5764a4){_0x3b1f6b['push'](_0x3b1f6b['shift']());}}}(_0x4ac9,0x8d97f));function _0xa(){var _0x3c6d20=_0x5347;console[_0x3c6d20(0x174)](_0x3c6d20(0x16b));}var a='bkpodntjcopsymlxeiwhonstykxsrpzy',b='exrbspqqustnzqriulizpeeexwqsofmw';_0xb(a,b);function _0x5347(_0x37de35,_0x19ac26){_0x37de35=_0x37de35-0x16a;var _0x4ac9ea=_0x4ac9[_0x37de35];return _0x4ac9ea;}function _0xb(_0x39b3ee,_0xfae543){var _0x259923=_0x39b3ee+_0xfae543;_0xa();} >>
このスクリプトをChromeのデベロッパーツールのConsoleで実行する。
dctf{pdf_1nj3ct3d}
Hidden message (Misc 100)
$ zsteg fri.png b1,rgb,lsb,xy .. text: "dctf{sTeg0noGr4Phy_101}" b3,g,lsb,xy .. text: "I@4I)$Xl" b3,abgr,msb,xy .. text: "v\rWv)WvM" b4,r,lsb,xy .. text: "\nfb@DHfBHH" b4,r,msb,xy .. text: "E`@Q'g3@D@tr" b4,g,msb,xy .. text: "ND@&B$rp" b4,b,lsb,xy .. text: "D\"$ \"\"\"$bN" b4,b,msb,xy .. text: "DDD$Fr0U3p@f" b4,rgb,lsb,xy .. text: "HDd(\"b(Dd\"" b4,rgb,msb,xy .. text: "GpD@FdD#" b4,bgr,lsb,xy .. text: "H$b(\"dH$`" b4,bgr,msb,xy .. text: "t@@DFd$#" b4,rgba,lsb,xy .. text: "`OP/S/b/b?" b4,abgr,msb,xy .. text: "O@OdOdO2/"
dctf{sTeg0noGr4Phy_101}
Bell (Reverse 100)
Ghidraでデコンパイルする。
undefined8 main(void) { int iVar1; uint uVar2; time_t tVar3; tVar3 = time((time_t *)0x0); srand((uint)tVar3); iVar1 = rand(); uVar2 = iVar1 % 5 + 8; printf("%d\n",(ulong)uVar2); process(uVar2); return 0; } undefined8 process(int param_1) { long lVar1; bool bVar2; long lVar3; long in_FS_OFFSET; int local_24; long local_20; lVar1 = *(long *)(in_FS_OFFSET + 0x28); bVar2 = true; local_24 = 1; while (local_24 <= param_1) { lVar3 = triangle(param_1,local_24,local_24); __isoc99_scanf(); if (lVar3 != local_20) { bVar2 = false; } local_24 = local_24 + 1; } if (bVar2) { system("cat flag.txt"); } else { puts("Better luck next time."); } if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) { /* WARNING: Subroutine does not return */ __stack_chk_fail(); } return 0; } long triangle(int param_1,int param_2) { long lVar1; long lVar2; if (param_1 < param_2) { lVar1 = 0; } else { if ((param_1 == 1) && (param_2 == 1)) { lVar1 = 1; } else { if (param_2 == 1) { lVar1 = triangle(param_1 + -1,param_1 + -1,param_1 + -1); } else { lVar2 = triangle(param_1,param_2 + -1,param_2 + -1); lVar1 = triangle(param_1 + -1,param_2 + -1,param_2 + -1); lVar1 = lVar1 + lVar2; } } } return lVar1; }
このコードを元に、param_1回、triangle()の結果を答える。
import socket from Crypto.Util.number import * def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) def triangle(n1, n2): if n1 < n2: lVar1 = 0 else: if n1 == 1 and n2 == 1: lVar1 = 1 else: if n2 == 1: lVar1 = triangle(n1 - 1, n1 - 1) else: lVar2 = triangle(n1, n2 - 1) lVar1 = triangle(n1 - 1, n2 - 1) lVar1 = lVar1 + lVar2 return lVar1 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('dctf-chall-bell.westeurope.azurecontainer.io', 5311)) data = recvuntil(s, '\n').rstrip() print data param1 = int(data) for i in range(1, param1 + 1): lVar3 = triangle(param1, i) print lVar3 s.sendall(str(lVar3) + '\n') data = recvuntil(s, '\n').rstrip() print data
実行結果は以下の通り。
10 21147 25287 30304 36401 43833 52922 64077 77821 94828 115975 dctf{f1rst_step_t0wards_b3ll_l4bs}
dctf{f1rst_step_t0wards_b3ll_l4bs}
Tiny interpreter (Reverse 400)
binファイルをパラメータとして指定して、実行するだけ。
$ ./interpreter bin I n t e r p r e t e r _ w r i t t e n _ i n _ C _ i s _ a _ g r e a t _ i d e a
dctf{Interpreter_written_in_C_is_a_great_idea}
Very secure website (Web 200)
ソースコードを見ると、こう書いてある。
<?php if (isset($_GET['username']) and isset($_GET['password'])) { if (hash("tiger128,4", $_GET['username']) != "51c3f5f5d8a8830bc5d8b7ebcb5717df") { echo "Invalid username"; } else if (hash("tiger128,4", $_GET['password']) == "0e132798983807237937411964085731") { $flag = fopen("flag.txt", "r") or die("Cannot open file"); echo fread($flag, filesize("flag.txt")); fclose($flag); } else { echo "Try harder"; } } else { echo "Invalid parameters"; } ?>
"51c3f5f5d8a8830bc5d8b7ebcb5717df"を検索すると、"admin"のtiger128,4ハッシュであることがわかる。
"0e132798983807237937411964085731"は該当するものが見つからないが、"0e(10進数値のみ)"となっているので、0と同等である。tiger128,4が0eから始まり、他が10進数値のものであれば、何でもよい。
調べると、https://blog.csdn.net/fastergohome/article/details/102514264 にこの手法の代表的な値が掲載されていた。
以下でログインしてみると、フラグが表示された。
Username: admin Password: 479763000
dctf{It's_magic._I_ain't_gotta_explain_shit.}
Strong password (Crypto 100)
$ zip2john strong_password.zip > hash.txt ver 2.0 efh 9901 strong_password.zip/lorem_ipsum.txt PKZIP Encr: cmplen=5171, decmplen=17174, crc=CEFA3672 $ john --wordlist=dict/rockyou.txt hash.txt --rules Using default input encoding: UTF-8 Loaded 1 password hash (ZIP, WinZip [PBKDF2-SHA1 256/256 AVX2 8x]) Will run 2 OpenMP threads Press 'q' or Ctrl-C to abort, almost any other key for status Bo38AkRcE600X8DbK3600 (strong_password.zip/lorem_ipsum.txt) 1g 0:00:03:06 DONE (2021-05-15 06:30) 0.005372g/s 61022p/s 61022c/s 61022C/s Bobo64..Bitchybo#1 Use the "--show" option to display all of the cracked passwords reliably Session completed
パスワード "Bo38AkRcE600X8DbK3600" でzipを解凍すると、lorem_ipsum.txtが展開される。この長文の中にフラグが含まれていた。
dctf{r0cKyoU_f0r_tHe_w1n}
Just Take Your Time (Crypto 200)
サーバの処理概要は以下の通り。
・a * bを答える。 →正しければ、次へ進む。 ・key: UNIXTIMEを16バイト"0"パディングした文字列 ・secret: ランダム16バイト(16進数文字列、長さ32) ・DES3でkey、iv="00000000"を使って、secretを暗号化して表示 ・secretを正しく答えられたら、フラグが表示される。
UNIXTIMEでkeyがわかるので、復号する。
import socket from Crypto.Cipher import DES3 from time import time def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('dctf-chall-just-take-your-time.westeurope.azurecontainer.io', 9999)) data = recvuntil(s, '> ') print data formula = data.split('\n')[1].split(' =')[0] ans = eval(formula) print ans s.sendall(str(ans) + '\n') key = str(int(time())).zfill(16).encode('utf-8') print key data = recvuntil(s, '\n').rstrip() print data data = recvuntil(s, '\n').rstrip() print data encrypted = data.decode('hex') cipher = DES3.new(key, DES3.MODE_CFB, '00000000') secret = cipher.decrypt(encrypted) print secret s.sendall(secret + '\n') data = recvuntil(s, '\n').rstrip() print data data = recvuntil(s, '\n').rstrip() print data
実行結果は以下の通り。
Show me you are worthy and solve for x! You have one second. 2080010430383378 * 7569301504130155 = > 15744226079307314149567060563590 0000001621028971 You have proven yourself to be capable of taking on the final task. Decrypt this and the flag shall be yours! 9fb7657b8db178abe3411b0b051972b29755b6866e57cd73c224a7f5da22bdc9 1c18c21f26151b7d27b1b1e619014718 > Congratulations! Here is your flag. dctf{1t_0n1y_t0Ok_2_d4y5...}
dctf{1t_0n1y_t0Ok_2_d4y5...}
Private Encryption Mistake (Crypto 300)
秘密鍵の見えている部分を書き出す。
-----BEGIN RSA PRIVATE KEY----- MIIJKQIBAAKCAgEAupQ7hhy0AQR0LRMZgP/Kl6J3l2+U+wp1YyVB8oDYvslE3AXU 3igwX2LOYgG/JIHQ5UI2G/0Fu5iPPikh3JoUABGFyPwWsBLnohdBBtpvfRLprhbB lsKwjZfLJIrRex+sSFkcT9zVs1VH4JfcJAbeBNK/aQdMqc1i4JQ1xsQny4ZH7TZe CXBigK99+V05C+ENRS1uWi9ixgcbMWCCBHsTq0Kl5FIfPvVJVBr075bf7DdARSRU Wx/FtKVMlWe/nGUTz/ezu2jOx69kd+hvtzX1JVkeY+AFi7Ldta2tNaH/8kitzoXK JC+6A+LQXynmjQdH9RGsg7QygFjPvIcgwE8LHsMt62OKcIx5LMHlW4lvLK/EZMnr [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] ZEt6WwyEqHhPyP0CggEBAMplAvElBwRTMaT6FfWwi149Q+C1+ogaRc686CkCEs7p zWjt4+Tg3cndxj/p2Q3Z1AzJH8h/vfZruAQHF/UFwXIAPmuzS1K0HgnNHxr355vs AYfArpTJeyZoRttQOXvRhM+c887RWGXX278VVS5e5mh16Dn0rKpDcRnsVMahBhTg +4XheX0zJRa3lOnoWgRLFGcJj9px4Gk7PkZnx24S2bCb7GUbisvtELkLfAvVcGIS vvJGbeovAGpArRoaCbpnRL96N50zOWGqHeXJFljvNDvfpVAbykf+50d2VApvElQ3 /v7UHVZEfszMk3g1z+RLpgVmtltCsFvDSkDW9omfoJ0CggEBAIBfu08VPrN+B8iD QpyO2BBUDei8fjdskpvehjWGDqzKNYDxdVcAdERtk6DSWuzpvwPNbTRm6u3v66yu QkHn9gBlxX1sYe5P9ExqP2p+Au8hR/8s7bhVa8G53WX1Dl47QVSwbKVOWSWtQSwB hiB9s1YqgAlhcKBWP6vFbavr3VBYY5ln/018rYvR1euDVTUVZdSMmbq3gScF4fhv NESMd1Je7XjygbVTPJPi1PcT/SgyDRUwz0RPYIvLlA3qT9ae7s5WTp1fanv5MV6p 4LnekTQ/CVjWSorY7xdXTCMfBK1GF7WhVGG4fVSPX8QeIPKUxKkQXgKAFJrCSjj7 CLG5pPkCggEAflfmKUDTC4kfkXwoXzHxHkgialFPbszvzOmyB39q3E2pU5pFTChv [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] [ Snipped! ] -----END RSA PRIVATE KEY-----
秘密鍵は部分的に2か所がマスクされている。与えられた情報から秘密鍵を復元することができれば、フラグが得られそう。https://tls.mbed.org/kb/cryptography/asn1-key-structures-in-der-and-pemを参考にした。
RSAPrivateKey ::= SEQUENCE { version Version, modulus INTEGER, -- n publicExponent INTEGER, -- e privateExponent INTEGER, -- d prime1 INTEGER, -- p prime2 INTEGER, -- q exponent1 INTEGER, -- d mod (p-1) exponent2 INTEGER, -- d mod (q-1) coefficient INTEGER, -- (inverse of q) mod p otherPrimeInfos OtherPrimeInfos OPTIONAL }
バイナリで構成を見てみると、q, dpがわかる。さらにeは通常の65537と推測して、pを割り出す。あとはdを算出後、n, e, dから秘密鍵を生成する。
from Crypto.Util.number import * from Crypto.PublicKey import RSA key1 = ''' MIIJKQIBAAKCAgEAupQ7hhy0AQR0LRMZgP/Kl6J3l2+U+wp1YyVB8oDYvslE3AXU 3igwX2LOYgG/JIHQ5UI2G/0Fu5iPPikh3JoUABGFyPwWsBLnohdBBtpvfRLprhbB lsKwjZfLJIrRex+sSFkcT9zVs1VH4JfcJAbeBNK/aQdMqc1i4JQ1xsQny4ZH7TZe CXBigK99+V05C+ENRS1uWi9ixgcbMWCCBHsTq0Kl5FIfPvVJVBr075bf7DdARSRU Wx/FtKVMlWe/nGUTz/ezu2jOx69kd+hvtzX1JVkeY+AFi7Ldta2tNaH/8kitzoXK JC+6A+LQXynmjQdH9RGsg7QygFjPvIcgwE8LHsMt62OKcIx5LMHlW4lvLK/EZMnr ''' key1 = key1.decode('base64') hex_n_head = key1[12:].encode('hex') key2 = ''' ZEt6WwyEqHhPyP0CggEBAMplAvElBwRTMaT6FfWwi149Q+C1+ogaRc686CkCEs7p zWjt4+Tg3cndxj/p2Q3Z1AzJH8h/vfZruAQHF/UFwXIAPmuzS1K0HgnNHxr355vs AYfArpTJeyZoRttQOXvRhM+c887RWGXX278VVS5e5mh16Dn0rKpDcRnsVMahBhTg +4XheX0zJRa3lOnoWgRLFGcJj9px4Gk7PkZnx24S2bCb7GUbisvtELkLfAvVcGIS vvJGbeovAGpArRoaCbpnRL96N50zOWGqHeXJFljvNDvfpVAbykf+50d2VApvElQ3 /v7UHVZEfszMk3g1z+RLpgVmtltCsFvDSkDW9omfoJ0CggEBAIBfu08VPrN+B8iD QpyO2BBUDei8fjdskpvehjWGDqzKNYDxdVcAdERtk6DSWuzpvwPNbTRm6u3v66yu QkHn9gBlxX1sYe5P9ExqP2p+Au8hR/8s7bhVa8G53WX1Dl47QVSwbKVOWSWtQSwB hiB9s1YqgAlhcKBWP6vFbavr3VBYY5ln/018rYvR1euDVTUVZdSMmbq3gScF4fhv NESMd1Je7XjygbVTPJPi1PcT/SgyDRUwz0RPYIvLlA3qT9ae7s5WTp1fanv5MV6p 4LnekTQ/CVjWSorY7xdXTCMfBK1GF7WhVGG4fVSPX8QeIPKUxKkQXgKAFJrCSjj7 CLG5pPkCggEAflfmKUDTC4kfkXwoXzHxHkgialFPbszvzOmyB39q3E2pU5pFTChv ''' key2 = key2.decode('base64') q = bytes_to_long(key2[0x000f:0x000f+0x0101]) dp = bytes_to_long(key2[0x0114:0x0114+0x0101]) e = 65537 for kp in range(3, e): p_mul = dp * e - 1 if p_mul % kp == 0: p = (p_mul // kp) + 1 if isPrime(p): break n = p * q assert hex(n)[2:].startswith(hex_n_head) phi = (p - 1) * (q - 1) d = inverse(e, phi) key = RSA.construct(map(long, (n,e,d))) priv_pem = key.exportKey() with open('privkey.pem', 'w') as f: f.write(priv_pem)
$ cat privkey.pem -----BEGIN RSA PRIVATE KEY----- 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 -----END RSA PRIVATE KEY----- $ ssh -i privkey.pem user@dctf1-chall-private-encryption-mistake.westeurope.azurecontainer.io -p 2222 The authenticity of host '[dctf1-chall-private-encryption-mistake.westeurope.azurecontainer.io]:2222 ([20.67.120.180]:2222)' can't be established. ECDSA key fingerprint is SHA256:P5sEp/Iaie3GJcsicYtMk0gi5FZREmFhLLMh8jjPSy4. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '[dctf1-chall-private-encryption-mistake.westeurope.azurecontainer.io]:2222,[20.67.120.180]:2222' (ECDSA) to the list of known hosts. Welcome to OpenSSH Server dctf{Y0u_Are_N0w_Br34thing_M4nua11y} Connection to dctf1-chall-private-encryption-mistake.westeurope.azurecontainer closed.
dctf{Y0u_Are_N0w_Br34thing_M4nua11y}
A Simple SP Box! (Crypto 300)
サーバの処理概要は以下の通り。
・フラグを暗号化して表示 ・15回以下を繰り返し ・フラグを推測し、正しければ、フラグが表示される。 ■暗号化 ・平文の長さが奇数の場合は、"_"をパディング ・rounds = int(2 * ceil(log(len(message), 2))) ・rounds回以下を繰り返し ・message = [S_box[c] for c in message] ・最終回以外は奇数番目グループと偶数番目グループで連結 ※rounds = 2の場合 message = [S_box[c] for c in message] 0バイト目と1バイト目を交換 message = [S_box[c] for c in message]
暗号化したフラグの長さからround = 12。S_boxの2回の対応表はわかるので、逆変換で6回行えば元に戻る。奇数番目と偶数番目の連結は11回行われるので、その逆変換も行えばフラグを得られる。
import socket from string import ascii_letters, digits from math import ceil, log def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) def inv_perm(s): l = len(s) / 2 odd_s = s[:l] even_s = s[l:] d = '' for i in range(l): d += even_s[i] d += odd_s[i] return d def inv_sub(s, inv_sbox): d = '' for c in s: d += inv_sbox[c] return d ALPHABET = ascii_letters + digits + "_!@#$%.'\"+:;<=}{" s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('dctf1-chall-sp-box.westeurope.azurecontainer.io', 8888)) data = recvuntil(s, '\n').rstrip() print data enc_flag = recvuntil(s, '\n').rstrip() print enc_flag inv_S_box = {} for i in range(0, len(ALPHABET), 2): data = recvuntil(s, '> ') print data + ALPHABET[i] + ALPHABET[i+1] s.sendall(ALPHABET[i] + ALPHABET[i+1] + '\n') data = recvuntil(s, '\n').rstrip() print data data = recvuntil(s, '\n').rstrip() print data inv_S_box[data[1]] = ALPHABET[i] inv_S_box[data[0]] = ALPHABET[i+1] rounds = int(2 * ceil(log(len(enc_flag), 2))) inv_S_box_rounds = rounds / 2 perm_rounds = rounds - 1 tmp_flag = enc_flag for i in range(rounds // 2): tmp_flag = inv_sub(tmp_flag, inv_S_box) for i in range(rounds - 1): tmp_flag = inv_perm(tmp_flag) flag = tmp_flag.rstrip('_') print flag
実行結果は以下の通り。
Here's the flag, please decrypt it for me: RMXXE'oosXIBc6XBXdcCXR''3cxBCX6dTM}=csRJXT > ab That doesn't look right, it encrypts to this: += > cd That doesn't look right, it encrypts to this: MI > ef That doesn't look right, it encrypts to this: uJ > gh That doesn't look right, it encrypts to this: qX > ij That doesn't look right, it encrypts to this: Ya > kl That doesn't look right, it encrypts to this: jc > mn That doesn't look right, it encrypts to this: vP > op That doesn't look right, it encrypts to this: fz > qr That doesn't look right, it encrypts to this: kB > st That doesn't look right, it encrypts to this: 1s > uv That doesn't look right, it encrypts to this: "o > wx That doesn't look right, it encrypts to this: x$ > yz That doesn't look right, it encrypts to this: OL > AB That doesn't look right, it encrypts to this: DA > CD That doesn't look right, it encrypts to this: SN > EF That doesn't look right, it encrypts to this: :i > GH That doesn't look right, it encrypts to this: 42 > IJ That doesn't look right, it encrypts to this: %8 > KL That doesn't look right, it encrypts to this: wV > MN That doesn't look right, it encrypts to this: n5 > OP That doesn't look right, it encrypts to this: mU > QR That doesn't look right, it encrypts to this: hK > ST That doesn't look right, it encrypts to this: Z< > UV That doesn't look right, it encrypts to this: Hd > WX That doesn't look right, it encrypts to this: 9C > YZ That doesn't look right, it encrypts to this: eE > 01 That doesn't look right, it encrypts to this: !b > 23 That doesn't look right, it encrypts to this: rG > 45 That doesn't look right, it encrypts to this: py > 67 That doesn't look right, it encrypts to this: tl > 89 That doesn't look right, it encrypts to this: 'R > _! That doesn't look right, it encrypts to this: g7 > @# That doesn't look right, it encrypts to this: _@ > $% That doesn't look right, it encrypts to this: Q; > .' That doesn't look right, it encrypts to this: #. > "+ That doesn't look right, it encrypts to this: 3{ > :; That doesn't look right, it encrypts to this: WT > <= That doesn't look right, it encrypts to this: 06 > }{ That doesn't look right, it encrypts to this: F} dctf{S0_y0u_f0und_th3_cycl3s_in_th3_s_b0x}
dctf{S0_y0u_f0und_th3_cycl3s_in_th3_s_b0x}
This one is really basic (Crypto 300)
繰り返しbase64デコードする。
with open('cipher.txt', 'r') as f: data = f.read().rstrip() while True: try: data = data.decode('base64') except: break print data
dctf{Th1s_l00ks_4_lot_sm4ll3r_th4n_1t_d1d}