社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  NGINX

nginx deny限制路径绕过

白帽子左一 • 1 年前 • 392 次点击  

扫码领资料

获网安教程



文章来源: https://xz.aliyun.com/t/14966

nginx deny限制路径绕过

简介

这篇文章中,分享一个技巧。解析问题来绕过路由限制

环境记录

采取docker-compose 部署

  • 部署nginx-docker

mkdir nginx_test
cd nginx_test
touch docker-compose.yml
mkdir -p nginx/conf.d
touch nginx/conf.d/default.conf
  • docker-compose.yml

version: '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.conf

server {
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 class Main {
public static void main(String[] args) {
String text = " Hello, World! ";
String trimmedText = text.trim();
System.out.println(trimmedText); // 输出: "Hello, World!"
}
}
  • C#

C# 中的 Trim 方法用于去除字符串两端的空白字符。

using System;

class Program {
static void Main() {
string text = " Hello, World! ";
string trimmedText = text.Trim();
Console.WriteLine(trimmedText); // 输出: "Hello, World!"
}
}
  • PHP

PHP 中的 trim 函数用于去除字符串两端的空白字符。

$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 发送请求,该请求也将被403

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;
}
}

写在最后

本文介绍的只是一些初步的相关知识,后续应该会继续写较为深入的版本

参考

https://github.com/detectify/vulnerable-nginx

https://rafa.hashnode.dev/exploiting-http-parsers-inconsistencies


声明:⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。所有渗透都需获取授权

如果你是一个网络安全爱好者,欢迎加入我的知识星球:zk安全知识星球,我们一起进步一起学习。星球不定期会分享一些前言漏洞,每周安全面试经验、SRC实战纪实等文章分享,微信识别二维码,只需25,即可加入,如不满意,72 小时内可在 App 内无条件自助退款。


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/172710
 
392 次点击