Dust Alleys

이강현·2026년 4월 13일

HTB Challenge

목록 보기
2/6

프로젝트 구조

UI

웹 상에서는 interact with Robot 버튼 이외에 별 다른 기능을 수행할 수 없었다.

바로 코드 상으로 가서 파악하였다.

Dockerfile

nginx 서버와 node.js 서버가 구축되고 있는 걸 확인할 수 있다.

flag는 환경 변수에 저장돼있는 것을 확인하였다.

*여기서 sed 명령어는 환경 파일에 하드코딩돼 있는 환경 변수 값을 실제로 설정된 값으로 변경하는 과정을 하는데 사용된다.

/etc/nginx/http.d/default.conf

현재 default.conf에서 두 개의 가상호스트(alley, guardian)를 설정하여 리버스 프록시를 사용하고 있다.

  1. alley 서브도메인
    • /alley
    • /think
  2. guardian 서브도메인
    • /guardian -> flag

해당 서브도메인에 접근하려면 각 서브도메인 이름에 $SECRET_ALLEY를 추가한 Host 헤더 값으로 요청을 보내야 nginx에서 이를 분기하여 요청을 전달한다.
여기서 alley는 기본값으로 세팅이 돼있어 아무런 작업 없이 해당 엔드포인트에 접근할 수 있다.

/app/package.json

package.json에서 발견된 취약점이다.

  • node-fetch 2.6.6 CVE-2022-0235

routes/guardian.js

alley: index.html 렌더링해서 반환 -> 여기서 guardian 엔드포인트 접근 가능
think: 요청 헤더값을 json 형식으로 반환
guardian

  • 쿼리 변수로 quote가 지정돼있지 않으면 guardian.html 반환.
  • quote가 지정돼있으면 quote를 URL 생성자 인자값으로 넘겨 location 변수에 할당한다.
  • location.hostname이 localhost로 끝나지 않거나 localhost가 아니면 에러 반환. -> 여기서 localhost로 끝나기만하면 필터링 로직 통과
  • node-fetch를 통해서 GET 방식으로 요청 보내는데 헤더로 flag값 첨가해서 보내고 있음. 그리고 요청받은 응답의 타입은 text/plain으로 하드코딩해서 최종 전달. -> node-fetch 취약한 버전 이용

guardian 엔드포인트 접근

현재 guardian 엔드포인트로 진입하기 위해서는 SECRET_ALLEY을 알아야한다. 이를 알기 위해서는 현재 default.conf에 적용된 로직의 허점을 이용하면 된다.

현재 alley 서브 도메인의 요청 처리에서는 Host 헤더값을 명시하지 않을 경우 기본값으로 설정된 alley.SECRET_ALLEY으로 요청을 전달한다.

이를 토대로 Burp Suite 상에서 Host 헤더를 지우거나 빈 값으로 해서 요청을 보냈는데 400 에러가 떴다.

이는 HTTP/1.1 프로토콜 규격상 Host 헤더가 필수이기 때문에, 이 제약사항을 우회하기 위해선 1.0 프로토콜을 사용해야해서 curl 명령어를 통해 HTTP/1.0 프로토콜로 요청을 보냈다.

curl -s --http1.0 -H "Host:" http://154.57.164.74:31983/think

그랬더니 응답이 잘 왔고, alley.firstalleyontheleft.com으로 설정된 것을 확인할 수 있었다.

direction 필터링 로직 우회

현재 이 필터링은 앞서 말했듯이 hostnmae이 localhost으로 끝나거나 localhost이면 통과되는 로직이다. 여기서 중요한 점은 헤더에 Flag값이 추가돼서 요청을 보내는데, 이때 헤더 값을 보여주는 /think로 요청을 보내면 그 응답값을 받아와 렌더링해주니 그냥 http://localhost:1337/think로 quote를 정의해서 요청을 보내면 flag 값을 받아올 수 있다.

profile
저는 정보보안전문가가 될 것입니다.

0개의 댓글