試合の実践には 6 つの問題があり、web、misc、crypto の問題が含まれています。この試合は顧客のために行われましたが、問題は難しくなく、そうでなければ小さな試合にはなりませんね。
第一問:1-1#
js を探し、キーワード flag を検索します。
dasctf{d6e9c56d7f078d298ed4695d899effbe}
第二問:2-1#
pdf を開きます。
画像にはテキストボックスがあります。
第三問:3-1#
問題のソースコードは以下の通りで、友人が解きました:
import libnum
import gmpy2
from Crypto.Util.number import *
import flag,e1,e2
#素数を生成
p=libnum.generate_prime(1024)
q=libnum.generate_prime(1024)
ec1=pow(bytes_to_long(str(e1).ljust(20,"D").encode()),3,p*q)
ec2=pow(bytes_to_long(str(e2).ljust(20,"A").encode()),5,p*q)
m=libnum.s2n(flag)
n=p*q
c1=pow(m,e1,n)
c2=pow(m,e2,n)
print("n1=",n)
print("ec1=",ec1)
print("c1=",c1)
print("n2=",n)
print("ec2=",ec2)
print("c2=",c2)
# n1= 27929259512873502442719286790227037320417984116570178470037376373267390909685621247157535458203218619293705428397911754453556082799420494496904478215709219317542924547049229150153308059698341011305505985823374280465467094476511869541135508518055946815227085548571701115773386101962695795789178321155174729047033298389886321980592410739667139376075568555729949442873964097042006391886635957242436522435588904492484342259494858627609438654632887244523845583473711604632109405043439047289868784236481926074763997559971182741918345193506253460323445846136663027639802131457594564405906763806426256107923417802076262573737
# ec1= 24979839185643431898760549059477070141596292955202172081572583839065034831779499992829742773873064296311713734486020739853343887094398935731264
# c1= 17695186679431856780362905635257355413310120106982055323913669124182832151093921194946365178919380690844190324897933591567360925332869903671651849060145290581360223200011298757871213149464298017718829480721410479504940393501845624196721013966839230696831321482946841011452400364600924503121451272593970649100410603943321149604376033957124800064565646929720179239631538966228020882733213221035707244692798307971636126058586394357032072695921642665492919186476321028415907982915011972040971875733852055633796811898421692604356476773910338982400925245494707729878821466569634334862311750349321720627252469986162120031838
# n2= 27929259512873502442719286790227037320417984116570178470037376373267390909685621247157535458203218619293705428397911754453556082799420494496904478215709219317542924547049229150153308059698341011305505985823374280465467094476511869541135508518055946815227085548571701115773386101962695795789178321155174729047033298389886321980592410739667139376075568555729949442873964097042006391886635957242436522435588904492484342259494858627609438654632887244523845583473711604632109405043439047289868784236481926074763997559971182741918345193506253460323445846136663027639802131457594564405906763806426256107923417802076262573737
# ec2= 2838620519239658396968146844964839207179863729944843241951228382052657801460586137213053314019699976475855578055607417923815486109050614096157077528657405905877896929808094661904905136761365045387901486261011216958309860644255996588189249
# c2= 10770781309274554738409447671578241895686779262243081931452089039730277591151694112684863740412412713684216227740930573490322958500198235497947657939304932868457999239593145330718657422535271157683896034543125292529800047408131765376686654378173684648427311300423776510153307756388404568013401217965931456538849277670384454454507752525534110389604969437991055504757081225690155489265359117617764571537216746554060783131168749700810806387918510612057149583061938836035963175555630655718716139689761210220525955656039741684390906935720406757364893793459339618913268943282961044530062475057887777134887741597041684698119
既知の値、公鍵
スクリプト内で次のパラメータが与えられています:n1、n2、ec1、ec2、c1、c2。ec1 と ec2 は小指数暗号で得られたもので、したがって直接 iroot で平方根を取ることで暗号指数 e1 と e2 を得ることができます。
変数 k を使用して、式ec2 + k * n
が完全な五次方数になる有効な k 値を探します。
while 1:
res=iroot(ec2+k*n,5) #print(res)
上記のループでは、スクリプトは式ec2 + k * n
の五次根を計算し、この五次根が整数であるかどうかをチェックします。整数であれば、その対応する文字列を印刷し、ループを抜けます。そうでなければ、k 値を増加させてループを続けます。
while True:
res = gmpy2.iroot(ec2 + k * n, 5) if res[1] == True: print(long_to_bytes(int(res[0])))
次に、スクリプトは拡張ユークリッドアルゴリズムを使用して公鍵 e1 と e2 の乗法逆元を計算し、s1 と s2 を得ます。最後に、スクリプトは c1 の s1 乗と c2 の s2 乗をそれぞれ計算し、これら 2 つの結果を掛け合わせ、n で割った余りを取ることで平文 m を得ます。これらの指数はそれぞれ暗号文 c1 と c2 を解読するために使用され、元のメッセージ m を得ることができます。
s, s1, s2 = gmpy2.gcdext(e1, e2)
m = (pow(c1, s1, n) * pow(c2, s2, n)) % n # m = (c1^s1) * (c2^s2)
解読スクリプトは以下の通りです:
import gmpy2
from Crypto.Util.number import *
n = 27929259512873502442719286790227037320417984116570178470037376373267390909685621247157535458203218619293705428397911754453556082799420494496904478215709219317542924547049229150153308059698341011305505985823374280465467094476511869541135508518055946815227085548571701115773386101962695795789178321155174729047033298389886321980592410739667139376075568555729949442873964097042006391886635957242436522435588904492484342259494858627609438654632887244523845583473711604632109405043439047289868784236481926074763997559971182741918345193506253460323445846136663027639802131457594564405906763806426256107923417802076262573737
ec2 = 2838620519239658396968146844964839207179863729944843241951228382052657801460586137213053314019699976475855578055607417923815486109050614096157077528657405905877896929808094661904905136761365045387901486261011216958309860644255996588189249
c1 = 17695186679431856780362905635257355413310120106982055323913669124182832151093921194946365178919380690844190324897933591567360925332869903671651849060145290581360223200011298757871213149464298017718829480721410479504940393501845624196721013966839230696831321482946841011452400364600924503121451272593970649100410603943321149604376033957124800064565646929720179239631538966228020882733213221035707244692798307971636126058586394357032072695921642665492919186476321028415907982915011972040971875733852055633796811898421692604356476773910338982400925245494707729878821466569634334862311750349321720627252469986162120031838
c2 = 10770781309274554738409447671578241895686779262243081931452089039730277591151694112684863740412412713684216227740930573490322958500198235497947657939304932868457999239593145330718657422535271157683896034543125292529800047408131765376686654378173684648427311300423776510153307756388404568013401217965931456538849277670384454454507752525534110389604969437991055504757081225690155489265359117617764571537216746554060783131168749700810806387918510612057149583061938836035963175555630655718716139689761210220525955656039741684390906935720406757364893793459339618913268943282961044530062475057887777134887741597041684698119
e1 = 34967
e2 = 65535
# 有効なk値を探す
k = 0
while True:
res = gmpy2.iroot(ec2 + k * n, 5)
if res[1] == True:
print(long_to_bytes(int(res[0]))) # 文字列に変換
break
k = k + 1
# 解読
s, s1, s2 = gmpy2.gcdext(e1, e2)
m = (pow(c1, s1, n) * pow(c2, s2, n)) % n # m = (c1^s1) * (c2^s2)
# 解読結果を印刷
print(long_to_bytes(m))
第四問:4-1#
元の問題のコードは以下の通りです:
from uuid import *
from caser import something
from secret import flag
base_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
result =""
for i in range(len(flag)):
if flag[i] in base_table:
result +=base_table[(base_table.index(flag[i])+33)%64]
else:
result +=flag[i]
print(result)
#khzj0m{9caZ87VV-8X77-WW/+-78Wa-eZVdaYYe9/dZ}
与えられたコードに基づいて解読スクリプトを作成します。
encrypted_flag = "khzj0m{9caZ87VV-8X77-WW/+-78Wa-eZVdaYYe9/dZ}"
base_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
flag = ""
for char in encrypted_flag:
if char in base_table:
index = (base_table.index(char) - 33) % 64
flag += base_table[index]
else:
flag += char
print(flag)
crypto タイプの問題は直接 chatgpt を使って解決します。
第五問:5-1#
与えられた添付ファイル pcap.pcap を分析します。
rar 圧縮ファイルのファイルヘッダー形式が存在し、上記の 16 進数の内容を抽出し、010editor に 16 進数形式で書き込みます。
書き込んだ後の具体的な内容は以下の通りです:
rar ファイルを得て、解凍すると flag.rar ファイルが得られますが、解凍パスワードが必要です。
ntfs ストリーム隠蔽を推測し、ntfs データストリーム処理ツールを使用して処理します。
base64 の一連の文字列を得ます。
パスワードはこの base64 値であり、圧縮パッケージを解凍します。