SECCON 2017 に参加したので writeup

SECCON CTFも3年目となるエンジョイ勢.

今年のチーム名は三森すずこ
一昨年は成瀬順で昨年は保登心愛(同名の強豪が出たため変更).

f:id:izugch73:20171210164115p:plain:w200

f:id:izugch73:20171210164144p:plain:w600

概ね目標通り.

writeup

コードを書く能力を失ってしまったのでいつもbinaryとmiscしか解けない.
結果解けたのは2問.

binary 100 "JPEG file"

Read this JPEG is broken.  
It will be fixed if you change somewhere by 1 bit.

jpgフォーマットっぽい画像.
brokenとなっているが一応開ける.1bit修正すると読めるらしい.

f:id:izugch73:20171210165303p:plain:w400

JPGのファイルフォーマットを調べる.
JPG ファイルフォーマット

jpg画像の解析ならこれが使える.HEX表示もできる.
JpegAnalyzer Plusの詳細情報 : Vector ソフトを探す!

f:id:izugch73:20171210165550p:plain:w400

FFから始まる2バイトはメタ情報が入るためのマーカーとして予約されているが
0x26FのFFFCが場所・意味ともに謎.
(0x261のFFDAから画像本文(?)だし,"FFFC"は予備の予約語.)

ということでFFを消したら見えた.

f:id:izugch73:20171210165955p:plain:w400

flag:SECCON{jp3g_study}

binary 300 "Powerful_Shell"

300が解けたのは史上初では? :congratulations:

名前の通りPowerShell問.
とりあえず実行するとロゴと謎の一文を残して終了する.

f:id:izugch73:20171210170615p:plain:w400

(前略)
$ECCON+=[char](18216/184);
$ECCON+=[char](21715/215);
$ECCON+=[char](12320/385);
$ECCON+=[char]([int][Math]::sqrt([Math]::pow(61,2)));
$ECCON+=[char](6976/218);
$ECCON+=[char](687-653);
(後略)

コードはずっとcharを作って,たまに2乗してsqrtして,みたいなのが2万行くらい.
Asciiをこねくり回して作ってそうなので,まずは$SECCONを吐いてみる.

Write-Output $ECCON | Out-File .\psout.txt

すると全体は大きく分けて4ブロックに分かれているようだ.

SECCONロゴ描画部分

[console]::BackgroundColor = "black";[console]::ForegroundColor = "white";cls;Set-Alias -Name x -Value Write-Host;$host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.Size 95,25;$host.UI.RawUI.WindowSize = New-Object System.Management.Automation.Host.Size 95,25;$host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.Size 95,25;$host.UI.RawUI.WindowSize = New-Object System.Management.Automation.Host.Size 95,25;x '
(中略)
' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x '  ' -b 15 -n;x;x;

ようやるわ.
特にそれ以外はなにもやってなさそうなので無視.

ホストチェック部

<# Host Check #>
Write-Host -b 00 -f 15 Checking Host... Please wait... -n
Try{
    If ((Get-EventLog -LogName Security | Where EventID -Eq 4624).Length -Lt 1000) {
        Write-Host "This host is too fresh!"
        Exit
    }
}Catch{
    Write-Host "Failed: No admin rights!"
    Exit
}
Write-Host "Check passed"

管理者権限を見てそう.
こういうよくわからないところは消すに限る.

キーボード描画部

$keytone=@{'a'=261.63}
$pk='a'
ForEach($k in ('w','s','e','d','f','t','g','y','h','u','j','k')){
    $keytone+=@{$k=$keytone[$pk]*[math]::pow(2,1/12)};$pk=$k  
}
Write-Host -b 00 -f 15 "Play the secret melody."

<中略>

$stage1=@();$f="";
While($stage1.length -lt 14){
    $key=(Get-Host).ui.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    $k=[String]$key.Character
    $f+=$k;
    If($keytone.Contains($k)){
        $stage1+=[math]::floor($keytone[$k])
        [console]::beep($keytone[$k],500)
    }
}
$secret=@(440,440,493,440,440,493,440,493,523,493,440,493,440,349)
If($secret.length -eq $stage1.length){
    For ($i=1; $i -le $secret.length; $i++) {
        If($secret[$i] -ne $stage1[$i]){
            Exit
        }
    }
    x "Correct. Move to the next stage."
}

261.63HzはC(ドの音).
そこから1オクターブ分のキーボードを作って,キーを押下するとbeepが鳴る仕組みを作っている.

f:id:izugch73:20171210172142p:plain:w400

いずれかのキーを14回押すとシステムが終了するが,$secretの順番でキーを押すとCorrectと言われる.

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

これも音階(Hz)になっており,ララシララシラシドシラシラファとなる.
曲は「さくらさくら」.

youtu.be

Enter the password部

f:id:izugch73:20171210172753p:plain:w400

$text=@"
YkwRUxVXQ05DQ1NOE1sVVU4TUxdTThBBFVdDTUwTURVTThMqFldDQUwdUxVRTBNEFVdAQUwRUxtT
<中略>
ShtME0EVTBFGF0BOE0gVQhNDF0wTVxVBTxFKF0wdQxVOEygXTBE2FxROE10VShZOTBFTF2E=
"@

$plain=@()
$byteString = [System.Convert]::FromBase64String($text)
$xordData = $(for ($i = 0; $i -lt $byteString.length; ) {
    for ($j = 0; $j -lt $f.length; $j++) {
        $plain+=$byteString[$i] -bxor $f[$j]
        $i++
        if ($i -ge $byteString.Length) {
            $j = $f.length
        }
    }
})
iex([System.Text.Encoding]::ASCII.GetString($plain))

base64の元ネタっぽいものをデコードしてまたコードが作られている.
iex前に $plain を吐くと以下のようなコードを得られる.

${;}=+$();${=}=${;};${+}=++${;};${@}=++${;};${.}=++${;};${[}=++${;};
${]}=++${;};${(}=++${;};${)}=++${;};${&}=++${;};${|}=++${;};
${"}="["+"$(@{})"[${)}]+"$(@{})"["${+}${|}"]+"$(@{})"["${@}${=}"]+"$?"[${+}]+"]";
${;}="".("$(@{})"["${+}${[}"]+"$(@{})"["${+}${(}"]+"$(@{})"[${=}]+"$(@{})"[${[}]+"$?"[${+}]+"$(@{})"[${.}]);
${;}="$(@{})"["${+}${[}"]+"$(@{})"[${[}]+"${;}"["${@}${)}"];"${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${(}${+}+${"}${&}${@}+${"}${+}${=}${+}+${"}${|}${)}+${"}${+}${=}${=}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${[}${]}+${"}${&}${=}+${"}${+}${+}${[}+${"}${+}${+}${+}+${"}${+}${=}${|}+${"}${+}${+}${@}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${(}${|}+${"}${+}${+}${=}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${+}${+}${[}+${"}${.}${@}+${"}${+}${+}${(}+${"}${+}${=}${[}+${"}${+}${=}${+}+${"}${.}${@}+${"}${+}${+}${@}+${"}${|}${)}+${"}${+}${+}${]}+${"}${+}${+}${]}+${"}${+}${+}${|}+${"}${+}${+}${+}+${"}${+}${+}${[}+${"}${+}${=}${=}+${"}${.}${|}+${"}${+}${.}+${"}${+}${=}+${"}${)}${.}+${"}${+}${=}${@}+${"}${[}${=}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${.}${@}+${"}${[}${]}+${"}${+}${=}${+}+${"}${+}${+}${.}+${"}${.}${@}+${"}${.}${|}+${"}${&}${=}+${"}${[}${&}+${"}${+}${+}${|}+${"}${(}${|}+${"}${+}${+}${[}+${"}${.}${(}+${"}${)}${@}+${"}${]}${+}+${"}${[}${|}+${"}${[}${|}+${"}${.}${|}+${"}${[}${+}+${"}${+}${@}${.}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${)}${+}+${"}${+}${+}${+}+${"}${+}${+}${+}+${"}${+}${=}${=}+${"}${.}${@}+${"}${)}${[}+${"}${+}${+}${+}+${"}${|}${&}+${"}${.}${.}+${"}${.}${|}+${"}${]}${|}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${[}+${"}${&}${.}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${.}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${]}+${"}${.}${[}+${"}${+}${.}+${"}${+}${=}+${"}${+}${@}${]}|${;}"|&${;}

うーんbrainfxxk.
とはいえ頭の方で数値が作られてから最終行でasciiをバンバン作ってそうなので,1つ1つ置き換えてみる.

まずは最終行以外.

${=}=${;};    <# 0 #>
${+}=++${;};    <# 1 #>
${@}=++${;};    <# 2 #>
${.}=++${;};    <# 3 #>
${[}=++${;};    <# 4 #>
${]}=++${;};    <# 5 #>
${(}=++${;};    <# 6 #>
${)}=++${;};    <# 7 #>
${&}=++${;};    <# 8 #>
${|}=++${;};    <# 9 #>

# "<CHar>"
${"}="["+"$(@{})"[${)}]+"$(@{})"["${+}${|}"]+"$(@{})"["${@}${=}"]+"$?"[${+}]+"]";

# "string Insert(int startIndex, string value)"
${;}="".("$(@{})"["${+}${[}"]+"$(@{})"["${+}${(}"]+"$(@{})"[${=}]+"$(@{})"[${[}]+"$?"[${+}]+"$(@{})"[${.}]);

最終行を置き換えたもの.

string Insert(int startIndex, string value)="$(@{})"["14"]+"$(@{})"[4]+"string Insert(int startIndex, string value)"["27"];"[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|string Insert(int startIndex, string value)"|&string Insert(int startIndex, string value)

ASCII変換.

$ECCON=Read-Host -Prompt 'Enter the password'
If($ECCON -eq 'P0wEr$H311'){
    Write-Host 'Good Job!';
    Write-Host "SECCON{$ECCON}"
}

というわけで最後に入力すべきパスワードはP0wEr$H311

f:id:izugch73:20171210174333p:plain:w400

flag:SECCON{P0wEr$H311}

謝辞

いつもどおり適当に声をかけるだけかけたのですが,joinしてくださったみなさまありがとうございます.

  • どやすちゃん
  • まんぼうさん
  • ぶちょう
  • パソコン持ち帰り忘れおじさん
  • 他 ご興味を持ってくださったみなさま