博多電光

blog.hkt.sh

6月のコミットまとめ

hakatashi (Koki Takahashi) · GitHub

f:id:hakatashi:20160705005359p:plain

コミット数が単調増加の傾向にある。どういうことなの……

今月は技術書典があり、執筆も全てGitHub上で行ったためコミット数が大幅に増えた。あと Google Summer of Code への取り組みで多少コミット数を稼いだ。

主な成果

awesome-prml-jaを作成

サークル活動でPRML勉強会に参加しているのだが、インターネット上に散逸する過去のPRML勉強会の資料をまとめたサイトがないので、少し前に流行ったawesomeの体裁でGitHubリポジトリを作った。作ってみて思ったが資料多すぎである。正直本買わなくてもこれだけで独学できてしまうのではないだろうか。

awesomeの統括リポジトリに登録申請するか迷ったが、日本語だし適切にフォーマットされてないのでやめた。

slack-ikkuを作成

アルバイト先のSlackで遊ぶために一晩で作ったどうしようもないネタBOT。後ほどブログを書く予定。

general-category 1.5.0 をリリース

ファイルサイズがさらに小さくなった。それからREADMEのサンプルコードを自動でテストするようにした。

あと1.4.0で使用したファイルサイズを小さくする技術について社内LTで発表した。各方面の技術を結集した謎スライド。

HakataFeedをQiitaとGithubに対応

個人的に使用している、WebサイトをスクレイピングしてAtomフィードに変換するやつ。もとはpixivの新着フィードを変換するためだけに動いていたが、様々なサイトを統一的に扱うためにクラス継承の仕組みをちゃんと整えた。あと取得したCookieファイルシステム上に永続するようにした。疲れた……。

LINE for Node.js

ネタで作ろうかと思ったが--line--というモジュール名が取得できなかったので諦めた。仕様だけ書いてある。

5月のコミットまとめ

hakatashi (Koki Takahashi) · GitHub

f:id:hakatashi:20160603043015p:plain

かなりcontributionしたと思った先月を軽く超えていてビビる。

Privateなcontribution数もプロフィールに表示できるようになったので、なかなか彩り豊かになって幸せである。

主な成果

mochify--browser-fieldオプションを実装

この画像には見えないが、mochifyに--browser-fieldなるオプションを実装したプルリクがマージされたのが一番の成果と思われる。他人のリポジトリにマージされたプルリクとしては、規模的にも自分史上最大のものになった。しばらく放置されていたので不安だったが、マージされた時は軽く小躍りしてしまった。

いまはGSoCの真っ最中である。自分の仕事がちゃんとマージされるようにがんばらなくては。

Sugoi Converter をアップデート

1.7.2 から 1.8.16 になった。新機能は以下のとおり。

  • Quoted-Printable の変換を実装
  • 各種依存パッケージのアップデート
  • 各種deprecatedパッケージの駆逐
    • JadeをPugに
    • ついでにGulpをベータバージョンの4にアップデート
  • Google Analytics を導入

npmモジュール general-category をアップデート

npmモジュール asianbreak のテストフレームワークをmochaからInternに変更

はい、GSoCの課題の一つです。

ついでにカバレッジも取れるようになって最高。

takuboku-project

おや、どうしたんだろう?

シンタックス・ハイライト機能で対応してほしい言語

お題「シンタックス・ハイライト機能で対応してほしい言語」

LiveScriptをリクエストするしかない。

require! 'prelude-ls': {unfoldr, map, concat}

export integer-array-to-buffer = ->
  it |> map ->
    it |> (+ 1) |> unfoldr ->
      if it is 0 then null
      else
        modulo = it %% 128
        base = it .>>. 7
        modulo .|.= 2~1000_0000 if base is 0

        [modulo, base]
    |> map (.^. 0xFF)
  |> concat
  |> buffer-from

general-category/util.ls at 4e494d9347d95471cce63d10a8c2dbdf0775beb9 · hakatashi/general-category · GitHub

HaskellにもCoffeeScriptにもなれなかった悲しい言語。

Google Summer of Code 2016 参加記 その1 応募編

f:id:hakatashi:20160528200323j:plain

今年の4月、Google Summer of Code 2016 に応募し、無事選出された。

それから2ヶ月も経過したが、何も音沙汰なしというのも殺生なので、軽く現時点での参加記を書いてみようと思う。

特に、ウェブ上で検索してもGSoCに参加する日本人のためのアドバイスがあまり見つからないので、そのあたりを頑張っていきたい。

Google Summer of Code とは

Google Summer of Code

ひとことで言うと、Googleが主催するリモートワークのインターン。もう少し詳しく言うと「著名なオープンソースソフトウェアのために3ヶ月間フルタイムでコミットし、報酬として$5500を受け取る、大学生のためのプログラム」である。

長いので略してGSoCと呼ばれることが多い。読み方はよく分からない*1オープンソースコミュニティの活発化のため、またコーディングに興味を持つ学生の育成のためにGoogleが全面的にバックアップするプログラムであり、2005年に開始されて今年で12回目になる。詳しくは Google Summer of Code の紹介ページを参照してもらいたいが、公式ページには、今までにこのプログラムでなんと5000万行のソースコードが生産されたと書いてある。

GSoCは今年全面的なリニューアルを行い、システムが全面的に刷新されたようだ。ウェブページは殺風景なデザインからマテリアルデザインに切り替わり、ロゴも新しくなった。去年見た時よりもだいぶ分かりやすくなっていて個人的には大歓迎である。

期間は、例年5月中旬から8月中旬にかけての3ヶ月間。これらのコーディング期間に加えて、その前に1ヶ月ほどの Community Bonding Period が存在する。これは米国の一般的な大学の夏休みに合わせたスケジュールである。

プログラムの流れは次の通りである。まず、Googleは学生を受け入れることができるオープンソース団体を募集する。選考でGoogleに承認された団体は学生に取り組んでほしいタスクのリストを予め用意しておき、学生は各団体のそれを読んで自分に合った団体と課題を決める。学生はその内容を提案書(Proposal Paper)と呼ばれる文書にまとめ、自分のやりたいこと、スキル、課題のスケジュールなどを盛り込んで提出する。各団体がそれを読んで選考を行い、無事選考通過した学生には参加する団体から1人か2人のメンターを配属され、全期間を通してメンターの指示と指導のもと、互いにコミュニケーションを取りながら各々の活動を行っていく。全プログラムを無事終了した暁には、総額$5500の報酬金が受け取れるという仕組みである。

例年全世界で5000~6000人ほどの学生がこのプログラムに応募し、1000人あまりの学生が選考を通過して Accepted Students となる。考えてみると応募率は5倍であり結構高いが、マニュアルをよく読んで真面目に提案書を書けばかなりの確率で通過できるのではないかと思われる。

日本人の参加について

GSoCには例年日本人も若干名ほど参加しており、統計情報によると今年は自分も含めて12名参加とのことである。

日本人が参加する際の一番のハードルは、やはり世界の大学との学事暦の違いだと思われる。一般的な9月入学2学期制の大学では春学期が5月に終わるため、そこから3ヶ月間みっちりと課題に取り組めるが、日本の大学では5月は夏学期のど真ん中である。GSoCでは通例週40時間のコーディングが要求されるため、やはり特別な事情がないと日本の大学生が参加するのは難しいと思われる。*2

第二に言語の問題がある。GSoCでは、書類選考やメンターとのコミュニケーションなど、当然だがすべて英語で行わなければいけない。大学生であれば英語はある程度読み書きできることと思われるが、自分も含めてそこまでのコミュニケーションを行う自信はついていないというのが正直なところである。また去年GSoCに応募した友人によると、選考過程でSkype越しの面接を要求され、言葉がうまく出ずにキョドって落とされたという話である。このあたりの選考過程は団体によって異なるが、もし面接を課せられていたら自分も落とされていたかもしれない。

逆に言えば、上の2点さえクリアできれば誰でも参加できる。

コーディング能力はあまり問われない。GSoCにはコーディングレベルに応じて様々な参加形態があり、簡単なタスクから複雑なタスクまで、自分に合った課題を自分で設定することができる。ほとんど初心者に近いような状態でも、学習しながら参加することもできるという話である。

日本はGSoCの本拠地であるアメリカから遠いが、これも問題にはならない。そもそもリモートワークなのでコーディングに地理的な距離は関係ないし、Googleからのいくつかの郵送物は、時間がかかるがちゃんと届く。報酬金はPayoneerを通して支払われ、ちゃんと日本の銀行口座に引き落とすことができる。

タイムゾーンの違いによるコミュニケーションの難しさは若干あるが、今のところ大きな問題にはなっていない。

5月から8月にかけて時間を取れる大学生は、ぜひGSoCに参加してみてほしい。

応募編

f:id:hakatashi:20160528191008p:plain

Googleの夏は3月から始まっている。GSoCに参加する場合には3月の応募期間中に提案書を書ききり、諸書類と一緒に提出しないといけない。どうせ夏だと思ってぼやっとしてるとあっという間に過ぎてしまうので注意が必要である。*3

そして更に重要なのは、GSoCの公式マニュアルによると応募期間以前からの活動が最も大事とのことである。提案書はなにも提出する時まで内緒にしておくことはない。提案書を作る前にどういう内容に取り組みたいかということを団体に相談し、フィードバックを受けながら書いていくのが最も良い書き方である。僕はこの文面を見落としていたため若干出遅れてしまったが、読者諸兄にはくれぐれも早め早めの行動を促したい。

僕の場合、応募期間が開始してから団体リストを眺め、得意なJavaScript関連のプロジェクトを探した。自分が知っているプロジェクトに応募するのが一番良いというのは聞き及んでいたことなので、めぼしいところで Mozilla, jQuery, Fedora, ownCloud などが候補に挙がった。

Fedora Project など、どの辺りがJavaScriptなのだとも思ったが、Idea List を見ると、意外といろいろな種類のタスクが挙げられている。このあたりはちゃんと読んでみないとわからないものだと感じた。

迷った末に、jQuery Foundation にある、InternというテストフレームワークCreate a sandbox interface for all Intern tests というタスクに応募することにした。Internというソフトウェア自体はあまり有名ではないが*4、個人的に Software Testing に興味があったのと、リストのだいぶ下のほうにあって誰も応募してないだろうという目論見により応募することにした。

f:id:hakatashi:20160528192358p:plain

そうと決めたらマニュアル通り開発者に連絡を取り、課題についていくつかの質問をした。そうして得た回答をもとに、提案書を書き進めた。提案書は、自分のやりたいことを明確にわかりやすく、そして誤解のないように書くことを心がけた。特に、取り組みたい課題の解決がなぜ必要とされるのかという点に重点を置いた。このあたりは、開発者とのコミュニケーションを通して得た、「今回は具体的な実装方法に関しては提案段階では考えない」という方針が基となっている。また、先程述べたような日本の大学の事情やタイムゾーンの問題なども、後から辛くならないようにここにしっかり書き記しておく必要がある。

ヒイヒイ言いながら慣れない提案書を書き上げ、最初のアップロードを行ったのが応募期間終了の3日前。期間に余裕がある場合はこの段階で団体側のフィードバックを待つことができるのだが、今回はギリギリだったのでフィードバックを受けることができず、応募期間終了前日に最終提案書を送信した。*5マニュアルも “Submit early” を何度も強調しているように、とにかくGSoCの応募は早めの行動が重要である。読者には同じ轍を踏まないようにしてもらいたい。

提案書は複数応募することもできるのだが、1個目の提案書を書き上げた時点で完全に疲弊していたし、マニュアルにも「そこそこの提案書を複数作るよりもハイクオリティーな提案書を1個作れ」と書いてあるのでここで切り上げた。

選考通過のメールを受け取るのは、提出から1ヶ月後、4月23日のことである。

「選考通過~Community Bonding Period編」に続く。

*1:個人的にはjeesockと読んでいる

*2:ちなみに博多市の場合の「特別な事情」は「2回目の留年中であり取るべき授業がほとんどない」というものである。

*3:博多市も去年は「いつの間にか応募期間が終わっていた」という悲しい経験をした

*4:実は僕もこのGSoCで初めて知った

*5:ちなみに何度でも再アップロードできる。

2016年4月のコミットまとめ

hakatashi (Koki Takahashi) · GitHub

f:id:hakatashi:20160503012026p:plain

今月はだいぶプルリクを送った。

主な成果

Sugoi Converter をアップデート

1.6.6 から 1.7.2 になった。新機能は以下のとおり。

  • NFCおよびNFKCの変換を実装
  • Node.js v6 のリリースにともなってnew Buffer()をコードから駆逐。これがかなり手間取った。なんとDefinitelyTypedのNode定義にBuffer.fromが定義されていなかったり、BrowserifyのBufferにBuffer.fromが実装されていなかったり(これはすぐ解消されたが)であちこち奔走する羽目になった。
  • HTTPからHTTPSに強制リダイレクト

npmモジュール“textlint-rule-blacklist-ja”を製作開始

NGワードでフィルタリングする汎用textlintルール」の予定。

テストにmochifyを使っているのだが、トークナイザであるkuromoji.jsとの相性が悪くて実装が進んでいない。いちおう解決するためのプルリクをmochifyに投げたが、音沙汰なしである。

2016年3月のコミットまとめ

hakatashi (Koki Takahashi) · GitHub

f:id:hakatashi:20160404172828p:plain

主な成果

Sugoi Converter をアップデート

1.4.9 から 1.6.6 になった。新機能は以下のとおり。

  • 完全HTTPS
  • HTML Escape, uuencode を追加
  • TSDがdeprecatedになったのでtypingsに移行

npmモジュール“mona-width”を公開

mona-width

与えられた文字のMSPゴシックにおける幅を返すモジュール。

README書かなきゃ……

npmモジュール“power-ascii”を製作開始

GitHub - hakatashi/power-ascii: Powerful ASCII Characters

進捗ダメです

Internetwache CTF 2016 writeup

TSG (東京大学理論科学グループ) のメンバーに誘われたので、2月20日から22日にかけて、チームTSGの一員として Internetwache CTF 2016 に参加した。

参加して初めて知ったがどうやらガチ初心者向けのCTFであるらしく(CSAWよりも簡単な印象)、メンバーがほいほい解いていくので僕の出番はほとんどなかったと言っていい。が、この広いインターネットで誰かの役に立つかもしれないので、いちおう一通りWriteupを書いてみる。

すでに書かれた他のメンバーのWriteupは以下を参照。

satos.hatenablog.jp

ちなみにチームTSGは2問を残して全完し、1492チーム中45位だった。

以下、解いた順。

misc50

こんなテキストファイルが与えられる。

0000000 126 062 126 163 142 103 102 153 142 062 065 154 111 121 157 113
0000020 122 155 170 150 132 172 157 147 123 126 144 067 124 152 102 146
0000040 115 107 065 154 130 062 116 150 142 154 071 172 144 104 102 167
0000060 130 063 153 167 144 130 060 113 012
0000071

これを8進数としてデコードしたあとASCIIコードとして復号する。

V2VsbCBkb25lIQoKRmxhZzogSVd7TjBfMG5lX2Nhbl9zdDBwX3kwdX0K

これをBase64でデコードする。

Well done!

Flag: IW{N0_0ne_can_st0p_y0u}

おしまい。

スクリプト

$ lsc -d
ls> require \fs .read-file-sync \README.txt |> (.to-string! / /\s/) |> filter (.length is 3) |> map parse-int _, 8 |> map String.from-code-point |> join '' |> Buffer _, \base64 |> (.to-string!) |> console.log
Well done!

Flag: IW{N0_0ne_can_st0p_y0u}

misc90

こんな画像が与えられる。

f:id:hakatashi:20160201143233j:plain

この時点で既に殺意しか湧かない。

Photoshopでぐりぐりいじって元のバーコードを復元する。

f:id:hakatashi:20160222223511j:plain

スマホバーコードリーダーで読み取ると、上から順に C0d3s}, _B4r_, IW{Bar となる。

Flag: IW{Bar_B4r_C0d3s}

web80

こんな文章とURLが与えられる。

I stumbled across this kinda oldskool blog. I bet it is unhackable, I mean, there's only static HTML.

https://0ldsk00lblog.ctf.internetwache.org/

static HTML と言われたら .git を確認するしかない。 https://0ldsk00lblog.ctf.internetwache.org/.git/config にアクセスすると、

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true

と表示されビンゴ。dvcs-ripper でまるっと落としてくる。

コミットログを見てみるとこの通り。

$ git show HEAD
commit 8c46583a968da7955c13559693b3b8c5e5d5f510
Author: Sebastian Gehaxelt <github@gehaxelt.in>
Date:   Fri Jan 22 02:58:01 2016 +0100

    My recent blogpost

diff --git a/index.html b/index.html
index 5508adb..25a3f35 100644
--- a/index.html
+++ b/index.html
@@ -3,9 +3,15 @@
        <title>0ldsk00l</title>
 </head>
 <body>
-       <h2>2000</h2>
+
+       <h1>Welcome to my 0ldsk00l blog.</h1>
+       <p>
+               Now this is some oldskool classic shit. Writing your blog manually without all this crappy bling-bling CSS / JS stuff.
+       </p>
+
+       <h2>2016</h2>
        <p>
-               Oh, did I say that I like kittens? I like flags, too: IW{G1T_1S_4W3SOME}
+               It's 2016 now and I need to somehow keep track of my changes to this document as it grows and grows. All people are talking about a tool called 'Git'. I think I might give this a try.
        </p>

        <h2>1990-2015</h2>

Flag: IW{G1T_1S_4W3SOME}

cry60

こんな公開鍵が3つと、

-----BEGIN PUBLIC KEY-----
MDgwDQYJKoZIhvcNAQEBBQADJwAwJAIdDVZLl4+dIzUElY7ti3RDcyge0UGLKfHs
+oCT2M8CAwEAAQ==
-----END PUBLIC KEY-----

こんな暗号文が与えられる。

DK9dt2MTybMqRz/N2RUMq2qauvqFIOnQ89mLjXY=

AK/WPYsK5ECFsupuW98bCFKYUApgrQ6LTcm3KxY=

CiLSeTUCCKkyNf8NVnifGKKS2FJ7VnWKnEdygXY=

公開鍵がえらく短い。中身を見てみると、

$ openssl pkey -in bob.pub -pubin -text
-----BEGIN PUBLIC KEY-----
MDgwDQYJKoZIhvcNAQEBBQADJwAwJAIdDVZLl4+dIzUElY7ti3RDcyge0UGLKfHs
+oCT2M8CAwEAAQ==
-----END PUBLIC KEY-----
Public-Key: (228 bit)
Modulus:
    0d:56:4b:97:8f:9d:23:35:04:95:8e:ed:8b:74:43:
    73:28:1e:d1:41:8b:29:f1:ec:fa:80:93:d8:cf
Exponent: 65537 (0x10001)

鍵長 228bit である。これなら変なテクニックを使わずとも力技で因数分解できる。

$ sage
┌────────────────────────────────────────────────────────────────────┐
│ SageMath Version 7.0, Release Date: 2016-01-19                     │
│ Type "notebook()" for the browser-based notebook interface.        │
│ Type "help()" for help.                                            │
└────────────────────────────────────────────────────────────────────┘
WARNING: Attempting to work in a virtualenv. If you encounter problems, please install IPython inside the virtualenv.
sage: factor(0x0d564b978f9d233504958eed8b744373281ed1418b29f1ecfa8093d8cf)
17963604736595708916714953362445519 * 20016431322579245244930631426505729
sage: e = 0x10001
sage: p = 17963604736595708916714953362445519
sage: q = 20016431322579245244930631426505729
sage: from base64 import b64decode
sage: c = int(b64decode('DK9dt2MTybMqRz/N2RUMq2qauvqFIOnQ89mLjXY=').encode('hex'), 16)
sage: d = inverse_mod(e, (p - 1) * (q - 1))
sage: m = pow(c, d, p * q)
sage: ('0' + format(int(m), 'x')).decode('hex')
'\x02\x99\xa0\xc1\xe2I\x90~\x87z\xc9\xc0\x88\xda\xaf8\xd0\x00IW{WEAK_R\n'

フラグの一部が見える。同じようにbob2.pubとbob3.pubも因数分解して復号したが、bob.pubと違ってまともな文字列にならない。これでしばらく悩んだが、あれこれ試してみたところ、どうもbob2.pubが3番目の暗号文に、bob3.pubが2番目の暗号文に対応してるようだった。なんじゃそりゃ。

2番目と3番目の復号後の文字列は以下のとおり。

'\x02\xa1\x06\xc7\x8c\xeaa\x90\x9aNyj\xc0\xfaVa\x00SA_K3YS_4R\n'
'\x02o\x03\x0e\xc9ba\x8e\xf65\x99\xbe\xe7\x80\x1a\xe3\x003_SO_BAD!}\n'

Flag: IW{WEAK_RSA_K3YS_4R3_SO_BAD!}

cry80

謎の踊る男のPV動画が与えられる。

とりあえず中身を見てみる。

$ ffprobe song.webm
ffprobe version 2.5.2 Copyright (c) 2007-2014 the FFmpeg developers
  built on Dec 30 2014 17:29:04 with gcc 4.9.2 (GCC)
  configuration: --disable-static --enable-shared --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-lzma --enable-decklink --enable-zlib
  libavutil      54. 15.100 / 54. 15.100
  libavcodec     56. 13.100 / 56. 13.100
  libavformat    56. 15.102 / 56. 15.102
  libavdevice    56.  3.100 / 56.  3.100
  libavfilter     5.  2.103 /  5.  2.103
  libswscale      3.  1.101 /  3.  1.101
  libswresample   1.  1.100 /  1.  1.100
  libpostproc    53.  3.100 / 53.  3.100
Input #0, matroska,webm, from 'song.webm':
  Metadata:
    encoder         : Lavf56.40.101
  Duration: 00:00:36.04, start: 0.000000, bitrate: 520 kb/s
    Stream #0:0: Video: vp8, yuv420p, 320x240, SAR 1:1 DAR 4:3, 1k fps, 30 tbr, 1k tbn, 1k tbc (default)
    Stream #0:1: Audio: vorbis, 44100 Hz, stereo, fltp (default)
    Stream #0:2: Audio: vorbis, 8000 Hz, mono, fltp

副音声があるので取り出して聞いてみる。

$ ffmpeg -i song.webm -map 0:2 out.wav
ffmpeg version N-50911-g9efcfbe Copyright (c) 2000-2013 the FFmpeg developers
  built on Mar 13 2013 21:26:48 with gcc 4.7.2 (GCC)
  configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-libass --enable-libbluray --enable-libcaca --enable-libfreetype --enable-libgsm --enable-libilbc --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libxavs --enable-libxvid --enable-zlib
  libavutil      52. 19.100 / 52. 19.100
  libavcodec     55.  0.100 / 55.  0.100
  libavformat    55.  0.100 / 55.  0.100
  libavdevice    54.  4.100 / 54.  4.100
  libavfilter     3. 45.103 /  3. 45.103
  libswscale      2.  2.100 /  2.  2.100
  libswresample   0. 17.102 /  0. 17.102
  libpostproc    52.  2.100 / 52.  2.100
Input #0, matroska,webm, from 'song.webm':
  Duration: 00:00:36.04, start: 0.000000, bitrate: 520 kb/s
    Stream #0:0: Video: vp8, yuv420p, 320x240, SAR 1:1 DAR 4:3, 1k fps, 1k tbr, 1k tbn, 1k tbc (default)
    Stream #0:1: Audio: vorbis, 44100 Hz, stereo, fltp (default)
    Stream #0:2: Audio: vorbis, 8000 Hz, mono, fltp
Output #0, wav, to 'out.wav':
  Metadata:
    ISFT            : Lavf55.0.100
    Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 8000 Hz, mono, s16, 128 kb/s
Stream mapping:
  Stream #0:2 -> #0:0 (vorbis -> pcm_s16le)
Press [q] to stop, [?] for help
size=     560kB time=00:00:35.84 bitrate= 127.9kbits/s
video:0kB audio:560kB subtitle:0 global headers:0kB muxing overhead 0.013963%

ダイヤル音が聞こえる。DTMFである。Audacityでスペクトログラムを見ながら元の番号に復号する。

f:id:hakatashi:20160222233339p:plain

軽く苦行だ。元の番号に戻すとこうなる。

0111 0127 0173 0104 0122 060 0116 063 0123 0137 0127 061 0124 0110 0137 0120 0110 060 0116 063 0123 0175

また8進数だ。8進数としてデコードしたあとASCIIコードとして復号する。

IW{DR0N3S_W1TH_PH0N3S}

思うにこれはcryptoではなくstegoではないだろうか。

スクリプト

$ lsc -d
ls> '0111 0127 0173 0104 0122 060 0116 063 0123 0137 0127 061 0124 0110 0137 0120 0110 060 0116 063 0123 0175' |> split ' ' |> map parse-int _, 8 |> map String.from-code-point |> join ''
'IW{DR0N3S_W1TH_PH0N3S}'

misc60

こんな感じのテキストファイルが降ってくる。

4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI
4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI
4paI4paI4paI4paI4paI4paI4paI4paICuKWiOKWiCAgICAgICAgICAgICAg4paI4paIICDiloji
loggIOKWiOKWiCAg4paI4paIICAgICAgICAgICAgICDilojilogK4paI4paIICDilojilojiloji
lojilojilojilojilojilojiloggIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCAg4paI
4paIICDilojilojilojilojilojilojilojilojilojiloggIOKWiOKWiArilojiloggIOKWiOKW
iCAgICAgIOKWiOKWiCAg4paI4paIICDilojilojilojiloggICAg4paI4paIICDilojiloggICAg
ICDilojiloggIOKWiOKWiArilojiloggIOKWiOKWiCAgICAgIOKWiOKWiCAg4paI4paI4paI4paI
4paI4paI4paI4paI4paI4paIICDilojiloggIOKWiOKWiCAgICAgIOKWiOKWiCAg4paI4paICuKW
iOKWiCAg4paI4paIICAgICAg4paI4paIICDilojiloggIOKWiOKWiOKWiOKWiCAg4paI4paI4paI
(略)

Base64としてデコードするとQRコードになる。

f:id:hakatashi:20160222234201p:plain

アナログな方法だが、これを一枚ずつ根気よくスマホバーコードリーダーで読み取っていく。するとこうなる。

Flagis:IW{QR_C0DES_RUL3}

スクリプト

$ lsc -d
ls> require \fs .read-file-sync \README.txt |> (.to-string!) |> split '\n' |> map(-> if it.length is 76 then it else it + ',') |> join '' |> split ',' |> map Buffer _, \base64 |> map (.to-string!) |> each console.log
██████████████████████████████████████████████
██              ██  ██  ██  ██              ██
██  ██████████  ██████████  ██  ██████████  ██
██  ██      ██  ██  ████    ██  ██      ██  ██
██  ██      ██  ██████████  ██  ██      ██  ██
██  ██      ██  ██  ████  ████  ██      ██  ██
██  ██████████  ████    ██  ██  ██████████  ██
(略)