BUUCTF [第二章 web进阶]SSRF Training
我真的是在认真摸鱼啊 2024-09-30 09:33:01 阅读 67
1.什么是SSRF?
SSRF(Server-Side Request Forgery,服务器端请求伪造) 是一种网络攻击,攻击者通过欺骗服务器,使其向本不该访问的内部或外部资源发出 HTTP 请求。这种攻击允许攻击者间接利用服务器发起请求,绕过防火墙、访问内网系统,甚至读取本地资源。
SSRF 攻击的基本概念:
在 SSRF 攻击中,攻击者并不直接访问目标资源,而是通过服务器充当代理来发起请求。通常,服务器会处理来自客户端的 URL、IP 地址或其他资源的请求,而 SSRF 攻击者则通过修改这些请求参数,使服务器访问攻击者指定的内部或外部资源。
SSRF 攻击的典型场景:
文件上传或下载功能:服务器接受文件的 URL 或者文件路径,然后下载或处理该文件。
URL 或 API 调用:服务器接受来自客户端的 URL 并发起相应的请求,如获取远程 API 数据。
图片加载或资源获取:服务器从 URL 获取图片或其他资源并返回给用户。
SSRF 攻击示例:
内网探测: 通过 SSRF,攻击者可以让服务器访问内网中的敏感资源(如内部管理系统、数据库服务等),这通常是外部攻击者无法直接访问的。
示例:
<code>http://example.com/page?url=http://127.0.0.1/admin
攻击者将 URL 参数修改为内部 IP 地址 127.0.0.1,服务器被欺骗去访问本地的管理页面。
获取敏感信息: 攻击者通过 SSRF 访问内部的 API 或者云服务的元数据服务器,可能获取敏感的配置信息。
示例: 在 AWS(亚马逊云服务)中,元数据服务器通常位于 http://169.254.169.254/latest/meta-data/,可以泄露云主机的关键信息,如临时凭证。
http://example.com/page?url=http://169.254.169.254/latest/meta-data/
跨站请求伪造(CSRF)结合 SSRF: SSRF 还可以与 CSRF 攻击结合使用,攻击者可以利用服务器发起对外部或第三方系统的恶意请求。
SSRF 攻击的影响:
访问内部网络资源:攻击者可以通过服务器访问原本受限的内部网络资源,包括数据库、管理界面等。数据泄露:服务器可能被用于访问内部系统或云基础设施的敏感信息,比如配置信息、数据库内容等。执行恶意操作:通过特定的请求,攻击者可以操控服务器发送请求,从而执行某些恶意操作(例如,修改数据、执行远程代码等)。
SSRF 的常见绕过手段:
攻击者通常会使用一些绕过方法来避免服务器的内网 IP 检查,比如:
使用 DNS 解析绕过:攻击者使用一个恶意的域名,它解析为内网 IP 地址,从而绕过直接的 IP 检查。多次重定向:攻击者让服务器跟随 URL 重定向,从外部 URL 重定向到内网地址,绕过简单的 URL 白名单过滤。伪造 IP 地址:通过伪造不同的 IP 格式(如整数形式的 IP 地址),绕过内网 IP 检查。、
2.解题思路
首先我们来看一下源代码:
<?php
highlight_file(__FILE__);
function check_inner_ip($url)
{
$match_result=preg_match('/^(http|https)?:\/\/.*(\/)?.*$/',$url);
if (!$match_result)
{
die('url fomat error');
}
try
{
$url_parse=parse_url($url);
}
catch(Exception $e)
{
die('url fomat error');
return false;
}
$hostname=$url_parse['host'];
$ip=gethostbyname($hostname);
$int_ip=ip2long($ip);
return ip2long('127.0.0.0')>>24 == $int_ip>>24 || ip2long('10.0.0.0')>>24 == $int_ip>>24 || ip2long('172.16.0.0')>>20 == $int_ip>>20 || ip2long('192.168.0.0')>>16 == $int_ip>>16;
}
function safe_request_url($url)
{
if (check_inner_ip($url))
{
echo $url.' is inner ip';
}
else
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$output = curl_exec($ch);
$result_info = curl_getinfo($ch);
if ($result_info['redirect_url'])
{
safe_request_url($result_info['redirect_url']);
}
curl_close($ch);
var_dump($output);
}
}
$url = $_GET['url'];
if(!empty($url)){
safe_request_url($url);
}
?>
check_inner_ip 通过 url_parse 检测是否为内网 ip 。
如果满足不是内网 ip ,通过 curl 请求 url 返回结果。
根据【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器提供的思路,url_parse 与curl的结果出现了差异:
http://foo@evil.com@google.com/
当 php_url_parse 认为 google.com 为目标的同时,curl 认为 evil.com:80 是目标。
根据网上的资料,parse_url 和 cURL 是 PHP 中的两个不同功能,用于处理 URL,但它们的用途和处理方式有所不同。下面是它们的主要区别:
parse_url
功能:
parse_url 是一个用于解析 URL 字符串的函数。它将一个完整的 URL 拆分为不同的组成部分,如协议、主机、端口、路径、查询参数等。
使用示例:
<code>$url = "http://www.example.com/path?arg=value#anchor";
$parsed = parse_url($url);
var_dump($parsed);
输出:
array(5) {
["scheme"] => string(4) "http"
["host"] => string(11) "www.example.com"
["path"] => string(5) "/path"
["query"] => string(8) "arg=value"
["fragment"] => string(6) "anchor"
}
目的:
主要用于从 URL 中提取和分析信息。它不会发起任何网络请求。
cURL
功能:
cURL 是一个强大的库,用于发送 HTTP 请求和处理响应。它支持多种协议(HTTP、HTTPS、FTP等)和多种选项(如设置请求头、处理重定向、发送数据等)。
使用示例:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://www.example.com");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
目的:
主要用于与外部服务进行网络交互,获取数据或发送请求。它能够处理请求和响应,但不会解析 URL。
主要区别
功能性:
parse_url 主要用于解析和分析 URL,而 cURL 用于实际的网络请求。
返回值:
parse_url 返回一个数组,包含 URL 的各个部分;cURL 返回请求的响应数据或状态。
操作对象:
parse_url 不涉及网络交互;cURL 则是与网络进行通信的工具。
用法场景:
使用 parse_url 来获取 URL 的结构信息,例如提取主机或路径;
使用 cURL 来获取或发送数据,处理 HTTP 请求和响应。
理解了后我们构造payload就容易了:
Payload 1:
http://foo@127.0.0.1:80 @www.baidu.com/flag.php
Payload解析:
在 URL 中使用两个 @ 符号实际上是利用了 URL 的标准格式和解析规则,来达到绕过防护机制的目的。让我们详细分析一下这两个 @ 符号的作用及其在 SSRF 攻击中的角色。
URL 标准格式
根据 URL 规范(RFC 3986),URL 的基本结构如下:
scheme://username:password@host:port/path?query#fragment
其中,username:password@ 是可选的,用来提供访问主机的身份认证信息(即在访问时指定用户名和密码)。常见的例子包括:
http://user:pass@host/path
这里的 user:pass 是用于访问 host 的认证信息。
在这种情况下,@ 符号用于分隔用户认证信息和主机名,解析时只使用 user:pass 作为认证,实际访问的仍然是 host。
第一个 @ 的作用
在构造的 payload http://foo@127.0.0.1:80@www.baidu.com/flag.php 中,第一个 @ 符号的作用是:
把 foo作为访问 127.0.0.1:80 的认证信息。
foo 是用户名,URL 的前半部分看起来像 http://foo@127.0.0.1:80,这意味着向 127.0.0.1 的请求是使用 foo 作为认证用户名。
由于 username:password@ 是标准的 URL 格式,这部分通常不会触发异常。
第二个 @ 的作用
第二个 @ 符号的作用是:
在某些情况下,URL 解析器会忽略第二个 @ 后面的部分,将它作为路径或注释的一部分,而不影响请求的目标主机。
根据 URL 标准,第二个 @ 后面的 www.baidu.com/flag.php 实际上会被解析为请求的路径(即 /flag.php),而不会真正改变主机名。
因此,即使你在 URL 中加入 www.baidu.com,它也不会改变实际请求的主机名,主机仍然是 127.0.0.1。
实际请求结果
URL 解析器会将整个 URL http://foo@127.0.0.1:80@www.baidu.com/flag.php 解析为:
主机:127.0.0.1
端口:80
认证:foo
路径:/flag.php
这样,最终发出的请求仍然是访问本地 127.0.0.1 上的 /flag.php,而不是 www.baidu.com。
为什么能获取到 flag?
通过构造双 @ 符号的 URL,攻击者能够:
误导服务器,使其访问 127.0.0.1 而不是外部的 www.baidu.com。
绕过内网访问限制,因为服务器自身访问 127.0.0.1 时可能不会受到防火墙的限制,直接访问内部的 /flag.php 文件。
如果本地存在 /flag.php 并且没有严格的访问控制,服务器就会返回 flag,成功触发 SSRF 攻击。
总结
第一个 @:用于指定用户名(如 foo)和主机(如 127.0.0.1),符合 URL 规范。
第二个 @:利用 URL 解析机制,欺骗服务器忽略 www.baidu.com 并继续访问指定的主机(即 127.0.0.1),从而绕过外部主机的验证。
这种双 @ 技巧在 SSRF 攻击中非常有效,因为它能够混淆 URL 解析器的工作逻辑,导致服务器错误地访问内部资源。
Payload 2:
http://127.0.0.1/flag.php
在一个典型的 SSRF(Server-Side Request Forgery)攻击中,http://127.0.0.1/flag.php 能够成功获取到 flag 通常是因为以下几个原因:
127.0.0.1 是本地回环地址
127.0.0.1 是本地回环地址,表示访问的是服务器自身。通常情况下,应用程序的某些资源或服务可能只在本地服务器上暴露,并且无法通过外部网络访问。
举例:
某些服务(如数据库、管理面板、或调试接口)会绑定在 127.0.0.1 上,因为它们不希望被暴露到外部网络,认为这些内部服务是安全的,只有本地系统可以访问。
然而,在 SSRF 攻击中,攻击者可以通过服务器发起请求,访问这些本地服务,并获取内部资源。例如:
/flag.php 文件可能在服务器的文件系统上可访问,且只有本地请求能访问到它。
内网资源的暴露
在很多应用中,/flag.php 或类似的敏感资源仅对内网或本地访问开放,不会对外网用户公开。例如:
竞赛环境(CTF)中的 Flag 可能被放置在一个本地可访问的路径中,且这些资源通常不会公开对外。
当服务器发出请求访问 127.0.0.1/flag.php 时,由于请求来自服务器自身,它能够绕过防火墙或权限限制,直接获取到敏感信息。
缺乏对本地请求的限制
一些服务器内部没有对本地请求进行足够的访问控制,因此即使 /flag.php 是敏感文件,只要请求是从本地发出的,服务器可能会直接返回文件内容。例如:
本地的 /flag.php 文件可能通过服务器应用返回敏感的 flag 值,原本是给管理员或内部服务使用的。
攻击者通过 SSRF,可以利用服务器来替他们发送请求访问这些文件,从而获得敏感数据。
服务的信任模型
许多系统内部服务、API 或应用依赖于信任模型,即假设来自本地的请求是可信的。例如:
内部系统可能通过 127.0.0.1 或 localhost 来提供管理功能或调试接口,而这些接口默认不会进行强认证,因为假设只有管理员能从本地访问这些接口。
SSRF 攻击绕过了这种信任模型,使得攻击者可以伪装成本地用户,发起对本地资源的请求。
http://127.0.0.1/flag.php与:http://foo@127.0.0.1:80 @www.baidu.com/flag.php的区别在哪里?
http://127.0.0.1/flag.php 和 http://foo@127.0.0.1:80@www.baidu.com/flag.php 之间的区别主要体现URL 解析方式、使用 @ 符号的目的,以及可能的攻击手法。让我们分别分析两者的不同点:
直接访问本地资源:http://127.0.0.1/flag.php
这个 URL 是标准的访问方式,目标是服务器自身的本地资源(127.0.0.1)上的 /flag.php 文件。
127.0.0.1 是本地回环地址,表示请求直接发往本地主机(服务器本身)。
服务器会解析这个 URL 并向其本地文件 /flag.php 发起请求,若存在该文件并且可访问,服务器会返回文件的内容。
使用场景:这种 URL 通常在 SSRF(Server-Side Request Forgery)攻击中利用,攻击者诱导服务器访问自身的敏感资源(例如 /flag.php)。
利用双 @ 符号混淆解析:http://foo@127.0.0.1:80@www.baidu.com/flag.php
这个 URL 的构造方式是利用了 URL 解析器对 @ 符号的处理方式,试图混淆实际的请求地址。
foo@127.0.0.1:80:这是用户认证信息 (foo) 和目标地址 (127.0.0.1:80) 的一部分。
在 URL 规范中,foo@ 通常表示用户名,用于认证访问服务器。
这个部分会被 URL 解析器解释为要访问 127.0.0.1,同时使用 foo 作为用户名。
第二个 @ 符号后的 www.baidu.com/flag.php:
URL 中的第二个 @ 符号实际上会被 URL 解析器忽略,主要目的是造成混淆。
根据标准 URL 解析,www.baidu.com/flag.php 只会被当作路径的一部分,而不会被当作真正的主机地址。
实际解析的结果:主机仍然是 127.0.0.1,请求的路径为 /flag.php。
使用场景:这个双 @ 技巧常见于某些 SSRF 攻击中,攻击者利用这种 URL 混淆机制绕过应用的安全防护。例如:
某些安全检查可能只针对 URL 中的主机名部分进行过滤,以为目标是 www.baidu.com,却没有意识到服务器实际仍在请求 127.0.0.1。
区别总结
直接访问 vs 混淆:
http://127.0.0.1/flag.php 直接访问本地资源,没有任何混淆,明确表示请求发送到本地的 127.0.0.1。
http://foo@127.0.0.1:80@www.baidu.com/flag.php 利用了 URL 的结构,通过双 @ 符号混淆,意图让应用程序或防火墙误认为目标是 www.baidu.com,但实际请求仍然指向 127.0.0.1。
绕过安全检查:
http://foo@127.0.0.1:80@www.baidu.com/flag.php 中的第二个 @ 符号,通常是用来绕过安全防护机制(如 URL 过滤器)的。例如,某些安全检查可能只对主机名进行过滤,认为 www.baidu.com 是安全的域名,从而绕过了对本地回环地址 127.0.0.1 的阻止。
攻击手段:
http://127.0.0.1/flag.php 是直接的 SSRF 攻击,目标清晰。
http://foo@127.0.0.1:80@www.baidu.com/flag.php 则是在攻击时添加了 URL 混淆,可能用来绕过一些弱的安全机制或应用层过滤,最终仍然对 127.0.0.1 发起请求。
为什么能获取到 Flag?
在这两种情况下,最终目标都是服务器上的本地资源 /flag.php:
在第一个 URL 中,服务器直接向自身发起请求,读取并返回 /flag.php 的内容。
在第二个 URL 中,通过构造双 @,服务器可能会绕过一些防护机制(如针对外网域名的限制),最终仍然向 127.0.0.1 发起请求,成功读取 /flag.php。
两者最终的结果都是让服务器自身访问了 127.0.0.1 的 flag.php 文件,进而泄露了 flag。
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。