Twitterのフォロワーに一様分布を依頼してみた

はじめに

こんにちは、カンムでバンドルカードの機械学習部分を担当しているfkubotaです。先日、Twitterでこんな感じのアンケートを取ってみました。

f:id:kanmu-tech:20210528204802p:plain

このアンケートの面白いところは、回答者は回答しないと現在の投票成績が見えないというところです。参加者は、「1を取る人が多いハズ、、、であれば2,3,4か?」とか裏を取ろうとします。裏の裏を取ろうとする人もいるでしょう。我ながらTwitterの投票システムを利用した面白い実験だったと思います。

結果はこんな感じ。

951票もいただきました。ありがとうございます。m(_ _)m

そんでもって

もちろん、面白い実験をして、あー面白かったで終わらせるつもりはなく、結果を考察するまでがこの実験の目的です。ちなみにみなさんは、上の結果を見て一様分布だと思いますか? 「全ての数字が同じではないから一様分布ではないよ」という意見もあれば、「まあこの程度の違いなら誤差だと思うよ」という意見もあるでしょう。このあたりどう議論すればいいでしょうか? 多少の誤差とは言いますが、どこまでが許せてどこまでが許せないのでしょうか? やっぱり定量的に賢くやりたいですよね。こういったときに使えるのがいわゆる統計学です。いろいろ手段はあると思うのですが今回は、統計的仮説検定というやつを使ってみます。統計的仮説検定がよくわからない人は、「検定 サイコロ」とか「検定 コイン」とかでググると簡単な例が出てくるので目を通すと良いかもしれません。この記事では、できるだけ検定がわからない人にもわかるようにも書きますが、事前に勉強しておくとより読みやすいと思います。 一様分布っぽさがふわふわしていて定量的にあつかえないもどかしさは、検定という手続きをつかえば定量的に扱えるという事が伝えられたら嬉しいです。

適合度検定

適合度検定(解説はこの記事とか)というのを使います。この検定はある事象がa:b:c:dで起こる時に実験値とのズレが誤差の範囲内であるかどうかを検証する時に使います。今回の場合は、アンケートの結果が一様分布になるはずだという仮説1:1:1:1に対して、実験結果は%で25:18:26:30になっており、投票数は238:181:247:285となっています。これが誤差の範囲なのかそれ以上に意味のある結果なのかを検証します。

計算するにあたりこちらのサイトを利用しました。
今回の条件数は4、観測度数はそれぞれ、238, 181, 247, 285であり、帰無仮説(一様分布である)のもとでの確率は1/4, 1/4, 1/4, 1/4となっているので、そのように入力して計算しました。また、有意水準は5%としています。 結果は以下のようになりました。

統計検定量χ2 = 23.2965
有意水準に相当するχ2の値 = 7.81743
p値 = 0.000035025

適合度検定はχ2検定で片側検定ですので、統計検定量χ^2有意水準に相当するχ^2の値 を上回っていることにより帰無仮説は棄却されます。p値についてちょっと解説すると(怖い...) 、今回の「アンケート結果は一様分布に従う」という帰無仮説が正しいとした場合、今回の結果は、0.0035%程度の確率で起こるよということを示しています。一様分布が正しい分布の場合でも今回の実験結果は起こり得る、ただし「0.0035%という低い確率」でということになります。あまりにも起こる低い確率で起こるのであればそれは仮説が間違っていると考えるのが自然だよね。であれば、5%までは許して5%以下の確率で起こる場合は、仮説が間違っていると考えようということで、有意水準5%を設定しています。

今回の結果としては、仮説が棄却されたので、検定の手続き上ではアンケート結果はどうやら一様分布ではないようです。「一様分布にして」とお願いしたので、一様分布にしようと参加者がいろいろ戦略を立てて投票しその戦略が偏った(似たような戦略を取る人が多かった?)結果なのかなと考えてみたりしました。ただこれ以上のことは今回の検証では何も言えません。今回の適合度検定で言えることは、「一様分布ではなさそう」というところまでです。「適当に投票して」というアンケートだと結果は変わったのかな?と思ったりもしました。

ちなみにどの程度であれば棄却されなかったのかと数字を少し変えて遊んでみたところ、 238, 181, 247, 285238, 230, 247, 285 にしたところ棄却されませんでした。
僕には285の数字がまだ大きく見えて一様分布には見えないなぁと思うのですが、適合度検定にはこれが一様分布に見えるようです。黙って従います。

今回の実験の背景

今回、なぜこのような実験をしようと思ったのか少し話ます。
弊社カンムはバンドルカードというサービスを開発していて、日々新しいデータが大量に入ってきます。僕自身、機械学習を担当しているということもありあらゆるデータに日々触れています。その時、もっとこうしたら良いんじゃないか?とかこれはどう説明できるだろうかなど仮説を立てて検証をしたくなることがあります。しかし僕自身この辺りの知識・業務経験に乏しくて、うまく扱えず歯痒い思いをよくしています。目の前にこれだけ質の高いデータがあるのに自分の力不足のために活用できないのはもったいないなと思い、最近はもっぱら統計的因果推論とか言われる分野を勉強しています。そして、ただ本を読むだけだと退屈だということで第一弾として簡単にできる検定をやってみたという次第です。アンケートご協力頂いた方、とても楽しかったです。ありがとうございました。

次回は、もう少し複雑な統計学の知識を使った分析をやりたいと思います。

お決まりですが

上記にもあるように、もっともっと輝けるのに力を発揮できずに眠ってしまっているデータが弊社には大量にあります。そのデータを統計学などのデータ分析の知識を生かしてさばけるデータアナリストを募集しています。僕もたくさん勉強してこのあたりも少しずつできるようになりたい。
一緒にやりませんか?

https://kanmu.co.jp/jobs/data-analyst/

僕は、2021年2月に入社してからもうすぐ4ヶ月が経ちますがとても入社してよかったなと日々思います。
なによりデータ、テクノロジーに対するリテラシーが高くデータ分析をする身としては、非常に働きやすく何より楽しいです。
社内のほとんどの人がSQL書けちゃったりします(参考記事)。 もちろんエンジニア以外の人もです。
他には、月に一度の TechDayでは、エンジニア・非エンジニアが日頃の業務の非効率をテクノロジーで解決するというイベントがあります。非エンジニア同士がGASがどうだとかSlackのbotがどうだとか議論したりするんです。僕より遥かにGASに詳しい非エンジニアがかなりいます。これは少し悔しい。

上記は一例ですが、こんな感じで企業文化がマッチすれば、楽しく働けることは少なくとも僕は保証しますので興味ある方は、データアナリストに限らず応募してください!!:)

https://kanmu.co.jp/jobs/

サイバーセキュリティ攻撃を学ぶことで防御を学ぶ

カンムでセキュリティを担当している12banです。といっても、つい最近までコーポレートエンジニアをやっていました。 一応、セキュリティはいろんな業務の中の1つとして、10年以上関わってきました。

セキュリティと一言に言っても実はものすごく幅広いです。 そんな中でPenetration Testingと呼ばれるセキュリティテストの分野があります。 これは一般的にはセキュリティ会社のペンテスターと言われる職種の人が学習する分野なのですが、 事業会社で攻撃を防御することにも役に立つのではと考え、今回チャレンジしてみました。

TryHackMeとは

今回チャレンジしてみたのはTryHackMeというサービスです。 このサイトはペンテスト(侵入攻撃)を手を動かして学べるサービスです。

全部で5つのコースがあるのですが、面白そうだなって思ったのは、 Offencive Pentesting と Cyber Defenceのラーニングパスです。

f:id:kanmu-tech:20210518190308p:plain
TryHackMeのラーニングパス例

このうち、攻撃を学びたかったため、Offencive Pentestingのパスを選んでやってみました。 下記の画像がOffcencive Pentestingの序盤です。

f:id:kanmu-tech:20210518190432p:plain
Offencive Pentesting序盤

難易度Easyの4つの部屋があり、最初のTutorial以外の3つの部屋で実際に攻撃対象となるマシンがあり、 それを攻撃して、特権(管理者権限)を取っていきます。

このうちvulnversityという部屋の攻略について記事をここに書きたいところですが、かなり内容が専門的になる、 かつ、かなり長文になるため、個人のブログに書きました。興味がある方はそちらを読んでみてください。

note.com

パズルのようで面白い

現時点で難易度Easyを4つ、難易度Mediumを1つ終わらせています。かなり面白く毎日少しずつやってます。 まだちょっとの経験しかないですが、攻撃はパターン化されているなと感じました。 言うなれば高校数学の解法パターンみたいな感じでしょうか。 最終的にはOffencive Pentesting と Cyber Defenceの2つのラーニングパスを最後までやってみようと思っています。ここまでやりきればもっと見えてくるものはありそうだと感じてます。

ちなみに今まで経験したパターンは、だいたい下記の流れです。

  • nmapを使って空きポート、使ってるサービスやアプリケーション名、バージョンを調査する
  • 脆弱性などを突いて、対象マシンに侵入する
  • 侵入後、同様に脆弱性などを突いて特権を取る

学び

今のところ、脆弱性を突いて対象マシンに侵入することが多いので、脆弱性管理の重要性を肌感として感じてます。 今までは脆弱性管理は重要と知っていても、ちょっとぐらい大丈夫という気持ちがあったような気がします。 特に従業員が使用するデバイスの方はモチベーションが上がらなかったり...

しかし、今は脆弱性管理をきっちりやりたいって気持ちでいっぱいです。脆弱性をついた攻撃は自動化されてるので、 使ってるアプリケーションとバージョンがわかってしまえば、簡単に脆弱性をついて侵入できることを実感として知ることができました。

攻撃を学ぶことで防御を学ぶことができる、というのは正しかったようです。またセキュリティ対策を会社全体で実行する時に、攻撃を知っていることで納得感のある説明ができる気がします。

事業会社のセキュリティエンジニアの良さ

このようにペンテストの経験は攻撃者の手法を知り、防御に活かすという点で、事業会社のセキュリティエンジニアにも有用だと感じました。

ちなみにこの学びは誰かから強制してやったわけではありません。業務に活かすことができるのでは?と自分で考えて行動しただけです。 事業会社のセキュリティエンジニアが扱うセキュリティ範囲は幅広いです。PCI DSSなどの第三者認証、IdPやMDMなどのエンドポイントセキュリティ、IaaSセキュリティ、プロダクトセキュリティ、リスクマネジメント、規定や監査など幅広い。 そんな中で今までの経験を活かせるところは活かし、足りないところは自分で考えて学んで活かす。そして顧客や企業、ビジネス、従業員を守ることで競合優位性を高めていけるのは事業会社のセキュリティエンジニアならではかなと思います。

最後に

セキュリティエンジニアに限らず、下記のように他にもセキュリティに関われるポジションがあるので、 まずは気軽にカジュアル面談してみませんか?

新しい環境にdotfilesをワンライナーで反映させる

はじめに

こんにちは、カンムでバンドルカードの機械学習を担当しているfkubotaです。テックブログ初参加なので今回はライトな内容で投稿させていただきます。イケイケ機械学習記事はいずれ...

この記事では、最近ちょっとだけ改善した dotfiles の管理について紹介したいと思います。
dotfiles とは、ホームディレクトリ($HOME) 下にある、.vimrc, .bashrc などの設定ファイル群を指します。
最終的には、コマンド1つでこのdotfilesが新しい環境に反映されます
魔法のコマンド:

bash -c "$(curl -fsSL https://raw.githubusercontent.com/fkubota/dotfiles/master/install.sh)"

このコマンドでdotfilesが反映されると、
これが f:id:kanmu-tech:20210520111556p:plain

こうなります f:id:kanmu-tech:20210520111616p:plain

結論だけ見たい方は、方法紹介 から見ると良いと思います。

  • こんな人が想定読者
    • dotfiles 管理しなきゃと思っているけど、何もしてません...TT
    • dotfiles をまとめたリポジトリはあるよ。でも新しい環境に反映させるのは少し面倒...。

上記に該当する人に有用な記事になるように頑張って書きます。

参考記事

基本的にはこの記事を参考にしています。
この記事の作者ほどヘビーユーザではない&もう少し気軽に使いたいのでちょっとコードを変更しています。

dotfilesを管理するモチベーション

機械学習をやっている人は、新しい環境で作業を行うという経験が多いのではないでしょうか?
会社の計算サーバーにssh接続して使うとか、GCPAWSのマシンを借りるとか。その都度、そこで自分の開発環境を構築するはずです。僕の場合であれば、vim, tmux, fish のオレオレ設定を普段使っているので新しい環境でもそれを構築しています。

僕自身、以前はめちゃくちゃしんどい管理の仕方をしていました。
歴史としてはこんな感じです。

  1. 新しい環境で作業するたびにdotfilesをコピペ
    • この管理だとどの環境が最新状態なのかわからなくなります
  2. gitで管理して、シンボリックリンクを作る
  3. シンボリックリンクを行うシェルスクリプトを作成
    • これで大分楽になった
  4. git cloneからシンボリックリンク作成までを ワンライナー
    • NOW!!

方法紹介

まずは、dotfilesリポジトリgithubで作成してください。
ちなみに僕のリポジトリこちら

今回は簡単のために、.vimrc のみを管理対象とします。
dotfiles リポジトリ内に、.vimrc を作成します。

touch dotfiles/.vimrc

次に、シンボリックリンクを行うためのシェルスクリプトをdotfilies下に作成します。
ファイル名は、install.sh としてください。
install.sh の中身は以下のようにします。

DOT_DIR={dotfilesリポジトリをクローンするディレクトリ}

# clone
git clone https://github.com/{your account name}/dotfiles.git ${DOT_DIR}

# link
ln -sf $DOT_DIR/.vimrc ~/.vimrc

上記の {dotfilesリポジトリをクローンするディレクトリ} と {your account name} をそれぞれ適切な値に設定してください。
僕の場合であれば、

DOT_DIR="$HOME/Git/dotfiles"

# clone
git clone https://github.com/fkubota/dotfiles.git ${DOT_DIR}

# link
ln -sf $DOT_DIR/.vimrc ~/.vimrc

となります。これで準備完了です。
このスクリプトを実行すれば、DOT_DIR で指定したディレクリにdotfilesリポジトリがクローンされ、.vimrcシンボリックリンクされます。lnコマンドに-fオプションが指定されているので、すでにある場合に上書きされてしまうので困る場合は外してください。

あとは、ワンライナーを叩くだけ!! です!
どこのディレクトリ下でもいいので、

bash -c "$(curl -fsSL https://raw.githubusercontent.com/{your account name}/dotfiles/main/install.sh)"

と叩いてみてください。指定した場所にリポジトリがクローンされ、シンボリックリンクが、~/.vimrc に作成されるはずです。 (デフォルトブランチ名がmainではなく、masterである場合は、mainmaster に変更してください)

ホームディレクトリ下で

ls -la

などで確認できます。僕の場合は、

.vimrc -> /home/fkubota/Git/dotfiles/vim/.vimrc

と出力されていました。

以上が簡単な紹介です。これを基本として追加したい項目を増やしていくだけです。 僕の場合は、 vim, tmux, fish のdotfilesを管理する以外にも必要なものを追加しています。
後はお好みで楽しんでください。
dotfiles、育てるとかわいくなっていきますよ。

おわりに

今回の記事で弊社のテックブログとしては、3本目。
今後も続々と楽しい記事をあげていく予定です。
カンムに少しでも興味ある方はぜひこちらから応募してください!!!

採用 | 株式会社カンム

PCI DSS のセグメンテーションテストに VPC Reachability Analyzer を使う

カンムでバンドルカードのバックエンドやインフラを担当している summerwind です。

バンドルカードはスマホ上で Visa のプリペイドカードを発行して決済に使える機能を提供しているため、クレジットカードのデータを安全に取扱うことを目的として策定された、クレジットカード業界のセキュリティ基準である PCI DSS に準拠しています。

PCI DSS にはセキュリティ基準として様々な要件が定義されており、中には次のようなものがあります。

11.3.4.1 Additional requirement for service providers only: If segmentation is used, confirm PCI DSS scope by performing penetration testing on segmentation controls at least every six months and after any changes to segmentation controls/methods.

これは、ネットワークセグメンテーションを使用してカードデータを扱う環境を分離している場合は、少なくとも6ヶ月ごとにそのセグメンテーション制御に対するテストを行ない、意図した状態になっているかをテストすることが求めています。実際には、カードデータを扱わないシステムとカードデータを扱うシステムの間の通信が必要なプロトコルやポートに制限されていることをテストします。

これまでカンムでは Nmap などのツールを利用してこのネットワークセグメンテーションのテストを行なってきましたが、以下のような課題がありました。

  • テストの実行手順が明確に定義されていない
  • Nmap などのツールの実行には時間がかかる

もうちょっと簡単に素早くテストできないかと考えて見つけたのが、2020年末にリリースされた VPC Reachability Analyzer です。これは AWS VPC 内の2つのエンドポイント間で通信の到達性を検証してくれる機能で、まさにセグメンテーションテストの要件にぴったりです。

VPC Reachability Analyzer の実行は AWS コンソールから簡単に行えます。VPC Reachability Analyzer のページにアクセスしたら、Create and analyze path ボタンを押して、Path を作成します。Path はテストしたい2つのエンドポイント間の経路を示すものになるので、送信元と送信先および通信に使用するプロトコルを指定します。

f:id:kanmu-tech:20210511131831p:plain
Create and analyze path

Path を作成すると初回の検証が自動実行され、これが完了すると、到達性について結果が表示されます。Not reachable であれば到達不可であることが確認できたこととなり、セグメンテーションが有効であることが分かります。

f:id:kanmu-tech:20210511131909p:plain
Path

後日同じ経路で改めて検証を実行したい場合は、作成した Path の画面にある Analyze path ボタンを押すだけですぐに検証ができるので便利です。PCI DSS の要件 11.3.4 では開発者以外の第三者的な立場でこのテストを実行することを求めているので、そういった観点でも VPC Reachability Analyzer を活用するのがよいのではないかと考えています。

今回は PCI DSS のセグメンテーションテストに VPC Reachability Analyzer を活用する方法を紹介しました。今後も PCI DSS の要件を達成する方法などを紹介できればと思っています。

カンムではセキュアでモダンなクレジットカード決済インフラを作りたいエンジニアを積極的に採用しています!

GoCon CTF と呼ばれた問題の紹介と解説

こんにちは、バンドルカードを作っている Kanmu という会社で CTO をしています。kneeです。

昨日行われた Go Conference 2021 Spring にて Kanmu としてスポンサーをさせていただいており、そのオフィスアワーにて「CTF なんて言葉聞いたこともない、strings コマンドなんて知らない、でも Go は触ったことあるよ」という方に向けて Go を少し絡めたゆるい CTF の rev っぽい問題を出題させていただきました。
それなりにたくさんの方に楽しんでいただけたようですので、解説と合わせて出題者の意図の紹介をします。
ちなみに自分は CTF 超絶にわかですのでその点はご容赦ください。

まだ解いてないけど、解いてみたいという方はぜひ読み進める前に解いてみてください。
所要時間は解いていた方の様子を見るに5分~3時間程度です。

問題の紹介

問題はこれです https://github.com/kanmu/gocon2021_office_hour
ヒントや解説は時間経過に応じて追加していったものですので、出題当時は以下のような感じでした。

以下のイメージの中にGoのプログラムをビルドした実行ファイルがおいてあります。 これを調べて秘密の答えを見つけてください!

docker run -it ghcr.io/kanmu/gocon2021-office-hour:latest /bin/bash

実際に中を見てみるとこんな感じ。
問題文にある実行ファイルと MEMO がおいてあるだけ。そして実行してみるといきなり答えを聞いてくる、そんな感じの問題です。

$ docker run -it ghcr.io/kanmu/gocon2021-office-hour:latest /bin/bash
root@7a909bfa6f26:/go/src/app# ls
MEMO  gocon2021_office_hour
root@7a909bfa6f26:/go/src/app# ./gocon2021_office_hour
Enter your answer 答えを入力してください: 

想定解答と出題意図

想定解答の解説をしつつ出題意図を説明していきます。

まずノーヒントなので MEMO を見ます。 ちなみにこのイメージにはデフォルトで file コマンドすらなく、この時点でなんだこれとなられた方も多かったようです。

$ cat MEMO
何回失敗しても諦めないで!
Don't give up no matter how many times you fail!

煽ってきていますね。
しかし実際に諦めないで何度も試してみるとヒントが出るようになっています。

$ ./gocon2021_office_hour
Enter your answer 答えを入力してください: a
Failed 残念
Enter your answer 答えを入力してください: b
Failed 残念
Enter your answer 答えを入力してください: c
Failed 残念
Enter your answer 答えを入力してください: d
Failed 残念
Enter your answer 答えを入力してください: e
Failed 残念
Enter your answer 答えを入力してください: f
Failed 残念

You can user one of go tool command. Let's run `go tool`.
go tool ~~~ コマンドで使えるものがあるかも…? `go tool` を実行してみてください

You can usertypo です。

gocon2021_office_hour 自体を直接調べるという選択肢を持っていない場合、できることとしてぱっと思いつくのは、実行していろいろ入力してみる、他のファイルを探しに行くことぐらいだろうと想定していました。ただ後者は脱線して時間がかかりますし、前者はただの当てずっぽうになってしまう。
そういった状況で自然に gocon2021_office_hour 自体の解析に誘導する必要があり、何回も実行するだけならどんな前提知識の方もいけるだろうということでこういう形をとりました。 ただノーヒントでわからんとなって1,2回入力して離脱したら悲しいので諦めないでという MEMO を置くことにしました。

$ go tool
addr2line
asm
buildid
cgo
compile
cover
dist
doc
fix
link
nm
objdump
pack
pprof
test2json
trace
vet

ちょっと Go 要素が出てきました。ここが一番の難所です。go tool を使えとだけヒントが出ているので、どれが使えるのか自分で調べる必要があります。ほとんどの方は普段使ったことないコマンドもたくさんあると思うので調べたり試行錯誤することになります。 この過程で普段触れることのない Go に関する情報にあたってもらえたらいいなーというような気持ちがこもっています。

ちなみに正解は go tool nm で、これはシンボルを列挙するコマンドです。が、その意味を理解しておらずとも問題はありません。
また go tool foo gocon2021_office_hour と件の実行ファイルを引数に渡して人間に可読っぽい出力がされるのはおそらく nm ぐらいかと思います。というところでなんとか答えににじり寄っていってくれたらうれしいなという感じですかね。

$ go tool nm gocon2021_office_hour
  4df6f8 r $f64.3eb0000000000000
  4df700 r $f64.3f847ae147ae147b
  ...
  54efa0 D unicode.foldLu
  54efa8 D unicode.foldM
  54efb0 D unicode.foldMn
  46dd40 T unicode.init
  46d500 T unicode/utf8.DecodeRune
  46d700 T unicode/utf8.DecodeRuneInString
  46d900 T unicode/utf8.EncodeRune
  46da80 T unicode/utf8.RuneCount
  46dbe0 T unicode/utf8.RuneCountInString
  53ff40 D unicode/utf8.acceptRanges
  5430e0 D unicode/utf8.first

とはいえその出力は2000行以上になるので、その中から必要な情報を見つける必要があります。ちなみに見つけてほしい行はこれです。

  49bc60 T type..eq.github.com/kanmu/gocon_2021_kanmu.LetsRunThisCommand_strings_gocon2021_office_hour_grep_question

ここで想定していたのは2種類の行動で、1つ目は長すぎて読めないのでとりあえず関係ありそうな単語で grep してみること。

$ go tool nm gocon2021_office_hour | grep gocon
  540560 D github.com/kanmu/gocon_2021_kanmu..inittask
  49bb60 T github.com/kanmu/gocon_2021_kanmu.New
  49bc60 T type..eq.github.com/kanmu/gocon_2021_kanmu.LetsRunThisCommand_strings_gocon2021_office_hour_grep_question

もう一つはどうすればいいかわからないけど、とりあえず実行結果を下からスクロールして眺めていったら不自然に長い行に気づく、です。出力順序は go tool nm の実装的にオプションを渡さない限りは変わらないのでスクロールしていくと割とすぐ出てくるはずです。

  466aa0 T type..eq.[6]string
  466b60 T type..eq.[9]string
  49b0e0 T type..eq.fmt.fmt
  49bc60 T type..eq.github.com/kanmu/gocon_2021_kanmu.LetsRunThisCommand_strings_gocon2021_office_hour_grep_question
  401c20 T type..eq.internal/cpu.CacheLinePad
  401c40 T type..eq.internal/cpu.option

この go tool nm を実行して、grep するなどしてこの行をみつけるところは難所だろうと思っていたので、出題してしばらく経過した後にヒントを公開しました。

続きます。 見つかった行は以下です。

  49bc60 T type..eq.github.com/kanmu/gocon_2021_kanmu.LetsRunThisCommand_strings_gocon2021_office_hour_grep_question

Let's Run This Command とあり、これが続きます strings_gocon2021_office_hour_grep_question

この _ で繋がれた文字列をみて strings コマンドを知っているかどうかで動きが変わります。知っていたらたぶんこのように分解するのは自明そうです。

strings gocon2021_office_hour | grep question

とはいえ知っていたらここにたどり着く前にゴールしてそうな気もしますし、そもそも想定解答者として strings コマンドも知らない人を置いている。かつ、そういった人にもこういうときに使う基本的なコマンドを一つでも覚えて帰ってもらいたいと思っていました。

ここで辿ってくれたらいいなーと思っていた思考の過程は以下です。 grep を知ってるのは前提で、途中で grep があるのでなにかを grep してるんじゃないかと想像し | grep question をひねり出す。つづいて strings_gocon2021_office_hour という部分の分解においては、 gocon2021_office_hour が実行ファイル名、また出題のリポジトリ名であることで一つの単語であることを想起し、余った strings という謎の存在を最後もしかしてこういうコマンドがあるのでは!?とひらめいてググってみるなどして答えにたどり着く。 という感じでした。

ここもやはり strings コマンド知らないとなかなか難しかったようですが、実際にそのような方が最終的に strings コマンドに辿り着いておられるのを拝見して、めちゃくちゃテンションがあがりました。

そしてここまで来たらもうゴールは目の前です。見つけたコマンドを実行します。

$ strings gocon2021_office_hour | grep question
P*gocon_2021_kanmu.LetsRunThisCommand_strings_gocon2021_office_hour_grep_question
  *************  question: what is the international standard of credit card messaging? The answer is ISOxxxx  ***************  000102030405060708091011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990w
type..eq.github.com/kanmu/gocon_2021_kanmu.LetsRunThisCommand_strings_gocon2021_office_hour_grep_question
github.com/kanmu/gocon_2021_kanmu.(*LetsRunThisCommand_strings_gocon2021_office_hour_grep_question).Run
type..eq.github.com/kanmu/gocon_2021_kanmu.LetsRunThisCommand_strings_gocon2021_office_hour_grep_question

明らかに怪しい部分があるので取り出してみると、問題がかいてあります。

*************  question: what is the international standard of credit card messaging? The answer is ISOxxxx  ***************

クレジットカードのメッセージングの国際標準が答えです。意味がわからなくても問題文をそのまま検索したらヒットします。

ということで答えは ISO8583 です。

ソースコード

使った Go のソースコードが気になるところだと思うので公開します。
直前に慌てて作問していてなぜかソースコードrm するという失態をおかしたのでそのままのソースコードは残っておらず思い出しながら書きました。おおまかな作りはあってるとおもいます。 真に知りたい方はデバッガで見るなどして補完ください。

package main

import (
    "bufio"
    "fmt"
    "io/ioutil"
    "os"
  
  "github.com/kanmu/gocon_2021_kanmu"
)

func m5(text string) string {
    hasher := md5.New()
    hasher.Write([]byte(text))
    return hex.EncodeToString(hasher.Sum(nil))
}

func main() {
    x := "*************  question: what is the international standard of credit card messaging? The answer is ISOxxxx  ***************"
    fmt.Fprintf(ioutil.Discard, x)
    y := gocon_2021_kanmu.New().Run()
    fmt.Fprintf(ioutil.Discard, y)

    answer := "bc9ad0a243f1c91268437fefb3beba6b"
    i := 0
    scanner := bufio.NewScanner(os.Stdin)
    for scanner.Scan() {
        if m5(scanner.Text()) == answer {
            fmt.Println("Success! 正解です!すごい、おめでとうございます!")
        } else {
            fmt.Println("Failed 残念")
            if i == 5 {
                fmt.Println("You can user one of go tool command. Let's run `go tool`.")
                fmt.Println("go tool ~~~ コマンドで使えるものがあるかも…? `go tool` を実行してみてください")
            }
            i += 1
        }
    }
    if err := scanner.Err(); err != nil {
        os.Exit(1)
    }
}
package gocon_2021_kanmu

import (
    "math/rand"
    "time"
)

type LetsRunThisCommand_strings_gocon2021_office_hour_grep_question struct {
    x string
    y int
}

func (h *LetsRunThisCommand_strings_gocon2021_office_hour_grep_question) Run() string {
    return h.x
}

func New() *LetsRunThisCommand_strings_gocon2021_office_hour_grep_question {
    rand.Seed(time.Now().UnixNano())
    y := rand.Int() + 1
    return &LetsRunThisCommand_strings_gocon2021_office_hour_grep_question{
        x: "x",
        y: y,
    }
}

おわりに

Twitter での反響を見るに想定していたよりとても多くの方に楽しんでいただけたようで大変うれしかったです。
次回機会があれば strings だけでは倒せない歯ごたえがある問題も用意しようと思うので、今回興味を持ってもらえた方はぜひ CTF に入門して倒せるように鍛えてきてください!

この記事は Kanmu のテックブログの一発目なのですが、まさかの CTF の解説になってしまいました。
今後 Kanmu での普段のプロダクト開発の様子もいろいろ紹介できればと思っているのでのでぜひお楽しみに!
採用 | 株式会社カンム

GoCon の運営の皆様も参加してくださった方々も本当に楽しい会をありがとうございました!
ではまた。