[Forensics] Layer Cake
Layer cake is so good. I have an mp3 file all about layer cake. Maybe you can find the flag there?
layer cake.mp3
というファイルが与えられる。まず、配布されたファイルの形式を確認してみる。
$ file layer\ cake.mp3 layer cake.mp3: MPEG ADTS, layer III, v1, 192 kbps, 44.1 kHz, JntStereo
一見するとMP3ファイルのように見えますが、hexdumpで内容を確認してみると
$ hd layer\ cake.mp3 | head -n 20 00000000 ff fb 68 30 14 00 00 00 00 00 e1 91 be 5a 00 00 |..h0.........Z..| 00000010 00 00 00 00 00 00 00 00 00 00 07 00 20 00 6c 61 |............ .la| 00000020 79 65 72 73 2f 75 78 0b 00 01 04 00 00 00 00 04 |yers/ux.........| 00000030 00 00 00 00 55 54 0d 00 07 26 85 39 68 a3 86 39 |....UT...&.9h..9| 00000040 68 26 85 39 68 50 4b 03 04 14 00 00 00 00 00 e1 |h&.9hPK.........| 00000050 91 be 5a 00 00 00 00 00 00 00 00 00 00 00 00 10 |..Z.............| 00000060 00 20 00 6c 61 79 65 72 73 2f 64 6f 63 50 72 6f |. .layers/docPro| 00000070 70 73 2f 75 78 0b 00 01 04 00 00 00 00 04 00 00 |ps/ux...........|
PK
というマジックバイトやlayers/
というディレクトリ名が見えることから、これはZIPファイルっぽい。ファイルをunzipしてみると色々解凍できて、Microsoft Word文書(.docx)っぽいものが出てくる。適当にgrepするとword/styles.xml
内でフラグを発見した。
<w:style w:type="paragraph" w:styleId="Heading5"><!-- grey{s0_f3w_lay3r5_w00p5} --><w:name w:val="heading 5"/>
[Forensics] Connection Issues
One of our employees was browsing the web when he suddenly lost connection! Can you help him figure out why?
chall.pcapが与えられる。ネットワークが使えないというのがヒントっぽい。適当に目grepすると以下のようなのが見つかる。
#1409: 192.168.100.1 is at bc:24:11:74:12:33 (duplicate use of 192.168.100.1 detected!) #1575: 192.168.100.1 is at bc:24:11:74:12:33 (duplicate use of 192.168.100.1 detected!)
ARP Spoofingか。これは通信ができなくなったというのも分かる。ということはARPに着目すればよさそうなので、ARPを適当に確認していくと、ARPパケットに異常な追加データが埋め込まれているのが見える。tsharkでダンプしてみる。
tshark -r chall.pcap -Y "arp and frame.len > 42" -x
なんか末尾にbase64エンコードされた文字列っぽいのが見える。適当に集める。
01: Z3JleXtk → grey{d 02: MWRfMV9q → 1d_1_j 03: dXM3X2dl → us7_ge 04: N19wMDFz → 7_p01s 05: b24zZH0= → on3d}
これを結合するとフラグになる。
[Crypto] Uwusignatures
As an uwu girl, I decided to make this digital signature scheme to share my signatures with everyone!
I'll only show you half of my signature though, because I'm shy...
Surely, no one would steal from a cutie like myself... right?
ソースコードは以下。
from Crypto.Util.number import * import json import hashlib KEY_LENGTH = 2048 FLAG = "grey{fakeflagfornow}" class Uwu: def __init__(self, keylen): self.p = getPrime(keylen) self.g = getRandomRange(1, self.p) self.x = getRandomRange(2, self.p) # x is private key self.y = pow(self.g, self.x, self.p) # y is public key self.k = getRandomRange(1, self.p) while GCD(self.k, self.p - 1) != 1: self.k = getRandomRange(1, self.p) print(f"{self.p :} {self.g :} {self.y :}") print(f"k: {self.k}") def hash_m(self, m): sha = hashlib.sha256() sha.update(long_to_bytes(m)) return bytes_to_long(sha.digest()) def sign(self, m): assert m > 0 assert m < self.p h = self.hash_m(m) r = pow(self.g, self.k, self.p) s = ((h - self.x * r) * pow(self.k, -1, self.p - 1)) % (self.p - 1) return (r, s) def verify(self, m, signature): r, s = signature assert r >= 1 assert r < self.p h = self.hash_m(m) lhs = pow(self.g, h, self.p) rhs = (pow(self.y, r, self.p) * pow(r, s, self.p)) % self.p return lhs == rhs def main(): print("Welcome to my super uwu secure digital signature scheme!") uwu = Uwu(KEY_LENGTH) sign_count = 0 while True: print("1. Show me some of your cutesy patootie signatures!") print("2. Get some of my uwu signatures (max 2)") choice = int(input("> ")) if choice == 1: data = json.loads(input("Send me a message and a signature: ")) m, r, s = data["m"], data["r"], data["s"] if m == bytes_to_long(b"gib flag pls uwu"): if uwu.verify(m, (r, s)): print("Very cutesy, very mindful, very demure!") print(FLAG) exit() else: print("Very cutesy, but not very mindful") exit() else: print("Not very cutesy") exit() elif choice == 2: if sign_count >= 2: print("Y-Y-You'd steal from poor me? U_U") exit() data = json.loads(input("Send me a message: ")) m = data["m"] if type(m) is not int or m == bytes_to_long(b"gib flag pls uwu"): print("Y-Y-You'd trick poor me? U_U") exit() r, s = uwu.sign(m) print(f"Here's your uwu signature! {s :}") sign_count += 1 else: print("Not very smart of you OmO") exit() if __name__ == "__main__": main()
ElGamal 署名が実装されている。コードを詳しく見ると、脆弱性が2つある。
ノンスが再利用されているので、そこからkを求めることができるのだが、kは与えられているのでそれを使うことにしよう。
- 1つの署名を取得
k
は既に分かっているので直接r = g^k mod p
を計算- 署名方程式から
x*r
を逆算 - 目標メッセージの署名を偽造
という流れでいい。以下のようなコードでフラグが得られる。
from Crypto.Util.number import * import hashlib import json from pwn import * def hash_m(m): sha = hashlib.sha256() sha.update(long_to_bytes(m)) return bytes_to_long(sha.digest()) r = remote("challs2.nusgreyhats.org", 33301) r.recvline() # Welcome message pub_line = r.recvline().decode().strip() p, g, y = map(int, pub_line.split()) k_line = r.recvline().decode().strip() k = int(k_line.split(":")[1].strip()) r.sendlineafter(b"> ", b"2") # 署名取得 m1 = 1337 r.recvuntil(b": ") r.sendline(json.dumps({"m": m1}).encode()) sig1_line = r.recvline().decode() s1 = int(sig1_line.split("!")[-1].strip()) h1 = hash_m(m1) k_inv = pow(k, -1, p - 1) r_calced = pow(g, k, p) target_msg = bytes_to_long(b"gib flag pls uwu") target_hash = hash_m(target_msg) x_r = (h1 - (s1 * k) % (p - 1)) % (p - 1) target_s = ((target_hash - x_r) * k_inv) % (p - 1) r.sendlineafter(b"> ", b"1") # 署名検証 forge_data = {"m": target_msg, "r": r_calced, "s": target_s} r.sendlineafter(b": ", json.dumps(forge_data).encode()) r.interactive()