sqlmapapi的作用
sqlmap每检测一个站点都需要开启一个新的命令行窗口或者结束掉上一个检测任务。虽然 -m 参数可以批量扫描URL,但是模式也是一个结束扫描后才开始另一个扫描任务。通过api接口,下发扫描任务就简单了,无需开启一个新的命令行窗口。
下载安装
sqlmap自带,没有的需要下载安装sqlmap程序。而sqlmap是基于Python 2.7.x 开发的,因此您需要下载Python 2.7.x。
Python 2.7.x 下载地址:https://www.python.org/downloads/release/python-2715/
sqlmap 下载地址:https://github.com/sqlmapproject/sqlmap/zipball/master
sqlmap的目录结构图如下
sqlmap安装完成后,输入以下命令,返回内容如下图一样,意味着安装成功:
python2 sqlmap.py -h
sqlmapapi
在sqlmap安装目录中找到一个 sqlmapapi.py 的文件,这个 sqlmapapi.py 文件就是sqlmmap api。sqlmap api分为服务端和客户端,sqlmap api有两种模式,一种是基于HTTP协议的接口模式,一种是基于命令行的接口模式。
python2 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服务端:
python2 sqlmapapi.py -s
命令成功后,在命令行中会返回一些信息。以下命令大概的意思是api服务端在本地8775端口上运行,admin token为e98dfc2b53cca0edbccbdafd78a3d2a4,IPC数据库的位置在/tmp/sqlmapipc-zOIGm_,api服务端已经和IPC数据库连接上了,正在使用bottle 框架wsgiref标准接口。
但是通过上面的这种方式开启api服务端有一个缺点,当服务端和客户端不是一台主机会连接不上,因此如果要解决这个问题,可以通过输入以下命令来开启api服务端:
python2 sqlmapapi.py -s -H "0.0.0.0" -p 8775
命令成功后,远程客户端就可以通过指定远程主机IP和端口来连接到API服务端
sqlmap api的两种模式
命令行接口模式
输入以下命令,可连接api服务端,进行后期的指令发送操作:
python2 sqlmapapi.py -c
交互式模式下的命令
api> helphelp 显示帮助信息new ARGS 开启一个新的扫描任务use TASKID 切换taskiddata 获取当前任务返回的数据log 获取当前任务的扫描日志status 获取当前任务的扫描状态option OPTION 获取当前任务的选项options 获取当前任务的所有配置信息stop 停止当前任务kill 杀死当前任务list 显示所有任务列表flush 清空所有任务exit 退出客户端
通过sqli-lab测试演示该模式接口下检测sql注入的流程
检测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(“/task/new”)
该接口用于创建一个新的任务,使用后会返回一个随机的taskid
@get(“/admin/list”)
该接口用于返回所有taskid。在调用时指定taskid
@get(“/task//delete”)
该接口用于删除taskid。
taskid存在的数量为0
@post(“/option//set”)
该接口为特定任务ID设置选项值,调用时请指定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调用程序
1、通过sqlmapapi_server.py输入sql的路径开启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等等。
sqlmapapi_server.py
import osstart=input('请输入sqlmap的路径:')try: os.chdir(start) d=os.system('python2 sqlmapapi.py -s') except: print('异常退出')
sqlmapapi_client.py
import sysimport timeimport requestsimport jsonimport platform def sqlmapi(url): data = { 'url': url } headers = { 'Content-Type': 'application/json' } try: task_new_url = 'http://'+apiurl+':8775/task/new' task_new_r = requests.get(url=task_new_url) pr = task_new_r.json()['taskid'] if 'success' in task_new_r.content.decode('utf-8'): print('创建ID:'+pr) task_set_url = 'http://'+apiurl+':8775/option/' + pr + '/set' task_set_r = requests.post(url=task_set_url, data=json.dumps(data), headers=headers) if 'success' in task_set_r.content.decode('utf-8'): print('配置信息设置成功') task_start_url = 'http://'+apiurl+':8775/scan/' + pr + '/start' task_start_r = requests.post(url=task_start_url, data=json.dumps(data), headers=headers) if 'success' in task_start_r.content.decode('utf-8'): while 1: task_status_url = 'http://'+apiurl+':8775/scan/' + pr + '/status' task_status_r = requests.get(url=task_status_url) if 'running' in task_status_r.content.decode('utf-8'): print('扫描目标->'+url) pass else: task_data_url = 'http://'+apiurl+':8775/scan/' + pr + '/data' task_data_r = requests.get(url=task_data_url).content.decode('utf-8') with open('res.txt','a+') as f: f.write(url+'\n') f.write(task_data_r+'\n') f.write('===================================================================\n') f.close() print(url+'扫描完成') task_del_url = 'http://'+apiurl+':8775/task/'+pr+'/delete' task_del_r=requests.get(url=task_del_url) if 'success' in task_del_r.content.decode('utf-8'): print('删除ID->'+pr) break time.sleep(5) except: print(url+'异常') if __name__ == '__main__': apiurl=input('输入服务端IP:') print('你正在使用的操作系统为:'+platform.platform()) with open('res.txt','w+') as f: f.truncate() try: task_new_url = 'http://'+apiurl+':8775/task/new' task_new_r = requests.get(url=task_new_url) except: print('请启动sqlmapapi的服务端') sys.exit() for url in open('url.txt','r'): url =url.replace('\n','') sqlmapi(url) print('全部扫描完毕,文件已保存到res.txt中')
效果如下