[n00bzCTF - WEB] Curl as a Service
n00bzCTF에서는 공식 writeup을 제공한다..!😄😆
롸업 정리하면서 공부해보자 !
https://github.com/n00bzUnit3d/n00bzCTF-OfficialWriteups/tree/main/web/CaaS
1. 문제설명
remote: https://challs.n00bzunit3d.xyz:30533/
challenge: https://ctf.n00bzunit3d.xyz/attachments/CaaS/challenge_redacted.py
2. 웹서비스 분석
드림핵에 비슷한 문제가 있었다. blind command 였나???
그때는 입력칸에 들어가는 값이 curl 명령어의 인자로 들어갔는데 이 문제에서는 curl command라고 써져있긴 한데 동작이 좀 다른 것 같다.
from flask import Flask, request, render_template, render_template_string, redirect
import subprocess
import urllib
app = Flask(__name__)
def blacklist(inp):
blacklist = ['{{','}}','import','os','system','[','\x5f',']']
for b in blacklist:
inp = inp.replace(b, '')
return inp
@app.route('/')
def main():
return redirect('/curl')
@app.route('/curl',methods=['GET','POST'])
def curl():
if request.method == 'GET':
return render_template('curl.html')
elif request.method == 'POST':
inp = request.values['curl']
#print(inp)
#p = subprocess.Popen(["python3", "admin.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
#print('a')
def admin():
return inp
print(admin())
webUrl = urllib.request.urlopen(f'{inp}')
data = webUrl.read()
#print(data)
#data = data.replace(b'\n',b'\r\n')
return f'Am Admin, Going to visit "{inp}" fingers crossed, Result:{data}</p>'
@app.route('REDACTED')
def flag():
return render_template('REDACTED')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
소스코드를 보니까 curl이 아니라 webUrl = urllib.request.urlopen(f'{inp}')
입력한 값을 urllib.request.urlopen()으로 열어서 read 해준다.
flag는 redacted?? 검색해보니까 중요한 정보를 지운다. 라는 뜻이라고 한다. 하여튼 flag가 안 보인다.
3. 취약점 분석
블랙리스트로 사용자가 입력한 값을 필터링하고 있다.
블랙리스트 필터링이어서 필터링하지 않는 문자들로 우회가 가능하다.
4. 익스플로잇
urllib.request.urlopen() 문서를 찾아보자.
urllib.request — URL을 열기 위한 확장 가능한 라이브러리 — Python 3.10.5 문서
urllib.request — URL을 열기 위한 확장 가능한 라이브러리 소스 코드: Lib/urllib/request.py urllib.request 모듈은 복잡한 세계에서 URL(대부분 HTTP)을 여는 데 도움이 되는 함수와 클래스를 정의합니다 — 기
docs.python.org
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
url에는 https://, http://, file://, ftp:// 형식으로 입력할 수 있다고 한다.
- urllib의 많은 용도는 이렇게 간단합니다 (‘http:’ URL 대신 ‘ftp:’, ‘file:’ 등으로 시작하는 URL을 사용할 수 있음에 유의하십시오).
그렇다면 최종 목적은 flag파일을 읽는 거니까 file:// 을 사용해서 파일을 읽어보자!
flag가 flag.txt에 저장되어있지 않다고 하니까 flag파일의 이름을 알아야한다.
LFI 취약점을 이용해서 /etc/passwd, /proc/self/environ 등 시스템 파일들을 읽어보자.
(유용한 파일 -> 드림핵 웹해킹 로드맵 참고 )
/proc/self : 현재 실행 중인 프로세스의 정보를 확인할 수 있다.
/proc/self/cmdline : 실행 중인 프로세스의 명령줄
challenge.py 라는 파이썬 코드를 실행하고 있나보다.
문제 소스 코드 이름이 challenge_redacted.py 이고 flag가 redacted로 안보였으니까 challenge.py에는 flag가 보이지 않을까?
challenge.py 파일을 읽어보자!
이 파일이 저장된 곳 = 디렉터리를 알아야 한다.
/proc/self/cwd가 프로세스의 현재 실행 중인 디렉터리의 심볼릭 링크 파일이라고 한다.
file:///proc/self/cwd/challenge.py , file:///chall/challenge.py
challenge.py에 flag 파일의 이름이 나와있다.