BSides Algiers 2021 Quals Writeup

この大会は2020/12/18 18:00(JST)~2020/12/20 4:00(JST)に開催されました。
今回もチームで参戦。結果は1056点で169チーム中15位でした。
自分で解けた問題をWriteupとして書いておきます。

Homer The Simp - 0x1 (Misc)

青い鳥のあるプラットフォームということからSNSの種類はTwitter。HomerTheSimpを検索すると、内容的に以下のURLに掲載していることが合う。

https://twitter.com/homerthesimp56/

そこからツイートをたどっていく。

https://twitter.com/Marge010556/status/1327162071113461761

f:id:satou-y:20201224225048p:plain
ここでフラグが書いてあった。

shellmates{w3_c4ught_h1m_s1mp!ng_l4ds}

It's Complicated My Pal (Forensics)

ICMPのデータ部にzipの断片が見えた。集めて、zipにする。

from scapy.all import *

packets = rdpcap('capture.pcap')

data = ''
for p in packets:
    if p.haslayer(ICMP):
        if p[IP].src == '192.168.1.200':
            data += p[Raw].load

with open('flag.zip', 'wb') as f:
    f.write(data)

パスワードがかかっているので、クラックする。

$ fcrackzip -u -D -p dict/rockyou.txt flag.zip


PASSWORD FOUND!!!!: pw == craccer
$ unzip -P craccer flag.zip
Archive:  flag.zip
  inflating: flag.jpg

解凍し、展開されたflag.jpgにフラグが書いてあった。
f:id:satou-y:20201224225241j:plain

shellmates{icmp_p@yl04d_4in't_us3l3ss_4ft3r_4ll_r1gHt?}

Sequences and Bases (Cryptography)

逆算していくためにまず素因数分解する。

$ python -m primefac 5654655333396589573009251270272824452868045532409847035578809519921971758405056586087615745288
5654655333396589573009251270272824452868045532409847035578809519921971758405056586087615745288: 2 2 2 3 157 179 4339 1112581 94333140093961 349904234337911801671 53693611291973 979906911043329098468466567737
p * q = 5654655333396589573009251270272824452868045532409847035578809519921971758405056586087615745288
      = 2**3 * 3 * 157 * 179 * 4339 * 1112581 * 94333140093961 * 349904234337911801671 * 53693611291973 * 979906911043329098468466567737

SequencesOf0は2進数にしたときの0の連続する数、SequencesOf1は2進数にしたときの1の連続する数。素因数分解の結果から、p, qの組み合わせの総当たりで復号する。

from Crypto.Util.number import *

def base_n(p, n):
    s = ''
    while True:
        s += str(p%n)
        p /= n
        if p == 0:
            break
    return s[::-1]

def seq_to_str(seq0, seq1):
    bin_s = ''
    for i in range(len(seq0)):
        bin_s += '0' * seq0[i]
        bin_s += '1' * seq1[i]
    s = ''
    for i in range(0, len(bin_s), 8):
        s += chr(int(bin_s[i:i+8], 2))
    return s

with open('ciphertext', 'rb') as f:
    n = bytes_to_long(f.read())

print '[+] n =', n

ps = []
for p0 in [1, 2, 4, 8]:
    for p1 in [1, 3]:
        for p2 in [1, 157]:
            for p3 in [1, 179]:
                for p4 in [1, 4339]:
                    for p5 in [1, 1112581]:
                        for p6 in [1, 53693611291973]:
                            for p7 in [1, 94333140093961]:
                                for p8 in [1, 349904234337911801671]:
                                    for p9 in [1, 979906911043329098468466567737]:
                                        p = p0 * p1 * p2 * p3 * p4 * p5 * p6 * p7 * p8 * p9
                                        ps.append(p)

found = False
for i in range(len(ps)):
    p = ps[i]
    q = n / p
    for maximum0 in range(1, 8):
        for maximum1 in range(1, 8):
            SequencesOf0 = map(int, list(base_n(p, maximum0 + 1)))
            SequencesOf1 = map(int, list(base_n(q, maximum1 + 1)))
            if len(SequencesOf0) == len(SequencesOf1):
                flag = seq_to_str(SequencesOf0, SequencesOf1)
                if flag.startswith('shellmates{'):
                    found = True
                    print '[+] p =', p
                    print '[+] q =', q
                    print '[+] Seq0 =', SequencesOf0
                    print '[+] Seq1 =', SequencesOf1
                    print '[*] flag =', flag
                    break
        if found:
            break
    if found:
        break

実行結果は以下の通り。

[+] n = 5654655333396589573009251270272824452868045532409847035578809519921971758405056586087615745288
[+] p = 157764541996625996565130847469449869788076056
[+] q = 35842371561016047939149570405318318265423962928523
[+] Seq0 = [1, 2, 1, 1, 4, 2, 1, 1, 1, 3, 1, 3, 1, 1, 1, 4, 1, 1, 3, 2, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1, 3, 1, 1, 4, 1, 1, 1, 2, 1, 1, 1, 2, 1, 3, 1, 3, 1, 3, 1, 1, 2, 2, 1, 4, 1, 3, 2, 1, 1]
[+] Seq1 = [3, 2, 2, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 1, 3, 1, 2, 1, 1, 3, 2, 4, 2, 1, 1, 1, 3, 1, 1, 3, 2, 3, 1, 1, 5, 2, 1, 1, 5, 3, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 1, 5, 2, 2, 2, 2, 2, 1, 2, 3, 5, 1]
[*] flag = shellmates{Just_a_sm4ll_fl4g}
shellmates{Just_a_sm4ll_fl4g}

AES ECB (Cryptography)

$ nc chall.bsidesalgiers.com 5002
   Oo    o.OOoOoo .oOOOo.        o.OOoOoo  .oOOOo.  o.oOOOo.  
  o  O    O       o     o         O       .O     o   o     o                                                                         
 O    o   o       O.              o       o          O     O                                                                         
oOooOoOo  ooOO     `OOoo.         ooOO    o          oOooOO.                                                                         
o      O  O             `O        O       o          o     `O                                                                        
O      o  o              o        o       O          O      o                                                                        
o      O  O       O.    .O        O       `o     .o  o     .O                                                                        
O.     O ooOooOoO  `oooO'        ooOooOoO  `OoooO'   `OooOO'                                                                         
                                                                                                                                     
                                 
You send me a string, I send you: BASE64(AES_ECB(input + flag, SECRET_KEY))
Your goal is to get the flag back
=> 1
The result : bO6QSoVwyjjWUG6k+BWtuEakMEZ4tmq3CN79M/WWRtQkvMas8omC3lCFp05k+PmIhk/kDBDAQlARAPYwfelmG8qFmIF4UaBUW31UrrYeCEE=
=> 11
The result : YQOWV/Ck03gqZ9GpGfQWCFu0c6EbXGKB73Cjjz6YVoqjfwBtAz+frVOmsIku8d1QRg8LiQuopFFWmjRR/+h0gVO2PVIL5fbVps07b7c14b4=
=> 111
The result : HDua1M3GoJEE3+GHESPKBIgSathq9vnuqLws9RmXq5iXL8RBiJ4hCqDQspct4Nr4pk10jLDxUtRlu5Th13yqOYbztZW5RDVriYyjedMC9A0=
=> 1111
The result : alRbRFxyqBAJyis5kVA2aNLt7gZB4sCGq48xFSkzxLLfQzotKbNSGrTZbum7mo7QmI2SfRQ2pww36QqATVR2n/d9Qj00iEIIAGnNK4R8yNM=
=> 11111
The result : ZTPr63sE/EEv1aA5+HDYsFAqsnqQDUtnXr2W0TxnPO6mc1PKf4atVde6h4X+8QhGw74qemTRG43rcZP1PCX4oiDt6cuqbN9P5u7IHKiI/+I=
=> 111111
The result : Erm5SNHRRzK2ig4DCgbb7Ny6X82C8TiPHjLyrn1gxKnVAbRTqbG5gs+MTjiAnJpmWBmzAB88xvH7FtSFLOjyZlvbji4jtkbBD88+PvFOltg=
=> 1111111
The result : fT8tuk9DPASDCX1x9hO9Yjx8qXDLCNybL5npIqCWJ9xL3DdIRbfZGAAY+oiuDNFXLeor0PdWywH96l3h6WhP5UyPPywYd6ePISF1QnhTkF4=
=> 11111111
The result : aoqRjR3wRoYC9eN29aJKippnOv8N3V/L4HVS+oQkK97WaHeNQx2NxMt387+vGm0idgRuHOfVYzmKGeNtoTY+U2IKijHXQdfPbA3dEIWltMI=
=> 111111111
The result : PPYYsyy218H0QdowYatDszAG8a1S238ZQMx+Mo+373t+5oO6NIhKiIxLEEPnnNzqfuxEL0W1RDgt0skTwaycnyOzzA1TmYmA9KLzRp5L3AQ=
=> 1111111111 
The result : xFBgEYax4pLQ1HlOMikHCV5srrgr3mOxP3xazzG46OZyJ5TNPLS3n21GSJkjeVl12UYXNWfoGYd/RN9grCFsPpLG01VnOcrVF9Um5VTFNU0=
=> 11111111111
The result : dIWj2IZzEG3LYVJdlu+zzpJdM5TqvxMxe8z5Gfe3L0yqTUU+Tj4ie9s4xYQnG79JdQqAi5gaMGX9KUMMvNSqLQf9aBwfsLYq7bnsx4C2A0Y=
=> 111111111111
The result : 0Uq6FplPYDzb5wC+TuJbT+00bZfMm6Yk1iSO47lAx9CxTurGxLYo0Vk0xnKaxUmPn3YMIeRjWvFSVaJ9//TgegXA4YXI/xS0WvzgOWyA23HGDotT/zOS8nueZVlsUDdb

入力が111111111111のときに、base64デコードした文字列の長さが80バイトから96バイトになる。平文は「[input][flag]」という形式。

0123456789abcdef
1111111111111FFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
PPPPPPPPPPPPPPPP

ブロック暗号であることを利用してパディング文字数を調整しながら、先頭からフラグを探り当てる。

0123456789abcdef
111111111111111?
1111111111111111
1111111111111111
1111111111111111
1111111111111111
111111111111111F
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFPPPPPPPPPPPPPP
import socket

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

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('chall.bsidesalgiers.com', 5002))

data = recvuntil(s, 'back\n').rstrip()
print data

flag = ''
for i in range(67):
    for code in range(32, 127):
        print '[+]', flag
        if i < 16:
            inp = '1' * (15 - i) + flag + chr(code) + '1' * (79 - i)
        else:
            inp = flag[-15:] + chr(code) + '1' * (79 - i)
        data = recvuntil(s, '=>')
        print data + inp
        s.sendall(inp + '\n')
        data = recvuntil(s, '\n').rstrip()
        print data
        enc = data.split(' : ')[1].decode('base64')
        enc0 = enc[16*0:16*1]
        enc5 = enc[16*5:16*6]
        if enc0 == enc5:
            flag += chr(code)
            break

print '[*] flag =', flag

実行結果は以下の通り。

   Oo    o.OOoOoo .oOOOo.        o.OOoOoo  .oOOOo.  o.oOOOo.  
  o  O    O       o     o         O       .O     o   o     o                                                                         
 O    o   o       O.              o       o          O     O                                                                         
oOooOoOo  ooOO     `OOoo.         ooOO    o          oOooOO.                                                                         
o      O  O             `O        O       o          o     `O                                                                        
O      o  o              o        o       O          O      o                                                                        
o      O  O       O.    .O        O       `o     .o  o     .O                                                                        
O.     O ooOooOoO  `oooO'        ooOooOoO  `OoooO'   `OooOO'                                                                         
                                                                                                                                     
                                 
You send me a string, I send you: BASE64(AES_ECB(input + flag, SECRET_KEY))
Your goal is to get the flag back
[+] 
=>111111111111111 1111111111111111111111111111111111111111111111111111111111111111111111111111111
 The result : Nm+4gsxsV6Q998Qy3e9OvbG9uRREt2s7AA+yzhxd1YGxvbkURLdrOwAPss4cXdWBsb25FES3azsAD7LOHF3VgbG9uRREt2s7AA+yzhxd1YGsHbqwnv0JDhtSAGsnZ7QcROo7IkzOY996Cfc5VFm/M/wzAnwvm7oV0FNQFTYyJpmDHwi26sCgpFaIEGwbEVOHnqPj7nBgZTiLseoqUTwJQHQIdX7XTw8ro9xwZj1C1mc=
[+] 
=>111111111111111!1111111111111111111111111111111111111111111111111111111111111111111111111111111
 The result : foz2dPzoyMr52E4xuCi6xLG9uRREt2s7AA+yzhxd1YGxvbkURLdrOwAPss4cXdWBsb25FES3azsAD7LOHF3VgbG9uRREt2s7AA+yzhxd1YGsHbqwnv0JDhtSAGsnZ7QcROo7IkzOY996Cfc5VFm/M/wzAnwvm7oV0FNQFTYyJpmDHwi26sCgpFaIEGwbEVOHnqPj7nBgZTiLseoqUTwJQHQIdX7XTw8ro9xwZj1C1mc=
[+] 
=>111111111111111"1111111111111111111111111111111111111111111111111111111111111111111111111111111
 The result : RgxCvaueFr+4DjJmdH6Lz7G9uRREt2s7AA+yzhxd1YGxvbkURLdrOwAPss4cXdWBsb25FES3azsAD7LOHF3VgbG9uRREt2s7AA+yzhxd1YGsHbqwnv0JDhtSAGsnZ7QcROo7IkzOY996Cfc5VFm/M/wzAnwvm7oV0FNQFTYyJpmDHwi26sCgpFaIEGwbEVOHnqPj7nBgZTiLseoqUTwJQHQIdX7XTw8ro9xwZj1C1mc=
[+] 
=>111111111111111#1111111111111111111111111111111111111111111111111111111111111111111111111111111
 The result : 3VWrwS5t/jieejg4JpNdR7G9uRREt2s7AA+yzhxd1YGxvbkURLdrOwAPss4cXdWBsb25FES3azsAD7LOHF3VgbG9uRREt2s7AA+yzhxd1YGsHbqwnv0JDhtSAGsnZ7QcROo7IkzOY996Cfc5VFm/M/wzAnwvm7oV0FNQFTYyJpmDHwi26sCgpFaIEGwbEVOHnqPj7nBgZTiLseoqUTwJQHQIdX7XTw8ro9xwZj1C1mc=
[+] 
=>111111111111111$1111111111111111111111111111111111111111111111111111111111111111111111111111111
 The result : TfXHLzwMUD3BMevZ8mmfMrG9uRREt2s7AA+yzhxd1YGxvbkURLdrOwAPss4cXdWBsb25FES3azsAD7LOHF3VgbG9uRREt2s7AA+yzhxd1YGsHbqwnv0JDhtSAGsnZ7QcROo7IkzOY996Cfc5VFm/M/wzAnwvm7oV0FNQFTYyJpmDHwi26sCgpFaIEGwbEVOHnqPj7nBgZTiLseoqUTwJQHQIdX7XTw8ro9xwZj1C1mc=
[+] 
=>111111111111111%1111111111111111111111111111111111111111111111111111111111111111111111111111111
 The result : jxmJzfxd9K6cveeLNO8OMLG9uRREt2s7AA+yzhxd1YGxvbkURLdrOwAPss4cXdWBsb25FES3azsAD7LOHF3VgbG9uRREt2s7AA+yzhxd1YGsHbqwnv0JDhtSAGsnZ7QcROo7IkzOY996Cfc5VFm/M/wzAnwvm7oV0FNQFTYyJpmDHwi26sCgpFaIEGwbEVOHnqPj7nBgZTiLseoqUTwJQHQIdX7XTw8ro9xwZj1C1mc=
                :
                :
                :
[+] shellmates{I_though_AES_w4s_m1l1tary_gr4de_encryp7ion_1n_al1_m0des
=>on_1n_al1_m0des|1111111111111
 The result : 24hlQghiXP72+3R3b0COPcssf4ZxVVWb22QjqFvUHflKpunAOjAiiCYyYgsHwkZc7RWQxn0dUSE4RmsC4zHJMNelvw6iWs7poZWBqSqqqtJUkr6moH0+OlaGl6av3jYzaxLF7pKy9Of5p+mCeycoiQ==
[+] shellmates{I_though_AES_w4s_m1l1tary_gr4de_encryp7ion_1n_al1_m0des
=>on_1n_al1_m0des}1111111111111
 The result : VJK+pqB9PjpWhpemr942M8ssf4ZxVVWb22QjqFvUHflKpunAOjAiiCYyYgsHwkZc7RWQxn0dUSE4RmsC4zHJMNelvw6iWs7poZWBqSqqqtJUkr6moH0+OlaGl6av3jYzaxLF7pKy9Of5p+mCeycoiQ==
[*] flag = shellmates{I_though_AES_w4s_m1l1tary_gr4de_encryp7ion_1n_al1_m0des}
shellmates{I_though_AES_w4s_m1l1tary_gr4de_encryp7ion_1n_al1_m0des}