web-ssrf

/img_viewer
- /img_viewer 경로로 POST 요청을 보내면, url 파라미터에 담긴 값이 서버로 전달되는데요.
app.py33-42라인에서 어떤 값을 반환할 지 판단하고 “img_viewer_html” 소스로 “img” 값을 전달합니다.

- 전달된 이미지 정보는 아래와 같이 “img_viewer” 경로에 반환되고 화면에 출력됩니다.

- 다시 “app.py” 소스를 살펴보겠습니다.
- (1)
url파라미터에 ”/” 값만 입력되면 “index.html” 페이지의 소스가 반환되고, - (2)
url파라미터의 “urlp.netloc” 값이localhost || 127.0.0.1이면error.png파일이 반환됩니다.
- (1)
- 따라서, SSRF로 플래그를 출력하기 위해서는 40-42 라인의 try 코드 블록으로 진입해야 합니다.

- 추가로, 49-52 라인을 보면 1500-1800번 포트 중 특정 포트에서 http 서버가 실행되고 있습니다.
http://127.0.0.1:{PORT}/flag.txt경로로 SSRF 요청을 보내면 플래그 확인이 가능해 보입니다.- 그러나 여기서 문제가 하나 있는데요. 36라인을 보면 “127.0.0.1, localhost” 문자열을 필터링 하고 있습니다.
requests.get(url)구조에서 reqeuests 는 아래의 순서로 동작한다고 하는데요.requests > urllib3 > Python socket > OS libc
- 이 때, Python의
socket.getaddrinfo()는 아래와 같은 IP 표현을 모두 허용합니다.
| IP Address | 의미 |
|---|---|
| 127.0.0.1 | 일반 IPv4 |
| 2130706433 | 10진수 정수표기 |
| 0177.00.00.01 | OCT(8진수) |
| 0x7F.0x00.0x00.0x01 | HEX(16진수) |
| 0x7F000001 | 32비트 정수의 hex |
| 127.1 | 축약표현 → 127.0.0.1 |
| 127.0.0.257 | 오버플로우 시도도 127.0.1.1 로 처리 |
- 위 표를 참고하여 “127.0.0.1” IP 주소를 우회하여 서버에 요청을 보내보겠습니다.
- 1500-1800번 포트 중 유효한 포트는 1729번 포트임을 확인했습니다.
- 요청도 정상적으로 보내지고 있네요.

- 그럼 이제, 1726번 포트로 플래그를 요청해보겠습니다.
- base64 인코딩 된 값이 반환되고 있는데요. 이 값을 디코딩 해보겠습니다.

- DH{…} 형태의 플래그 획득에 성공했습니다.

🐛.. 🐛.. 🐛..