Week 4 - Australian Cyber Security Games - 2025
Master of Time and Space
By Raahguu (Joshua Finlayson)6 min read
Description
While the government has provided the source code to the world, the mobile app won’t run properly because of geolocation and time restrictions! Can you identify the time and coordinates required for spoofing? Don’t forget to submit it to the relevant APIs to double check it’s correct (and get the flag).
This challenge also gave a png file, that you just need the visible text on.
The backend code for all of week 4 was the same, so we had that aswell.
Solution
The poster has on it the time zone: 2030-01-01T08:00:00Z
till 2030-01-01T18:00:00Z
And it also has the location of a voting booth: Croydon Public School
The code on the backend for submitting the time and location to is the following
##### POLLING LOCATION CHECKS
@voting_bp.route("/check-hours", methods=["POST"])
def check_polling_hours():
"""
Check if given timestamp is within polling location operating hours.
"""
try:
data = request.get_json()
if not data:
return jsonify({"error": "No JSON data provided"}), 400
timestamp = data.get("timestamp")
if not timestamp:
return jsonify({"error": "Missing required field: timestamp"}), 400
db = Database()
is_open, message = db.check_timestamp_in_polling_hours(timestamp)
return jsonify({
"polling_open": is_open,
"message": message
})
except Exception as e:
return jsonify({"error": f"Failed to check polling hours: {str(e)}"}), 500
@voting_bp.route("/check-location", methods=["POST"])
def check_location_in_polling_area():
"""
Check if given coordinates are within any polling location"s geolocation box.
"""
try:
data = request.get_json()
if not data:
return jsonify({"error": "No JSON data provided"}), 400
latitude = data.get("latitude")
longitude = data.get("longitude")
if latitude is None or longitude is None:
return jsonify({"error": "Missing required fields: latitude, longitude"}), 400
try:
lat = float(latitude)
lng = float(longitude)
except (ValueError, TypeError):
return jsonify({"error": "Invalid latitude or longitude format"}), 400
db = Database()
found, location_data = db.check_geolocation_in_polling_area(lat, lng)
if found:
return jsonify({
"within_polling_area": True,
"polling_location": location_data,
"master_of_time_and_space_flag": current_app.config["MASTER_OF_TIME_AND_SPACE_FLAG"]
})
else:
return jsonify({
"within_polling_area": False,
"polling_location": None
})
except Exception as e:
return jsonify({"error": f"Failed to check location: {str(e)}"}), 500
So we just need to submit json data to the API in order to get the flag. The time is very easy, as we get given the exact timestamp, lets just submit one an hour after voting begins
$ curl -X POST "http://mobile-app.commission.freedonia.vote/api/voting/check-hours" -H "Content-Type: application/json" -d '{"timestamp":"2030-01-01T09:00:00Z"}'
{"message":"Polling location is open","polling_open":true}
So clearly, the messages work, lets get the location now. Searching Croydon Public School
on google maps and then zooming in gets me to the link
https://www.google.com/maps/@-33.8803213,151.1149813,41m
This URL contains the lattitude and longitude -33.8803213,151.1149813
now I mixed these two up a lot and has a lot of trouble, but the numbers here go lattitude
then longitude
So we just need to submit the location in a post request
$ curl "http://mobile-app.commission.freedonia.vote/api/voting/check-location" -X POST -H "Content-Type: application/json" \
-d '{"latitude": -33.8803213, "longitude": 151.1149813}'
{"master_of_time_and_space_flag":"cysea{what_time_is_it_fr_tho_faca748a2d}","polling_location":{"geolocation_box":{"northeast":{"lat":-33.876598,"lng":151.118939},"northwest":{"lat":-33.876598,"lng":151.110849},"southeast":{"lat":-33.882984,"lng":151.118939},"southwest":{"lat":-33.882984,"lng":151.110849}},"id":1,"key":"POL001","polling_location":"Croydon Public School","state":"Izzi","voting_status":"Not Started"},"within_polling_area":true}
That gets us the flag cysea{what_time_is_it_fr_tho_faca748a2d}
Back