Attack All Around

今やCTFと競プロばかりだが、トビタテ生のアメリカ留学やTOEFL奮闘記

HeroCTF v3 writeup

m1z0r3はWPICTFにも参加していたのですが難しすぎて私はすぐ撤退…。
HeroCTFはそこそこの難易度でcryptoは全完できたのでよかったです!

https://www.heroctf.fr

Result

f:id:partender810:20210426143616p:plain
result

もう少しで1000ptと2桁順位が見えたので悔しいですね…


Writeup

Blockchain

Transfer 25pt

We've been tracking drug dealers for a few years. The only thing we got from their network is a hash : bfa8b1c8b7f6acc867d6984968756cafd0da99060aa6d90dfb0db1a9ef0c96a2
Can you tell us where the money is gone?

Blockchainというジャンルは初めてです。いつもはよくEtherscanを使っているのですがそちらでは見つからず、こちらでhash検索で見つかりました。

Transaction: bfa8b1c8b7f6acc867d6984968756cafd0da99060aa6d90dfb0db1a9ef0c96a2 | Blockchain Explorer

Hero{1PQBh6tddet14bYDsSbUiox1YJb5EL185A}


Crypto

h4XOR 75 pt

Can you recover the flag.png image ?
Hint : The xor function is from the pwntools module.
ファイル:flag.png.enc, xor.py

まずxor.pyについて読んでいきます。flag.pngのバイナリデータと、ランダムな8bytesと[0-9]の内どれかをバイト列として繋げた9bytesをxorしてflag.png.encに書き込んでいます。ここでpwntoolsでのxorは特殊で、xorする際に両方の長さを揃えるようにします。長い方に合わせる形で短い方を伸ばします。短い方の長さが長い方の倍数で無い場合、先頭bytesを付け加えます。例えばb"ABCDE"を12bytesにしたい場合、b"ABCDEABCDEAB"という感じです。

ランダムな9bytesの方ですが、後ろ1bytesは10通りしかないのでbrute force可能です。ですが前8bytesをbrute forceするのは2568 = O(1020)とかなりかかるので不可能です。なので別の方法を考えましょう。

PNG画像ファイルのフォーマットはこちらで勉強しました。

PNG ファイルフォーマット

PNG画像ファイルの先頭8bytesは16進数で "89504E470D0A1A0A"と決まっています。なのでこの値とencの先頭8bytesをxorするとランダムな8bytesの値が手に入ります。あとは0~9の10通りを試せばOKです。

from os import urandom
from random import randint
from pwn import xor
from Crypto.Util.number import *


outpout_img = open("flag.png.enc", "rb").read()
head = 0x89504E470D0A1A0A
k = long_to_bytes(bytes_to_long(outpout_img[:8])^head)
img0 =open("flag0.png", "wb")
img1 =open("flag1.png", "wb")
img2 =open("flag2.png", "wb")
img3 =open("flag3.png", "wb")
img4 =open("flag4.png", "wb")
img5 =open("flag5.png", "wb")
img6 =open("flag6.png", "wb")
img7 =open("flag7.png", "wb")
img8 =open("flag8.png", "wb")
img9 =open("flag9.png", "wb")
key0 = k + bytes([0])
key1 = k + bytes([1])
key2 = k + bytes([2])
key3 = k + bytes([3])
key4 = k + bytes([4])
key5 = k + bytes([5])
key6 = k + bytes([6])
key7 = k + bytes([7])
key8 = k + bytes([8])
key9 = k + bytes([9])
img0.write(xor(outpout_img, key0))
img1.write(xor(outpout_img, key1))
img2.write(xor(outpout_img, key2))
img3.write(xor(outpout_img, key3))
img4.write(xor(outpout_img, key4))
img5.write(xor(outpout_img, key5))
img6.write(xor(outpout_img, key6))
img7.write(xor(outpout_img, key7))
img8.write(xor(outpout_img, key8))
img9.write(xor(outpout_img, key9))

f:id:partender810:20210425222308p:plain
9でした

もっと綺麗なsolverはあるはず

Hero{123_xor_321}


ExtractMyBlocks 125 pt

The company PasswordS3cure created a new password reset functionality. Could you crack it and find the flag ?
nc chall0.heroctf.fr 10000
ファイル:challenge.py

challenge.pyを読んでいきます。

文字列を投げるとaccount_idとして処理され、それやflagを含むmsg変数にある文字列がAESのECBモードで暗号化され、それを16進数にした値が渡されます。KEYの値は不明です。

AESのECBモードはもっとも単純な暗号化方式になります。

f:id:partender810:20210425224952p:plain
AES ECB mode wikipediaから引用

KEYが同じ場合、同じ平文なら同じ暗号文が返されます。CBCモードと異なり、同じ16bytesの平文を二つ繋げた文字列を暗号化すると、16bytesの同じ暗号文が二つ繋げた状態で返ってきます。何ブロック目かなんて関係ないです。flagの文字列も一緒に暗号化されるので、同じ文字列を送れば同じ暗号文になり情報が得られそうです。ただし16bytes毎に区切っているので開始位置に注意する必要があります。これらを考慮しながら入力を調整していく方向で考えていきます。

flagをいきなりbrute forceするのは無理があります。長さも分からないので無謀です。しかし、一文字ごと特定するのであれば64くらい×(flag長)なのでそんなに時間がかからないです。では一文字ずつ特定していきましょう。

flagが含まれるmsg変数のflagが始まる10文字を注目していきます。(その10文字)+"Hero{"+(flagの1文字目) (=Fとします )が一つのblockとして扱われるよう(blockを跨ぐことのないよう)入力を調整していきます。(その10文字)の先頭が16*k+1文字目になればOKです。※(その10文字) = "assword : "

ではこちらが送る文字列も(その10文字)+"Hero{"+(flagの1文字目をbrute forceで試している1文字) (=Tとします )が一つのblockとして扱われるようにこちらも入力を調整していきます。

下の図について、\は改行を、*はT,Fが1blockに収まるように調整を、?はbrute forceで試す1文字を表しています。これはflagの{以降の最初の文字を調べる時の図です。

f:id:partender810:20210426155738p:plain
flagの1文字目を求めたい

上から2,4番目の文字列が等しくなる場合、つまり?にflagの1文字目が入った場合、暗号文の2,4 block目(16~32bytesと48~64bytes目)が同じ値になります。これで1文字目が"_"ということが分かりました(1文字目でこの文字は不安になる)。

次に2文字目についてです。

f:id:partender810:20210426155838p:plain
2文字目を求めたい

2block目を1文字シフトさせ3block目のpaddingを一つ減らすことで、上手く2,4block目を対応させます。
このようにして?に"}"が当てはまるまで繰り返していきます。3block目のpaddingが0になったら次は16個増やして2,5 block目が同じならOKという感じにシフトしていきます。flag長が16を超えたら3,6block目にしないと…と考えてたらかなり短かったです。

candi = "ABCDEFGHJIKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890{}_"
FLAG = "Hero{test_flag}" #簡易的なflag。途中msgを出力している際に入力として送る文字列が正しい長さ確認する
flag = "Hero{"
isbreak = False #終了条件
#tempをシフトさせていって1文字ずつbrute forceしていく
temp = "assword : Hero{"
k = len(" !\n\nYour p") #paddingする際の長さ
print(k)
L = 16 #paddingで送る長さ調整。k=16になった時は32にする。
M = 3 #暗号化されたflagが何blockにあたるか
while True:
    printmsg = True
    print("k :",k)
    for i in candi:
        print(i)
        HOST, PORT = "chall0.heroctf.fr", 10000
        s, f = sock(HOST, PORT)
        _ = read_until(f)
        read_until(f,"ID : ")
        account_id = "12" + temp + i + "0"*(L-k)
        _msg = f"""
Welcome back {account_id} !

Your password : {FLAG}

Regards
"""
        #送る入力が正しいものになっているか。特に長さの確認
        if printmsg:
            for j in range(0,len(_msg),16):
                print(j//16,_msg[j:j+16])
        msg = "12" + temp + i + "0"*(L-k)
        s.send(msg.encode()+b"\n")
        ct = read_until(f).strip()
        assert len(ct)%32 == 0
        cip = []
        for j in range(0,len(ct),32):
            cip.append(ct[j:j+32])
        if cip[1] == cip[M]:
            print(i)
            s.close()
            flag += i
            if i == "}":
                print("This is the flag!")
                print(flag)
                isbreak = True
                break
            print(flag)
            temp = temp[1:] + i
            k += 1
            if k == 16:
                L += 16
                M += 1
            break
        s.close()
        printmsg = False
    if isbreak: break

Hero{_BL0CK5_}


Forensics

We need you 1/5 50pt

Interpol and the FBI have been investigating for over a year now. They are trying to get their hands on two hackers very well known for their ransomware and their ultra efficient botnet.
After long months of investigation, they managed to get their hands on one of their servers. But, when they got it back the PC caught fire because of a defense mechanism set up by the two hackers.
The hard drive could not be saved, but they had time to put the RAM in liquid nitrogen and analyze it later.
You know what you have to do!
For this first step, find the name of the PC!
Download, here.
Format: Hero{Name}
ファイル:Challenge.zip

zipファイルを解凍するとcapture.memが得られます。memファイルの解析ってなんだ、とググるとvolatilityが使えることが判明!

ずばり欲しいデータを得られるコマンドを教えてくれるサイトがありました。

Volatility/Retrieve-hostname - aldeid

$ volatility -f capture.mem imageinfo
Volatility Foundation Volatility Framework 2.6
INFO    : volatility.debug    : Determining profile based on KDBG search...
          Suggested Profile(s) : Win7SP1x86_23418, Win7SP0x86, Win7SP1x86
          (省略)

$ volatility -f capture.mem --profile=Win7SP1x86 hivelist
Volatility Foundation Volatility Framework 2.6
Virtual    Physical   Name
---------- ---------- ----
(省略)
0x823859c8 0x2b5d99c8 \SystemRoot\System32\Config\SAM
0x8940c5e8 0x2d5415e8 [no name]
0x8941a2c0 0x2d58d2c0 \REGISTRY\MACHINE\SYSTEM
(省略)


$ volatility -f capture.mem --profile=Win7SP1x86 printkey -o 0x8941a2c0 -K 'ControlSet001\Control\ComputerName\ComputerName'
Volatility Foundation Volatility Framework 2.6
Legend: (S) = Stable   (V) = Volatile

----------------------------
Registry: \REGISTRY\MACHINE\SYSTEM
Key name: ComputerName (S)
Last updated: 2021-04-19 17:00:09 UTC+0000

Subkeys:

Values:
REG_SZ                        : (S) mnmsrvc
REG_SZ        ComputerName    : (S) KANNIBAL

Hero{KANNIBAL}


We need you 2/5 75pt

It must be their team name.
For this second step, find the user's name and password in clear text.
Format: Hero{Username:Password}

先程使ったサイト、他にも欲しい情報くれるので最高過ぎる

Volatility/Retrieve-password - aldeid

1/5で使ったimageinfoとhivelistを使います

$ volatility -f capture.mem --profile=Win7SP1x86 hashdump -y 0x8941a2c0 -s 0x823859c8
Volatility Foundation Volatility Framework 2.6
Administrateur:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
Invit:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
Razex:1000:aad3b435b51404eeaad3b435b51404ee:78d9c7e905c695087ee3baa755ce43e4:::

f:id:partender810:20210426001458p:plain
crack成功!

UsernameがRazexであることに気付かず、crackしてから時間かかりました…。

Hero{Razex:liverpoolfc123}


We need you 3/5 80pt

We know for sure that this server allowed to connect to infected machines. Can you check if a connection was instantiated?
Format: Hero{IP:Port}

接続を確認するのはconnectionsコマンドだろうと実行するもサポートしてないと指摘される。うーん、他にないかな。

Volatility, my own cheatsheet (Part 5): Networking | Andrea Fortuna

netscanでもいいのかありがたい。

$ volatility -f capture.mem --profile=Win7SP1x86 netscan
Volatility Foundation Volatility Framework 2.6
Offset(P)          Proto    Local Address                  Foreign Address      State            Pid      Owner          Created
(省略)
0x7ee41538         TCPv4    10.0.2.15:49159                146.59.156.82:4444   ESTABLISHED      3296     nc.exe
(省略)

他を省略していますがStateが唯一ESTABLISHEDとなっているものがあったのでForeign Addressを投げたら通りました。

Hero{146.59.156.82:4444}


Misc

Discord 1pt

Join our Discord server and read the rules !
URL : https://discord.gg/PhNkPrfeJG

discord内に分かりやすく書いてほしい…。

Hero{3njoy_th3_3v3nt}


Cubes 40pt

#257 ; #260 ; #282 ; #12 ; #349:2 ; #344 ; #383:120 ; #368
The flag is in in lowercase, without spaces.

これ解けたの嬉しい!

暗号ぽいので「cube cipher」でググるとrubik's cube cipherがヒットしました。ルービックキューブは9個*6面の54種類のスペース(?)があるのに対し、暗号文の数が大きすぎます。そもそも「383:120」などのコロンが付いているやつが何も分かりません。

この特徴的な値に注目し「383:120 cube」でググると…。

Minecraft ID List - Minecraft Info

めちゃくちゃぽい!!

頭文字を並べてみると"iamscese"となる。"iam"はそれっぽいのに最後がなんか変。提出してもincorrectでした。

方向性は間違っていないだろうとminecraftのIDリストを調べてみるとどうやら見ていたのが古いバージョンだった模様。こちらで調べて頭文字を調べるとcorrectとなりました!

Minecraft ID List (1.16) | Minecraft Item IDs

Hero{iamsteve}


Russian Doll 50pt

Go deeper !
ファイル:archive.zip

問題文と問題名よりzip解凍するとめちゃくちゃディレクトリ階層の深いのだろうと…ビンゴ。ただ予想をはるかに超える深さでした。最下層にflag.txtがあるのが見えたので、なんとか検索できる術はないかと模索したところ、見つかりました!

[Linux]grepでディレクトリ以下の全てのファイルを検索する │ TEAM T3A

$ find ./ -type f | xargs grep "Hero{"
Binary file ./archive.zip matches
./you/are/about/to/get/rick/rolled/rickRollIncoming/no/iMean/really/lastWarning/toldYou/you/should/have/listened/now/stop/looking/in/someoneElse/stuff/cuteCatPictures/goAway/stop/clicking/manually/through/folders/like/that/write/a/script/to/do/it/for/you/come/on/waste/of/time/what/about/a/recipe/now/200/g/de/pois/chiches/500/g/de/feve/seches/1/oignon/moyen/2/gousses/dail/1/bouquet/de/persil/3/cuilleres/a/soupe/de/farine/1/cuillere/a/cafe/de/cumin/en/poudre/1/cuillere/a/cafe/de/coriandre/en/poudre/1/cuillere/à/cafe/de/paprika/3/cuilleres/a/soupe/de/basilic/frais/hache/sel/huile/de/friture/faites/tremper/les/pois/chiches/et/les/feves/dans/leau/12h/les/egoutter/et/les/cuire/45/mn/a/l/auto/cuiseur/peler/oignon/et/ail/les/hacher/ainsi/que/le/persil/passer/les/feves/et/les/pois/chiches/au/mixer/ourobot/melanger/avec/le/persil/loignon/lail/la/farine/les/epices/le/sel/petrissez/le/tout/avec/vos/mains/en/ajoutant/un/peu/deau/si/necessaire/rassemblez/la/pate/et/laisser/reposer/au/refrigerateur/pendant/minimum/30mn/faconner/une/trentaine/de/boulettes/de/la/grosseur/dune/piece/de/2/euros/les/faire/frire/2-3/mn/puis/les/egoutter/sur/du/papier/absorbant/servir/chaud/ou/froid/avec/des/petites/sauces/tomates/aux/herbes/ou/sauces/yaourts/et/voila/cest/pret/bon/appetit/notPorn/stillNotPorn/reallyNot/seriousStuff/work/realWork/porn/did/you/really/think/there/would/be/porn/inA/work/directory/now/stop/looking/in/someoneElseS/stuff/cuteCatPictures/goAway/stop/clicking/manually/through/folders/like/that/write/a/script/to/do/it/for/you/come/on/waste/of/time/what/about/a/recipe/now/200/g/de/pois/chiches/500/g/de/feve/seches/1/oignon/moyen/2/gousses/dail/1/bouquet/de/persil/3/cuilleres/a/soupe/de/farine/1/cuillere/a/cafe/de/cumin/en/poudre/1/cuillere/a/cafe/de/coriandre/en/poudre/1/cuillere/à/cafe/de/paprika/3/cuilleres/a/soupe/de/basilic/frais/hache/sel/huile/de/friture/faites/tremper/les/pois/chiches/et/les/feves/dans/leau/12h/les/egoutter/et/les/cuire/45/mn/a/l/auto/cuiseur/peler/oignon/et/ail/les/hacher/ainsi/que/le/persil/passer/les/feves/et/les/pois/chiches/au/mixer/ourobot/melanger/avec/le/persil/loignon/lail/la/farine/les/epices/le/sel/petrissez/le/tout/avec/vos/mains/en/ajoutant/un/peu/deau/si/necessaire/rassemblez/la/pate/et/laisser/reposer/au/refrigerateur/pendant/minimum/30mn/faconner/une/trentaine/de/boulettes/de/la/grosseur/dune/piece/de/2/euros/les/faire/frire/2-3/mn/puis/les/egoutter/sur/du/papier/absorbant/servir/chaud/ou/froid/avec/des/petites/sauces/tomates/aux/herbes/ou/sauces/yaourts/et/voila/cest/pret/bon/appetit/ok/you/win/hereIsTheFlag/haha/what/about/a/recipe/now/200/g/de/pois/chiches/500/g/de/feve/seches/1/oignon/moyen/2/gousses/dail/1/bouquet/de/persil/3/cuilleres/a/soupe/de/farine/1/cuillere/a/cafe/de/cumin/en/poudre/1/cuillere/a/cafe/de/coriandre/en/poudre/1/cuillere/à/cafe/de/paprika/3/cuilleres/a/soupe/de/basilic/frais/hache/sel/huile/de/friture/faites/tremper/les/pois/chiches/et/les/feves/dans/leau/12h/les/egoutter/et/les/cuire/45/mn/a/l/auto/cuiseur/peler/oignon/et/ail/les/hacher/ainsi/que/le/persil/passer/les/feves/et/les/pois/chiches/au/mixer/ourobot/melanger/avec/le/persil/loignon/lail/la/farine/les/epices/le/sel/petrissez/le/tout/avec/vos/mains/en/ajoutant/un/peu/deau/si/necessaire/rassemblez/la/pate/et/laisser/reposer/au/refrigerateur/pendant/minimum/30mn/faconner/une/trentaine/de/boulettes/de/la/grosseur/dune/piece/de/2/euros/les/faire/frire/2-3/mn/puis/les/egoutter/sur/du/papier/absorbant/servir/chaud/ou/froid/avec/des/petites/sauces/tomates/aux/herbes/ou/sauces/yaourts/et/voila/cest/pret/bon/appetit/bonOk/flag.txt:Hero{if_yOu_gOt_HEre_By_clIcKInG_mANnUaLly_YoU_sHOuLd_REalLy_SeE_SoMeOne}

Hero{if_yOu_gOt_HEre_By_clIcKInG_mANnUaLly_YoU_sHOuLd_REalLy_SeE_SoMeOne}


OSINT

Find me 10pt

Could you retrieve where this photo was taken ?
Format : Hero{place}
ファイル:find_me.jpg

画像検索で一発です。

f:id:partender810:20210426141422p:plain
便利だなぁ

Hero{portes mordelaises}


Social ID #1 15pt

Can you find the twitter ID of @HeroCTF.
Format : Hero{twitter_id}

twitter ID って@HeroCTFじゃないのか?と調べたところある整数値がIDだそうです。スクリーンネーム(@以降)を投げると教えてくれるサイトがありました。

idtwi | Twitter IDチェッカー(変更履歴の追跡)

Hero{815907006708060160}


Pushhhh 35pt

The flag is in one of the two Github repositories of the last HeroCTF edition. Could you find it ?

今回がv3なのでv2のgithubを調べれば良さそうです。色々見たところbranchが複数…。

f:id:partender810:20210426142049p:plain
怪しすぎる

ここを覗いてみるとflagがありました。

HeroCTF_v2/flag.txt at flag · HeroCTF/HeroCTF_v2 · GitHub

Hero{y0u_re_g00d_4t_g1t_250820}


Social ID #2 50pt

Can you find the @username of this Twitter ID 44196397.
Format : Hero{username}

先程のidtwiでOKです。

Hero{@elonmusk}


Prog

Ping Pong 45pt

Could you get the flag ?
ファイル:output.txt

ProgってProgrammingかな?

output.txtを見ると"PING"か"PONG"のどちらかが書いてあります。長さが176と8の倍数であることと、文字列として違うのがIとOなので、"PING" = 1, "PONG" = 0とした2進数を8桁ごとでchrしたらうまく復号されました。

from Crypto.Util.number import *
f = open("output.txt")
a = f.readlines()
ans = ""
for i in a:
    if i.strip() == "PING": ans += "1"
    else: ans += "0"
for i in range(0,len(ans),8):
    print(chr(int(ans[i:i+8],2)),end="")
print()

Hero{p1n6_p0n6_15_fun}


PRo Random Guesser 50pt

Everybody loves a little guessing challenge right ? Guess the number \o/
- Love, Mersenne
/!\ If you are using a script, you have to append '\n' to any data you wish to send back.
Host : chall0.heroctf.fr Port : 7003

数字を予測しろとのことなので、何かの乱数を生成しているのだろう。問題文から恐らくメルセンヌ・ツイスターかな。

メルセンヌ・ツイスタ - Wikipedia

細かい仕組みは全く分からないですが、こちらをコードをパクって解けました。ももテクさんには頭が上がらないです。

Mersenne Twisterの出力を推測してみる - ももいろテクノロジー

def untemper(x):
    x = unBitshiftRightXor(x, 18)
    x = unBitshiftLeftXor(x, 15, 0xefc60000)
    x = unBitshiftLeftXor(x, 7, 0x9d2c5680)
    x = unBitshiftRightXor(x, 11)
    return x

def unBitshiftRightXor(x, shift):
    i = 1
    y = x
    while i * shift < 32:
        z = y >> shift
        y = x ^ z
        i += 1
    return y

def unBitshiftLeftXor(x, shift, mask):
    i = 1
    y = x
    while i * shift < 32:
        z = y << shift
        y = x ^ (z & mask)
        i += 1
    return y

HOST, PORT = "chall0.heroctf.fr", 7003
s, f = sock(HOST, PORT)
print(read_until(f))
print(read_until(f))
print(read_until(f))
x = []
for i in range(624):
    print(i)
    read_until(f,"Guess me : ")
    s.send(b"1337\n")
    recv_m = read_until(f).split()
    x.append(int(recv_m[3]))
    read_until(f)
mt_state = tuple([untemper(z) for z in x] + [624])
random.setstate((3, mt_state, None))
ans = int(random.getrandbits(32))
s.send(str(ans).encode()+b"\n")
while True: print(read_until(f))

Hero{n0t_s0_r4nd0m_4ft3r_4ll}


Reverse

EasyAssembly 40pt

Don't worry, this one is quite easy :) Could be a good introduction to assembly !
Format : Hero{input:modified}
ファイル:EasyAssembly.asm

IDAなど色々ツールを使ったのですが、結局catすれば分かりました。

$ cat EasyAssembly.asm
(省略)
# EasyAssembly.c:19:    modified = input >> 2;
        movl    -8(%rbp), %eax  # input, tmp89
        sarl    $2, %eax        #, tmp88
        movl    %eax, -4(%rbp)  # tmp88, modified
# EasyAssembly.c:21:    if(modified == 1337404)
        cmpl    $1337404, -4(%rbp)      #, modified
        jne     .L5     #,
# EasyAssembly.c:22:            isGood = 0;
        movl    $0, isGood(%rip)        #, isGood
.L5:
# EasyAssembly.c:24:    if(!isGood)
        movl    isGood(%rip), %eax      # isGood, isGood.1_1
# EasyAssembly.c:24:    if(!isGood)
        testl   %eax, %eax      # isGood.1_1
        jne     .L6     #,
# EasyAssembly.c:25:            printf("Well done ! You can validate with the flag Hero{%d:%d}\n", input, modified);
(省略)

"if(modified == 1337404)" とあるのでmodifiedは1337404でしょう。"modified = input >> 2" からinputはmodifiedを2ビット左シフトさせたものでしょう。エントロピーが2bitsなのでbrute forceすればいいかなと思い提出したら一発で通りました。

Hero{5349616:1337404}


Steganography

HolyAbbot 15pt

A certain abbot tried to give us a message...
(the message is in lower case) (No need to speak French)
Format : Hero{messageinlowercase}
ファイル:HolyAbbot.txt

steganoって全部画像ファイルの解析と思ってたらテキストでびっくり。
しかもテキストの先頭行をググったら一発。RITSEC CTFでもやった、Ave Maria cipherのフランス語バージョンでした。Steganoというよりcryptoじゃん。

partender810.hatenablog.com

Ave Maria de Trithème - Déchiffrer, Décoder, Encoder en Ligne

decodeしたものを小文字に変更して終了です。

Hero{substitution}


Nice PDF 20pt

Don't think to much ;)
ファイル:NicePDF.pdf

pdfの解析か…。問題文から察するにそんな難しいことはせずに解けそうです。exiftoolやbinwalkなどのツールやPDFを実際に開いてプロパティを見るとかしましたが分からず…。

藁にも縋る思いでgoogleに頼るとこんなオンラインツールが。

PDF Extract Tool

textで解析すると以下の結果が得られました。

 93,02  760,68 H
  99,86  760,68 ses
 113,90  760,68 e
 119,42  760,68 Histoires,
 161,54  760,68 r
 165,38  760,68 l'historien
 209,93  760,68 o
 215,81  760,68 grec
 234,89  760,68 {
 238,37  760,68 Hérodote
 281,09  760,68 E
 286,49  760,68 rapporte
 325,99  760,68 4
 331,63  760,68 ainsi
 352,03  760,68 S
 357,07  760,68 une
 373,99  760,68 Y
 379,39  760,68 anecdote
 421,27  760,68 _
 426,79  760,68 qui
 440,86  760,68 P
 446,62  760,68 eut
 461,50  760,68 D
 468,34  760,68 lieu
 484,66  760,68 F
 489,70  760,68 au
 500,74  760,68 }

一文字おきに読むとflagになりました。

Hero{E4SY_PDF}


Problems&solver

GitHub - ksbowler/HeroCTF_v3

今回、ファイルサイズが大きくあげられないものがありました。ご了承ください。

  • forensics We need you Challenge.zip
  • OSINT Russian doll archive.zip