리눅스 명령어를 실행하는 웹 서비스가 작동하고 있다고 한다.
그리고 웹 서비스의 코드가 첨부파일로 주어졌다. (코드의 해석은 이 글의 맨 아래에 있다.)
이 안에서 flag.txt 파일을 찾는 것이 목적이다.
일단 웹 페이지로 들어가보자.
리눅스 명령어를 실행한다는 점과 echo $를 보니 저 검은색 부분은 리눅스의 터미널과 같은 동작을 할 것으로 추측되었다. 또 그 결과는 Result에 출력될 것이다.
flag.txt 파일을 찾아보라고 하였으므로, ls 명령어를 입력해보았다.
hint.txt라는 파일이 눈에 띈다. cat hint.txt 를 입력해 해당 파일을 열어보자.
flag가 있는 경로를 알려주었다! 그렇다면 flag의 전체 경로는 ./dream/hack/hello/flag.txt가 될 것이다.
cat 명령어를 통해 flag.txt 파일을 읽어주자.
내가 입력을 잘못했다면 No! 말고 아예 아무런 창도 뜨지 않았어야 한다. 문제 파일로 주어진 소스코드를 분석해보자.
#!/usr/bin/env python3
import subprocess
from flask import Flask, request, render_template
APP = Flask(__name__)
@APP.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
user_input = request.form.get('user_input')
cmd = f'echo $({user_input})'
if 'flag' in cmd:
return render_template('index.html', result='No!')
try:
output = subprocess.check_output(['/bin/sh', '-c', cmd], timeout=5)
return render_template('index.html', result=output.decode('utf-8'))
except subprocess.TimeoutExpired:
return render_template('index.html', result='Timeout')
except subprocess.CalledProcessError:
return render_template('index.html', result='Error')
return render_template('index.html')
if __name__ == '__main__':
APP.run(host='0.0.0.0', port=8000)
소스 코드 중간에 cmd에 'flag'가 있다면 'No!'를 반환하는 코드가 있었다.
이는 와일드카드를 사용하여 우회할 수 있다.
- 와일드카드란?
와일드카드(Wildcards)
리눅스에서 임의의 다른 문자를 나타낼 수 있는 특수 문자들을 의미한다. 주로 명령어를 다른 문자열로 대체하기 위해 사용된다.
?나 *와 같은 문자가 a-z, 0-9 범위 내 임의의 0개 이상의 문자로 대체될 수 있다.
ex) fl*g.txt는 fl과 g 사이에 어떤 문자가 몇 글자나 있든 상관없이 모두 일치시킨다. flg.txt도 fl*g.txt에 일치한다.
ex) fl?g.txt는 fl과 g 사이에 정확히 한 문자가 있는 파일과 일치한다.
[] : [문자1-문자2] 혹은 [문자1, 문자2, ...] 형태로 범위를 지정한다. 범위 내 모든 문자로 대체될 수 있다.
ls test[0-9] : 파일명이 test로 시작하고 마지막이 숫자인 파일을 모두 출력한다.
와일드카드를 사용해 flag.txt 말고 fl?g.txt를 이용해주자.
이렇게 하면 최종적으로 flag값을 얻을 수 있다.
- Python 소스 코드 분석
#!/usr/bin/env python3
import subprocess
from flask import Flask, request, render_template
APP = Flask(__name__) # Flask를 이용하여 초기화
@APP.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST': # 'POST'방식일 때만 작동
user_input = request.form.get('user_input') # 사용자의 입력을 받음
cmd = f'echo $({user_input})' # cmd는 echo $({user_input}) 형식으로 실행
if 'flag' in cmd: # 만약 사용자가 입력한 내용에 flag가 있으면 'No!' 출력
return render_template('index.html', result='No!')
try: # 명령어를 실행하고 그 결과를 웹 페이지에 출력
output = subprocess.check_output(['/bin/sh', '-c', cmd], timeout=5)
return render_template('index.html', result=output.decode('utf-8'))
except subprocess.TimeoutExpired: # 명령어 실행이 5초 이상 걸릴 경우 Timeout 출력
return render_template('index.html', result='Timeout')
except subprocess.CalledProcessError: # 명령어 실행에 실패하면 'Error' 출력
return render_template('index.html', result='Error')
return render_template('index.html')
if __name__ == '__main__':
APP.run(host='0.0.0.0', port=8000) #0.0.0.0:8000에서 실행하여 모든 IP주소에서 서버에 접근할 수 있도록 설정
공부하는 중에 분석한 코드라 부족하거나 틀린 부분이 있을 수 있습니다! 코드 지적은 언제든지 환영입니다.
'Study > Dreamhack' 카테고리의 다른 글
[Dreamhack] Begineer 워게임 64se64 풀이 (0) | 2024.08.16 |
---|