メインコンテンツまでスキップ
非公開のページ
このページは非公開です。 検索対象外となり、このページのリンクに直接アクセスできるユーザーのみに公開されます。

「crypto」タグの記事が7件件あります

全てのタグを見る

[SECCON Beginners CTF 2020] Noisy equations

metarin

noise hides flag.

from os import getenv
from time import time
from random import getrandbits, seed


FLAG = getenv("FLAG").encode()
SEED = getenv("SEED").encode()

L = 256
N = len(FLAG)


def dot(A, B):
assert len(A) == len(B)
return sum([a * b for a, b in zip(A, B)])

coeffs = [[getrandbits(L) for _ in range(N)] for _ in range(N)]

seed(SEED)

answers = [dot(coeff, FLAG) + getrandbits(L) for coeff in coeffs]

print(coeffs)
print(answers)

解説

「FLAG44文字だし44回分サンプル取ってz3投げれば解けるやろ!」という発想のもとスクリプトを書きました

  • サンプルを錬成するツール

    #!/usr/bin/env python3
    import os
    for i in range(0, 44):
    os.system("nc noisy-equations.quals.beginners.seccon.jp 3000 > log/log%02d.log" % i)
  • ソルバー

    #!/usr/bin/env python3
    from z3 import *
    import json

    def dot(A, B):
    return sum([a * b for a, b in zip(A, B)])

    N = 44

    logs = []
    for i in range(N):
    with open("log/log%02d.log" % i, "r") as f:
    t = f.read().split('\n')
    coeffs = eval(t[0])
    answers = eval(t[1])
    logs.append({"coeffs": coeffs, "answers": answers})

    s = Solver()
    flag = IntVector("flag", N)
    srnd = IntVector("srnd", N)

    for h in range(N):
    for i in range(N):
    b = dot(flag, logs[h]["coeffs"][i])
    s.add(b + srnd[i] == logs[h]["answers"][i])

    r = s.check()
    print(r)
    if r == sat:
    m = s.model()
    else:
    print(r)
    exit()

    print(m)

15分ほど待つとflagが得られます ctf4b{r4nd0m_533d_15_n3c3554ry_f0r_53cur17y}

[SECCON Beginners CTF 2020] R&B

yudegaki

解説

FLAGをRとBからなる文字列に従って難読化されたものが与えられます. 文字がRの場合は'R'と全体をROT13,つまりA~Zの文字を13個分後ろにずらす(超過した場合にはAに戻って処理を進める)処理をしたものを結合しています. Bの場合は'B'とBase64でFLAG全体がエンコードされたものを結合しています.

[SECCON Beginners CTF 2020] RSA Calc

metarin

F(1337)=FLAG!

from Crypto.Util.number import *
from params import p, q, flag
import binascii
import sys
import signal


N = p * q
e = 65537
d = inverse(e, (p-1)*(q-1))


def input(prompt=''):
sys.stdout.write(prompt)
sys.stdout.flush()
return sys.stdin.buffer.readline().strip()

def menu():
sys.stdout.write('''----------
1) Sign
2) Exec
3) Exit
''')
try:
sys.stdout.write('> ')
sys.stdout.flush()
return int(sys.stdin.readline().strip())
except:
return 3


def cmd_sign():
data = input('data> ')
if len(data) > 256:
sys.stdout.write('Too long\n')
return

if b'F' in data or b'1337' in data:
sys.stdout.write('Error\n')
return

signature = pow(bytes_to_long(data), d, N)
sys.stdout.write('Signature: {}\n'.format(binascii.hexlify(long_to_bytes(signature)).decode()))

def cmd_exec():
data = input('data> ')
signature = int(input('signature> '), 16)

if signature < 0 or signature >= N:
sys.stdout.write('Invalid signature\n')
return

check = long_to_bytes(pow(signature, e, N))
if data != check:
sys.stdout.write('Invalid signature\n')
return

chunks = data.split(b',')
stack = []
for c in chunks:
if c == b'+':
stack.append(stack.pop() + stack.pop())
elif c == b'-':
stack.append(stack.pop() - stack.pop())
elif c == b'*':
stack.append(stack.pop() * stack.pop())
elif c == b'/':
stack.append(stack.pop() / stack.pop())
elif c == b'F':
val = stack.pop()
if val == 1337:
sys.stdout.write(flag + '\n')
else:
stack.append(int(c))

sys.stdout.write('Answer: {}\n'.format(int(stack.pop())))


def main():
sys.stdout.write('N: {}\n'.format(N))
while True:
try:
command = menu()
if command == 1:
cmd_sign()
if command == 2:
cmd_exec()
elif command == 3:
break
except:
sys.stdout.write('Error\n')
break


if __name__ == '__main__':
signal.alarm(60)
main()

解説

cmd_exec()1337,Fを実行させられればflagを得ることが出来ます cmd_execで計算を実行するには署名が必要になりますが、署名を発行するcmd_sign()1337およびFの入った入力を禁止しています また、Nは1024bitあるため秘密鍵を大会期間中に解析するのは現実的ではありません

RSAでは公開鍵N以上の情報を暗号化すると、Nで剰余を取る際にデータの損失が発生します しかし、cmd_sign()では署名するデータを256B(=2048bit)まで受けつけています これを利用して署名の衝突を発生させます

[SECCON Beginners CTF 2021] GFM

Namerou
  • Github Flavored Markdown
  • Google Facebook Microsoft
  • And...?

問題

FLAGの情報を含む行列Mが前後から行列keyをかけることによって隠されてしまいました。Mの情報を取り出したいのですが、与えられている情報は乱数決定に用いられたp、行列key、計算結果のencだけです。


FLAG = b'<censored>'

SIZE = 8
p = random_prime(2^128)
MS = MatrixSpace(GF(p), SIZE)

key = MS.random_element()
while key.rank() != SIZE:
key = MS.random_element()

M = copy(MS.zero())
for i in range(SIZE):
for j in range(SIZE):
n = i * SIZE + j
if n < len(FLAG):
M[i, j] = FLAG[n]
else:
M[i, j] = GF(p).random_element()

enc = key * M * key

print('p:', p)
print('key:', key)
print('enc:', enc)

output

p: 331941721759386740446055265418196301559
key: [116401981595413622233973439379928029316 198484395131713718904460590157431383741 210254590341158275155666088591861364763 63363928577909853981431532626692827712 85569529885869484584091358025414174710 149985744539791485007500878301645174953 257210132141810272397357205004383952828 184416684170101286497942970370929735721]
[ 42252147300048722312776731465252376713 199389697784043521236349156255232274966 310381139154247583447362894923363190365 275829263070032604189578502497555966953 292320824376999192958281274988868304895 324921185626193898653263976562484937554 22686717162639254526255826052697393472 214359781769812072321753087702746129144]
[211396100900282889480535670184972456058 210886344415694355400093466459574370742 186128182857385981551625460291114850318 13624871690241067814493032554025486106 255739890982289281987567847525614569368 134368979399364142708704178059411420318 277933069920652939075272826105665044075 61427573037868265485473537350981407215]
[282725280056297471271813862105110111601 183133899330619127259299349651040866360 275965964963191627114681536924910494932 290264213613308908413657414549659883232 140491946080825343356483570739103790896 115945320124815235263392576250349309769 240154953119196334314982419578825033800 33183533431462037262108359622963646719]
[ 53797381941014407784987148858765520206 136359308345749561387923094784792612816 26225195574024986849888325702082920826 262047729451988373970843409716956598743 170482654414447157611638420335396499834 270894666257247100850080625998081047879 91361079178051929124422796293638533509 34320536938591553179352522156012709152]
[266361407811039627958670918210300057324 40603082064365173791090924799619398850 253357188908081828561984991424432114534 322939245175391203579369607678957356656 63315415224740483660852444003806482951 224451355249970249493628425010262408466 80574507596932581147177946123110074284 135660472191299636620089835364724566497]
[147031054061160640084051220440591645233 286143152686211719101923153591621514114 330366815640573974797084150543488528130 144943808947651161283902116225593922999 205798118501774672701619077143286382731 317326656225121941341827388220018201533 14319175936916841467976601008623679266 112709661623759566156255015500851204670]
[306746575224464214911885995766809188593 35156534122767743923667417474200538878 35608800809152761271316580867239668942 259728427797578488375863755690441758142 29823482469997458858051644485250558639 137507773879704381525141121774823729991 29893063272339035080311541822496817623 292327683738678589950939775184752636265]
enc: [133156758362160693874249080602263044484 293052519705504374237314478781574255411 72149359944851514746901936133544542235 56884023532130350649269153560305458687 67693140194970657150958369664873936730 227562364727203645742246559359263307899 98490363636066788474326997841084979092 323336812987530088571937131837711189774]
[244725074927901230757605861090949184139 63515536426726760809658259528128105864 297175420762447340692787685976316634653 279269959863745528135624660183844601533 203893759503830977666718848163034645395 163047775389856094351865609811169485260 103694284536703795013187648629904551283 322381436721457334707426033205713602738]
[ 17450567396702585206498315474651164931 105594468721844292976534833206893170749 10757192948155933023940228740097574294 132150825033376621961227714966632294973 329990437240515073537637876706291805678 57236499879418458740541896196911064438 265417446675313880790999752931267955356 73326674854571685938542290353559382428]
[270340230065315856318168332917483593198 217815152309418487303753027816544751231 55738850736330060752843300854983855505 236064119692146789532532278818003671413 104963107909414684818161043267471013832 234439803801976616706759524848279829319 173296466130000392237506831379251781235 34841816336429947760241770816424911200]
[140341979141710030301381984850572416509 248997512418753861458272855046627447638 58382380514192982462591686716543036965 188097853050327328682574670122723990784 125356457137904871005571726686232857387 55692122688357412528950240580072267902 21322427002782861702906398261504812439 97855599554699774346719832323235463339]
[298368319184145017709393597751160602769 311011298046021018241748692366798498529 165888963658945943429480232453040964455 240099237723525827201004876223575456211 306939673050020405511805882694537774846 7035607106089764511604627683661079229 198278981512146990284619915272219052007 255750707476361671578970680702422436637]
[ 45315424384273600868106606292238082349 22526147579041711876519945055798051695 15778025992115319312591851693766890019 318446611756066795522259881812628512448 269954638404267367913546070681612869355 205423708248276366495211174184786418791 92563824983279921050396256326760929563 209843107530597179583072730783030298674]
[ 662653811932836620608984350667151180 304181885849319274230319044357612000272 280045476178732891877948766225904840517 216340293591880460916317821948025035163 79726526647684009633247003110463447210 36010610538790393011235704307570914178 284067290617158853279270464803256026349 45816877317461535723616457939953776625]

解説

このプログラムはsageで書かれています。sage?何それおいしいの?って感じですね。Outputを見るとencとkeyは行列であるようです。プログラムの方に戻って見てみるとenc = key * M * key(21行目)の意味は分かりますね?encはkeyとMとkeyを掛けた値(行列積)だということです。ここで今不明なものはMです。Mはなんの行列なのでしょうか。少しさかのぼって13行目から19行目を見ると、どうやらMにFLAGの値を入力しているようです。ここでわかるのはMさえわかればFLAGの値が分かるということです!あとはもう簡単ですね!keyの逆行列を計算し、encの両側から掛けてあげましょう!ちょっと何を言っているかわからない人は行列、逆行列の性質について調べてみてください。 *私たちはsage上で計算しましたがうまく計算できず、、、、。key = matrix(GF(p), [[...要素...]];と宣言したところうまく動きました。GF(p)にはpの桁数分の計算を保持するのではないでしょうか?(迷推理)(要出典)

[SECCON Beginners CTF 2021] Imaginary

metarin

虚数は好きですか?

問題

リモートで虚数を追加、表示できるアプリが動いています 各虚数はRe + Imiのようなキー名で保存されます また、虚数のリストを暗号化してエクスポートしたりそのデータをインポートしたりすることもできます これらの機能を上手く使って、キー名が1337iのデータを作成して_secret()を呼べばflagが得られるようです

[SECCON Beginners CTF 2021] Logical_SEESAW

shihei

We have an innovative seesaw!

問題

ソースコードとoutput.txtが配布されます。 flagをビット列に変換したものとランダムなビット列を用意し、flagの各ビットに対して1/2の確率でランダムビット列とのANDを取ったものに書き換えているらしい。 その試行の16回分の出力がoutput.txtに入ってます。

from Crypto.Util.number import *
from random import random, getrandbits
from flag import flag

flag = bytes_to_long(flag.encode("utf-8"))
length = flag.bit_length()
key = getrandbits(length)
while not length == key.bit_length():
key = getrandbits(length)

flag = list(bin(flag)[2:])
key = list(bin(key)[2:])

cipher_L = []

for _ in range(16):
cipher = flag[:]
m = 0.5

for i in range(length):
n = random()
if n > m:
cipher[i] = str(eval(cipher[i] + "&" + key[i]))

cipher_L.append("".join(cipher))


print("cipher =", cipher_L)

解説

ビット同士でANDを取るとき、1が0になることはあれど0が1になることはありません。 つまり0は16回試行しようがその全てで0となっているはず。 逆に1は1になったり0になったりしてますが16回も試行すりゃ1回くらい1になってるはず。 つまり出力の全パターンに対してORを取ればflagが復元できるはず。

[SECCON Beginners CTF 2021] simple_RSA

metarin

Let's encrypt it with RSA!

問題

RSAの暗号化スクリプトとn, e, cが渡される

from Crypto.Util.number import *
from flag import flag

flag = bytes_to_long(flag.encode("utf-8"))

p = getPrime(1024)
q = getPrime(1024)
n = p * q
e = 3

assert 2046 < n.bit_length()
assert 375 == flag.bit_length()

print("n =", n)
print("e =", e)
print("c =", pow(flag, e, n))

解説

eの値がかなり小さいので、Low Public Exponent Attackができた。 ctf4b{0,1,10,11...It's_so_annoying.___I'm_done}