CTF4b 2018 writeup

Published on:
Tags: ctf writeup

約1ヶ月前に新しく研究室に加わった後輩達の勧めでCTFを始めました。 その後彼らの管理しているCTFサイトの問題を解いたりしていたのですが、今回初心者向けのCTFとしてSECCON Beginners CTFが開かれるとのことで後輩達とチームを組んで出場する運びとなりました。

いわく、「解いた問題のwriteupを公開するまでがCTF」らしいのでここにwriteupを記します。

[Warmup] plain mail

与えられたパケットを調べるとパスワード付きのzipファイルとパスワードが見つかるのでzipファイルを解凍するとフラグが得られる。

ctf4b{email_with_encrypted_file}

RSA is Power

与えられた$N$を素因数分解して、$N=p\times q$ となるような $p, q$ を求めます。

p = 299681192390656691733849646142066664329
q = 324144336644773773047359441106332937713

あとは $de \equiv 1\bmod (p-1)(q-1)$ を満す $d$ を拡張ユークリッド互除法を用いて求めてやれば、 Wikipedaに載っているとおりに $C^{d} \bmod N$ とすれば 復号できます。

d = 88509020092584531671107468782943602124921999287671161687233461555074737950465
C^d mod N =  0x63746634627b35696d706c655f7273345f31735f336173795f6630725f757d 

得られるフラグは16進数表記なので適当に文字列に変換します。

ctf4b{5imple_rs4_1s_3asy_f0r_u}

Streaming

フラグの先頭がctf4bであることが分かっているのでそれを使って初期seedを求め、そこから次々にseedを求めながら複合していけばフラグを得られます。

こんな感じのコードを書きました。

def next(seed):
    A = 37423
    B = 61781
    C = 34607
    return (A*seed+B)%C

f = open('encrypted', 'rb')
encrypted = f.read()
decrypted = ""
d = int(hex(ord(encrypted[0])), 16) + int(hex(ord(encrypted[0+1])), 16) * 256
#init seed
seed = d ^ 25460
decrypted += chr(int(hex(d^seed)[2:4], 16)) + chr(int(hex(d^seed)[4:6], 16))
print(hex(d^seed))
for i in range(1, len(encrypted)//2):
    d = int(hex(ord(encrypted[2*i])), 16) + int(hex(ord(encrypted[2*i+1])), 16) * 256
    seed = next(seed)
    d = d^seed
    print(hex(d))
    if len(hex(d)) <= 4:
        decrypted += chr(int(hex(d)[2:4], 16))
    else:
        decrypted += chr(int(hex(d)[2:4], 16)) + chr(int(hex(d)[4:6], 16))
print(decrypted)

ctf4b{lcg-is-easily-predictable}

てけいさんえくすとりーむず

サーバにアクセスすると四則演算を解かされます。 自分はえくすとりーむなてけいさんのプロではないのでプログラムにやらせました。

import socket
import re

class Netcat:
    """ Python 'netcat like' module """
    def __init__(self, ip, port):
        self.buff = ""
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect((ip, port))

    def read(self, length = 1024):
        """ Read 1024 bytes off the socket """
        return self.socket.recv(length)

    def read_until(self, data):
        """ Read data into the buffer until we have data """
        while not data in self.buff:
            self.buff += self.socket.recv(1024)
        pos = self.buff.find(data)
        rval = self.buff[:pos + len(data)]
        self.buff = self.buff[pos + len(data):]
        return rval

    def write(self, data):
        self.socket.send(data)
        
    def close(self):
        self.socket.close()

nc = Netcat('133.242.234.140', 8690)
nc.read_until('Stage.1)')
for i in range(1, 101):
    print(nc.read_until('Stage.'+str(i)+')'))
    expr = nc.read_until('=')
    expr = expr.strip()
    m = re.match(r'(\d+)\s*(\+|-|\*|/)\s*(\d+).*', expr)
    term1 = int(m.group(1))
    op = m.group(2)
    term2 = int(m.group(3))
    ans = ""
    if op == "+":
        ans = term1 + term2
    elif op == "-":
        ans = term1 - term2
    elif op == "*":
        ans = term1 * term2
    elif op == "/":
        ans = term1 / term2
    print(expr), 
    print(ans)
    nc.write(str(ans) + '\n')
print(nc.read())

Netcatクラスの部分のコードはここのやつをそのまんま使ってます。

これを実行すると

(Stage.1)
908 * 509 = 462172
 (Stage.2)
925 * 757 = 700225
 (Stage.3)
940 - 850 = 90
 (Stage.4)
618 + 921 = 1539
 (Stage.5)
625 - 536 = 89
    .
    .
    .
 (Stage.100)
860 + 823 = 1683
Congrats.
Flag is: "ctf4b{ekusutori-mu>tekeisann>bigina-zu>2018}"

ctf4b{ekusutori-mu>tekeisann>bigina-zu>2018}

感想

初心者向けということで簡単な問題だけかと思ってたんですが、結構難しい問題もあったなという印象でした。 でも、Cryptoは結構解けたので良かったです。Pwn, Reversingはゼンゼンワカランカッタ。

Comments

Copyright © 2019 pipopa . Powered by Hugo | Theme is hugo-fabric, fork from hexo-fabric by wd