satto1237’s diary

s4tt01237’s diary

ラーメンとかCTFとかセキュリティとか

RiceTeaCatPanda CTF 2020 Write-up

はじめに

2020/01/20 ~ 2019/01/25に開催されたRiceTeaCatPanda CTFにチーム(NekochanNano!)で参加しました.

成績

チームとしては29問解いて34位でした (1323チーム中).
今回は自分が解いた6問のWrite-upを書きます.

Reverse Engineering

What's the Password: Revisited [300pts]

There's a password somewhere...

> file whats-the-password-revisited
whats-the-password-revisited: ELF 64-bit LSB shared object x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=36f742e6516c60be312a3b60eb7e4f3fbf703161, stripped

アプローチ:Ghidraでデコンパイル

配布ファイルを実行するとパスワードの入力を求められます.

> ./whats-the-password-revisited 
Whats the password? satto1237
Hey, that's not right!

配布ファイルをGhidraデコンパイルして,内部処理を確認すると 入力文字列に対して排他的論理和をとった値とDAT_00301020を比較していることが分かるので後はデコーダを書けば終わりです.

undefined8 FUN_001007c0(void)
{
  // [snip]
  byte local_3b [20];
  
  // [snip]
  __fgets_chk(local_3b,0x16,0x1c);
  
  // [snip]
  lVar1 = 0;
  do {
    if ((int)(char)(&DAT_00301020)[(long)(int)lVar1 * 0x50] !=
        ((int)(char)(local_3b[lVar1] ^ 0x32) + 1U ^ 0x32)) {
      puts("Hey, that\'s not right!");
                    /* WARNING: Subroutine does not return */
      exit(0);
    }
    lVar1 = lVar1 + 1;
  } while (lVar1 != 0x14);

  // [snip]
}
# DAT_00301020
DAT = [0x3a, 0x31, 0x52, 0x30, 0x34, 0x36, 0x52, 0x30, 0x33, 0x5c, 0x3a, 0x51, 0x73, 0x30, 0x35, 0x45, 0x5c, 0x31, 0x5a, 0x34]

passwd = ''
for x in DAT:
    passwd += chr(((x ^ 0x32) - 1) ^ 0x32)
print(passwd)
> python solve.py
50m371m32_5Pr34D_0U7
> ./whats-the-password-revisited 
Whats the password? 50m371m32_5Pr34D_0U7
Nice job! Here's your flag: rtcp{fL492_r_50m371m32_5Pr34D_0U7}

rtcp{fL492_r_50m371m32_5Pr34D_0U7}

screams [1500pts]

You know what, you fix this lol
https://github.com/JEF1056/riceteacatpanda/tree/master/screams%20(1500)

aaaaaaaaaaaaaaaaaa.wav

> file aaaaaaaaaaaaaaaaaa.wav
aaaaaaaaaaaaaaaaaa.wav: RIFF (little-endian) data, WAVE audio, stereo 44100 Hz

ur-worst-nightmare.py

import cv2 as               a
import soundfile as         b
import random as            c
import numpy as             d
from tqdm import tqdm as    e
import os as                f
import binascii as          z

g, h = a.imread("pls-no.jpg"), b.SoundFile("oh-gawd-plsno.wav", 'r')
i, j = g.shape[0], 0
k=d.zeros((i*i,2), dtype=d.float64)
l, m = e(total=i*i), h.read()
l.set_description(" nuKiNG")
h.close()
u=True

t = b'9\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
v = b'@\xe4\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

for             n           in range(0,i):
    for         o       in range(0,i):
        if      u     == True:

            p, q, r = g[n][o][0], g[n][o][1], g[n][o][2]; p, q, r = str(p), str(q), str(r)
                        #    me          me          me
            while len(p) < 3:
                p="0"+p
                while len(q) < 3:
                    q="0"+q
                    while len(r) < 3:
                        r="0"+r#eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
            result = p+q+r
            for w in range(0, j+1):
                x=z.b2a_uu(t);                y=z.b2a_uu(v)
            t = z.a2b_uu("0.00")
            #         ww
            v = z.a2b_uu("-0.00")
            s=c.randint(0,1)
            if s == 0: k[j]=(m[j][0]*2,float(x.decode()[:-2].strip(" ")+result))
            if s == 1: k[j]=(m[j][0]*2,float(y.decode()[:-2].strip(" ")+result))
            j+=1
           #b
            l.update(1)

            #wow   0   then
b.write('out.wav', k, 44100, 'FLOAT')

アプローチ:頑張ってエンコーダを読む

aaaaaaaaaaaaaaaaaa.wavur-worst-nightmare.pyが配布されます.

ur-worst-nightmare.pyはエンコーダで,恐らくaaaaaaaaaaaaaaaaaa.wavはフラグ画像が埋め込まれた音声ファイルだと考えられます(guessingしたくないのでファイル名をout.wavに」してくれ

ur-worst-nightmare.pyの処理を簡単にまとめると以下のようになります.

  • フラグ画像の読み込み
  • 音声ファイルの読み込み
  • フラグ画像のBGRの各ピクセル値を取得
  • ピクセル値を3桁で0パディング
  • 0.00または-0.00と0パディングしたピクセル値を連結して小数化
  • 小数化したピクセル値をwavに埋め込み

これらを踏まえてソルバを書くこと以下のようになります.

from PIL import Image
import soundfile

img = Image.new('RGB', (500,500))
wav = soundfile.SoundFile("aaaaaaaaaaaaaaaaaa.wav", 'r')
wav_data = wav.read()
wav.close()

count = 0
for y in range(500):
    for x in range(500):
        b = int(abs(wav_data[count][1] * 100000))
        g = int(abs(wav_data[count][1] * 100000 * 1000)) % 1000
        r = int(abs(wav_data[count][1] * 100000 * 1000 * 1000)) % 1000
        count += 1
        img.putpixel((x,y),(r,g,b))

# img.show()
img.save('./flag.jpg')

f:id:satto1237:20200129014124j:plain

rtcp{uh_oh_sisters_342}

General Skills

Treeeeeeee [200pts]

It appears that my cat has gotten itself stuck in a tree... It's really tall and I can't seem to reach it. Maybe you can throw a snake at the tree to find it?

Oh, you want to know what my cat looks like? I put a picture in the hints.

treemycatisin.7z

> file treemycatisin.7z
treemycatisin.7z: 7-zip archive data, version 0.4

アプローチ:ハッシュ値

treemycatisin.7zを解凍すると27847のディレクトリと1337のファイルを含んだbigtreeフォルダを得ることができます.

f:id:satto1237:20200130002409p:plain

bigtree内のファイルを眺めるとどうやら2種類のjpgファイルが大量に存在することが分かります.

f:id:satto1237:20200130002055j:plain

f:id:satto1237:20200130002154j:plain

1つ1つ調べるのは手間がかかるのでハッシュ値を利用してサクッと目的のファイルを検索します.

> mkdir jpg
> find ./bigtree -type f | grep "\.jpg$" | xargs -J% cp -p % ./jpg
> md5 ./jpg/*.jpg | awk '{print $4}' | sort | uniq -c
  655 2d7b81239b77deb7fbda026d9521939b
  681 49390dd9695e7ab7c49fbea6697bc1a9
    1 aeb3e033f8bdbf2ec44fda714da72f77
> md5 ./jpg/*.jpg | grep aeb3e033f8bdbf2ec44fda714da72f77
MD5 (./jpg/ENP92.jpg) = aeb3e033f8bdbf2ec44fda714da72f77
> open ./jpg/ENP92.jpg

f:id:satto1237:20200130002908j:plain

RTCP{MEOW_SHARP_PIDGION_RICE_TREE}

Cryptography

HOOOOOOOOOOMEEEEEE RUNNNNNNNNNNNNN!!!!! [50pts]

AND JAKE IS ROUNDING THE BASES
HE PASSES BASE 32!!!
HE ROUNDS BASE 64!!!!!!!
WE'RE WITNESSING A MIRACLE!!!!!!!!!!!!!

Just one more base to go ;D

Ecbf1HZ_kd8jR5K?[";(7;aJp?[4>J?Slk3<+n'pF]W^,F>._lB/=r

アプローチ:base85

base85でデコードするとflagになります.

rtcp{uH_JAk3_w3REn't_y0u_4t_Th3_uWust0r4g3}

View Hintを使わないと問題が見れないのってどうなの

It was just a typical day in the bakery for Delphine. She was preparing her famous chocolate cake, when all of a sudden a GIANt burst through the doors of her establishment and demanded a cookie. Being the strong-willed girl she was, Delphine refused and promptly threw her rolling pin at the GIANt. Doing what any sensible being would do when faced with projectiles, the GIANt let out a shriek and ran out of the shop. Delphine smiled to herself, it was another day well done. But oh? What's this? It seems the GIANt dropped this behind while he was screaming and scrambling out of the shop.

69acad26c0b7fa29d2df023b4744bf07

アプローチ:md5のクラック

以下のオンラインツールを利用してmd5をクラックします.

crackstation.net

rtcp{chocolate mmm}

15 [100pts]

Lhzdwt eceowwl: Dhtnwt Pcln Eaao Qwoohvw

Okw qsyo okcln bah'i fslo cl baht Dhtnwt Pcln dhtnwt cy yazwalw'y eaao ehlnhy. Dho sy co ohtly aho, okso zcnko dw fkso bah nwo. S 4vksllwt hmqasiwi s mkaoa slalbzahyqb oa okw ycow ykafvsycln kcy ewwo cl s mqsyocv dcl ae qwoohvw, fcok okw yosowzwlo: "Okcy cy okw qwoohvw bah wso so Dhtnwt Pcln." Sizcoowiqb, kw ksi ykawy al. Dho okso'y wgwl fatyw.

Okw mayo fwlo qcgw so 11:38 MZ al Xhqb 16, sli s zwtw ofwlob zclhowy qsowt, okw Dhtnwt Pcln cl rhwyocal fsy sqwtowi oa okw tanhw wzmqabww. So qwsyo, C kamw kw'y tanhw. Kaf ici co ksmmwl? Fwqq, okw DP wzmqabww ksil'o twzagwi okw WJCE isos etaz okw hmqasiwi mkaoa, fkcvk yhnnwyowi okw vhqmtco fsy yazwfkwtw cl Zsbecwqi Kwcnkoy, Akca. Okcy fsy so 11:47. Oktww zclhowy qsowt so 11:50, okw Dhtnwt Pcln dtslvk siitwyy fsy mayowi fcok fcykwy ae ksmmb hlwzmqabzwlo. Ecgw zclhowy qsowt, okw lwfy yosocal fsy valosvowi db slaokwt 4vksllwt. Sli oktww zclhowy qsowt, so 11:58, s qclp fsy mayowi: DP'y "Owqq hy sdaho hy" alqclw eathz. Okw eaao mkaoa, aokwtfcyw plafl sy wjkcdco S, fsy soosvkwi. Vqwgwqsli Yvwlw Zsnsuclw valosvowi okw DP cl rhwyocal okw lwjo isb. Fkwl rhwyocalwi, okw dtwspesyo ykceo zslsnwt ysci "Ak, C plaf fka okso cy. Kw'y nwoocln ectwi." Zbyowtb yaqgwi, db 4vksl. Laf fw vsl sqq na dsvp oa wsocln aht esyo eaai cl mwsvw.

tovm{v4T3Ehq_f1oK_3J1e_i4O4}

アプローチ:quipqiup

換字式暗号っぽいのでquipqiupに投げます.

rtcp{c4R3Ful_w1tH_3X1f_d4T4}

まとめ

  • guessingが多すぎてしんどかった
  • 途中で飽きてしまった(チームメンバのみなさん申し訳ないです)