LoginSignup
4
3

More than 5 years have passed since last update.

SECCON 2017 Online CTF Writeup

Last updated at Posted at 2017-12-10

チームnicklegrで個人参加。
1000点で230位(1028チーム中)でした。

Vigenere3d (Crypto 100)

ヴィジュネル暗号リベンジ。今年は置換表が3次元配列。鍵は14文字。

通常のヴィジュネル暗号では平文と暗号文のペアがあれば一文字ずつ鍵が分かる。
置換表が3次元なので鍵は2文字の組み合わせになる。なので一意には決まらないけど、どの組み合わせでも解読結果は同じになるので、適当に1つ選べばいい。(たぶん。うまく言えない)

下記を実行すると、

def find(plain, cipher):
    s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz_{}"
    t = [[_l((i+j) % len(s), s) for j in range(len(s))] for i in range(len(s))]
    i1 = 0
    i2 = 0

    for i in range(len(plain)):
        try:
            for i1 in range(len(s)):
               for i2 in range(len(s)):
                    if t[s.find(plain[i])][s.find(s[i1])][s.find(s[i2])] == cipher[i]:
                        print "%s, %s" % (s[i1], s[i2])
                        raise
        except Exception:
            pass

find("SECCON{", "POR4dny")

下記が出力される。

A, _
A, K
A, P
A, 2
A, Z
A, a
A, _

鍵の先頭7文字分が分かった。k1を逆順にしてk2を作っているので、逆順にして後ろにくっつければ14文字の鍵が出来上がる。

def decode(cipher, k1, k2):
    s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz_{}"
    t = [[_l((i+j) % len(s), s) for j in range(len(s))] for i in range(len(s))]
    i1 = 0
    i2 = 0
    plain = ""
    for a in cipher:
        for i in range(len(s)):
            if t[i][s.find(k1[i1])][s.find(k2[i2])] == a:
                plain += s[i]
                break
        i1 = (i1 + 1) % len(k1)
        i2 = (i2 + 1) % len(k2)
    return plain

print decode("POR4dnyTLHBfwbxAAZhe}}ocZR3Cxcftw9", "AAAAAAAAAAAAAA", "_KP2Za__aZ2PK_")
SECCON{Welc0me_to_SECCON_CTF_2017}

Run me! (Programming 100)

フィボナッチ数列の第11011項を計算する。
サンプルプログラムは再帰で書かれていて、いつまで経っても終わらないので普通に高速化する。

def fib(x)
  n = [0, 1]
  for i in 2..x
    v = n[0] + n[1]
    n.shift
    n[1] = v
  end
  n[1]
end

puts fib(11011).to_s[0, 32]
SECCON{65076140832331717667772761541872}

putchar music (Programming 100)

ワンライナーでputcharで音楽を演奏する謎技術。4Kデモみたいだ。

ソースが古い書き方でコンパイルが通らないので適当に直す。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int t_, const char* i_[], const char* j_[]){
    int t,i,j;
    unsigned char p[]="###<f_YM\204g_YM\204g_Y_H #<f_YM\204g_YM\204g_Y_H #+-?[WKAMYJ/7 #+-?[WKgH #+-?[WKAMYJ/7hk\206\203tk\\YJAfkkk";
    for(i=0;t=1;i=(i+1)%(sizeof(p)-1)){
        double x=pow(1.05946309435931,p[i]/6+13);
        for(j=1+p[i]%6;t++%(8192/j);)
            putchar(t>>5|(int)(t*x));
    }
}

"putchar music"でググると下記のサイトが出てくる。soxというツールに通せばいいらしい。
http://royal-paw.com/2012/01/bytebeats-in-c-and-python-generative-symphonies-from-extremely-small-programs/

$ gcc putchar_music.cpp -o putchar_music -lm
$ ./putchar_music | sox -r 8000 -b 8 -c 1 -t raw -s - -d

誰でも知ってるあの曲が流れる。すごい。

SECCON{STAR_WARS}

ネイティブのLinuxを用意する必要があるかと思ったけど、VirtualBox上のubuntuでもちゃんと動いた。

というか、誰でも知ってる映画の曲という時点で有名どころを適当に試せば正解しそう。
なので初手で何も考えず SECCON{BACK_TO_THE_FUTURE} を投げてみたのは秘密。

SHA-1 is dead (Crypto 100)

SHA-1が衝突する2つのファイルをアップロードする。
ただしファイルサイズは2017KB以上、2018KB以下。

超有名サイト https://shattered.io/ でSHA-1が同じPDFが2種類手に入る。
この後ろにダミーデータを追加してもSHA-1は衝突したまま。ファイルの中身は問われないので問題ない。

# 2018*1024 - 422435 = 1643997バイト追加すればいい。超えないようにちょっと減らす。

% dd if=/dev/zero of=zero.dat bs=1 count=1643900
% cat shattered-1.pdf zero.dat > s1.dat
% cat shattered-2.pdf zero.dat > s2.dat
% sha1sum s1.dat s2.dat
2631368404fae2c264abea95d3a46033be733f9e  s1.dat
2631368404fae2c264abea95d3a46033be733f9e  s2.dat
SECCON{SHA-1_1995-2017?}

Powerful_Shell (Binary 300)

PowerShell嫌い…問題名を見た時点で萎えた。でもがんばった。

難読化した文字列をevalしてる感じ。

$ECCON="";
$ECCON+=[char](3783/291);
$ECCON+=[char](6690/669);
$ECCON+=[char](776-740);
$ECCON+=[char](381-312);
$ECCON+=[char](403-289);
$ECCON+=[char](-301+415);
# (略)
$ECCON+=[char](520-510);
Write-Progress -Completed -Activity "Extracting Script";.([ScriptBlock]::Create($ECCON))

最後の行をこう変えると、デコード後のスクリプトが得られる。

$ECCON | Out-File script.ps1
  • なんかイベントログの内容チェックしてる
  • 画面にキーボードを表示して"Play the secret melody."とのこと

前者はコメントアウトすればいい。後者は結果を次のスクリプトのデコードに使ってるので解かないといけない。

$secret=@(440,440,493,440,440,493,440,493,523,493,440,493,440,349)

周波数表と音階を照らし合わせると、h,h,j,h,h,j,h,j,k,j,h,j,h,fと叩けばいい。
ちなみに曲は「さくらさくら」外国人へのサービスかしらん。

正解すると下記が実行され、Stage 2に進める。

iex([System.Text.Encoding]::ASCII.GetString($plain))

ここも同様に書き換えておくと、Stage 2のスクリプトが手に入る。

[System.Text.Encoding]::ASCII.GetString($plain) | Out-File script2.ps1
script2.ps1
${;}=+$();${=}=${;};${+}=++${;};${@}=++${;};${.}=++${;};${[}=++${;};
${]}=++${;};${(}=++${;};${)}=++${;};${&}=++${;};${|}=++${;};
${"}="["+"$(@{})"[${)}]+"$(@{})"["${+}${|}"]+"$(@{})"["${@}${=}"]+"$?"[${+}]+"]";
${;}="".("$(@{})"["${+}${[}"]+"$(@{})"["${+}${(}"]+"$(@{})"[${=}]+"$(@{})"[${[}]+"$?"[${+}]+"$(@{})"[${.}]);
${;}="$(@{})"["${+}${[}"]+"$(@{})"[${[}]+"${;}"["${@}${)}"];"${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${(}${+}+${"}${&}${@}+${"}${+}${=}${+}+${"}${|}${)}+${"}${+}${=}${=}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${[}${]}+${"}${&}${=}+${"}${+}${+}${[}+${"}${+}${+}${+}+${"}${+}${=}${|}+${"}${+}${+}${@}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${(}${|}+${"}${+}${+}${=}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${+}${+}${[}+${"}${.}${@}+${"}${+}${+}${(}+${"}${+}${=}${[}+${"}${+}${=}${+}+${"}${.}${@}+${"}${+}${+}${@}+${"}${|}${)}+${"}${+}${+}${]}+${"}${+}${+}${]}+${"}${+}${+}${|}+${"}${+}${+}${+}+${"}${+}${+}${[}+${"}${+}${=}${=}+${"}${.}${|}+${"}${+}${.}+${"}${+}${=}+${"}${)}${.}+${"}${+}${=}${@}+${"}${[}${=}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${.}${@}+${"}${[}${]}+${"}${+}${=}${+}+${"}${+}${+}${.}+${"}${.}${@}+${"}${.}${|}+${"}${&}${=}+${"}${[}${&}+${"}${+}${+}${|}+${"}${(}${|}+${"}${+}${+}${[}+${"}${.}${(}+${"}${)}${@}+${"}${]}${+}+${"}${[}${|}+${"}${[}${|}+${"}${.}${|}+${"}${[}${+}+${"}${+}${@}${.}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${)}${+}+${"}${+}${+}${+}+${"}${+}${+}${+}+${"}${+}${=}${=}+${"}${.}${@}+${"}${)}${[}+${"}${+}${+}${+}+${"}${|}${&}+${"}${.}${.}+${"}${.}${|}+${"}${]}${|}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${[}+${"}${&}${.}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${.}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${]}+${"}${.}${[}+${"}${+}${.}+${"}${+}${=}+${"}${+}${@}${]}|${;}"|&${;}

…執念を感じる。

これもよく読むと、${;}にスクリプトを生成して最後の|&${;}でevalしてるので、ここを消して次の行に"${;}"を足すと

[CHar]36+[CHar]69+[CHar]67+[CHar]67+[CHar]79+[CHar]78+[CHar]61+[CHar]82+[CHar]101+[CHar]97+[CHar]100+[CHar]45+[CHar]72+[CHar]111+[CHar]115+[CHar]116+[CHar]32+[CHar]45+[CHar]80+[CHar]114+[CHar]111+[CHar]109+[CHar]112+[CHar]116+[CHar]32+[CHar]39+[CHar]69+[CHar]110+[CHar]116+[CHar]101+[CHar]114+[CHar]32+[CHar]116+[CHar]104+[CHar]101+[CHar]32+[CHar]112+[CHar]97+[CHar]115+[CHar]115+[CHar]119+[CHar]111+[CHar]114+[CHar]100+[CHar]39+[CHar]13+[CHar]10+[CHar]73+[CHar]102+[CHar]40+[CHar]36+[CHar]69+[CHar]67+[CHar]67+[CHar]79+[CHar]78+[CHar]32+[CHar]45+[CHar]101+[CHar]113+[CHar]32+[CHar]39+[CHar]80+[CHar]48+[CHar]119+[CHar]69+[CHar]114+[CHar]36+[CHar]72+[CHar]51+[CHar]49+[CHar]49+[CHar]39+[CHar]41+[CHar]123+[CHar]13+[CHar]10+[CHar]9+[CHar]87+[CHar]114+[CHar]105+[CHar]116+[CHar]101+[CHar]45+[CHar]72+[CHar]111+[CHar]115+[CHar]116+[CHar]32+[CHar]39+[CHar]71+[CHar]111+[CHar]111+[CHar]100+[CHar]32+[CHar]74+[CHar]111+[CHar]98+[CHar]33+[CHar]39+[CHar]59+[CHar]13+[CHar]10+[CHar]9+[CHar]87+[CHar]114+[CHar]105+[CHar]116+[CHar]101+[CHar]45+[CHar]72+[CHar]111+[CHar]115+[CHar]116+[CHar]32+[CHar]34+[CHar]83+[CHar]69+[CHar]67+[CHar]67+[CHar]79+[CHar]78+[CHar]123+[CHar]36+[CHar]69+[CHar]67+[CHar]67+[CHar]79+[CHar]78+[CHar]125+[CHar]34+[CHar]13+[CHar]10+[CHar]125|iex

下記のように書き換えて実行。

[CHar]36+[CHar]69+[CHar]67+[CHar]67+[CHar]79+[CHar]78+[CHar]61+[CHar]82+[CHar]101+[CHar]97+[CHar]100+[CHar]45+[CHar]72+[CHar]111+[CHar]115+[CHar]116+[CHar]32+[CHar]45+[CHar]80+[CHar]114+[CHar]111+[CHar]109+[CHar]112+[CHar]116+[CHar]32+[CHar]39+[CHar]69+[CHar]110+[CHar]116+[CHar]101+[CHar]114+[CHar]32+[CHar]116+[CHar]104+[CHar]101+[CHar]32+[CHar]112+[CHar]97+[CHar]115+[CHar]115+[CHar]119+[CHar]111+[CHar]114+[CHar]100+[CHar]39+[CHar]13+[CHar]10+[CHar]73+[CHar]102+[CHar]40+[CHar]36+[CHar]69+[CHar]67+[CHar]67+[CHar]79+[CHar]78+[CHar]32+[CHar]45+[CHar]101+[CHar]113+[CHar]32+[CHar]39+[CHar]80+[CHar]48+[CHar]119+[CHar]69+[CHar]114+[CHar]36+[CHar]72+[CHar]51+[CHar]49+[CHar]49+[CHar]39+[CHar]41+[CHar]123+[CHar]13+[CHar]10+[CHar]9+[CHar]87+[CHar]114+[CHar]105+[CHar]116+[CHar]101+[CHar]45+[CHar]72+[CHar]111+[CHar]115+[CHar]116+[CHar]32+[CHar]39+[CHar]71+[CHar]111+[CHar]111+[CHar]100+[CHar]32+[CHar]74+[CHar]111+[CHar]98+[CHar]33+[CHar]39+[CHar]59+[CHar]13+[CHar]10+[CHar]9+[CHar]87+[CHar]114+[CHar]105+[CHar]116+[CHar]101+[CHar]45+[CHar]72+[CHar]111+[CHar]115+[CHar]116+[CHar]32+[CHar]34+[CHar]83+[CHar]69+[CHar]67+[CHar]67+[CHar]79+[CHar]78+[CHar]123+[CHar]36+[CHar]69+[CHar]67+[CHar]67+[CHar]79+[CHar]78+[CHar]125+[CHar]34+[CHar]13+[CHar]10+[CHar]125 | Out-File script3.ps1
script3.ps1
$ECCON=Read-Host -Prompt 'Enter the password'
If($ECCON -eq 'P0wEr$H311'){
    Write-Host 'Good Job!';
    Write-Host "SECCON{$ECCON}"
}

ふう。

SECCON{P0wEr$H311}

Log search (Web 100)

WebサーバのアクセスログをElasticsearchで検索できるサービス。

/, {, }, (, ), :などの文字を入れると

Something wrong... X(

とか出るので、NoSQL injectionするっぽい。

いろいろ試したけどうまくいかず、ふとflagで検索したら

09/Dec/2017:19:15:02 +0900  GET   /flag-b5SFKDJicSJdf6R5Dvaf2Tx5r4jWzJTX.txt  200

というログがあったのでアクセスしたらフラグ取れた。
そういうのは興醒めするからちゃんと対策しておいてほしい…

SECCON{N0SQL_1njection_for_Elasticsearch!}

JPEG file (Binary 100)

壊れたJPEGファイル。1ビットだけ書き換えるとちゃんと表示できるらしい。ほほー

$ jpeginfo -c tktk.jpg
tktk.jpg  339 x 53   24bit JFIF  N   11628  Corrupt JPEG data: premature end of data segment  Unsupported marker type 0xfc  [ERROR]

JPEGのマーカーはFF + 1バイトらしいので、FF FCで検索。1カ所だけヒット。
FFをマーカーと誤認識しちゃってるのかな。
EF FCに書き換えたら、多少絵が壊れてるけど表示できた。

SECCON{jp3g_study}

Simon and Speck Block Ciphers (Crypto 100)

解けなかった。

Simon_96_64, ECB, key="SECCON{xxxx}", plain=0x6d564d37426e6e71, cipher=0xbb5d12ba422834b5

鍵の不明な部分は4バイト、表示できる文字に限れば0 <= x <= 127でよさそう。
2^28なので総当たりするだけ…と思ったけど正解が見つからなかった。なんでだろう…

実装は下記を借りた。テストもちゃんと書いてあるから信頼できそうなんだけど。
https://github.com/inmcm/Simon_Speck_Ciphers/tree/master/C

Thank you for playing! (Thank you! 100)

SECCON{We have done all the challenges. Enjoy last 12 hours. Thank you!}

他の方のWriteup

4
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3