NoSQLi(Redis)
- 5. NoSQLとは
Not only SQL
->SQLに限定されない言語やインターフェースを用いる。Yes/Noではない
膨大な非構造化データを柔軟に扱える
->RDBMSのような厳密なスキーマ定義が不要
- 6. NoSQLとは
キー値:
いわゆるKey-Value型とかいわれるやつ。シンプルでレスが早いらしい。
ドキュメント:
上記概念の拡張版。PinPでいうパラメータをKey 、値のJSONをValueにしたイメージ。スキーマレス。
列指向:
1:nな2列?(Key-Value)のExcel。大量集計、大量更新が得意っぽい。
グラフ:
Node(Entity)とedge(Relation)、property(左2つの属性情報)を管理する。ER図っぽい。
[Microsoft Azure - NoSQL Database - NoSQL とは] https://azure.microsoft.com/ja-jp/overview/nosql-database/
[Microsoft Docs -非リレーショナル データと NoSQL] https://docs.microsoft.com/ja-jp/azure/architecture/data-guide/big-data/non-relational-data
- 9. Redisとは
オンメモリ
Key-Value型のデータ構造ストア
DB、キャッシュ、メッセージブローカーとして利用可能
セット、ビットマップ、HyperLogLog、地理空間インデックス、streamなどのデータ構造を提供
サポート言語/ライブラリ
https://redis.io/clients
[redis - Introduction to Redis] https://redis.io/topics/introduction
- 11. 検証環境
ホスト
Windows 10 Pro 1909
Python 3.9.1
redis 3.5.3
ゲスト(WSL2)
Kali 2021.1
Redis 6.0.10 64 bit
[Github -andymccurdy/redis-py] https://github.com/andymccurdy/redis-py#getting-started
- 13. ソースコード
pool = redis.ConnectionPool(host=‘IP', port=6379, db=0)
r = redis.StrictRedis(connection_pool=pool)
~省略~
def do_POST(self):
~省略~
q = parse_qs(param, keep_blank_values=1).get('q')[0]
lua = "return redis.call('SET', 'test', '%s’)” % q
multiply = r.register_script(lua)
try:
with open('./html/nosqli.html' , encoding='utf-8') as f:
html = f.read() % (q, multiply(), r.get('test’))
Redisへ接続
検査文字列
「') and redis.call('info」
↓
Lua Script
「return redis.call('SET', 'test', '') an
d redis.call('info')」
下線部でLua Scriptの実行
- 14. セキュアなコード
pool = redis.ConnectionPool(host=‘IP', port=6379, db=0)
r = redis.StrictRedis(connection_pool=pool)
~省略~
def do_POST(self):
~省略~
q = parse_qs(param, keep_blank_values=1).get('q')[0]
ret = r.set('test’, q)
try:
with open('./html/nosqli.html' , encoding='utf-8') as f:
html = f.read() % (q, multiply(), r.get('test’))
検査文字列 「‘) and redis.call(’info」 が
set関数によって、ただの文字列として扱われる
- 15. 検査文字列の検討
インジェクションできないコマンド例
Redisサーバのディレクトリ情報を取得するコマンド(lsコマンド相当)
「’) and redis.call(’config’, ’get’, ’dir」
↓
サーバエラーログ
->Redisのソースsentinel.cにおいて、
redisCommand構造体で「admin」や「no-auth」の要素を持つコマンドは実行できない
redis.exceptions.ResponseError: Error running script (call to
f_c1f38d90c20f2f994ed60271597f364280c952b4): @user_script:1:
@user_script: 1: This Redis command is not allowed from scripts
- 16. 検査文字列の検討
127.0.0.1:6379> keys *
1) "dest"
2) "test1"
3) "test"
4) "key1"
5) "key2"
127.0.0.1:6379> del *
(integer) 0
127.0.0.1:6379> del _
(integer) 0
127.0.0.1:6379> del %
(integer) 0
127.0.0.1:6379> del key*
(integer) 0
127.0.0.1:6379> del dest
(integer) 1
127.0.0.1:6379> keys *
1) "test1"
2) "test"
3) "key1"
4) "key2"
redis-cliによる全件削除可能性の確認
- 19. 参考
[aredis - LUA Scripting] https://aredis.readthedocs.io/en/latest/scripting.html
[Redis公式] https://redis.io/commands/
[HackTricks - Pentesting Redis] https://book.hacktricks.xyz/pentesting/6379-pentesting-redis
[sqreen – Redis injection] https://www.sqreen.com/plugins/redis-injection
Editor's Notes
- マスタ型:マスタノードが他のノードも管理、マスタが落ちると全部落ちる
P2P型:すべてのノードが互いを補完、単一障害点を回避できる
オンメモリ:データの永続性が保証されない
オンディスク:複数サーバにDBを分割して保有するといった拡張性が無い