hacktricks/network-services-pentesting/pentesting-web/nginx.md

20 KiB
Raw Blame History

Nginx

{% hint style="success" %} Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks
{% endhint %}

취약점 평가 및 침투 테스트를 위한 즉시 사용 가능한 설정. 20개 이상의 도구 및 기능을 사용하여 어디서나 전체 침투 테스트를 실행하세요. 우리는 침투 테스터를 대체하지 않습니다 - 우리는 그들이 더 깊이 파고들고, 쉘을 터뜨리고, 재미를 느낄 수 있도록 맞춤형 도구, 탐지 및 악용 모듈을 개발합니다.

{% embed url="https://pentest-tools.com/?utm_term=jul2024&utm_medium=link&utm_source=hacktricks&utm_campaign=spons" %}

Missing root location

Nginx 서버를 구성할 때, root 지시어는 파일이 제공되는 기본 디렉토리를 정의함으로써 중요한 역할을 합니다. 아래 예를 고려하세요:

server {
root /etc/nginx;

location /hello.txt {
try_files $uri $uri/ =404;
proxy_pass http://127.0.0.1:8080/;
}
}

이 구성에서 /etc/nginx는 루트 디렉토리로 지정됩니다. 이 설정은 /hello.txt와 같은 지정된 루트 디렉토리 내의 파일에 대한 접근을 허용합니다. 그러나 특정 위치(location /hello.txt)만 정의되어 있다는 점이 중요합니다. 루트 위치(location / {...})에 대한 구성은 없습니다. 이 누락은 루트 지시어가 전역적으로 적용되어, 루트 경로 /에 대한 요청이 /etc/nginx 아래의 파일에 접근할 수 있게 합니다.

이 구성에서 중요한 보안 고려 사항이 발생합니다. GET /nginx.conf와 같은 간단한 GET 요청은 /etc/nginx/nginx.conf에 위치한 Nginx 구성 파일을 제공함으로써 민감한 정보를 노출할 수 있습니다. 루트를 /etc와 같은 덜 민감한 디렉토리로 설정하면 이 위험을 완화할 수 있지만, 여전히 다른 구성 파일, 접근 로그 및 HTTP 기본 인증에 사용되는 암호화된 자격 증명과 같은 다른 중요한 파일에 대한 의도치 않은 접근을 허용할 수 있습니다.

Alias LFI Misconfiguration

Nginx의 구성 파일에서는 "location" 지시어에 대한 면밀한 검토가 필요합니다. Local File Inclusion (LFI)로 알려진 취약점은 다음과 유사한 구성을 통해 우연히 도입될 수 있습니다:

location /imgs {
alias /path/images/;
}

이 구성은 서버가 /imgs../flag.txt와 같은 요청을 의도된 디렉토리 외부의 파일에 접근하려는 시도로 해석하기 때문에 LFI 공격에 취약합니다. 이는 실제로 /path/images/../flag.txt로 해결됩니다. 이 결함은 공격자가 웹을 통해 접근할 수 없어야 하는 서버의 파일 시스템에서 파일을 검색할 수 있게 합니다.

이 취약점을 완화하기 위해 구성은 다음과 같이 조정되어야 합니다:

location /imgs/ {
alias /path/images/;
}

더 많은 정보: https://www.acunetix.com/vulnerabilities/web/path-traversal-via-misconfigured-nginx-alias/

Accunetix 테스트:

alias../ => HTTP status code 403
alias.../ => HTTP status code 404
alias../../ => HTTP status code 403
alias../../../../../../../../../../../ => HTTP status code 400
alias../ => HTTP status code 403

안전하지 않은 경로 제한

다음 페이지를 확인하여 다음과 같은 지시문을 우회하는 방법을 알아보세요:

location = /admin {
deny all;
}

location = /admin/ {
deny all;
}

{% content-ref url="../../pentesting-web/proxy-waf-protections-bypass.md" %} proxy-waf-protections-bypass.md {% endcontent-ref %}

안전하지 않은 변수 사용 / HTTP 요청 분할

{% hint style="danger" %} 취약한 변수 $uri$document_uri가 있으며, 이를 $request_uri로 교체하여 수정할 수 있습니다.

정규 표현식도 취약할 수 있습니다:

location ~ /docs/([^/])? { … $1 … } - 취약함

location ~ /docs/([^/\s])? { … $1 … } - 취약하지 않음 (공간 확인)

location ~ /docs/(.*)? { … $1 … } - 취약하지 않음 {% endhint %}

Nginx 구성의 취약점은 아래 예제로 설명됩니다:

location / {
return 302 https://example.com$uri;
}

HTTP 요청에서 \r (캐리지 리턴) 및 \n (라인 피드) 문자는 새 줄 문자를 나타내며, 이들의 URL 인코딩 형태는 %0d%0a로 표현됩니다. 잘못 구성된 서버에 이러한 문자를 포함한 요청(예: http://localhost/%0d%0aDetectify:%20clrf)을 보내면 서버는 Detectify라는 새 헤더를 발급합니다. 이는 $uri 변수가 URL 인코딩된 새 줄 문자를 디코딩하여 응답에 예상치 못한 헤더가 포함되기 때문입니다:

HTTP/1.1 302 Moved Temporarily
Server: nginx/1.19.3
Content-Type: text/html
Content-Length: 145
Connection: keep-alive
Location: https://example.com/
Detectify: clrf

CRLF 주입 및 응답 분할의 위험에 대해 더 알아보려면 https://blog.detectify.com/2019/06/14/http-response-splitting-exploitations-and-mitigations/를 방문하세요.

또한 이 기술은 이 강의에서 설명됩니다 취약한 예제와 탐지 메커니즘과 함께. 예를 들어, 블랙박스 관점에서 이 잘못된 구성을 감지하기 위해 다음 요청을 사용할 수 있습니다:

  • https://example.com/%20X - 모든 HTTP 코드
  • https://example.com/%20H - 400 잘못된 요청

취약한 경우, 첫 번째는 "X"가 모든 HTTP 메서드이므로 반환되고, 두 번째는 H가 유효한 메서드가 아니므로 오류가 반환됩니다. 따라서 서버는 GET / H HTTP/1.1과 같은 것을 수신하게 되고, 이는 오류를 유발합니다.

또 다른 탐지 예제는 다음과 같습니다:

  • http://company.tld/%20HTTP/1.1%0D%0AXXXX:%20x - 모든 HTTP 코드
  • http://company.tld/%20HTTP/1.1%0D%0AHost:%20x - 400 잘못된 요청

그 강의에서 발견된 취약한 구성 중 일부는 다음과 같습니다:

  • 최종 URL에서 **$uri**가 그대로 설정된 방법을 주목하세요.
location ^~ /lite/api/ {
proxy_pass http://lite-backend$uri$is_args$args;
}
  • 다시 **$uri**가 URL에 있는 것을 주목하세요 (이번에는 매개변수 안에 있습니다)
location ~ ^/dna/payment {
rewrite ^/dna/([^/]+) /registered/main.pl?cmd=unifiedPayment&context=$1&native_uri=$uri break;
proxy_pass http://$back;
  • 이제 AWS S3에서
location /s3/ {
proxy_pass https://company-bucket.s3.amazonaws.com$uri;
}

Any variable

사용자 제공 데이터가 특정 상황에서 Nginx 변수로 처리될 수 있다는 것이 발견되었습니다. 이 행동의 원인은 다소 불분명하지만, 드물지 않으며 검증하기도 간단하지 않습니다. 이 이상 현상은 HackerOne의 보안 보고서에서 강조되었으며, 여기에서 확인할 수 있습니다. 오류 메시지에 대한 추가 조사는 Nginx 코드베이스의 SSI 필터 모듈 내에서 발생하는 것을 확인하게 되었으며, 서버 사이드 인클루드(SSI)가 근본 원인으로 지목되었습니다.

잘못된 구성탐지하기 위해, 다음 명령을 실행할 수 있으며, 이는 변수 출력을 테스트하기 위해 referer 헤더를 설정하는 것을 포함합니다:

$ curl -H Referer: bar http://localhost/foo$http_referer | grep foobar

이 잘못된 구성에 대한 스캔 결과, 사용자가 Nginx 변수를 출력할 수 있는 여러 사례가 발견되었습니다. 그러나 취약한 인스턴스의 수가 감소한 것은 이 문제를 패치하기 위한 노력이 어느 정도 성공적이었다는 것을 시사합니다.

원시 백엔드 응답 읽기

Nginx는 proxy_pass를 통해 백엔드에서 생성된 오류 및 HTTP 헤더를 가로채는 기능을 제공하여 내부 오류 메시지와 헤더를 숨기도록 합니다. 이는 Nginx가 백엔드 오류에 대한 사용자 정의 오류 페이지를 제공함으로써 이루어집니다. 그러나 Nginx가 잘못된 HTTP 요청을 처리할 때 문제가 발생합니다. 이러한 요청은 수신된 대로 백엔드로 전달되며, 백엔드의 원시 응답은 Nginx의 개입 없이 클라이언트에게 직접 전송됩니다.

uWSGI 애플리케이션과 관련된 예시 시나리오를 고려해 보십시오:

def application(environ, start_response):
start_response('500 Error', [('Content-Type', 'text/html'), ('Secret-Header', 'secret-info')])
return [b"Secret info, should not be visible!"]

이를 관리하기 위해 Nginx 구성에서 특정 지시어가 사용됩니다:

http {
error_page 500 /html/error.html;
proxy_intercept_errors on;
proxy_hide_header Secret-Header;
}
  • proxy_intercept_errors: 이 지시어는 Nginx가 상태 코드가 300보다 큰 백엔드 응답에 대해 사용자 정의 응답을 제공할 수 있도록 합니다. 이는 예시로 든 uWSGI 애플리케이션의 경우 500 Error 응답이 Nginx에 의해 가로채지고 처리되도록 보장합니다.
  • proxy_hide_header: 이름에서 알 수 있듯이, 이 지시어는 클라이언트로부터 지정된 HTTP 헤더를 숨겨 개인 정보 보호 및 보안을 강화합니다.

유효한 GET 요청이 이루어지면 Nginx는 이를 정상적으로 처리하여 비밀 헤더를 노출하지 않고 표준 오류 응답을 반환합니다. 그러나 유효하지 않은 HTTP 요청은 이 메커니즘을 우회하여 비밀 헤더와 오류 메시지를 포함한 원시 백엔드 응답이 노출됩니다.

merge_slashes를 off로 설정

기본적으로 Nginx의 merge_slashes 지시어는 **on**으로 설정되어 있어 URL의 여러 개의 슬래시를 하나의 슬래시로 압축합니다. 이 기능은 URL 처리를 간소화하지만, Nginx 뒤에 있는 애플리케이션에서 특히 로컬 파일 포함(LFI) 공격에 취약한 경우 취약점을 숨길 수 있습니다. 보안 전문가 Danny Robinson과 Rotem Bar는 Nginx가 리버스 프록시로 작동할 때 이 기본 동작과 관련된 잠재적 위험을 강조했습니다.

이러한 위험을 완화하기 위해, 이러한 취약점에 취약한 애플리케이션에 대해 merge_slashes 지시어를 끄는 것이 권장됩니다. 이는 Nginx가 URL 구조를 변경하지 않고 애플리케이션에 요청을 전달하도록 보장하여 기본적인 보안 문제를 숨기지 않도록 합니다.

자세한 내용은 Danny Robinson과 Rotem Bar를 확인하세요.

Maclicious Response Headers

이 글에서 보여준 바와 같이, 웹 서버의 응답에 존재하는 특정 헤더는 Nginx 프록시의 동작을 변경합니다. 이들을 문서에서 확인할 수 있습니다:

  • X-Accel-Redirect: Nginx가 요청을 지정된 위치로 내부 리디렉션하도록 지시합니다.
  • X-Accel-Buffering: Nginx가 응답을 버퍼링할지 여부를 제어합니다.
  • X-Accel-Charset: X-Accel-Redirect를 사용할 때 응답의 문자 집합을 설정합니다.
  • 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**의 내용을 전송하게 됩니다 (경로 탐색).

Map Directive의 기본값

Nginx 구성에서 map 지시어는 종종 인증 제어에서 역할을 합니다. 일반적인 실수는 기본 값을 지정하지 않는 것으로, 이는 무단 접근으로 이어질 수 있습니다. 예를 들어:

http {
map $uri $mappocallow {
/map-poc/private 0;
/map-poc/secret 0;
/map-poc/public 1;
}
}
server {
location /map-poc {
if ($mappocallow = 0) {return 403;}
return 200 "Hello. It is private area: $mappocallow";
}
}

default가 없으면, 악의적인 사용자/map-poc 내에서 정의되지 않은 URI에 접근하여 보안을 우회할 수 있습니다. Nginx 매뉴얼에서는 이러한 문제를 피하기 위해 기본값을 설정할 것을 권장합니다.

DNS 스푸핑 취약점

특정 조건에서 Nginx에 대한 DNS 스푸핑이 가능합니다. 공격자가 Nginx에서 사용하는 DNS 서버를 알고 그 DNS 쿼리를 가로챌 수 있다면, DNS 레코드를 스푸핑할 수 있습니다. 그러나 Nginx가 DNS 해석을 위해 **localhost (127.0.0.1)**를 사용하도록 구성된 경우, 이 방법은 효과적이지 않습니다. Nginx는 다음과 같이 DNS 서버를 지정할 수 있습니다:

resolver 8.8.8.8;

proxy_passinternal 지시어

proxy_pass 지시어는 요청을 내부 또는 외부의 다른 서버로 리디렉션하는 데 사용됩니다. internal 지시어는 특정 위치가 Nginx 내에서만 접근 가능하도록 보장합니다. 이러한 지시어 자체는 취약점이 아니지만, 보안 누수를 방지하기 위해 구성에 대한 신중한 검토가 필요합니다.

proxy_set_header Upgrade & Connection

nginx 서버가 Upgrade 및 Connection 헤더를 전달하도록 구성된 경우 h2c Smuggling 공격를 수행하여 보호된/내부 엔드포인트에 접근할 수 있습니다.

{% hint style="danger" %} 이 취약점은 공격자가 proxy_pass 엔드포인트와 직접 연결을 설정할 수 있게 합니다 (http://backend:9999의 경우) 이 콘텐츠는 nginx에 의해 확인되지 않습니다. {% endhint %}

/flag를 훔치기 위한 취약한 구성 예시 여기에서 확인할 수 있습니다:

server {
listen       443 ssl;
server_name  localhost;

ssl_certificate       /usr/local/nginx/conf/cert.pem;
ssl_certificate_key   /usr/local/nginx/conf/privkey.pem;

location / {
proxy_pass http://backend:9999;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
}

location /flag {
deny all;
}

{% hint style="warning" %} proxy_passhttp://backend:9999/socket.io와 같은 특정 경로를 가리키고 있더라도, 연결은 http://backend:9999로 설정되므로 해당 내부 엔드포인트 내의 다른 경로에 연락할 수 있습니다. 따라서 proxy_pass의 URL에 경로가 지정되어 있는지는 중요하지 않습니다. {% endhint %}

직접 해보세요

Detectify는 Docker를 사용하여 이 기사에서 논의된 몇 가지 잘못된 구성으로 취약한 Nginx 테스트 서버를 설정할 수 있는 GitHub 리포지토리를 만들었습니다. 직접 찾아보세요!

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

정적 분석 도구

GIXY

Gixy는 Nginx 구성을 분석하는 도구입니다. Gixy의 주요 목표는 보안 잘못된 구성을 방지하고 결함 탐지를 자동화하는 것입니다.

Nginxpwner

Nginxpwner는 일반적인 Nginx 잘못된 구성 및 취약점을 찾기 위한 간단한 도구입니다.

참고자료

취약성 평가 및 침투 테스트를 위한 즉시 사용 가능한 설정. 20개 이상의 도구 및 기능을 사용하여 어디서나 전체 침투 테스트를 실행하세요. 우리는 침투 테스터를 대체하지 않습니다 - 그들이 더 깊이 파고들고, 쉘을 터뜨리고, 재미를 느낄 수 있도록 맞춤형 도구, 탐지 및 악용 모듈을 개발합니다.

{% embed url="https://pentest-tools.com/?utm_term=jul2024&utm_medium=link&utm_source=hacktricks&utm_campaign=spons" %}

{% hint style="success" %} AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks 지원하기
{% endhint %}