關於sqlmapapi一點記錄


關於sqlmapapi自己練習的還是很少 今天看見freebuf上師傅的分享的內容 自己練習了一下

來自: https://www.freebuf.com/articles/web/204875.html 這位師傅總結非常好 

 

為什么要使用SQLMAP API?

由於SQLMAP每檢測一個站點都需要開啟一個新的命令行窗口或者結束掉上一個檢測任務。雖然 -m 參數可以批量掃描URL,但是模式也是一個結束掃描后才開始另一個掃描任務。通過api接口,下發掃描任務就簡單了,無需開啟一個新的命令行窗口。

 

sqlmap api

在sqlmap安裝目錄中找到一個 sqlmapapi.py 的文件,這個 sqlmapapi.py 文件就是sqlmmap api。sqlmap api分為服務端和客戶端,sqlmap api有兩種模式,一種是基於HTTP協議的接口模式,一種是基於命令行的接口模式。

 

python sqlmapapi.py -h

返回的信息:

Usage: sqlmapapi.py [options]

Options:
  -h, --help            顯示幫助信息並退出
  -s, --server          做為api服務端運行
  -c, --client          做為api客戶端運行
  -H HOST, --host=HOST  指定服務端IP地址 (默認IP是 "127.0.0.1")
  -p PORT, --port=PORT  指定服務端端口 (默認端口8775)
  --adapter=ADAPTER     服務端標准接口 (默認是 "wsgiref")
  --username=USERNAME   可空,設置用戶名
  --password=PASSWORD   可空,設置密碼

 

開啟api服務端

無論是基於HTTP協議的接口模式還是基於命令行的接口模式,首先都是需要開啟api服務端的。通過輸入以下命令即可開啟api服務端:

python sqlmapapi.py -s

命令成功后,在命令行中會返回一些信息。以下命令大概的意思是api服務端在本地8775端口上運行,admin token為e98dfc2b53cca0edbccbdafd78a3d2a4,IPC數據庫的位置在/tmp/sqlmapipc-zOIGm_,api服務端已經和IPC數據庫連接上了,正在使用bottle 框架wsgiref標准接口。

但是通過上面的這種方式開啟api服務端有一個缺點,當服務端和客戶端不是一台主機會連接不上,因此如果要解決這個問題,可以通過輸入以下命令來開啟api服務端:

python sqlmapapi.py -s -H "0.0.0.0" -p 8775

命令成功后,遠程客戶端就可以通過指定遠程主機IP和端口來連接到API服務端。

 

固定admin token

如果您有特殊的需求需要固定admin token的話,可以修改文件api.py,該文件在sqlmap目錄下的/lib/utils/中,修改該文件的第661行代碼,以下是源代碼:

DataStore.admin_token = hexencode(os.urandom(16))

sqlmap api的兩種模式

命令行接口模式

輸入以下命令,可連接api服務端,進行后期的指令發送操作:

python sqlmapapi.py -c

如果是客戶端和服務端不是同一台計算機的話,輸入以下命令:

python sqlmapapi.py -c -H "192.168.1.101" -p 8775

輸入以上命令后,會進入交互模式,如下圖所示:

 

 

命令行接口模式的相關命令

通過在交互模式下輸入help命令,獲取所有命令,以下是該接口模式的所有命令:

 

api> help
help           顯示幫助信息
new ARGS       開啟一個新的掃描任務
use TASKID     切換taskid
data           獲取當前任務返回的數據
log            獲取當前任務的掃描日志
status         獲取當前任務的掃描狀態
option OPTION  獲取當前任務的選項
options        獲取當前任務的所有配置信息
stop           停止當前任務
kill           殺死當前任務
list           顯示所有任務列表
flush          清空所有任務
exit           退出客戶端        

既然了解了命令行接口模式中所有命令,那么下面就通過一個sql注入來演示該模式接口下檢測sql注入的流程。

 

這里我在另外一台2003上的sqli-lab測試

 

檢測GET型注入

通過輸入以下命令可以檢測GET注入

new -u "url"

雖然我們僅僅只指定了-u參數,但是從返回的信息中可以看出,輸入new命令后,首先先請求了/task/new,來創建一個新的taskid,后又發起了一個請求去開始任務,因此可以發現該模式實質也是基於HTTP協議的。

 

通過輸入 status 命令,來獲取該任務的掃描狀態,若返回內容中的status字段為terminated,說明掃描完成,若返回內容中的status字段為run,說明掃描還在進行中。下圖是掃描完成的截圖:

 

通過輸入 data 命令,來獲取掃描完成后注入出來的信息,若返回的內容中data字段不為空就說明存在注入。下圖是存在SQL注入返回的內容,可以看到返回的內容有數據庫類型、payload、注入的參數等等。

 

 

 

檢測POST型、cookie、UA等注入

通過輸入以下命令,在data.txt中加入星號,指定注入的位置,來達到檢測POST、cookie、UA等注入的目的:

new -r data.txt

 

基於HTTP協議的接口模式

下列都是基於HTTP協議API交互的所有方法:提示:“@get”就說明需要通過GET請求的,“@post”就說明需要通過POST請求的;POST請求需要修改HTTP頭中的Content-Type字段為application/json

#輔助
@get('/error/401')    
@get("/task/new")
@get("/task/<taskid>/delete")

#Admin 命令
@get("/admin/list")
@get("/admin/<token>/list")
@get("/admin/flush")
@get("/admin/<token>/flush")

#sqlmap 核心交互命令
@get("/option/<taskid>/list")
@post("/option/<taskid>/get")
@post("/option/<taskid>/set")
@post("/scan/<taskid>/start")
@get("/scan/<taskid>/stop")
@get("/scan/<taskid>/kill")
@get("/scan/<taskid>/status")
@get("/scan/<taskid>/data")
@get("/scan/<taskid>/log/<start>/<end>")
@get("/scan/<taskid>/log")
@get("/download/<taskid>/<target>/<filename:path>")

@get(‘/error/401′)

該接口首先需要登錄(Admin token),不然會返回狀態碼401。具體代碼如下:

response.status = 401
return response

@get(“/task/new”)

該接口用於創建一個新的任務,使用后會返回一個隨機的taskid

下圖是調用該接口的截圖:

@get(“/task//delete”)

該接口用於刪除taskid。

@get(“/admin/list”)

該接口用於返回所有taskid。在調用時指定taskid

 

 

 

@get(“/admin/flush”)

該接口用於刪除所有任務。在調用時指定admin token,

 

@post(“/option//get”)

該接口可獲取特定任務ID的選項值,調用時請指定taskid

 

@post(“/option//set”)

該接口為特定任務ID設置選項值,調用時請指定taskid

 

@post(“/scan//start”)

該接口定義開始掃描特定任務,調用時請指定taskid

@get(“/scan//stop”)

該接口定義停止掃描特定任務,調用時請指定taskid

 

 

總結

基於HTTP的接口模式用起來可能比較繁瑣,但是對於程序調用接口還是很友善的。總之該模式的流程是:

1、通過GET請求 http://ip:port/task/new 這個地址,創建一個新的掃描任務;

2、通過POST請求 http://ip:port/scan//start 地址,並通過json格式提交參數,開啟一個掃描;通過GET請求 http://ip:port/scan//status 地址,即可獲取指定的taskid的掃描狀態。這個返回值分為兩種,一種是run狀態(掃描未完成),一種是terminated狀態(掃描完成);3、掃描完成后獲取掃描的結果。

使用Python3編寫sqlmapapi調用程序

 下面就來編寫一個sqlmapapi調用程序,首先我們得再次明確一下流程:

1、通過 sqlmapapi.py -s -H “0.0.0.0″ 開啟sqlmap api的服務端。服務端啟動后,在服務端命令行中會返回一個隨機的admin token值,這個token值用於管理taskid(獲取、清空操作),在這個流程中不需要amin token這個值,可以忽略。之后,服務端會處於一個等待客戶端的狀態。

2、通過GET請求 http://ip:port/task/new 這個地址,即可創建一個新的掃描任務,在響應中會返回一個隨機的taskid。這個taskid在這個流程中尤為重要,因此需要通過變量存儲下來,方便后面程序的調用。

3、通過POST請求 http://ip:port/scan//start 地址,並通過json格式提交參數(待掃描的HTTP數據包、若存在注入是否獲取當前數據庫用戶名),即可開啟一個掃描任務,該請求會返回一個enginedid。

4、通過GET請求 http://ip:port/scan//status 地址,即可獲取指定的taskid的掃描狀態。這個返回值分為兩種,一種是run狀態(掃描未完成),一種是terminated狀態(掃描完成)。

5、判斷掃描狀態,如果掃描未完成,再次請求 http://ip:port/scan//status 地址 ,直到掃描完成。6、掃描完成后獲取掃描的結果,是否是SQL注入,若不存在SQL注入,data字段為空,若存在SQL注入,則會返回數據庫類型、payload等等。

#!/usr/bin/python
# -*- coding:utf-8 -*-
# wirter:En_dust
import requests
import json
import time

class Client():
    def __init__(self,server_ip,server_port,admin_token="",taskid="",filepath=None):
        self.server = "http://" + server_ip + ":" + server_port
        self.admin_token = admin_token
        self.taskid = taskid
        self.filepath = ""
        self.status = ""
        self.scan_start_time = ""
        self.scan_end_time = ""
        self.engineid=""
        self.headers = {'Content-Type': 'application/json'}



    def create_new_task(self):
        '''創建一個新的任務,創建成功返回taskid'''
        r = requests.get("%s/task/new"%(self.server))
        self.taskid = r.json()['taskid']
        if self.taskid != "":
            return self.taskid
        else:
            print("創建任務失敗!")
            return None

    def set_task_options(self,url):
        '''設置任務掃描的url等'''
        self.filepath = url



    def start_target_scan(self,url):
        '''開始掃描的方法,成功開啟掃描返回True,開始掃描失敗返回False'''
        r = requests.post(self.server + '/scan/' + self.taskid + '/start',
                      data=json.dumps({'url':url,'getCurrentUser':True,'getBanner':True,'getCurrentDb':True}),
                      headers=self.headers)
        if r.json()['success']:
            self.scan_start_time = time.time()
            #print(r.json())
            #print(r.json()['engineid'])
            return r.json()['engineid']
        else:
            #print(r.json())
            return None

    def get_scan_status(self):
        '''獲取掃描狀態的方法,掃描完成返回True,正在掃描返回False'''
        self.status = json.loads(requests.get(self.server + '/scan/' + self.taskid + '/status').text)['status']
        if self.status == 'terminated':
            self.scan_end_time = time.time()
            #print("掃描完成!")
            return True
        elif self.status == 'running':
            #print("Running")
            return False
        else:
            #print("未知錯誤!")
            self.status = False



    def get_result(self):
        '''獲取掃描結果的方法,存在SQL注入返回payload和注入類型等,不存在SQL注入返回空'''
        if(self.status):
            r = requests.get(self.server + '/scan/' + self.taskid + '/data')
            if (r.json()['data']):
                return r.json()['data']
            else:
                return None

    def get_all_task_list(self):
        '''獲取所有任務列表'''
        r = requests.get(self.server + '/admin/' + self.admin_token + "/list")
        if r.json()['success']:
            #print(r.json()['tasks'])
            return r.json()['tasks']
        else:
            return None

    def del_a_task(self,taskid):
        '''刪除一個任務'''
        r = requests.get(self.server + '/task/' + taskid + '/delete')
        if r.json()['success']:
            return True
        else:
            return False

    def stop_a_scan(self,taskid):
        '''停止一個掃描任務'''
        r = requests.get(self.server + '/scan/' + taskid + '/stop')
        if r.json()['success']:
            return True
        else:
            return False

    def flush_all_tasks(self):
        '''清空所有任務'''
        r =requests.get(self.server + '/admin/' + self.admin_token + "/flush")
        if r.json()['success']:
            return True
        else:
            return False

    def get_scan_log(self):
        '''獲取log'''
        r = requests.get(self.server + '/scan/' + self.taskid + '/log')
        return r.json()

Githun地址:https://github.com/FiveAourThe/sqlmap_api_demo

mian.py

#!/usr/bin/python
# -*- coding:utf-8 -*-
# wirter:En_dust
from Service import Client
import time
from threading import Thread

def main():
    '''實例化Client對象時需要傳遞sqlmap api 服務端的ip、port、admin_token和HTTP包的絕對路徑'''
    print("————————————————Start Working!—————————————————")
    target = input("url:")
    task1 = Thread(target=set_start_get_result,args=(target,))
    task1.start()



def time_deal(mytime):
     first_deal_time = time.localtime(mytime)
     second_deal_time = time.strftime("%Y-%m-%d %H:%M:%S", first_deal_time)
     return  second_deal_time


def set_start_get_result(url):
    #/home/cheng/Desktop/sqldump/1.txt
    current_taskid =  my_scan.create_new_task()
    print("taskid: " + str(current_taskid))
    my_scan.set_task_options(url=url)
    print("掃描id:" + str(my_scan.start_target_scan(url=url)))
    print("掃描開始時間:" + str(time_deal(my_scan.scan_start_time)))
    while True:
        if my_scan.get_scan_status() == True:
            print(my_scan.get_result())
            print("當前數據庫:" + str(my_scan.get_result()[-1]['value']))
            print("當前數據庫用戶名:" + str(my_scan.get_result()[-2]['value']))
            print("數據庫版本:" + str(my_scan.get_result()[-3]['value']))
            print("掃描結束時間:" + str(time_deal(my_scan.scan_end_time)))
            print("掃描日志:\n" + str(my_scan.get_scan_log()))
            break




if __name__ == '__main__':
    my_scan = Client("127.0.0.1", "8775", "c88927c30abb1ef6ea78cb81ac7ac6b0")
    main()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM