TSG CTF Writeup

この大会は2019/5/4 16:00(JST)~2019/5/5 16:00(JST)に開催されました。
今回もチームで参戦。結果は868点で334チーム中19位でした。
メインの問題は一問も解けず残念!暗号問題を1問は解きたかった。
一応自分で解けた問題をWriteupとして書いておきます。

Sanity Check (Warmup)

Discordに入ると、#announcementsチャネルのところにフラグが書いてある。

TSGCTF{ur_here_cuz_u_absolutely_won_inshack_ctf?}

Survey (Cooldown)

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

TSGCTF{Hosting_a_CTF_is_really..._REALLY_tough_and_challenging!}

ALLMN CTF19 Writeup

この大会は2019/5/1 9:00(JST)~2019/5/4 23:00(JST)に開催されました。
今回もチームで参戦。結果は3475点で417チーム中8位でした。
自分で解けた問題をWriteupとして書いておきます。

Free point (Warmup 10)

問題にフラグが書いてあった。

ALLMN{Y3S_TH1S_1S_Y0UR_FLAG_27SJAL}

Discord (Warmup 10)

Discordに入って、ピン止めされたメッセージを見ると、フラグが書いてあった。

ALLMN{TH4NKS_F0R_J01N1NG_US_2JKLPO}

Saturn.MN (Social Engineering 30)

タブ表示になっている、viewやaboutなどを見ていく。
http://saturn.mn/p/425にフラグが書かれていた。

ALLMN{W3LC0M3_T0_S4TURN_MN}

Easy Math (Warmup 30)

128と56のGCD(最大公約数)は8、LCMは128*56/8で896。

ALLMN{896_8}

Funny Website (Web 50)

HTMLソースコードのコメントにフラグの一部が書いてある。

<!-- ALLMN{W3LL_Y0U -->

http://chall.all.mn/funny/style.cssのコメントにフラグの一部が書いてある。

/*_C4N_1NSP3CT */

http://chall.all.mn/funny/function.jsのコメントにフラグの一部が書いてある。

// _M3_I28DJA}

全部繋げると、フラグになる。

ALLMN{W3LL_Y0U_C4N_1NSP3CT_M3_I28DJA}

Robots (Web 70)

http://chall.all.mn/robot/robots.txtにアクセスする。

User-agent: *
Disallow: /allmnflag.php

http://chall.all.mn/robot/allmnflag.phpにアクセスすると、フラグが表示された。

ALLMN{W3B_R0B0TS_TXT_7DHJ9E}

Question & Answer (Crypto 100)

添付ファイルのテキストはシーザー暗号なので、https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipherで復号する。

Rotation 18:
hey, you did a nice job! so here is your answer: eqra_cpf_rcuvg_vjku . but make sure it is in reverse form.

さらにeqra_cpf_rcuvg_vjkuの部分を復号する。

Rotation 2:
copy_and_paste_this

http://chall.all.mn/asuult/index.php?q=1でcopy_and_paste_thisを答えると、フラグが表示された。

ALLMN{Y3S_Y0U_D1D_1T_4Y7JKP}

What is this? (Crypto 100)

Brainfuck言語なので、https://sange.fi/esoteric/brainfuck/impl/interp/i.htmlで実行すると、フラグが表示された。

ALLMN{1_L0V3_BR41N_F4CK_3IQKAP}

Damn! (Crypto 100)

ChromeデベロッパーツールのConsoleで実行してみると、以下のエラーが発生。

Uncaught ReferenceError: f4ckjs is not defined
    at eval (eval at  (local-ntp.html:1), :3:1)
    at :1:4558

f4ckjsがフラグとなるワードとして通った。

ALLMN{f4ckjs}

Find that word (Misc 100)

添付ファイルを解凍すると大量のファイルが展開される。

$ grep -ilr ALLMN findtheflag/*
findtheflag/76.txt
$ grep ALLMN findtheflag/76.txt
         Pauses in Heaven doyoureallywanttoknowtheflag?hereitisALLMN{GR3P_1S_S1mple}.
ALLMN{GR3P_1S_S1mple}

SQL (Web 100)

SQLインジェクションで攻撃。以下の通り入力してログインすると、フラグが表示された。

Username: ' or 1=1 #
ALLMN{W0W_Y0U_D1D_SQLi}

Do you know that? (Crypto 100)

https://github.com/JohnHammond/ctf-katanaのDNAコード表を見てデコードする。

RCCDE{1E_DP_UE4}

https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipherで復号する。

Rotation 17:
ALLMN{1N_MY_DN4}
ALLMN{1N_MY_DN4}

My favorite number (Reversing 150)

逆アセンブルする。関係する部分は以下のようになっている。

push    rbp
mov     rbp, rsp
sub     rsp, 10h
mov     rax, fs:28h
mov     [rbp+var_8], rax
xor     eax, eax
lea     rdi, s          ; "Minii durtai toog oruulna uu"
call    _puts
lea     rax, [rbp+x]
mov     rsi, rax
lea     rdi, format     ; "%d"
mov     eax, 0
call    _scanf
mov     eax, [rbp+x]
cmp     eax, 4D1h
jnz     short loc_797

0x4D1と比較している。Pythonで0x4D1の値を確認する。

>>> 0x4D1
1233
ALLMN{1233}

ROCK (Forensics 150)

PDFファイルにパスワードがかかっているので、pdfcrackでパスワードを割り出す。

$ pdfcrack --wordlist=dict/rockyou.txt level-1.pdf 

PDF version 1.5
Security Handler: Standard
V: 2
R: 3
P: -4
Length: 128
Encrypted Metadata: True
FileID: a474737d247fa5259a6fc058ef096d2b
U: d18066309b9c6a7058223fcfa93890430122456a91bae5134273a6db134c87c4
O: 884bb701492d79d69ff17a588a87adb263143d261bdf1dbb0a616a47944d713e
Average Speed: 34703.2 w/s. Current Word: 'avril84'
Average Speed: 34329.1 w/s. Current Word: 'porn123tip'
Average Speed: 32437.8 w/s. Current Word: 'aritzel'
Average Speed: 31514.0 w/s. Current Word: 'xwettie'
Average Speed: 35259.1 w/s. Current Word: 'target0899'
Average Speed: 33870.6 w/s. Current Word: 'salimd'
Average Speed: 34358.9 w/s. Current Word: 'penchalick'
Average Speed: 30534.2 w/s. Current Word: 'ms.kylan'
Average Speed: 30263.8 w/s. Current Word: 'm0891553577'
Average Speed: 30269.2 w/s. Current Word: 'kiri404'
Average Speed: 29818.8 w/s. Current Word: 'jaspal209'
Average Speed: 28429.8 w/s. Current Word: 'hair821sold381'
Average Speed: 28589.2 w/s. Current Word: 'erestodoparamimau'
Average Speed: 31237.2 w/s. Current Word: 'crosby87fan'
Average Speed: 35053.8 w/s. Current Word: 'bisina'
Average Speed: 35201.6 w/s. Current Word: 'ai3office1'
Average Speed: 35135.8 w/s. Current Word: 'JenJen!'
Average Speed: 33758.6 w/s. Current Word: '898989r'
found user-password: '551731'

このパスワードでPDFファイルを開くと、フラグが書いてあった。

ALLMN{Y0U_DID_IT!}

Windows XP (Web 150)

UserAgentを該当するものにして、アクセスする

例)Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
$ curl -H "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" http://chall.all.mn/windows/
<!DOCTYPE html>
<!--
__  __          _____  ______   ______     __
|  \/  |   /\   |  __ \|  ____| |  _ \ \   / /
| \  / |  /  \  | |  | | |__    | |_) \ \_/ /
| |\/| | / /\ \ | |  | |  __|   |  _ < \   /
| |  | |/ ____ \| |__| | |____  | |_) | | |
|_|__|_/_/    \_\_____/|______| |____/__|_|____    _ _____ _   _  _____  ____  __  __ _   _ _____          _
/ ____|  /\   | \ | |/ ____| |  | |_   _|  __ \  ( )_   _| \ | |/ ____|/ __ \|  \/  | \ | |_   _|   /\   ( )
| (___   /  \  |  \| | |    | |__| | | | | |__) | |/  | | |  \| | (___ | |  | | \  / |  \| | | |    /  \  |/
\___ \ / /\ \ | . ` | |    |  __  | | | |  _  /      | | | . ` |\___ \| |  | | |\/| | . ` | | |   / /\ \
____) / ____ \| |\  | |____| |  | |_| |_| | \ \     _| |_| |\  |____) | |__| | |  | | |\  |_| |_ / ____ \
|_____/_/ _  \_\_| \_|\_____|_|_ |_|_____|_|  \_\   |_____|_| \_|_____/ \____/|_|  |_|_| \_|_____/_/    \_\
   /\   | |    | |      |  \/  | \ | |
  /  \  | |    | |      | \  / |  \| |
 / /\ \ | |    | |      | |\/| | . ` |
/ ____ \| |____| |____ _| |  | | |\  |
/_/    \_\______|______(_)_|  |_|_| \_|
-->
<html lang="mn" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>ALL.MN Academy</title>
    <link rel="icon" href="icon.png">
    <link rel="stylesheet" href="style.css" type="text/css">
  </head>
  <body>
    <div class="blocked">
      <img src="icon.png" width="200px"><br><br>
      Sorry, you cannot enter!<br>
      You can enter if you are using Windows XP and Internet Explorer.<br>
      ALLMN{CH4NG3_TH3_US3R_AG3NT_WD8KKA}    </div>
  </body>
</html>
ALLMN{CH4NG3_TH3_US3R_AG3NT_WD8KKA}

Encrypted (Crypto 250)

暗号は16進数で長さは608。1文字ずつMD5にしてつなげていると、推測して復号する。

import hashlib

h_dic = {}
for code in range(32, 127):
    h = hashlib.md5(chr(code)).hexdigest()
    h_dic[h] = chr(code)

with open('encrypted.txt', 'r') as f:
    data = f.read().rstrip()

flag = ''
for i in range(0, len(data), 32):
    flag += h_dic[data[i:i+32]]

print flag
ALLMN{MD5_1S_CR4ZY}

Admin panel (Crypto 250)

John the Ripperでパスワードを割り出す。

$ unshadow passwd shadow > passwd_shadow
$ john --wordlist=../dict/rockyou.txt passwd_shadow
Loaded 1 password hash (crypt, generic crypt(3) [?/64])
Press 'q' or Ctrl-C to abort, almost any other key for status
hellokitty       (root)
1g 0:00:00:01 100% 0.7462g/s 214.9p/s 214.9c/s 214.9C/s alyssa..brenda
Use the "--show" option to display all of the cracked passwords reliably
Session completed

root/hellokittyでログインする。

$ ./login
Sain uu? Ta nevtreh ner bolon nuuts ugee oruulna uu! CTF19.ALL.MN Admin Login
Nevtreh ner: 
root
Nuuts ug: 
hellokitty
ALLMN{G00DJ0B_Y0U_AR3_T00_G00D_SHD8WK}
ALLMN{G00DJ0B_Y0U_AR3_T00_G00D_SHD8WK}

My Little Electric CodeBook (Crypto 300)

ブロック暗号のECBモードの問題。ブロックごとに暗号文が同じであれば平文が同じことを使って解く。
以下の2つに暗号文を16バイトずつ区切って同じものを探す。

4c9e192389e8791554ae342a77069573
661a44fa2a2ab220ed33af9081049b8d

すると、以下の2行が見つかる。

4c9e192389e8791554ae342a77069573fd3281ec97b52ba8817e8560af2b187d:ALLMN{KTZFQVTLIPMONKTERRSCERKLK}
2d3d123382b1fcc266bf0bc5086da8b2661a44fa2a2ab220ed33af9081049b8d:ALLMN{HBSOPKYGXEPHNMSYKYHFXQIVW}

それぞれ前半と後半を切り出す。

ALLMN{KTZFQVTLIP
PHNMSYKYHFXQIVW}

結合するとフラグになる。

ALLMN{KTZFQVTLIPPHNMSYKYHFXQIVW}

CSA Capture The Flag 2019 Writeup

この大会は2019/4/25 11:00(JST)~2019/5/2 11:00(JST)に開催されました。
今回もチームで参戦。結果は5076点で363チーム中3位でした。
自分で解けた問題をWriteupとして書いておきます。

Sanity check(0x00)

問題にフラグが書いてあった。

CSACTF{w3lc0m3_t0_csa_ctf_2019}

Zippy (Forensics)

zipのヘッダ4バイトが壊れているので、修正する。

(誤) 00 00 00 00
(正) 50 4b 03 04

展開すると、flag.txtにフラグが書いてあった。

CSACTF{z1ppy_z1p_z1p}

Down to basic (Crypto)

フラグの先頭がCSACTF{となることからXOR鍵を算出し、さらに推測して、復号する。

c = '\x13\x13eg#v\t\x05\x0f#HE\x04CC\x07\x0f0V\x14\x15\\\x17\t\x0f2AU\x02\x01\x00\x01#\x1fE{\x14\\\x13\x17#qG{\x04\x00\x1e\x11$q\x14J\n'

pre_flag = 'CSACTF{'

key = ''
for i in range(len(pre_flag)):
    code = ord(c[i]) ^ ord(pre_flag[i])
    key += chr(code)

print key

## guess key ##
key += 'd'
print key

flag = ''
for i in range(len(c)):
    code = ord(c[i]) ^ ord(key[i%len(key)])
    flag += chr(code)

print flag

これでXOR鍵はP@$$w0rdであることがわかり、復号できた。

CSACTF{a_class1c_pr0blem_requ1res_a_class1c_s0lut10n}

Flag server (Crypto)

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

・入力データはBase64Base64デコードして以下の文字列にする。
 rowdy123 + <入力> +  + 
・AES暗号化してBase64エンコードして表示

文字列の長さを変えて試すと、10文字にしたとき、80バイトになったので、フラグの長さは46バイトであることもわかり、以下のようなイメージになる。

0123456789abcdef
rowdy123XXXXXXXX
XXFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
PPPPPPPPPPPPPPPP
0123456789abcdef
rowdy123XXXXXXXX
XXXXXXXXXXXXXXXC
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFPPP

上記のようなイメージで、1文字ずつフラグをはみ出させ、2ブロック目と5ブロック目が一致するものを探すことを繰り返し、フラグを割り出す。

import socket
from base64 import *

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

flag = ''
for i in range(46):
    for c in range(32, 127):
        print '*** flag: %s ***' % flag
        print c, chr(c)

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(('34.74.132.34', 1337))

        data = recvuntil(s, '\n').rstrip()
        #print data
        if i < 16:
            text = 'X' * 8 + 'X' * (15 - (i % 16)) + flag + chr(c) \
                + 'X' * (47 - len(flag))
            print text
        else:
            text = 'X' * 8 + flag[i-15:i] + chr(c) \
                + 'X' * (47 - len(flag))
            print text
        text = b64encode(text)
        #print text
        s.sendall(text + '\n')

        size = len('rowdy123') + 71 - i + 46
        size = size + 16 - size % 16

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

        b64 = ''
        for j in range(size * 4 / (3 * 76) + 1):
            data = recvuntil(s, '\n').rstrip()
            #print data
            b64 += data

        enc = b64decode(b64)
        block1 = enc[16*1:16*2]
        block4 = enc[16*4:16*5]
        if block1 == block4:
            flag += chr(c)
            break

print flag
CSACTF{ser10usly_1_d0nt_kn0w_what_t0_put_here}

Shakespeare (Crypto)

eの値が小さく、平文の上位bitの大半がわかっている。このことから、以下のようなスクリプトで復号することができる。

# solve.sage
n = 1006836100850250538339995467613886290568442651407025704748377068277336663840322807255631910003671238333129747821401677091458273063019582521876226866878065342813920204554381690287329117261946553416320027957955605766622398073392496765842697469834794925876050925562024075006141634323253929247109497487662672405697258396584137509321741864516634651999799054786449300271622909227600883634147669010834991795161523697131426220251208433781244773539764161842505052231971382919967824210675662840663441620651420266255868914927411521784353964212033587445690357323252291991393014956932340980364269027698921907294758481600334348209162447060613941156368610501127037691522939020923578832525761118629677247463329559736428451094014067976185200082383567782696893487896242261214414477694719976590065452677776148568775926581762818443660878148364426201543151986222827020715235149143660874147096198623408316970919847284217769846103787437353010406070576416824522568438694050123611781945190356349091784143598551629255439066014442622323403606886940586598393546395396681244923344136771626115764972416530481118005853215560607832082875977841855163209032040736208394910518736188520737990966314657947406636362327107362260153133199038686467983874712019134795287956681
e = 5
c = 86369436556821828495369673854162831950166653329442831115191625341047835876798749659300641169348489814397657938758507056245452483528302648820602222051650089244062216320589929210206763500165600876025118953025309329553936210852805389539140958630003420335312979086383557665369163943903938569533466433527007050293325014896256907213847510652960137337747717702046541551623527661916693185081633247755853469488660176161381955671005765896319088865538114135666529015146105463393845863266076934785270480138522718706320412272484373838264459071202162126712065303703239606240172920462289657145390815683884595752646574944533803755632028037260059034716445191212182713792979655078091574530502495357406706909373119165806528380721574497499485062395281364120812874772053936952075952742036541816610742884797177390325939200184871385346082698051189479559236698554746173964482593646082680562341702105913029374921266420784671717205191676584949585227373190247242357902713051455202286347791244123645109240863246131183709864782892090906846140511095936549733130467184197878019539182792149521284353941031177248258779486351865884845751206163429977363088579292444338819912920250044064118502755440223212479004336304705210529515747947096857605944524561963438120052349

beta = 1
epsilon = beta^2/7

nbits = n.nbits()
kbits = floor(nbits*(beta^2/e-epsilon))

with open('msg.txt', 'r') as f:
    m0 = int(f.read().rstrip().replace('X', '\x00').encode('hex'), 16)

def_string = ' Message ends.'
def_size = len(def_string)

PR.<x> = PolynomialRing(Zmod(n))
f = (m0 + x * (256**def_size))^e - c
f = f.monic()

x0 = f.small_roots(X=2^kbits, beta=1)[0]
m = m0 + x0 * (256**def_size)
msg = ('%x' % m).decode('hex')
print msg

実行結果は以下の通り。

Message begins. To be, or not to be: that is the question: Whether 'tis nobler in the mind to suffer. The slings and arrows of outrageous fortune. Or to take arms against a sea of troubles. And by opposing end them. To die: to sleep; - Hamlet contemplating suicide in his famous soliloquy. (Hamlet) - CSACTF{w1ll14m-sh4k3sp34r3} Message ends.
CSACTF{w1ll14m-sh4k3sp34r3}

A game of apples (Misc)

90個以上あるリンゴから、サーバプレーヤーと交互に取っていき、最後のリンゴを取れれば、フラグを得ることができる。
残り10個目を取ると負けるので、そうならないようスクリプトを組み実行する。

import socket
from base64 import *

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(('34.74.132.34', 1338))

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

data = recvuntil(s, '\n').rstrip()
print data
if data.split(' ')[1] == 'I':
    data = recvuntil(s, '\n').rstrip()
    print data
    data = recvuntil(s, '\n').rstrip()
    print data

remain = 999
count = 9
last = False
while True:
    if remain > 10 and remain < 20:
        count = remain - 10
    elif remain < 10:
        count = remain
        last = True
    data = recvuntil(s, '?\n').rstrip()
    print data
    print count
    s.sendall(str(count) + '\n')
    if last:
        break
    data = recvuntil(s, '\n').rstrip()
    print data
    data = recvuntil(s, '\n').rstrip()
    print data
    data = recvuntil(s, '\n').rstrip()
    print data
    remain = int(data.split(' ')[3])

data = recvuntil(s, '\n').rstrip()
print data
CSACTF{0n3_4ppl3_tw0_4ppl3_thr33_4ppl3}

Linux 1 (Misc)

$ ssh user@35.231.176.102 -p1773
The authenticity of host '[35.231.176.102]:1773 ([35.231.176.102]:1773)' can't be established.
ECDSA key fingerprint is SHA256:jnrxrLz++wBMSIAGbBB4KOK2Qpr9LW8kQ5tNvFN5LKc.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[35.231.176.102]:1773' (ECDSA) to the list of known hosts.
user@35.231.176.102's password: 

_________   _________   _____  _______________________________
\_   ___ \ /   _____/  /  _  \ \_   ___ \__    ___/\_   _____/
/    \  \/ \_____  \  /  /_\  \/    \  \/ |    |    |    __)  
\     \____/        \/    |    \     \____|    |    |     \   
 \______  /_______  /\____|__  /\______  /|____|    \___  /   
        \/        \/         \/        \/               \/                                                                                                  
Welcome to CSACTF 2019!

If you find any problems, please report to admin.

-[ Rule ]-
 A few rules before you get started:
     + don't leave orphan processes running
     + don't leave exploit-files laying around
     + don't annoy other players
     + don't share passwords/solutions
     + last but not least, don't spoil the fun!

Have fun!
     - Blue
user@23ee3cd1ea3b:~$ ls -la
total 44
drwxr-xr-x 1 user user 4096 Apr 25 03:04 .
drwxr-xr-x 1 root root 4096 Apr 22 20:12 ..
-rw-r--r-- 1 user user  220 Aug 31  2015 .bash_logout
-rw-r--r-- 1 user user 3796 Apr 25 03:03 .bashrc
drwx------ 2 user user 4096 Apr 25 03:04 .cache
-rw-r--r-- 1 user user  655 May 16  2017 .profile
-rw-rw-r-- 1 user user    0 Apr 25 03:04 ahahaha
-rwxrwxr-x 1 root root  267 Apr 22 20:09 flag_reader.py
-rw-rw-r-- 1 root root   40 Apr 22 19:25 readme.txt
-rw-r--r-- 1 user user   19 Apr 25 03:03 temp.txt
user@23ee3cd1ea3b:~$ cat flag_reader.py 
#!/usr/bin/python
import time
import os

f = open('flag.txt', 'r')

# ==== Reading the flag
flag = f.read()
with open('temp.txt','w') as tmp:
  tmp.write('Reading the flag...')

#print flag
time.sleep(99999)

# ==== Done, Cleaning up
os.remove('temp.txt')

f.close()
user@abb60ff15525:~$ ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 11:44 ?        00:00:00 /bin/bash /root/init.sh
user        13     1  0 11:44 ?        00:00:00 python /home/user/flag_reader.py
root        16     1  0 11:44 ?        00:00:00 /usr/sbin/sshd -D
root        18    16  0 11:44 ?        00:00:00 sshd: user [priv]
user        22    18  0 11:44 ?        00:00:00 sshd: user@pts/0
user        23    22  0 11:44 pts/0    00:00:00 -bash
user        38    23  0 11:48 pts/0    00:00:00 ps -ef

python /home/user/flag_reader.pyが実行できて、処理中のようだ。実行中のプロセスの標準出力を見る。

user@abb60ff15525:~$ ls -l  /proc/13/fd/
total 0
lr-x------ 1 user user 64 Apr 25 11:49 0 -> /dev/null
l-wx------ 1 user user 64 Apr 25 11:49 1 -> pipe:[2690442]
l-wx------ 1 user user 64 Apr 25 11:49 2 -> pipe:[2690443]
lr-x------ 1 user user 64 Apr 25 11:49 3 -> /home/user/flag.txt (deleted)
user@abb60ff15525:~$ cat /proc/13/fd/3
CSACTF{f34r_cuts_d33p3r_th4n_sw0rds}
CSACTF{f34r_cuts_d33p3r_th4n_sw0rds}

stephanography (Misc)

ステガノグラフィーの問題だが、使用しているツールに関することが問題文に書かれている。https://github.com/stncal/appaで該当するツールを見つけた。

$ python3 appa.py -d secret_new.png
    :
Appa found an extremely large string in the image. To save your console, results are saved to file: secret_new.results
String length: 187142

secret_new.resultsはhexデータだが、jpgになりそう。hexデコードすると、jpg画像にフラグが書いてあった。
f:id:satou-y:20190506160817j:plain

CSACTF{y1p_y1p!}

We are CSA (Reconnaissance)

https://ctf.utsacyber.com/challenges#We%20are%20CSAのResponceを見る。

{"data": {"files": [], "description": "There's nothing here.\r\n", "tags": [], "minimum": 50, "id": 6, "type_data": {"templates": {"create": "/plugins/dynamic_challenges/assets/create.html", "update": "/plugins/dynamic_challenges/assets/update.html", "view": "/plugins/dynamic_challenges/assets/view.html"}, "scripts": {"create": "/plugins/dynamic_challenges/assets/create.js", "update": "/plugins/dynamic_challenges/assets/update.js", "view": "/plugins/dynamic_challenges/assets/view.js"}, "id": "dynamic", "name": "dynamic"}, "hints": [], "category": "Reconnaissance", "name": "We are CSA", "solves": 28, "decay": 50, "initial": 500, "value": 369, "state": "visible", "type": "dynamic", "max_attempts": 0}, "success": true}

Responceにはこんなコメントが入っている。

<!-- Oops, you found me! Part 1: Q1NBQ1RGe1VORDNSU1Q Check out: http://utsacyber.com/resources.html. We have tons of resources for beginners, especially about RE. -->

Base64デコードしてみる。

$ echo Q1NBQ1RGe1VORDNSU1Q | base64 -d
CSACTF{UND3RSTbase64: 無効な入力

まだ他の場所にもBase64文字列が隠れていそう。http://utsacyber.com/resources.htmlにアクセスしてHTMLソースを見る。
今度はこんなコメントが入っている。

<!-- Part 2: 0TkQxTkdfQ1lCM1JfUz One of our great members, Missing, has an awesome tutorial on Bug Hunting (and MIPS), you might want to check it out.-->

先ほどのBase64文字列と結合して、Base64デコードする。

$ echo Q1NBQ1RGe1VORDNSU1Q0TkQxTkdfQ1lCM1JfUz | base64 -d
CSACTF{UND3RST4ND1NG_CYB3R_Sbase64: 無効な入力

まだ情報が足りない。このページにMissing's Bug Hunting Cookbookというリンクがある。そのページ https://bh-cookbook.github.io/ にアクセスする。
コメントにはこう書かれている。

<!-- Part 3: NDVVIxVFlfMU5fNExMX Thank you Eli for designing the fancy logo on the CTF Homepage. -->

先ほどのBase64文字列とさらに結合して、Base64デコードする。

$ echo Q1NBQ1RGe1VORDNSU1Q0TkQxTkdfQ1lCM1JfUzNDVVIxVFlfMU5fNExMX | base64 -d
CSACTF{UND3RST4ND1NG_CYB3R_S3CUR1TY_1N_4LLbase64: 無効な入力

次はhttps://ctf.utsacyber.com/のページのロゴ画像をダウンロードすると、PNGファイルの後ろにデータがある。

Part 4: zFUU19EME00MU5TfQo=

先ほどのBase64文字列とさらに結合して、デコードする。

$ echo Q1NBQ1RGe1VORDNSU1Q0TkQxTkdfQ1lCM1JfUzNDVVIxVFlfMU5fNExMXzFUU19EME00MU5TfQo= | base64 -d
CSACTF{UND3RST4ND1NG_CYB3R_S3CUR1TY_1N_4LL_1TS_D0M41NS}
CSACTF{UND3RST4ND1NG_CYB3R_S3CUR1TY_1N_4LL_1TS_D0M41NS}

SECCON 令和CTF Writeup

この大会は2019/4/30 23:00(JST)~2019/5/1 2:00(JST)に開催されました。
この大会は個人戦。結果は210点で858人中107位でした。
解けた問題をWriteupとして書いておきます。

フラグの例は?(Misc)

問題にフラグが書いてあった。

SECCON{reiwa}

bREInWAck (Misc)

このファイルが添付されている。

令和和和和和和和和和和和和和和和和「令和
和和和和令和和和和令和和和和和和和令和和
和和和和令和和平平平平平成」令和和和。令
和和和和和。成成。。平成成成成。成。令令
和和和和和和和和和和和。令和和。平平平和
和和和。令和和。和和和和。令令和和和和和
和和和和和和和。平平平和和和和和和和和和
和和和和。成成成成成成成成。令成成成成成
成成成。令令。成成成成成。成成成成成成。
令和。平平和和。令令令和和和和和和和和和
和。

問題タイトルから推測しても、Brainfuck言語で、使われている2バイト文字と1:1対応しているようだ。使われている文字の意味と数を考え、以下のように置き換えた。

>++++++++++++++++[>+
++++>++++>+++++++>++
++++>++<<<<<-]>+++.>
+++++.--..<----.-.>>
+++++++++++.>++.<<<+
+++.>++.++++.>>+++++
+++++++.<<<+++++++++
++++.--------.>-----
---.>>.-----.------.
>+.<<++.>>>+++++++++
+.

以下のBrainfuck言語のオンラインインタプリタでこのコードを実行する。
sange.fi

SECCON{bREIn_WAnic!}

零は? (Misc)

ncで接続すると?を含む式が出てくる。式が成り立つ?を求めていくPPCの問題のようだ。99問目と100問目は方程式として成り立っていないので、解なしの場合は0で答えるようにする。

import socket
import re
import sympy

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(('zerois-o-reiwa.seccon.jp', 23615))

for i in range(100):
    data = recvuntil(s, '?=')
    formula = data.split('\n')[-2].replace('?', 'x').split('=')[1]
    sol = sympy.solve(formula)
    if len(sol) == 1:
        ans = sol[0]
    else:
        ans = 0
    print data + str(ans)
    s.sendall(str(ans) + '\n')

data = recvuntil(s, '\n').rstrip()
print data
data = recvuntil(s, '\n').rstrip()
print data
SECCON{REIWA_is_not_ZERO_IS}

*CTF 2019 Writeup

この大会は2019/4/27 10:00(JST)~2019/4/29 10:00(JST)に開催されました。
今回もチームで参戦。結果は593点で334チーム中98位でした。
Welcome問題しか解けませんでしたが、
自分で解けた問題をWriteupとして書いておきます。

checkin (Misc)

IRCのfreenodeで#*ctf2019チャネルに入る。

10:41 *topic : welcome to *CTF2019, here is first flag *CTF{welcome} :P
*CTF{welcome}

UUT CTF Writeup

この大会は2019/4/25 22:30(JST)~2019/4/28 22:30(JST)に開催されました。
今回もチームで参戦。結果は1374点で441チーム中15位でした。
自分で解けた問題をWriteupとして書いておきます。

Web WarmUp (Web 10)

HTMLソースにこう書いてあった。

<!-- Flag -->
<p style="color:rgba(255, 0, 0, 0.001);">The Flag is: UUTCTF{P0SCon: Welcome to UUTCTF! Happy hacking ;)}</p>
UUTCTF{P0SCon: Welcome to UUTCTF! Happy hacking ;)}

Solve the Crypto (Crypto 25)

Fermat法でnを素因数分解できるので、そのまま復号する。

from Crypto.PublicKey import RSA
from Crypto.Util.number import *

def isqrt(n):
    x = n
    y = (x + n // x) // 2
    while y < x:
        x = y
        y = (x + n // x) // 2
    return x

def fermat(n):
    x = isqrt(n) + 1
    y = isqrt(x * x - n)
    while True:
        w = x * x - n - y * y
        if w == 0:
            break
        elif w > 0:
            y += 1
        else:
            x += 1
    return x - y, x + y

with open('pub.key', 'r') as f:
    pub_data = f.read()

pubkey = RSA.importKey(pub_data)
n = pubkey.n
e = pubkey.e

with open('enc.message', 'rb') as f:
    c = bytes_to_long(f.read())

p, q = fermat(n)

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)

flag = long_to_bytes(m)
print flag

実行結果は以下の通り。

Nfsタ・"xァリF・オx。縲・゚モ繃E゙碵・jョ哮ウV・イ轄L4ウチ抄[レラ靕農イ籟・メ-Dォ。「ミfuuoク_ーDnエ+μェセ枻ク⊇Mー SGllcl9pc3RfZGVpbmVfRmxhZ2dl

だが、そのままフラグにはならず、最後の方にBase64文字列があるので、デコードする。

$ echo SGllcl9pc3RfZGVpbmVfRmxhZ2dl | base64 -d
Hier_ist_deine_Flagge
UUTCTF{Hier_ist_deine_Flagge}

Break the RSA (Crypto 50)

Fermat法でnを素因数分解できるので、そのまま復号する。

from Crypto.Util.number import *

def isqrt(n):
    x = n
    y = (x + n // x) // 2
    while y < x:
        x = y
        y = (x + n // x) // 2
    return x

def fermat(n):
    x = isqrt(n) + 1
    y = isqrt(x * x - n)
    while True:
        w = x * x - n - y * y
        if w == 0:
            break
        elif w > 0:
            y += 1
        else:
            x += 1
    return x - y, x + y

n = 114869651319530967114595389434126892905129957446815070167640244711056341561089
e = 113
c = 102692755691755898230412269602025019920938225158332080093559205660414585058354

p, q = fermat(n)

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)

flag = long_to_bytes(m)
print flag
UUTCTF{easy sH0Rt RSA!!!}

Find the Word Flag (Forensics 75)

word\document.xmlのスペース数がばらばらで不自然。最大14くらいなので、2つでASCIIコード(16進数2桁)になると予測して、デコードする。

codes = [0x55, 0x55, 0x54, 0x43, 0x54, 0x46, 0x7b, 0x4d, 0x65, 0x61, 0x6e, \
    0x69, 0x6e, 0x67, 0x66, 0x75, 0x6c, 0x47, 0x61, 0x58, 0x73, 0x7d]

flag = ''
for code in codes:
    flag += chr(code)

print flag
UUTCTF{MeaningfulGaXs}

The Criminal (Forensics 150)

pcapファイルが与えられている。NetworkMinerで開き、Filesを見てみる。
No.90296にfl4g.7z.x-7z-compressedがあるので抽出する。この7zファイルはパスワードがかかっている。
No.88888にsecret_password-1024x64.pngがあるので、抽出する。
f:id:satou-y:20190430155343p:plain
ヒントにパスワードは小文字であることが記載されているので、それを念頭に画像に書いてあるパスワードを読み取る。さらに拡大して画像をよく見ると、Dの中の文字はDになっていて、PASSWORDのOの中の文字は0、FORの中の文字はOになっていることに気を付け、パスワードを読み取る。

this_is_th3_s3cr3t_passw0rd_for_flag

このパスワードで通った。解凍し展開したflag.txtにフラグが書いてあった。

UUTCTF{d0_n0t_sav3_pa$$word_in_public}

Blaze CTF 2019 Writeup

この大会は2019/4/21 5:20(JST)~2019/4/26 1:20(JST)に開催されました。
今回もチームで参戦。結果は2520点で250チーム中14位でした。
自分で解けた問題をWriteupとして書いておきます。

Blaze (MISC)

freenodeで#hackerswhoblazeチャネルに入る。

06:13 *topic : BLAZE 4/20 4:20 || blizz it || http://ctf.420blaze.in/ || sftp || https://www.youtube.com/watch?v=1LGDN4HVyQ0 | blaze{}
blaze{}

Hashishe cryptos (CRYPTO)

Elgamal暗号で、暗号処理は以下のようになっている。

y = g**x mod p

c1 = g**r
c2 = m*(y**r)

rにより、c1は固定。c2はmod pの空間の中で、mに比例する。m = 1 を指定したときのC2の何倍かでflagを求める。以下のような計算になる。

c2 = C2 * flag mod p
flag = c2 * inverse(C2, p)
import socket
import re
from Crypto.Util.number import *

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(('chal.420blaze.in', 42003))

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

pattern = 'p=(.+)\n  g=.+c2=(.+)\n'
m = re.search(pattern, data, re.DOTALL)
p = int(m.group(1))
c2 = int(m.group(2))

print '\x01'
s.sendall('\x01\n')
data = recvuntil(s, 'blaze it').rstrip()
print data

pattern = 'C2=(.+)\n'
m = re.search(pattern, data)
C2 = int(m.group(1))

flag = (c2 * inverse(C2, p)) % p
flag = long_to_bytes(flag)
print flag
blaze{i_wuz_bl4z1n_s0_much_i_r3used_m4h_k3ys}