Gen's blog

CTFとか、競プロとか、その他諸々

Electronでスクリーンショットを即ツイートするための何かを作った話

この記事は FUN Advent Calendar 2016 10日目の記事(になる予定だったもの)です。

f:id:Gen_IUS:20161212215147j:plainf:id:Gen_IUS:20161212215332j:plain

本当に申し訳ない。

言い訳

SECCON 2016に出てました。チームはHarekazeに誘って頂いて、1300ptで61位でした。私はVoIPで音声聞き取ったのが全盛期でした。もっと精進したい。


本題

私は3年前ぐらいに今使用しているMacbook Pro Retina 13を購入しました。(ちょうど推薦合格したあとだったので、本当にこれぐらいの時期だったと思います)

その頃の私はターミナルの存在すら知りませんでしたが、購入したばかりのMBPを色々といじってみていました。その中で感動した機能の一つが、スクリーンショットです。もちろんWindowsでもスクリーンショットは撮れますが、Macスクリーンショット機能はより強力に感じました。

Command+Shift+3で全体、Command+Shift+4で矩形選択、矩形選択中にSpaceでウィンドウ単位で撮影可能。いつでも撮りたいときにすぐ撮れて、煩わしさを感じさせません。

しかし、それ故にちょっと残念だなと思うことがありました。

スクリーンショットを撮影した後にすること、それは9割Twitterです。(脳内調べ)

せっかくスクリーンショットをストレスなく撮影できるのに、その後、Twitterクライアントを開き、「Add Image」のようなボタンを押して、スクリーンショットディレクトリを探し、目当てのスクリーンショットを探すという作業が入ってしまいます。

面倒くさいなあと思った私は、3年越しにそれを解消する何かを作ることにしました。

これです↓

ちょっとわかりにくいかもしれませんが、上のメニューバーにあるオレンジ色のアイコンが私の作ったものです。アイコンをクリックすると、ツイートを入力するテキストエリアと、最新のスクリーンショットを表示します。GIFではマウスが動いていますが、ウィンドウが開いた時点でテキストエリアにフォーカスが移るようにしたので、そのままツイートを入力できます。

ツイートは、よくある感じで、(Ctrl|Command)+Enterで送信することができます。ツイートを送信したらそのままウィンドウも隠れます。

つまり、以前は

  1. Twitterクライアントを開く
  2. 画像を追加するためのボタンを押す
  3. スクリーンショットディレクトリを探す
  4. 目的のスクリーンショットを探す
  5. ツイートを入力
  6. 送信

のような手順を踏んでいたのが、

  1. アイコンをクリック
  2. ツイートを入力
  3. (Ctrl|Command)+Enter

で済むようになったわけです!

あ、一応名前もつけたんですが、ss-fast-tweetといいます。

技術的な話

Electronを使って実装しました。Electronを知らない人は、この辺を読むと詳しく書かれています。

Electronでアプリケーションを作ってみよう - Qiita

ざっくりいうと、メインプロセスとレンダラプロセスという2つのプロセスで成り立っていて、メインプロセスはNode.js、レンダラプロセスはChromiumが動いています。この2つのプロセスでプロセス間通信を行い、簡単にGUIアプリケーションが作れるよ!という感じでしょうか。

HTMLやCSSJavaScriptなどの知識がそのまま使えるので、Web系やってたけどネイティブアプリ作りたいって人にはかなりオススメです。

で、さっきのss-fast-tweetは、


ウィンドウが表示されるのをトリガーにして、メインプロセスで最新のスクリーンショットのパスを取得し、レンダラプロセスに渡す。

レンダラプロセスは、imgタグのsrc属性を渡されたパスに書き換える。


(Ctrl|Command)+Enterが押されると、textareaの内容をメインプロセスに渡す。

メインプロセスがツイートを行う。


雑に書くとこんな処理をしています。

まとまらない

普段私はあんまり何か作ろうとか思わないんですよね。確かに、自動化したいなと思うことはあるんですが、自動化する手間すらも面倒くさいと感じてしまい…という感じです。

でも、Electronを使ってみたら結構さっくり作れたので、これからも何か作るかもしれないです。

実は、色々と忙しかったせいで、Electronを触ったのは実質3~5日ぐらいだと思います。 Node.jsとかも初だったので、完全に学びながらでしたが、ある程度のものは出来ました(少なくとも私は満足しています)。 この手軽さもElectronの魅力の一つかなと思います。

Processingよりも本格的なアプリを作りたい1年生とかにもいいんじゃないでしょうか。

まとめる

Electronはいいぞ!!

追記

一応GitHubリポジトリを作りました github.com

SIGINTを受け取ったときのsleepの終了状態で詰まった話

誰も書かなそうなので、FUN Advent Calendar 2016 1日目の記事です。
某ステムプログラミングの課題の途中で感じた違和感について調べてみたという話です。

$whoami

学部3年、@neglect_ypです。
素因数分解をする某プロジェクトに所属しています。

終了ステータスが何か変だぞ…?

以前に作ったオレオレシェルを改造し、シグナルハンドラを用いてCtrl-Cを押した際に実行中のプロセスにSIGINTを送れるようにしようというのが、今回の課題でした。

実装自体はサクッと行い、一見うまくSIGINTを送れているようにも見えたのですが、終了ステータスが0であるという表示が出ており、頭に「?」が浮かびました。SIGINTを送って中断したということは、正常に終了してはいないのだから、終了ステータスが0であるのはおかしいのではないか?という考えです。

とりあえず、検証用にサイズの小さいコードを書いてみました。

結果は変わらず、終了ステータスは0でした。zsh上では終了ステータスが130になることも確認しました。

ここで僕がした勘違いは、「sleepはSIGINTによって終了したときは、終了ステータスが130になるのが正常な動作なんだ!」と思い込んでしまったことです。

そして、「sleepを実行していたプロセスの終了ステータスが格納されている変数から、どうにかして130という値が取り出せるはずだ」という思考になって、結構な時間を費やしてしまいました。

つまりどういうこと?

なんかうまくまとまらなかったので無理やり結論に…

zsh上でsleepに対してSIGINTを送って、echo $?したときに出てくる数字は、zshが勝手に決めています。 勝手にというと語弊があるかもしれませんが、POSIXでは、「シグナルによって終了したプロセスの終了ステータスは128より大きい値」であることが要求されているようです。しかし、具体的な値は定められていません。

そこで、zshbashなどのシェルでは「128+シグナルの番号」という形で終了ステータスを表しているようです。違う実装になっているシェルもあり、以下に詳しく載っています。

したがって130という値は128+2(SIGINT)の計算結果であり、sleepがSIGINTを受け取ったときにexit(130)するわけではありません。

思ったこと

私の主観ですが、本学はWebサービスを作ったりだとか人工知能に興味がある人が多いと思っています。逆に、私が興味を持っている、システムプログラミングやセキュリティの分野はあまり人気がないと感じていて、もっと好きになってほしいなあと思っています。こんな記事でしたが、興味を持っていただけたなら幸いです。

続きを読む

SANS NETWARS 2016に参加しました

SANS NETWARSトーナメント2016 | イベントのご案内 | 情報セキュリティのNRIセキュア

8/19(金) 〜 8/20(土) に開催された,SANS NETWARS 2016に参加してきました.

SANS NETWARSは,今年で2回目の参加です.

1日目に講義を受け,2日目にCTFをやるという日程で,充実した内容でした.

内容の公開はNGなので,詳しくは書けませんが,去年の内容よりもボリュームが増えていたし,CTFの問題もすべて変更されていて新鮮な気持ちで取り組めました.

去年は2日目のCTFの順位が32位だったので,今年は20位ぐらいを目指そうと思っていました.

結果は,23位でした.それなりに目標に近く悪くない結果だったと個人的には思います.

f:id:Gen_IUS:20160820202641p:plain

もう少しで解けそうだった問題が1問あったので,それだけが心残りです.来年も開催されれば,リベンジしに行きたいと思います.

チーム戦になるかもしれないという話もあったので,足を引っ張らないように今から精進したいと思います.

Ubuntu 14.04+nginxでHTTP2なWebサーバを建てたと思ったらChromeに対応できてなかった話

特にコンテンツもないけど,唐突にWebサーバを建てたくなったので,建てることにしました. せっかくなので,HTTPS,HTTP2にも対応する感じで.

HTTPS,HTTP2に関わるnginxの設定は,セキュリティミニキャンプin北海道で学んだし,そんなに詰まることもなく終了. 証明書はLet's encryptを用いて発行しました.

手元のFirefoxからアクセスし,それぞれ設定が反映されていることが確認できたので,「これで終わったぞー」と思っていたらChromeからだとHTTP2になっていない様子.

調べてみると,古いバージョンのOpenSSL(1.0.1以前)を使用している場合,Chrome(build 51以降)でHTTP2でのアクセスができなくなるようです.

ALPNというTLSの拡張に対応していないのが問題みたい.

ALPNについては,こちらのサイトがわかりやすかったです.

そういうわけで,OpenSSL 1.0.2の導入とnginxの再コンパイルをしました.

Chromeからアクセスすると,青い稲妻が表示されて,万事解決.

情報セキュリティスペシャリストになりました

セキュキャンに落ちてから,かなりナーバスになっていましたが,数日後に情報セキュリティスペシャリストの合格発表があったので,一応確認したら受かっていました.

勉強方法

情報セキュリティスペシャリスト(高度情報処理技術者試験)になりました - kumar8600の日記

こちらの記事を参考にしました.

実は参考書は買ったものの,ほとんど読んでおらず,なんで受かったんだろう…という気持ちです.午後問に至っては当日の朝方まで初見でした. 多分,普段からセキュリティの勉強をしていれば特別な対策はせずとも受かると思います.

失敗談

前回の情報処理技術者試験応用情報技術者に受かっていたのに,午前Ⅰの免除を申請していませんでした.セキュリティ分野の勉強ばかりして他を怠っていると,最大の障壁になり得るので,これから受ける人は可能であれば免除申請したほうが良いと思います.

セスペがなくなるらしい

ニュース - 情報セキュリティスペシャリスト合格者は「情報処理安全確保支援士」試験免除へ:ITpro

情報処理安全確保支援士試験になるらしいですね.長いし画数が激増しているので,手書きでは書きたくないです.

心の叫び

セキュリティ・キャンプ全国大会2016の応募用紙を晒す

今年も死んだよ。選択問題だけ晒す。


選択問題. 1

hogeはローカル変数であり、int型の10個ぶんの配列である。main関数の中でスタックポインタ(rsp)がずらされることにより、必要なサイズ(sizeof(int)*10bytes)がスタック上に確保される。C言語で配列名は配列の先頭アドレスを指すので、hogeにはスタック上に確保されたメモリの先頭アドレスが格納されていることになる。よって、0x7fff539799f0付近はスタックのアドレスであることがわかる。 fugaはintポインタとして宣言されており、malloc()により動的に確保されたメモリのアドレスが格納されている。malloc()はヒープ上にアドレスを確保するので、0x7fca11404c70付近はヒープのアドレスであることがわかる。

選択問題. 2

  1. HTTPS
    Webブラウザのアドレスバーに書かれている、スキーマからHTTPSを用いていることがわかる。Firefoxでは、ページ内で右クリック→ページ情報の情報を表示→「セキュリティ」タブと操作することで、より詳しい内容が表示できる。この内容から、認証局が「Google Inc」であることや、暗号化の方式が「TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256」であることがわかる。
  2. Cache-Controlヘッダ
    Firefoxでは、ツール→Web開発→ネットワークと操作することで、Webサーバとのやりとりを詳しく見ることができる。その中で、サーバからの応答の中に、「Cache-Control: "private, max-age=0"」というヘッダがあることがわかる。privateのほうは、コンテンツが複数のユーザで共有するキャッシュに記録されるべきでないことを示している。max-age=0は変更をその都度確認させるための指定だ。「Expires: "-1"」というヘッダもあり、これは「Cache-Control: "max-age=0"」と同様の記述らしいが、ブラウザによっては片方しかサポートしていないため、両方書かれているらしい。
  3. X-Frame-Optionsヘッダ
    「X-Frame-Options: "SAMEORIGIN"」というヘッダがあることから、自身と生成元が同じフレーム内に限り、ページを表示することができる。これによって、<iframe>タグなどを用いたクリックジャッキング攻撃を防止することができる。
  4. X-XSS-Protectionヘッダ
    「X-XSS-Protection: "1; mode=block"」というヘッダがあることから、IEXSSフィルターが有効になることがわかる。有効にするだけなら、「X-XSS-Protection: "1"」だけでよいのだが、mode=blockを指定することでより強固になる。過去のバージョンのIEでは、XSS Filterでブロックしたスクリプトをそのままブラウザ上で表示していた。これによって、XSS Filterを利用したXSSが生まれてしまった。現在はmode=blockがなくても、直接ソースが表示されるようなことはないようだが、過去のブラウザを利用している人も多いだろうから、mode=blockが指定されているのだと思う。

選択問題. 6

'や"など、SQLのメタ文字を入力してみる。なぜならば、IDとパスワードを入力してユーザ認証を行っているWebアプリは、大抵の場合、裏でデータベースにアクセスし、問い合わせの結果でログインの可否を判断しているからだ。もし、入力サニタイズが不十分であるなら、エラーが表示されるはずだ。そうなれば、SQLインジェクションができる可能性があり、大きな脅威となる。

選択問題. 8

まず、この逆アセンブルを眺めて気づいたのは、この逆アセンブルが大きく2つの部分に分かれることです。 0x400080...0x4000fcは、主にpushq命令で構成されていて、 0x400101...0x40012eは、主にretq命令、pop命令で構成されています。 脳内で上から順番に実行してみると、ROPのような挙動をすることがわかりました。 すなわち、0x400080...0x4000fcで戻りアドレスやレジスタにセットする値をスタック上にpushしておき、 0x400101...0x40012eでretqをjmp、popをmovのように使用しています。 したがって、これはROPを応用し、難読化が施されたバイナリの逆アセンブルであることがわかりました。 若干読みにくいので、手動で難読化を解除してみることにしました。

mov $0x0,%rax
mov $0x0,%rdi
mov %rsp,%rsi
mov $0x0,%r10
mov $0x8,%rdx
syscall ;read(STDIN,%rsi,0x8,0)
mov $0xffffffffffffffe0,%rbp
mov $0x7,%rcx
xorb $0x55,(%rsi,%rcx,1) ;-> 標準入力から受け取った文字列の最後の文字と0x55のXORをとっている。
; decが0x7->0x0までループする
dec %rcx
xorb $0x55,(%rsi,%rcx,1)
; ループここまで
mov $0x0,%rdi
movabs $0x63391a67251b1536,%rax
cmp %rax,(%rsi)
mov 0x3c,%rax
(jne $0x40012c ;もし入力のすべての文字を0x55とXORした結果が$0x63391a67251b1536と一致しないなら)
(syscall ;一致した時の処理, exit(0))
mov $0x1,%rdi
syscall ;exit(1)

若干不整合がある気がしますが…

  1. 基本的には、標準入力から8文字受け取り
  2. すべての文字を0x55とXORをとった結果に変更し、
  3. 0x63391a67251b1536と比較する(リトルエンディアンなことに注意する)
  4. 一致していれば、exit(0)、していなければexit(1)

というプログラムのようです。 すなわち、"c@Np2Ol6"という入力であれば、正常終了するプログラムであるということがわかりました。 (Pythonインタプリタで、0x63391a67251b1536をpackして、listにして、mapして...として求めました。

xorb $0x55,(%rsi,%rcx,1)がどういう処理をするのか、最初わかりませんでしたが、 rasm2を用いてintel記法にしてみると、xor byte [rsi + rcx], 0x55となり、理解できました。

正直、ループのところはあまりちゃんと読んでいないのですが、decとjneがあることから、%rcxが0まで回るループだろうなと断定して読み進めた結果、それらしい感じになりました。

CTFのような問題で、非常に楽しめました。個人的には一番好きな設問です。


提出前の僕


その後

来年も一応応募資格はあるけれど、これで3回落ちているし最早受かる気がしないので迷っている。

スタックとメモリ解放の話

Twitterで、とあるコードについて話題になっていたので、まとめてみる。

問題のコード

#include <stdio.h>

int* func(){
    int a = 114514;
    return &a;
}

int main(){
    printf("%d\n", *func());
}

結論としては、動作は未定義である。環境によって挙動が変わる。 ということらしいが、実際にはどのような挙動をする可能性があるのだろうか。

様々な挙動

  1. 114514と表示される
    私が普段使用している環境だと、この挙動を示した。 「局所変数aの領域がページアウトされていない」かつ、「printf()の呼び出しの際、引数や局所変数で上書きされていない」場合にこの挙動を示す。

  2. Segmentation fault
    wandbox(C++コンパイラ)で確認した挙動。 局所変数aがページアウトされていた」場合にこの挙動を示す。 コンパイラがnull返すようにしてくれていたようです。Thanks, うさぎさん

  3. 別の値が表示される
    printf()呼び出しの際に、引数や局所変数で上書きされた」場合に起こりうる。 未確認。

追記:gcc 4.9以前と5.1以降で変わるらしい。5.1以降だとnullを返すようになる。 d.hatena.ne.jp

感想的な

そもそも、CとかC++はコードの安全面はプログラマに任せているというような話を聞いた気がするし、 こんなコード書くなという話なんだけれど…

こういった、未定義のコードの挙動について考えてみるのって楽しい。もっと探ってみたい。