Serenityを使ってDiscordをRustから遊ぶ
はじまり
ちょっと作りたいものがあったのでDiscordのAPIを調べてました。
ぶっちゃけた話、Pythonでdiscord.pyを使った方が楽なんだと思うんですけど、Pythonをみたら発狂して転げ回る病気にかかったということにしているので今回はRustで。
RustでDiscordAPIを叩くライブラリを探してみるとSorenityというライブラリが見つかりました。
日本語で説明しているページが見当たらなかったので、しばらくあちこちにらめっこしながら、とりあえずサンプルが動いたのでそこまで書いておきます。
下準備
まずはDiscord向けのbotを作る準備をしないといけません。Discord向けのアプリを作るためにまずデベロッパーポータルへ行きましょう。
Discordにログインした状態でアクセスすると、下のようなページが出ると思います。
右上の"New Application"をクリックし、作成するアプリケーションの名前を入力して作成します。
日本語でも大丈夫みたいですね。
作成すると下のようなページが出るはずです。
そうしたら上図の赤丸のBOTをクリックします。
右のADDBOTをクリックすると、
"ADD A BOT TO THIS APP? "
"Adding a bot user gives your app visible life in Discord. However, this action is irrevocable! Choose wisely."
と、「bot追加したらもう戻れねえぜ!賢い選択を。」的なことを聞かれるので"Yes, do it !"を力強くクリックしましょう。
余談ですが、"Choose wisely"は『インディー・ジョーンズ/最後の聖戦』を元ネタとするミームみたいですね
それはさておき、クリックすると、
上図のようなページに移動します。
"A wild bot has appeared!"
「あ!やせいの BOTが とびだしてきた!」ですかね。
Discordは本当にゲーム関連の洒落が多くて素敵ですね。
それもさておき、上図の赤丸部分がプログラムで使用することになるトークンです。後で使います。覚えておいてください。
訪れるたびに毎回少しずつ変化しますが、いつ作ったものを使っても問題ないです。
次に、左カラムのOAuth2をクリックします。
移動先のページをスクロールすると、下図のようなチェックボックスが大量に出てくるかと思います。
ここではbotにチェックを入れます。するとさらに下に下図のようなチェックボックス群が出てきます。
このチェックボックスでbotに与える権限を設定できます。これはbotを招待する際に権限オフにもできます。
とりあえず試すために管理者にチェックを入れます。
その後2つ上の図の赤丸でリンクをコピーし、それにアクセスすると下図のような画面が出ます。
そこから追加するサーバーを選んで認証を押してやると
BOTがサーバーに参加します。
が、当然このままでは何もできません。
プログラムで動かしてやる必要があります。
SerenityでDiscord BOTを動かす
とりあえずSerenityをcloneしてきましょう。
git clone https://github.com/serenity-rs/serenity.git
そうしたらexampleディレクトリ内の01_basic_ping_botに移動しましょう。
cd serenity/examples/01_basic_ping_bot/
それでもってcargo run・・・といきたいところですが、このままだと「トークンの環境変数がないぞ」と怒られて動きません。
トークンをプログラム内か環境変数に書いてやる必要があります。
コードをいじらないで動かす場合は、
export DISCORD_TOKEN=<ここにトークン>
とでもしておけばいいと思います。
コードをいじって動かす場合は45,46行目の
let token = env::var("DISCORD_TOKEN") .expect("Expected a token in the environment");
を
let token = "ここにトークン"
としておきましょう。
そうしたらcargo runします。
無事起動し、サーバーに接続できると、コンソールに
<BOTの名前> is connected!
が出ますので、そうしたらDiscord上で"!ping"と書き込んでやると・・・動きましたね。
バーニラバニラで練習題
ことの始まり
サークルの先輩方との飲み会にてズンドコキヨシプログラムを知った。
→パイセン「バニラの求人のやつもありやな」
→詳細な仕様がサークルのSlackに上がってきた(!?)
→Golangの練習がてら書いてみるか〜
→書 き ま し た
バニラの歌詞
こんな感じだったような
※ V A N I L LA バニラ! V A N I L LA バニラ! ※※ バーニラ バニラ バーニラ 求人 バーニラ バニラ 高収入 バーニラ バニラ バーニラ 求人 バーニラ バニラでアルバイト ※※繰り返し ※繰り返し バニラの求人見たーいー 見たーいー 見たーいー バニラの求人見たーいー ニャニャニャーニャーニャニャーニャー
仕様
下記のSTEP1からSTEP6までを実行。「見たーいー見たーいー・・・」の部分については考えないことにした(「にゃにゃにゃーにゃーにゃにゃーにゃー」は含めてもよさそう?)
- STEP1
V!, a!, n!, i!, l!, la!の中からランダムに出力
V!, a!, n!, i!, l!, la!の順番で出てきたら”バニラ!”を出力。
- STEP2
STEP1をもう一回
- STEP3
“バーニラ”, “バニラ”, “バニラで” の中からランダムに出力
バーニラ, バニラ, バーニラ の順番で出てきたら”求人!”を出力
- STEP4
“バーニラ”, “バニラ”, “バニラで” の中からランダムに出力
バーニラ, バニラ の順番で出てきたら”高〜収〜入〜!”を出力
- STEP5
STEP3をもう一回
- STEP6
“バーニラ”, “バニラ”, “バニラで” の中からランダムに出力
バーニラ, バニラで の順番で出てきたら”高~収~入~!”を出力しておわり。
コード
gitに投げた。
github.com
感想
Golangのいい練習になった。
ズンドコ節を知らない世代が増えてきた頃にはもしかすると需要があるのではないだろうか(本当に?)
頭の中に残る繰り返しを含む歌は練習用の題材としていいのかもしれない。多分。
.pcapファイルについてちょっと調べた
パケットキャプチャではおなじみのpcapファイルについて、調べたのでまとめます。
動機
研究室で取り扱っているpcapファイルを管理するためにpcapパーサーを作ろうと思った。
そのためにpcapファイルの構造を調べたが、知りたい情報のある日本語の解説が見つからなかったので調べてまとめた。
pcapファイルの構造
HTTPパケットの入力の概要
上記ページはHitachiのuCosminexus Stream Data Platform - Application Framework システム構築・運用ガイドである。pcapファイルの構造についてはこちらに書かれてたので参考になった。
図を見た方が早いが、
- Pcapファイル自体のファイルヘッダ(24バイト)
- キャプチャしたパケット
- キャプチャしたパケットのヘッダ(16バイト)
- キャプチャしたパケットのデータ(可変長)
という構造になっているようだ。
Pcapファイル自体のファイルヘッダの構造
Development/LibpcapFileFormat - The Wireshark Wiki
上記のページによると、Pcapファイルのヘッダは下記のようになっているとのこと。
typedef struct pcap_hdr_s { guint32 magic_number; /* magic number */ guint16 version_major; /* major version number */ guint16 version_minor; /* minor version number */ gint32 thiszone; /* GMT to local correction */ guint32 sigfigs; /* accuracy of timestamps */ guint32 snaplen; /* max length of captured packets, in octets */ guint32 network; /* data link type */ } pcap_hdr_t;
それぞれについての説明を見ていくと、
magic_number
ファイルの種類を識別する際に用いる。4バイト。
version_major
ファイルフォーマットのメジャーバージョン(ver:x.yのxの方)。2バイト。
version_minor
ファイルフォーマットのマイナーバージョン(ver:x.yのyの方)。2バイト。
sigfigs
キャプチャしたパケットのタイムゾーンの精度?らしい。基本的に値は0になるとのこと。4バイト。
snaplen
"snapshot length"の略で、パケットのキャプチャサイズを制限するために用いるもの?らしい。通常は65535もしくはそれ以上とのこと。4バイト。
network
リンク層の種類。
www.tcpdump.org
上記のサイトに書かれている数値が入るらしい。Ethernetの場合、値は1になる。4バイト。
パケットのヘッダの構造
同じページを参照した。下記のような構造になっているとのこと。
typedef struct pcaprec_hdr_s { guint32 ts_sec; / *タイムスタンプ秒* / guint32 ts_usec; / *タイムスタンプマイクロ秒* / guint32 incl_len; / *ファイルに保存されたパケットのオクテット数* / guint32 orig_len; / *パケットの実際の長さ* / } pcaprec_hdr_t;
ts_usec
パケットがキャプチャされた時間のマイクロ秒にあたる部分。4バイト。
incl_len
キャプチャした際に、実際に「保存された」パケットデータのバイト数
orig_len
キャプチャした際に、実際に「観測された」パケットデータのバイト数
パケットのデータの構造
incl_lenの長さで実際のパケットがそのまま現れる。
構造を確認してみる
SampleCaptures - The Wireshark Wiki
上記Wiresharkのwikiから"http.pcap"をダウンロードし、Wiresharkとバイナリエディタで開いて確認してみた。
pcap_hdr_s
magic_number
値は、
0xA1B2C3D4
D4 C3 B2 A1でググると、
File Signature Database:: D4C3B2A1 File Signatures
からwinpcapのキャプチャファイルだとわかります。
version_major,version_minor
それぞれ、
0x0002
0x0004
となっているので、バージョンは2.4だとわかる。
上記に挙げたWiresharkのページでも
"the commonly used format in its current version 2.4. This format version hasn't changed for quite a while (at least since libpcap 0.4 in 1998),"
と書いてあり、1998年からずっとバージョンは2.4の模様。
thiszone
0x0
sigfigs
0x0
snaplen
0xFFFF
10進数に直すと65535なので、通常の値だとわかる。
network
0x0001
Ethernetを示している模様
pcaprec_hdr_t
ts_sec
0x40A34B23
10進数に直すと1084443427である。下記のサイトでUnix時間からJSTに変換したところ、西暦2004年 3月 13日 19時 17分 7秒だとわかる。UNIXタイムスタンプ変換ツール
Wiresharkで表示されている時刻と一致していることがわかる。
ts_usec
0x0004BFB8
10進数に直すと311224である。マイクロ秒と一致していることがわかる。
incl_len,orig_len
両方とも0x3Eで、10進数に直すと62
以降の62バイトとWiresharkで表示されているパケット本体が一致していることが確認できた。
FEHの投票大戦からデータ取ってきてみた(Python)(スクレイピング)
最初に調べたこと
robots.txtを見てみる
スクレイピングする上ではやっぱり注意しないといけないのが「スクレイピング禁止」かどうかでしょうか
FEH投票大戦スコアページのrobots.txtをとりあえず見てきました。
よし(適当)多分大丈夫でしょう。
Pythonでのスクレイピング方法
ライブラリは前にBeautifulSoupというものがあるのを見たので、これについて使い方を調べてみました。
Python3 + urllib + BeautifulSoupでネット上の情報を取得する
HTMLのタグをもとに掘り下げていけば目的の部分を取り出せるようです。
スクレイピング対象の観察
今度はFEH投票大戦スコアページのソースを見に行きました。
ご存知、Chromeのデベロッパーツール(うちはSRWareIronですが)でソースを見てみると、「n回戦」がarticleタグ単位で、「キャラVSキャラ」がliタグ単位で、「キャラ名とスコア」がpタグで表示されているとわかりました。
また、過去の大戦結果のページを見てみると、最新の対戦カードは上から二番目のarticleタグにくることがわかりました。
また、クラス名は'body-section-tournament'であることもわかりました。
articleタグのクラス名'body-section-tournament'に絞ってスクレイピングしてみると、一番上のarticleタグ、クラス名'body-section-tournament current'まで拾ってきてしまいました。調べてみた感じだと、どうやら同じ文字列が入ってることだけが原因みたいでした。
仕方ないので常に上から二番目のarticle要素より、データを引っ張ってくることにしました。
実際にスクレイピング
articleタグ内のliタグ内のpタグの要素を引っ張ってきて出力してみると、取り出したかったデータが確認できました。
Twitterに投稿する
ついでなのでTwitterに取得したデータをPythonから投稿してみました。
Twitterへの投稿方法
いつも通りTwitter APIを使えるようにしました(書くの面倒)
pip install twitter
したら、あとはTwitter用のライブラリを導入して、キーやらなんやらを設定して投稿!だけなのですが、このままだと生のコンシューマキーとシークレットを晒すことになって危険です。
そこで、以前Rubyで作成したupdate_name*1でも環境変数をファイルに書いて外部に見えないようにしたのを思い出しました。Pythonでも同じことができると思い、環境変数からキーを読み込む方法を調べてみました。
【GitHub】に載せたくない環境変数の書き方 Python
こちらを参考に、.envにキーを書いて、コードをコピペして終わり!(書くの飽きてきた)
今後
とりあえず今の投票大戦期間で自動的に大戦経過をツイートできないかと考えている感じ。herokuだと止まっている時間が長いので、Red Hat Open Shiftに目をつけ始めている。
あとは劣勢時に通知が飛ばせればなぁとかそんな感じ。過去の傾向から予測して劣勢の予測とかもしてみたいなぁ(以前某所で見たことがあるけども)
2018/5/26〜27のBeginnersCTFに参加してみた件
CTF4b参加してみた
去年も一昨年も参加できなかったCTF for Beginnersがオンラインで開催すると聞いて参戦しました。
CTF自体はガチの初心者で、CpawCTFに挑戦してつまづいたっきり放置してました。
開始してから研究室のSlack見るまでずっと忘れてたので遅めに開始しましたが、楽しかったです(小並感)
結果
一人ぼっちで参加したのでチーム名はハンドルにしようか悩んだのですが時期も考えて、
古 戦 場 か ら 逃 げ る な
にしました。解けた問題の割合みたいなやつは下です。
Pwn以外を1問ずつ、Miscは全完でした。
解法
とりあえず書くほどでもないのでしょうが、どんな風に解いたのか反省も込みで書き残したいと思います。解いた順番です。
[Warmup] plain mail
pcapファイルが渡されました。Wiresharkで開いてみると、SMTPプロトコルがちらほら見えるので、smtpでフィルタをかけてみていきました。
「最初のメールで秘密のファイルを、次のメールでパスワードを送るぜぇ〜(意訳)」みたいなことが書いてあったので、パケットからメールを復元する方法を調べると、IMFでフィルタをかけてeml形式でエクスポートしたら復元できる〜とのことだったので、「ファイル」→「オブジェクトをエクスポート」→「IMF」で復元できた。
[Warmup] Veni, vidi, vici
3つのtxtファイルが入ったzipが渡されました。
とりあえず初手、Googleで「Veni,vidi,vici」を検索。
ejje.weblio.jp
『ガイウス・ユリウス・カエサルが...』なるほど。おなじみのシーザー暗号かな?ということで、シーザー暗号の複合ができるサイトで見てみることに。
part1は『pgs4o{a0zber』の部分がどうみてもflagなので"pgs4o"が"ctf4b"に対応するように鍵を指定して複合。
part2もどう見てもシーザー暗号なので、同じ鍵で複合してみるも文にならない。じっくり見てみると、コロンまでの文字数が一致していることから、全く同じ文章を別の鍵で暗号化したものだと推定。通るように複合。
part3はパッと見てひっくり返した文字になってるのがわかったので頑張ってモニターをひっくり返した。CTFは筋肉も使うんだなぁ...たまげた(?)
[Warmup] Simple Auth
よくわかんないファイルが渡されたので、とりあえずfileコマンドにかけてみる。するとどうやらelfファイルのようなので、Ubuntuにコピーしてreadelf
chmod +xして実行できる状態にして、ltraceで実行したらフラグの文字列が見えたのでおわり。
Find the messages
ディスクイメージが渡された。中身は1,2,3のディレクトリで、1はtxt、2はpng、3は何も入ってない状態だった。
1のtxtは終わりの文字が'='だったので、base64の匂いがするのでbase64でデコードしたらflagの破片がでてきた。
2は開こうとしても開けないので、file、stringで調査してみるも、怪しい点が見当たらない。試しにバイナリエディタに入れてみるとファイルヘッダが全部58になっていたので、正しいファイルヘッダに書き換えたら無事開くことができた。画像にflagの破片が書かれていた。
3はディスクイメージ自体の問題なのではないかと疑って、foremostコマンドにかけてやるとpdfが出てきた。中身はそのままflagの破片だったので無事AC
てけいさんえくすとりーむず
書いてある通りのコマンドを実行してみると、「3桁どうしの計算を300秒で100問解いたらフラグをやるよ(意訳)」といった内容だったので、どうみても手計算じゃできません本当にありがとうございました。
pythonとかrubyで標準出力から計算式持ってきてevalしたらいけそうだなーと思ったので頑張ってみるも、上手くできない。なんでだろうと思っていたら、どうもgetsだと改行が出てこないせいで処理が止まってしまう様子。仕方ないのでgetcで9文字取ってはevalして標準入力にwriteを繰り返す方法でクリア。
[Warmup] Greeting
割と早めに手を出したのに解けたのは最後になってしまった。
「adminだけがフラグを読めるで(意訳)」とあったので、とりあえず何も考えずにadminを入力したら「偽管理者」に書き換えられてしまった。
下の方にコードが書いてあり、噂に聞こえたすごいphpなのを見ていて、XSSかな?と思ったけどもhtmlspecialcharsでエスケープされているので無理なのを知る。
書き換えが発生する箇所の下をみるとcookieから名前を取ってくる際には書き換えないことが見て取れるのでEdit this Cookieのchrome拡張でcookieを書き換えてみるも、上手くいかない。ここで後回しにすることを決めた。
後になってからpythonのcookiejar使えばいけそうじゃないか?と思ったのでcookiejar経由でwebページを取得したらフラグが出てきてAC
他の人の解説を見てみたら普通にEdit this cookieでいけてるので謎
『OS自作入門』を読んでいくよ 1日目
図書館で目に付いた『OS自作入門』を借りてきて読むことにした。副題によると「30日でできる」らしいので(30個に記事を分けているという意味なので、30日で本当にできるかどうかは人次第らしいけども)、それなりに毎日読んで記事でも書こうかと思っている。
まとめ
CPUについて
電気信号を処理する装置としてのCPU
→ON/OFFを数字の1/0として対応して2進数を表現して計算ができるように
→数字と文字を対応させて文章を表現できるように
CPUへの命令も電気信号
→0と1で全部あらわせる
→バイナリエディタで作れないものは無いな強いな
uint32_tに代入したASCIIコードのビット列をchar[4]の文字列に変換したい
union uint32converter{ uint32_t value; char str[4]; };
Usage:
uint32converter conv; uint32_t val; //この辺でvalになんか入れる conv.value=val; cout<<conv.str<<endl;
なるほど。