点击上方[蓝字],关注我们
本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者及本公众号团队不为此承担任何责任。
文章正文
简介
这篇文章中,分享一个技巧。解析问题来绕过路由限制
环境记录
采取docker-compose 部署
-
• 部署nginx-dockermkdir nginx_test cd nginx_test touch docker-compose.yml mkdir -p nginx/conf.d touch nginx/conf.d/default.conf
-
• docker-compose.ymlversion: '3' services: nginx: image: nginx:latest ports: - "80:80" volumes: - ./nginx/conf.d:/etc/nginx/conf.d - ./html:/usr/share/nginx/html
-
• nginx/conf.d default.confserver { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } }
-
• nodejs、django会在下文说明
从nginx解析问题开始
Nginx
是一个高性能的 HTTP
服务器和反向代理服务器,广泛应用于网站托管和负载均衡。解析问题通常指Nginx
在处理客户端请求时遇到的各种安全问题
Missing root location
-
• 在 Nginx 配置中,
root
指令用于指定请求静态文件的根目录。缺少root
指令可能会导致请求无法找到正确的文件路径,root 指令通过定义提供文件的基本目录发挥着关键作用 -
• 问题配置举例server { root /etc/nginx; location /hello.txt { try_files $uri $uri/ =404; proxy_pass http://127.0.0.1:8080/; } }
如上,这个nginx配置例子,/etc/nginx
被指定为根目录。此设置允许访问指定根目录中的文件,例如 /hello.txt
。但是,配置中并没有根位置 ( location / {...}
) 的配置。意味着 root 指令全局适用,允许对根路径 /
的请求访问 /etc/nginx
下的文件,攻击者可通过提供位于 /etc/nginx/nginx.conf
的 Nginx
配置文件来暴露敏感信息
攻击举例:
Alias LFI Misconfiguration
在Nginx
的配置文件中,存在一类本地文件包含 (LFI) 的漏洞,如下demo配置:
location /imgs {
alias /path/images/;
}
-
• 攻击者payload:
/imgs../flag.txt
会解析为/path/images/../flag.txt
,从而进行目录穿越&绕过限制获取敏感文件内容 -
• 修复方式location /imgs/ { alias /path/images/; }
Unsafe path restriction 限制路径绕过
本文主要分享如下配置的绕过
location = /admin {
deny all;
}
location = /admin/ {
deny all;
}
-
• 讲在前面:HTTP 协议在 Web 应用程序中发挥着重要作用,但是,不同框架的 HTTP 解析器的实现可能会引入细微的差异,从而导致潜在的安全漏洞。比如:nginx+uwsgi+flask 框架。也就是利用各个框架解析的差异,造成路径限制绕过
-
• 说回这个配置,nginx拒绝对
/admin
的http访问,如果web用户访问此路径,则会403 error
trim方法
在编程中,trim
函数用于去除字符串两端的空白字符(例如空格、制表符、换行符等)是一个常用的字符串操作,对于清理和规范化输入数据非常有用。不同编程语言的 trim
函数可能名称略有不同,但功能基本相同。下面介绍常见编程语言中 trim
函数的使用示例
-
• Python
Python 中的 strip
方法用于去除字符串两端的空白字符。
text = " Hello, World! "
trimmed_text = text.strip()
print(trimmed_text) # 输出: "Hello, World!"
-
• JavaScript
JavaScript 中的 trim
方法用于去除字符串两端的空白字符。
let text = " Hello, World! ";
let trimmedText = text.trim();
console.log(trimmedText); // 输出: "Hello, World!"
-
• Java
Java 中的 trim
方法用于去除字符串两端的空白字符。
public classMain{
publicstaticvoid main(String[] args){
String text =" Hello, World! ";
String trimmedText = text.trim();
System.out.println(trimmedText);// 输出: "Hello, World!"
}
}
-
• C#
C# 中的 Trim
方法用于去除字符串两端的空白字符。
using System;
classProgram{
staticvoidMain(){
string text =" Hello, World! ";
string trimmedText = text.Trim();
Console.WriteLine(trimmedText);// 输出: "Hello, World!"
}
}
-
• PHP
PHP 中的 trim
函数用于去除字符串两端的空白字符。
<?php
$text = " Hello, World! ";
$trimmed_text = trim($text);
echo $trimmed_text; // 输出: "Hello, World!"
?>
-
• Ruby
Ruby 中的 strip
方法用于去除字符串两端的空白字符。
text = " Hello, World! "
trimmed_text = text.strip
puts trimmed_text # 输出: "Hello, World!"
-
• Go
Go 语言中没有内置的 trim
方法,但可以使用 strings
包中的 TrimSpace
函数。
package main
import(
"fmt"
"strings"
)
func main(){
text :=" Hello, World! "
trimmedText := strings.TrimSpace(text)
fmt.Println(trimmedText)// 输出: "Hello, World!"
}
-
• SQL
在 SQL 中,可以使用 TRIM
函数去除字符串两端的空白字符。
SELECT TRIM(' Hello, World! ') AS trimmed_text;
本文主要介绍python 和 nodejs作为后台此类问题绕过情况
-
• 虽说每种语言都是借助trim方法做一定的格式化字符串操作,但每种语言处理逻辑又有不同,例如:python strip() 删除字符
x85
,而 JavaScript 则不使用trim()
删除字符x85
s = "xa0 laotie233 x85" print(bytes(s.encode())) print(bytes(s.strip().encode()))
s = "xa0 laotie233 x85"
s.trim()
nodejs绕过
-
• nodejs后台服务器代码const express = require('express'); const app = express(); const port = 3000;// 中间件示例:记录请求日志 app.use((req, res, next) => { console.log(
${req.method} ${req.url}
); next(); });// 中间件示例:解析 JSON 请求体 app.use(express.json());// /admin 路由 app.get('/admin', (req, res) => { return res.send('ADMIN'); });// 404 错误处理 app.use((req, res, next) => { res.status(404).send('404 Not Found'); });// 全局错误处理 app.use((err, req, res, next) => { console.error(err.stack); res.status(500).send('Something broke!'); });app.listen(port, '0.0.0.0', () => { console.log(Server is running on http://0.0.0.0:${port}
); });
-
• nginx 外部访问server { listen 80; server_name localhost; location = /admin { deny all; } location = /admin/ { deny all; } # location / { # root /usr/share/nginx/html; # index index.html index.htm; # } location / { proxy_pass http://192.168.56.130:3000; } }
-
• 绕过姿势:按照
trim()
逻辑,Node.js 会去除路径名中的字符xA0
,但 Nginx 认为它们作为 URL 的一部分 -
• 绕过poc如下
-
• 成功绕过
python类后台绕过
-
• 这里拿
django
举例
-
• 代码示例
-
• nginx配置同理server { listen 80; server_name localhost; location = /admin { deny all; } location = /admin/ { deny all; } # location / { # root /usr/share/nginx/html; # index index.html index.htm; # } location / { proxy_pass http://192.168.56.130:8000; } }
-
• 绕过姿势
修复方式
location ~* ^/admin {
deny all;
}
-
• 这块的代码
~
表达式正则匹配路径名/admin
,不过有损的是,如果用户向/admin_test
发送请求,该请求也将被403server { listen 80; server_name localhost; location ~* ^/admin { deny all; } location ~* ^/admin/ { deny all; } # location / { # root /usr/share/nginx/html; # index index.html index.htm; # } location / { proxy_pass http://192.168.56.130:8000; } }
写在最后
本文介绍的只是一些初步的相关知识,后续应该会继续写较为深入的版本
参考
https://github.com/detectify/vulnerable-nginx
https://rafa.hashnode.dev/exploiting-http-parsers-inconsistencies
文章来源:https://xz.aliyun.com/t/14966
技术交流
原文始发于微信公众号(Z2O安全攻防):nginx deny限制路径绕过
原文始发于微信公众号(Z2O安全攻防):nginx deny限制路径绕过
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论