自作CTFを作ってみた

ある日 twitterをやっていたら、以下のような良記事が目に飛び込み

「ちょうど後輩もLinux使い始めるし、新しい講義で初めてHTML CSS JSを触るし、WEBサーバーとかやってみたいし、なんか作った実績欲しいし、一石四鳥だから自分もCTF作るか」となったので、ここに作るまでの手順と難しかったこと詰まったことを自分が忘れないように書こうと思った。

*間違えはできるだけなくすようにしていますが、素人なので間違っている可能性があるので間違ってたら指摘してもらえると嬉しいです。

tigerszk.hatenablog.com

やりたいこと

webサーバーの用意

本当は最近流行っているらしいDockerなるものを使ってみたかったけど、どうやら難しいらしいので辞めて、なんでもサーバーサイドでも使えるNode.jsというので実装しようと思った。

偉い人から「先ずはExpressというフレームワークでやってみたら?」とアドバイスを貰ったので「Node.js Express ログイン機能」と検索したら、とても参考になる資料があり、これでほとんどの機能を実装しました。

とても参考になりました、作った人どうもありがとうございます。

Node.jsで会員登録システムを導入しよう · osamu38/node-express-curriculum Wiki · GitHub

 

詰まったこと

  • TypeError:Router.use() requires middleware function but got a Objectというエラーが出てきた
  • MySQLのクエリがうまく動かなかった

まずroutes以下に新しいプログラムを置いて実行したら上のような謎の英語エラーが起きた、そこでgoogle先生にそのまま貼り付けて質問をしたら、stackoverflowがヒットし解決案の一つに

「module.exports = router;が足りてないのでは?」と書いてあり、試して見たら解決した。

よく見たら、参考元にもちゃんと書いてあったのに何故か自分は書いてなかったらしく、ただの凡ミスでした。

 

次のはMySQL

let query = "SELECT * FROM hoge WHERE id = "+ user_id;

みたいに書くやり方が上手くいかなかった。

(たぶん自分の写経が悪かった可能性が高い、でも、このやり方だとSQLインジェクションの可能性があるかもしれないみたい?)

なので

let query = "SELECT * FROM hoge WHERE id = ?";

という疑問符プレースホルダを使ったら上手くいった、これだと値をエスケープしてくれるので安心。sqlmapで攻撃を試してみたけど大丈夫だった。

 

あと出来上がったサイトはこんな感じ流石に全部作るのは無理なので無料のホームページテンプレートを使わさせてもらった(欲深いので50000兆円になっています)

f:id:yosh1da:20170630235535p:plain

動的にグラフを作りたい

全員の現在のポイントを表示するグラフを作りたかったのでChart.jsというものを

使ってみようと思った。

公式サイト Chart.js · GitBook

CDNでローカルにダウンロードしなくても良いってのが嬉しいね、あと更新しなくていいのもうれしい。

目指す機能としては

  1. グラフの表示がデータによって変化するのでどうにかしたい。
  2. マウスが重なるとラベル名とデータ内容がでるので、それを少し変えたい
  3. サーバ側のjsのデータをクライアント側のjsに渡したい(この表現で正しいのだろうか・・)つまりMySQLのデータをroutes下のjsで持ってきて、それをpublic/javascripts下のjsに点数と名前を渡したい

 

上の1、2はoptionsを以下のようにして解決した。

    options: {
        legent:{
        },
        tooltips: {
          callbacks: {
              //tooltipItemはマウスが上に乗った時の番地などを教えてくれる。
            label: function (tooltipItem, data) {
                console.log(tooltipItem.datasetIndex);
              return data.datasets[tooltipItem.datasetIndex].label
                + ": "
                + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]
                + " 兆円";
            }
          }
        } ,
        scales: {
            yAxes: [{
                ticks:{
                    beginAtZero:true,
                    max:5000,
                }
            }]
        },
        title:{
            display: true,
            text: "億万長者リスト"
        }
    }

3は最初にクライアント側のjsからmysqlに繋いでデータを取得して加工しようと考えていたが結局できなかった。(そもそも、クライアント側でmysql繋いだらクエリが丸見えだし色々危ないじゃないの?)

なので

qiita.com

を参考にroutes側で以下のような感じでデータを送ることで解決した。(命名がごっちゃになってるし、コードごちゃごちゃしてるのは雑魚初心者プログラマーなのでゆるして欲しいです(;^ω^)あと非同期処理あるのでpromise使いたかった)

let user_data=[];
router.get('/', function(req, res, next) {
    connection.query(query2,function(err, rows) {
        if (!err) {
            for(let x in rows){
                let datum = {};
                datum["label"]=rows[x].name;
                datum["data"] = [rows[x].point];
                datum["backgroundColor"] = pattern(rows[x].point);
                user_data[x]=datum;
            }
        }
        let userId = req.session.user_id;
        if (userId) {
    		let query = 'SELECT user_id, name FROM users WHERE user_id = ? LIMIT 1';
          	connection.query(query,[userId], function(err, rows) {
          		if (!err) {
    				res.render("point",{users:rows[0].name,chart:user_data});
          		}
            });
        }else{
            res.render('point',{chart:user_data});
        }
    });
});

書いた人間にしかわからない部分があるので軽く説明させていただきますと

user_dataはChart.jsのdatasetsに渡す配列のデータ

patternは点数によって返す色を変える関数

datasetsは[{label:hoge,data:[100]},{...},]みたいな感じの形をとるので、最初のconnection.queryで全てのユーザーの名前と点数を持ってきてdatasetsに合うようにデータを作って

res.render('point',{chart:user_data});
res.render("point",{users:rows[0].name,chart:user_data});

のように"point.ejs"(グラフを表示するページ)にデータをchartという名前でおくることにした

 詰まったところ

非同期処理が分からなくてとにかく大変だった。最初は

let user_data=[];
let datum = {};
for(let x in rows){
        datum["label"]=rows[x].name;
        datum["data"] = [rows[x].point];
        datum["backgroundColor"] = pattern(rows[x].point);
        user_data[x]=datum;
}

とdatumを外に置いていたら、最終的に生成されるuser_dataが変なデータで埋まっていた。たぶん非同期処理が関係しているのだろうと思い、datumをfor文内に置くことで何故か上手くいった。

結果できたのがこんな感じです。

 

f:id:yosh1da:20170630224428p:plain

SSHの環境設定

OverTheWireみたいにsshでつなげて問題を解かせたいと思った。

とりあえず仮想マシン(ubuntu)にapt-get install sshdをやって接続できるようにしたが、繋いだ人間には自分のホームディレクトリ以外のファイルを見られてくないと思った。そこでsshで繋いだ人間は制限するような方法がないか探したら、とても参考になるサイトを見つけた

http://tech.godpress.net/?p=361

この人の説明どおりにchrootの設定を行い、あとは/etc/ssh/sshd_configを編集しrootログインを禁止した。

参考になりました、ありがとうございます。

詰まったこと

  1. sshに接続したときのメッセージを変えたい
  2. 毎回新しくユーザーを作ってchrootするために/bin /libとかをコピーするのが面倒
  3. タブ補間が出来なくなった

1でsshなどでログインしたときに出てくるメッセージはmotdとか言うものらしく、それを弄れば良い /etc/update-motd.dに表示したいメッセージを書けばできる。

できた結果はこんな感じ、このロゴみたいなのはfigletというのを使った。

f:id:yosh1da:20170701003347p:plain

 

2はユーザーのホームディレクトリを"usermod -d /home/最初に作ったユーザー/次のユーザー/  次のユーザー"のように 最初に作ったユーザーのディレクトリ内に置けばパスが同じ(?)なので共有できる。

3はタブキーを押すと補間してくれる機能が、ディレクトリの書き込み権限がないとかで無効になっていたので権限を777にしたら、できるようになったがルートディレクトリでも権限を777にしたらsshがbroken pipeとでてきて接続できなくなったので仕方なく権限を755などにした。

しかし、これだとファイルが消せてしまうので所有者しか消せないようにするスティッキービットを追加することで解決した。

感想とその他

肝心な問題の内容は後輩にbashとかちょっとしたものを教えたかったので

  • rot13
  • ls -a で隠しファイルを探す
  • cat stringsなどで画像ファイルに埋め込んだ文字列を探す
  • ちょっとしたBOF攻撃
  • historyコマンドを使ったフォレンジック
  • Exifで場所の特定
  • POSTデータの改ざん
  • pythonのlambda式を使って難読化

などの問題を考えた。ちなみにこのCTFは色々セキュリティがダメなので公開してないです。

感想としては、色々なサイトを参考にして作ったけど調べたら案外なんでも揃ってるなと思った、ただ自分の欲しい情報にたどり着くまでの道のりが長かった(Chart.jsのマウスがグラフの上に乗った時の表示を変える方法なんかは何て探せば良いのか分からず地味に探すのが大変だった)

あと自分の汚いコードを人が見られる場所に置くのは恥ずかしいと思った、今度からは綺麗で簡潔で命名規則も一貫したコードになるように頑張る。

自分用備忘録 導入編

前から物忘れが酷いのでやったことをここに書いて覚えておこうという魂胆

目標としては機械学習で画像判断ができるようになりたい。最近twitter萌え絵を検索すると全く関係ない誰かの子供の写真や〇〇ちゃん@hoge みたいな名前のどうでもいい写真がひっかかるので、これを機会に

渋とか△みたいなsnsで同じ画像を収集→機械に学習させる→twitterで画像を収集→関係ない画像を弾く電車内でニヤニヤする

のような流れで最近の流行に乗っていこうと思った(たしかアニメの人物をweb上で判定してくれるのがあるからそれ使えばいいじゃん!というのは抜きにして、こういうのを作れたらCGCみたいな大会にでれるかもしれないし苦手な数学の勉強にもなるし色々なうま味があるのでやりたい)

そういうわけで図書館からそれらしい本を借りてきたので今度からかいてある内容を忘れないように要約していきたいと思います

 

 

借りてきた本たち

__________________________________

行列プログラマー ―Pythonプログラムで学ぶ線形代数

行列プログラマー ―Pythonプログラムで学ぶ線形代数

 

 機械学習をしらべると必ずnumpyみたいな行列の話がでてくるので借りてきた、めちゃくちゃ大きい。ざっと読んだ感じ大学1年あたりで勉強する数学の基礎がないと進めるのが難しい。でも本の雰囲気は好き

 

ウェブデータの機械学習 (機械学習プロフェッショナルシリーズ)

ウェブデータの機械学習 (機械学習プロフェッショナルシリーズ)

 

 もう知ってるよね?みたいな感じで進む典型的な本(初心者向けと書いてないので難しいのは当たり前だけど数学が苦手なものからしたらwikiとにらめっこしながら読む羽目になる)

 

Pythonによる機械学習入門

Pythonによる機械学習入門

 

 まだ読んでないので後から読む予定