mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/network-services-pentesting/pentesting-web/nginx.md'] t
This commit is contained in:
parent
caedef470a
commit
c3124de418
BIN
src/images/nginx_try_files.png
Normal file
BIN
src/images/nginx_try_files.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 190 KiB |
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
## Missing root location <a href="#missing-root-location" id="missing-root-location"></a>
|
## Missing root location <a href="#missing-root-location" id="missing-root-location"></a>
|
||||||
|
|
||||||
Nginx 서버를 구성할 때, **root directive**는 파일이 제공되는 기본 디렉토리를 정의함으로써 중요한 역할을 합니다. 아래 예를 고려해 보십시오:
|
Nginx 서버를 구성할 때, **root directive**는 파일이 제공되는 기본 디렉토리를 정의함으로써 중요한 역할을 합니다. 아래의 예를 고려해 보십시오:
|
||||||
```bash
|
```bash
|
||||||
server {
|
server {
|
||||||
root /etc/nginx;
|
root /etc/nginx;
|
||||||
@ -16,7 +16,7 @@ proxy_pass http://127.0.0.1:8080/;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
이 구성에서 `/etc/nginx`는 루트 디렉토리로 지정됩니다. 이 설정은 `/hello.txt`와 같은 지정된 루트 디렉토리 내의 파일에 대한 접근을 허용합니다. 그러나 특정 위치(`location /hello.txt`)만 정의되어 있다는 점에 유의해야 합니다. 루트 위치(`location / {...}`)에 대한 구성은 없습니다. 이 누락은 루트 지시어가 전역적으로 적용되어 요청이 루트 경로 `/`에서 `/etc/nginx` 아래의 파일에 접근할 수 있게 함을 의미합니다.
|
이 구성에서 `/etc/nginx`는 루트 디렉토리로 지정됩니다. 이 설정은 `/hello.txt`와 같은 지정된 루트 디렉토리 내의 파일에 대한 접근을 허용합니다. 그러나 특정 위치(`location /hello.txt`)만 정의되어 있다는 점이 중요합니다. 루트 위치(`location / {...}`)에 대한 구성은 없습니다. 이 누락은 루트 지시어가 전역적으로 적용됨을 의미하며, 루트 경로 `/`에 대한 요청이 `/etc/nginx` 아래의 파일에 접근할 수 있게 합니다.
|
||||||
|
|
||||||
이 구성에서 중요한 보안 고려 사항이 발생합니다. `GET /nginx.conf`와 같은 간단한 `GET` 요청은 `/etc/nginx/nginx.conf`에 위치한 Nginx 구성 파일을 제공함으로써 민감한 정보를 노출할 수 있습니다. 루트를 `/etc`와 같은 덜 민감한 디렉토리로 설정하면 이 위험을 완화할 수 있지만, 여전히 다른 중요한 파일, 다른 구성 파일, 접근 로그 및 HTTP 기본 인증에 사용되는 암호화된 자격 증명에 대한 의도치 않은 접근을 허용할 수 있습니다.
|
이 구성에서 중요한 보안 고려 사항이 발생합니다. `GET /nginx.conf`와 같은 간단한 `GET` 요청은 `/etc/nginx/nginx.conf`에 위치한 Nginx 구성 파일을 제공함으로써 민감한 정보를 노출할 수 있습니다. 루트를 `/etc`와 같은 덜 민감한 디렉토리로 설정하면 이 위험을 완화할 수 있지만, 여전히 다른 중요한 파일, 다른 구성 파일, 접근 로그 및 HTTP 기본 인증에 사용되는 암호화된 자격 증명에 대한 의도치 않은 접근을 허용할 수 있습니다.
|
||||||
|
|
||||||
@ -91,9 +91,9 @@ Connection: keep-alive
|
|||||||
Location: https://example.com/
|
Location: https://example.com/
|
||||||
Detectify: clrf
|
Detectify: clrf
|
||||||
```
|
```
|
||||||
CRLF 주입 및 응답 분할의 위험에 대해 더 알아보려면 [https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/](https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/)를 방문하세요.
|
CRLF 주입 및 응답 분할의 위험에 대해 더 알아보세요 [https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/](https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/).
|
||||||
|
|
||||||
또한 이 기술은 [**이 발표에서 설명됩니다**](https://www.youtube.com/watch?v=gWQyWdZbdoY&list=PL0xCSYnG_iTtJe2V6PQqamBF73n7-f1Nr&index=77) 취약한 예제와 탐지 메커니즘과 함께. 예를 들어, 블랙박스 관점에서 이 잘못된 구성을 탐지하기 위해 다음 요청을 사용할 수 있습니다:
|
또한 이 기술은 [**이 강의에서 설명됩니다**](https://www.youtube.com/watch?v=gWQyWdZbdoY&list=PL0xCSYnG_iTtJe2V6PQqamBF73n7-f1Nr&index=77) 취약한 예제와 탐지 메커니즘과 함께. 예를 들어, 블랙박스 관점에서 이 잘못된 구성을 탐지하기 위해 다음 요청을 사용할 수 있습니다:
|
||||||
|
|
||||||
- `https://example.com/%20X` - 모든 HTTP 코드
|
- `https://example.com/%20X` - 모든 HTTP 코드
|
||||||
- `https://example.com/%20H` - 400 잘못된 요청
|
- `https://example.com/%20H` - 400 잘못된 요청
|
||||||
@ -105,9 +105,9 @@ CRLF 주입 및 응답 분할의 위험에 대해 더 알아보려면 [https://b
|
|||||||
- `http://company.tld/%20HTTP/1.1%0D%0AXXXX:%20x` - 모든 HTTP 코드
|
- `http://company.tld/%20HTTP/1.1%0D%0AXXXX:%20x` - 모든 HTTP 코드
|
||||||
- `http://company.tld/%20HTTP/1.1%0D%0AHost:%20x` - 400 잘못된 요청
|
- `http://company.tld/%20HTTP/1.1%0D%0AHost:%20x` - 400 잘못된 요청
|
||||||
|
|
||||||
그 발표에서 발견된 취약한 구성 중 일부는 다음과 같습니다:
|
그 강의에서 발견된 취약한 구성 중 일부는 다음과 같습니다:
|
||||||
|
|
||||||
- 최종 URL에서 **`$uri`**가 그대로 설정된 것을 주목하세요.
|
- 최종 URL에서 **`$uri`**가 그대로 설정된 방법을 주목하세요.
|
||||||
```
|
```
|
||||||
location ^~ /lite/api/ {
|
location ^~ /lite/api/ {
|
||||||
proxy_pass http://lite-backend$uri$is_args$args;
|
proxy_pass http://lite-backend$uri$is_args$args;
|
||||||
@ -127,7 +127,7 @@ proxy_pass https://company-bucket.s3.amazonaws.com$uri;
|
|||||||
```
|
```
|
||||||
### Any variable
|
### Any variable
|
||||||
|
|
||||||
**사용자 제공 데이터**가 특정 상황에서 **Nginx 변수**로 처리될 수 있다는 것이 발견되었습니다. 이 행동의 원인은 다소 불분명하지만, 드물지 않으며 검증하기도 간단하지 않습니다. 이 이상 현상은 HackerOne의 보안 보고서에서 강조되었으며, [여기](https://hackerone.com/reports/370094)에서 확인할 수 있습니다. 오류 메시지에 대한 추가 조사는 [Nginx 코드베이스의 SSI 필터 모듈](https://github.com/nginx/nginx/blob/2187586207e1465d289ae64cedc829719a048a39/src/http/modules/ngx_http_ssi_filter_module.c#L365) 내에서 발생하는 것을 확인하게 되었으며, 서버 사이드 인클루드(SSI)가 근본 원인으로 지목되었습니다.
|
**사용자 제공 데이터**가 특정 상황에서 **Nginx 변수**로 처리될 수 있다는 것이 발견되었습니다. 이 행동의 원인은 다소 불분명하지만, 드물지 않으며 검증하기도 간단하지 않습니다. 이 이상 현상은 HackerOne의 보안 보고서에서 강조되었으며, [여기서](https://hackerone.com/reports/370094) 확인할 수 있습니다. 오류 메시지에 대한 추가 조사는 [Nginx 코드베이스의 SSI 필터 모듈](https://github.com/nginx/nginx/blob/2187586207e1465d289ae64cedc829719a048a39/src/http/modules/ngx_http_ssi_filter_module.c#L365) 내에서 발생하는 것을 확인하게 되었으며, 서버 사이드 인클루드(SSI)가 근본 원인으로 지목되었습니다.
|
||||||
|
|
||||||
이 **잘못된 구성**을 **탐지하기 위해**, 다음 명령을 실행할 수 있으며, 이는 변수 출력을 테스트하기 위해 referer 헤더를 설정하는 것을 포함합니다:
|
이 **잘못된 구성**을 **탐지하기 위해**, 다음 명령을 실행할 수 있으며, 이는 변수 출력을 테스트하기 위해 referer 헤더를 설정하는 것을 포함합니다:
|
||||||
```bash
|
```bash
|
||||||
@ -135,9 +135,59 @@ $ curl -H ‘Referer: bar’ http://localhost/foo$http_referer | grep ‘foobar
|
|||||||
```
|
```
|
||||||
이 잘못된 구성에 대한 스캔 결과, 사용자가 Nginx 변수를 출력할 수 있는 여러 사례가 발견되었습니다. 그러나 취약한 사례의 수가 감소한 것은 이 문제를 패치하기 위한 노력이 어느 정도 성공적이었다는 것을 시사합니다.
|
이 잘못된 구성에 대한 스캔 결과, 사용자가 Nginx 변수를 출력할 수 있는 여러 사례가 발견되었습니다. 그러나 취약한 사례의 수가 감소한 것은 이 문제를 패치하기 위한 노력이 어느 정도 성공적이었다는 것을 시사합니다.
|
||||||
|
|
||||||
|
### $URI$ARGS 변수를 사용한 try_files
|
||||||
|
|
||||||
|
다음 Nginx 잘못된 구성은 LFI 취약점으로 이어질 수 있습니다:
|
||||||
|
```
|
||||||
|
location / {
|
||||||
|
try_files $uri$args $uri$args/ /index.html;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
우리 구성에서는 지정된 순서로 파일의 존재 여부를 확인하는 데 사용되는 `try_files` 지시어가 있습니다. Nginx는 찾은 첫 번째 파일을 제공합니다. `try_files` 지시어의 기본 구문은 다음과 같습니다:
|
||||||
|
```
|
||||||
|
try_files file1 file2 ... fileN fallback;
|
||||||
|
```
|
||||||
|
Nginx는 지정된 순서로 각 파일의 존재 여부를 확인합니다. 파일이 존재하면 즉시 제공됩니다. 지정된 파일이 모두 존재하지 않으면 요청은 대체 옵션으로 전달되며, 이는 다른 URI 또는 특정 오류 페이지일 수 있습니다.
|
||||||
|
|
||||||
|
그러나 이 지시문에서 `$uri$args` 변수를 사용할 때, Nginx는 요청 URI와 쿼리 문자열 인수를 결합하여 일치하는 파일을 찾으려고 시도합니다. 따라서 이 구성을 악용할 수 있습니다:
|
||||||
|
```
|
||||||
|
http {
|
||||||
|
server {
|
||||||
|
root /var/www/html/public;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri$args $uri$args/ /index.html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
다음 페이로드:
|
||||||
|
```
|
||||||
|
GET /?../../../../../../../../etc/passwd HTTP/1.1
|
||||||
|
Host: example.com
|
||||||
|
```
|
||||||
|
우리의 페이로드를 사용하여 Nginx 구성에서 정의된 루트 디렉토리를 탈출하고 `/etc/passwd` 파일을 로드할 것입니다. 디버그 로그에서 Nginx가 파일을 시도하는 방식을 관찰할 수 있습니다:
|
||||||
|
```
|
||||||
|
...SNIP...
|
||||||
|
|
||||||
|
2025/07/11 15:49:16 [debug] 79694#79694: *4 trying to use file: "/../../../../../../../../etc/passwd" "/var/www/html/public/../../../../../../../../etc/passwd"
|
||||||
|
2025/07/11 15:49:16 [debug] 79694#79694: *4 try file uri: "/../../../../../../../../etc/passwd"
|
||||||
|
|
||||||
|
...SNIP...
|
||||||
|
|
||||||
|
2025/07/11 15:49:16 [debug] 79694#79694: *4 http filename: "/var/www/html/public/../../../../../../../../etc/passwd"
|
||||||
|
|
||||||
|
...SNIP...
|
||||||
|
|
||||||
|
2025/07/11 15:49:16 [debug] 79694#79694: *4 HTTP/1.1 200 OK
|
||||||
|
|
||||||
|
```
|
||||||
|
Nginx의 위에서 언급한 구성에 대한 PoC:
|
||||||
|

|
||||||
|
|
||||||
## 원시 백엔드 응답 읽기
|
## 원시 백엔드 응답 읽기
|
||||||
|
|
||||||
Nginx는 `proxy_pass`를 통해 백엔드에서 생성된 오류 및 HTTP 헤더를 가로채는 기능을 제공하여 내부 오류 메시지와 헤더를 숨기도록 설계되었습니다. 이는 Nginx가 백엔드 오류에 대한 사용자 정의 오류 페이지를 제공함으로써 이루어집니다. 그러나 Nginx가 잘못된 HTTP 요청을 처리할 때 문제가 발생합니다. 이러한 요청은 수신된 대로 백엔드로 전달되며, 백엔드의 원시 응답은 Nginx의 개입 없이 클라이언트에게 직접 전송됩니다.
|
Nginx는 `proxy_pass`를 통해 백엔드에서 생성된 오류 및 HTTP 헤더를 가로채는 기능을 제공하여 내부 오류 메시지와 헤더를 숨기도록 설계되었습니다. 이는 Nginx가 백엔드 오류에 대한 사용자 정의 오류 페이지를 제공함으로써 이루어집니다. 그러나 Nginx가 유효하지 않은 HTTP 요청을 처리할 때 문제가 발생합니다. 이러한 요청은 수신된 대로 백엔드로 전달되며, 백엔드의 원시 응답은 Nginx의 개입 없이 클라이언트에게 직접 전송됩니다.
|
||||||
|
|
||||||
uWSGI 애플리케이션을 포함한 예시 시나리오를 고려해 보십시오:
|
uWSGI 애플리케이션을 포함한 예시 시나리오를 고려해 보십시오:
|
||||||
```python
|
```python
|
||||||
@ -162,13 +212,13 @@ proxy_hide_header Secret-Header;
|
|||||||
|
|
||||||
기본적으로 Nginx의 **`merge_slashes` 지시어**는 **`on`**으로 설정되어 있어 URL의 여러 개의 슬래시를 하나의 슬래시로 압축합니다. 이 기능은 URL 처리를 간소화하지만, Nginx 뒤에 있는 애플리케이션에서 특히 로컬 파일 포함(LFI) 공격에 취약한 경우 취약점을 숨길 수 있습니다. 보안 전문가 **Danny Robinson과 Rotem Bar**는 Nginx가 리버스 프록시로 작동할 때 이 기본 동작과 관련된 잠재적 위험을 강조했습니다.
|
기본적으로 Nginx의 **`merge_slashes` 지시어**는 **`on`**으로 설정되어 있어 URL의 여러 개의 슬래시를 하나의 슬래시로 압축합니다. 이 기능은 URL 처리를 간소화하지만, Nginx 뒤에 있는 애플리케이션에서 특히 로컬 파일 포함(LFI) 공격에 취약한 경우 취약점을 숨길 수 있습니다. 보안 전문가 **Danny Robinson과 Rotem Bar**는 Nginx가 리버스 프록시로 작동할 때 이 기본 동작과 관련된 잠재적 위험을 강조했습니다.
|
||||||
|
|
||||||
이러한 위험을 완화하기 위해, 이러한 취약점에 취약한 애플리케이션에 대해 **`merge_slashes` 지시어를 off로 설정하는 것이 권장됩니다**. 이는 Nginx가 URL 구조를 변경하지 않고 애플리케이션에 요청을 전달하도록 보장하여 기본적인 보안 문제를 숨기지 않도록 합니다.
|
이러한 위험을 완화하기 위해, 이러한 취약점에 취약한 애플리케이션에 대해 **`merge_slashes` 지시어를 끄는 것이 권장됩니다**. 이는 Nginx가 URL 구조를 변경하지 않고 애플리케이션에 요청을 전달하도록 보장하여 기본 보안 문제를 숨기지 않도록 합니다.
|
||||||
|
|
||||||
자세한 내용은 [Danny Robinson과 Rotem Bar](https://medium.com/appsflyer/nginx-may-be-protecting-your-applications-from-traversal-attacks-without-you-even-knowing-b08f882fd43d)를 확인하세요.
|
자세한 내용은 [Danny Robinson과 Rotem Bar](https://medium.com/appsflyer/nginx-may-be-protecting-your-applications-from-traversal-attacks-without-you-even-knowing-b08f882fd43d)를 확인하세요.
|
||||||
|
|
||||||
### **Maclicious Response Headers**
|
### **Maclicious Response Headers**
|
||||||
|
|
||||||
[**이 글**](https://mizu.re/post/cors-playground)에서 보여준 바와 같이, 웹 서버의 응답에 존재하는 특정 헤더는 Nginx 프록시의 동작을 변경할 수 있습니다. 이들에 대한 정보는 [**문서에서**](https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/) 확인할 수 있습니다:
|
[**이 글**](https://mizu.re/post/cors-playground)에서 보여준 바와 같이, 웹 서버의 응답에 존재하는 특정 헤더는 Nginx 프록시의 동작을 변경할 수 있습니다. 이들은 [**문서에서 확인할 수 있습니다**](https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/):
|
||||||
|
|
||||||
- `X-Accel-Redirect`: Nginx가 요청을 지정된 위치로 내부 리디렉션하도록 지시합니다.
|
- `X-Accel-Redirect`: Nginx가 요청을 지정된 위치로 내부 리디렉션하도록 지시합니다.
|
||||||
- `X-Accel-Buffering`: Nginx가 응답을 버퍼링할지 여부를 제어합니다.
|
- `X-Accel-Buffering`: Nginx가 응답을 버퍼링할지 여부를 제어합니다.
|
||||||
@ -176,11 +226,11 @@ proxy_hide_header Secret-Header;
|
|||||||
- `X-Accel-Expires`: X-Accel-Redirect를 사용할 때 응답의 만료 시간을 설정합니다.
|
- `X-Accel-Expires`: X-Accel-Redirect를 사용할 때 응답의 만료 시간을 설정합니다.
|
||||||
- `X-Accel-Limit-Rate`: X-Accel-Redirect를 사용할 때 응답의 전송 속도를 제한합니다.
|
- `X-Accel-Limit-Rate`: X-Accel-Redirect를 사용할 때 응답의 전송 속도를 제한합니다.
|
||||||
|
|
||||||
예를 들어, 헤더 **`X-Accel-Redirect`**는 Nginx에서 내부 **리디렉션**을 유발합니다. 따라서 **`root /`**와 같은 Nginx 구성이 있고 웹 서버의 응답에 **`X-Accel-Redirect: .env`**가 포함되면 Nginx는 **`/.env`**의 내용을 전송하게 됩니다 (경로 탐색).
|
예를 들어, 헤더 **`X-Accel-Redirect`**는 Nginx에서 내부 **리디렉션**을 발생시킵니다. 따라서 **`root /`**와 같은 설정을 가진 Nginx 구성과 웹 서버의 응답에 **`X-Accel-Redirect: .env`**가 포함되면 Nginx는 **`/.env`**의 내용을 전송하게 됩니다 (경로 탐색).
|
||||||
|
|
||||||
### **Map Directive의 기본값**
|
### **Map Directive의 기본값**
|
||||||
|
|
||||||
**Nginx 구성**에서 `map` 지시어는 종종 **인증 제어**에서 역할을 합니다. 일반적인 실수는 **기본** 값을 지정하지 않는 것으로, 이는 무단 접근으로 이어질 수 있습니다. 예를 들어:
|
**Nginx 구성**에서 `map` 지시어는 종종 **권한 제어**에서 중요한 역할을 합니다. 일반적인 실수는 **기본** 값을 지정하지 않는 것으로, 이는 무단 접근으로 이어질 수 있습니다. 예를 들어:
|
||||||
```yaml
|
```yaml
|
||||||
http {
|
http {
|
||||||
map $uri $mappocallow {
|
map $uri $mappocallow {
|
||||||
@ -239,11 +289,11 @@ deny all;
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> `proxy_pass`가 `http://backend:9999/socket.io`와 같은 특정 **경로**를 가리키고 있더라도, 연결은 `http://backend:9999`와 설정되므로 **해당 내부 엔드포인트 내의 다른 경로에 연락할 수 있습니다. 따라서 proxy_pass의 URL에 경로가 지정되어 있는지는 중요하지 않습니다.**
|
> `proxy_pass`가 `http://backend:9999/socket.io`와 같은 특정 **경로**를 가리키고 있더라도, 연결은 `http://backend:9999`로 설정되므로 **내부 엔드포인트 내의 다른 경로에 연락할 수 있습니다. 따라서 proxy_pass의 URL에 경로가 지정되어 있는지는 중요하지 않습니다.**
|
||||||
|
|
||||||
## 직접 해보세요
|
## 직접 해보세요
|
||||||
|
|
||||||
Detectify는 이 기사에서 논의된 몇 가지 잘못된 구성으로 취약한 Nginx 테스트 서버를 설정하기 위해 Docker를 사용할 수 있는 GitHub 리포지토리를 만들었습니다. 직접 찾아보세요!
|
Detectify는 이 기사에서 논의된 몇 가지 잘못된 구성으로 자신의 취약한 Nginx 테스트 서버를 설정하기 위해 Docker를 사용할 수 있는 GitHub 리포지토리를 만들었습니다. 직접 찾아보세요!
|
||||||
|
|
||||||
[https://github.com/detectify/vulnerable-nginx](https://github.com/detectify/vulnerable-nginx)
|
[https://github.com/detectify/vulnerable-nginx](https://github.com/detectify/vulnerable-nginx)
|
||||||
|
|
||||||
@ -257,7 +307,7 @@ Gixy는 Nginx 구성을 분석하는 도구입니다. Gixy의 주요 목표는
|
|||||||
|
|
||||||
Nginxpwner는 일반적인 Nginx 잘못된 구성 및 취약점을 찾기 위한 간단한 도구입니다.
|
Nginxpwner는 일반적인 Nginx 잘못된 구성 및 취약점을 찾기 위한 간단한 도구입니다.
|
||||||
|
|
||||||
## 참고 문헌
|
## 참고자료
|
||||||
|
|
||||||
- [**https://blog.detectify.com/2020/11/10/common-nginx-misconfigurations/**](https://blog.detectify.com/2020/11/10/common-nginx-misconfigurations/)
|
- [**https://blog.detectify.com/2020/11/10/common-nginx-misconfigurations/**](https://blog.detectify.com/2020/11/10/common-nginx-misconfigurations/)
|
||||||
- [**http://blog.zorinaq.com/nginx-resolver-vulns/**](http://blog.zorinaq.com/nginx-resolver-vulns/)
|
- [**http://blog.zorinaq.com/nginx-resolver-vulns/**](http://blog.zorinaq.com/nginx-resolver-vulns/)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user