문제풀이
API_KEY = os.environ.get('API_KEY', None)
def key_required(view):
@wraps(view)
def wrapped_view(**kwargs):
apikey = request.args.get('API_KEY', None)
if API_KEY and apikey:
if apikey == API_KEY:
return view(**kwargs)
return 'Access Denined !'
return wrapped_view
@app.route('/', methods=['GET'])
def index():
return 'API Index'
@app.route('/file', methods=['GET'])
def file():
path = request.args.get('path', None)
if path:
data = open('./files/' + path).read()
return data
return 'Error !'
@app.route('/admin', methods=['GET'])
@key_required
def admin():
cmd = request.args.get('cmd', None)
if cmd:
result = subprocess.getoutput(cmd)
return result
else:
return 'Error !'
○ 코드 분석
/file
- path 파라미터로 임의의 파일을 읽을 수 있다.
/admin
- cmd 파라미터로 임의의 시스템 명령어를 실행하고 결과를 받을 수 있다.
/admin
에 접속해서 정상적인 기능을 동작하기 위해서는 환경 변수로 가져오는 옳바른 API_KEY를 같이 전송해야한다.- API_KEY에 대한 검증은
key_required()
를 통해서 진행한다.
- API_KEY에 대한 검증은
정리하면 /admin
으로 원하는 명령을 실행하도록 command injection을 진행해야하는데, 문제는 API_KEY를 모른다는 것이다.
API_KEY를 알아내보자.
API_KEY = os.environ.get('API_KEY', None)
API_KEY는 환경변수로부터 가져온다는 것을 알 수 있다.
/file
를 이용해서 원하는 파일을 읽을 수 있다고 했다. 그렇다면, 환경변수가 저장된 파일을 읽으면 되지 않을까?
바로 시도해보자.
/file?path=../../etc/profile
에 접속했고 [그림]과 같이 환경변수가 저장된 /etc/profile
을 읽었다.
하지만 API_KEY는 존재하지 않았다.
○ nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/nginx_error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/nginx_access.log main;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
}
daemon off;
제공된 파일중에는 nginx.conf도 있다.
nginx.conf는 nginx 서버 설정 파일이다.
설정을 보면, access_log /var/log/nginx/nginx_access.log
가 눈에 띈다.
access_log는 서버에 접속한 기록을 저장한 파일 경로를 의미한다.
그렇다면 정상적인 사용자가 /admin
에 접속해서 명령을 실행했던 적이 있다면, nginx_access.log 파일에 API키가 남아있을 것이다.
확인해보자.
확인해보니 /admin
에 접속하면서 API_KEY를 전달한 기록이 남아있다.
API_KET가 "d22cb18e86fc9e23996650150461c9f794ad3a4f"라는 것을 알아냈다.
/admin
에 접속해서 명령을 실행해보자.
__pycache__ files main.py nginx.conf prestart.sh requirements.txt uwsgi.ini
ls를 실행해보니 정상적으로 실행된 것을 확인할 수 있다.
flag를 찾고 읽어보자.
app bin boot dev entrypoint.sh etc flag home install-nginx-debian.sh lib lib64 media mnt opt proc root run sbin srv start.sh sys tmp usr uwsgi-nginx-entrypoint.sh var
최상위 경로에 flag가 있다.
실행해보자.