about

3/4~6に開催されていたUniversity of Marylandのチームが主催するCTFです.

チームDCDCとして参加し,1pt以上獲得した552チーム中16位でした.

result

以下,自分が解いた問題で覚えている物のwriteupです

Pwn

Legacy

なんかガチャガチャやってると,

Traceback (most recent call last):
  File "/home/ctf/legacy.py", line 15, in <module>
    if (input(str(3-i) + " chances left! \n") == secret):
  File "<string>", line 1, in <module>
NameError: name 'hoge' is not defined

って言われるのでsecretって入力してみるとflagがもらえます.

Pwnこれしか解いてない.俺は無力.

forensics

Renzik’s Case

普通にbinwalkすると出てきます.

Magic Plagueis the Wise

magic numberの先頭1byteだけ改変されたPNGが入ってたので,先頭1byteだけ読み出すとflag出てきます.

jdata

unzipせずにbinwalkするとバイナリが入っていて,そこで呼ばれている関数の名前とunzipした時の画像を組み合わせたらflagになります.

これは@mmmlyがほぼ解いていたのを俺がsubmitしただけです.

misc

ChungusBot v2

Botが使っているのと同じアイコンにするとflagくれます.面倒くせぇ.

RSI 1

OSU!のリプレイっぽいフォーマットのファイルが渡されるので,なんか気合でパースするとflag出てきます.

普通にPythonのライブラリがあったらしい.自作のはバグってそうな雰囲気もあるし無駄な努力した.

#!/usr/bin/env python3.9
import leb128
import time
import sys
import lzma

if len(sys.argv) < 2:
    print(f'Usage: {sys.argv[0]} SOMEFILE.osr')
    exit(0)

f = open(sys.argv[1], 'rb')

def read_string() -> str:
    has = f.read(1)
    if has == b'\x0b':
        l = leb128.u.decode(f.read(1))
        return f.read(l).decode('utf-8', 'ignore')
    else:
        return ''

def read_long() -> int:
    return int.from_bytes(f.read(8), byteorder='little', signed=False)

def read_int() -> int:
    return int.from_bytes(f.read(4), byteorder='little', signed=False)

def read_short() -> int:
    return int.from_bytes(f.read(2), byteorder='little', signed=False)

def read_byte() -> int:
    return int.from_bytes(f.read(1), byteorder='little', signed=False)

gameMode = ['osu! Standard', 'Taiko', 'Catch the Beat', 'osu!mania'][read_byte()]
print(f'Game Mode = {gameMode}')

print(f'Version of the game when the replay was created =                                           {read_int()}')
print(f'osu! beatmap MD5 hash =                                                                     {read_string()}')
print(f'Player name =                                                                               {read_string()}')
print(f'osu! replay MD5 hash (includes certain properties of the replay) =                          {read_string()}')
print(f'Number of 300s =                                                                            {read_short()}')
print(f'Number of 100s in standard, 150s in Taiko, 100s in CTB, 100s in mania =                     {read_short()}')
print(f'Number of 50s in standard, small fruit in CTB, 50s in mania =                               {read_short()}')
print(f'Number of Gekis in standard, Max 300s in mania =                                            {read_short()}')
print(f'Number of Katus in standard, 200s in mania =                                                {read_short()}')
print(f'Number of misses =                                                                          {read_short()}')
print(f'Total score displayed on the score report =                                                 {read_int()}')
print(f'Greatest combo displayed on the score report =                                              {read_short()}')
print(f'Perfect/full combo (1 = no misses and no slider breaks and no early finished sliders) =     {read_byte()}')
modsUsed = read_int()
print(f'Mods used. See below for list of mod values. =                                              {modsUsed}')
print(f'Life bar graph =                                                                            {read_string()}')
print('comma separated pairs u/v, where u is the time in milliseconds into the song and v is a floating point value from 0 - 1 that represents the amount of life you have at the given time (0 = life bar is empty, 1= life bar is full)')
t = int.from_bytes(f.read(8), byteorder='big', signed=False)
print(f'Time stamp =                                                                                {time.strftime("%Y-%m-%dT%H:%M:%SZ",time.localtime(t))}')
bytelen = read_int()
print(f'Length in bytes of compressed replay data =                                                 {bytelen}')
replay_data = lzma.decompress(f.read(bytelen)).strip(b'\x00').decode('utf-8', 'ignore')
print(f'Compressed replay data =                                                                    {replay_data}')
print(f'Online Score ID =                                                                           {read_long()}')
print(f'Additional mod information. =                                                               {read_long()}')

print('-*-*-*-*-*-*-*-*-*-*-*-')
print('     Mods Used')
print('-*-*-*-*-*-*-*-*-*-*-*-')

def mod_check(n: int) -> bool:
    return (modsUsed >> n) & 1

if modsUsed == 0:
    print('None mods')
    exit(0)

if mod_check(1):
    print('NoFail')
if mod_check(2):
    print('Easy')
if mod_check(3):
    print('TouchDevice')
if mod_check(4):
    print('Hidden')
if mod_check(5):
    print('HardRock')
if mod_check(6):
    print('DoubleTime')
if mod_check(7):
    print('Relax')
if mod_check(8):
    print('HalfTime')
if mod_check(9):
    print('NightCore')
if mod_check(10):
    print('Flashlight')
if mod_check(11):
    print('Autoplay')
if mod_check(12):
    print('SpunOut')
if mod_check(13):
    print('Relax2')
if mod_check(14):
    print('Perfect')
if mod_check(15):
    print('Key4')
if mod_check(16):
    print('Key5')
if mod_check(17):
    print('Key6')
if mod_check(18):
    print('Key7')
if mod_check(19):
    print('Key8')
if mod_check(15) and mod_check(16) and mod_check(17) and mod_check(18) and mod_check(19):
    print('keyMod')
if mod_check(20):
    print('Fadeln')
if mod_check(21):
    print('Random')
if mod_check(22):
    print('LastMod')
if mod_check(23):
    print('TargetPractice')
if mod_check(24):
    print('Key9')
if mod_check(25):
    print(('Coop'))
if mod_check(26):
    print('Key1')
if mod_check(27):
    print('Key3')
if mod_check(28):
    print('Key2')
if mod_check(29):
    print('ScoreV2')
if mod_check(30):
    print('Mirror')