Crypto on the Web

Billions of people use cryptography on a daily basis without realising it. The 2010s saw the widespread adoption of encryption on the web, accelerated by the Snowden disclosures: in 2015, 30% of pages loaded on Android were protected by Transport Layer Security (TLS), but by 2020, it was 90%. Alongside TLS, major websites employ hash functions for password storage, signed tokens for authorisation, and complex protocols for handling payment-card data.

However, as we've seen from other categories, cryptography is full of subtleties, and teams building web apps often get it wrong. This highly practical category explores common ways that cryptography is used in web apps, together with devastating implementation errors that are seen in the real world.

JSON Web Tokens

  • Token Appreciation
    5 pts · 2554 Solves

    JavaScript Object Signing and Encryption (JOSE) is a framework specifying ways to securely transmit information on the internet. It's most well-known for JSON Web Tokens (JWTs), which are used to authorise yourself on a website or application. JWTs typically do this by storing your "login session" in your browser after you have authenticated yourself by entering your username and password. In other words, the website gives you a JWT that contains your user ID, and can be presented to the site to prove who you are without logging in again. JWTs look like this:


    You can recognise it because it's base64-encoded data split into three parts (separated by a .): the header, the payload, and the signature. In fact, it's a variant of base64 encoding, where the + and / have been replaced by different special characters since they can cause issues in URLs.

    Some developers believe that the JWT encoding is like encryption, so they put sensitive data inside the tokens. To prove them wrong, decode the JWT above to find the flag. There are online tools to do this quickly, but working with Python's PyJWT library will prepare you best for future challenges.

    You must be logged in to submit your flag.

  • JWT Sessions
    10 pts · 2067 Solves

    The traditional way to store sessions is with session ID cookies. After you login to a website, a session object is created for you on the backend (the server), and your browser (the client) is given a cookie which identifies that object. As you make requests to the site, your browser automatically sends the session ID cookie to the backend server, which uses that ID to find your session in its own memory and thus authorise you to perform actions.

    JWTs work differently. After you login, the server sends your web browser the whole session object in a JWT, containing a payload of key-value pairs describing your username, privileges, and other info. Also included is a signature created using the server's secret key, designed to prevent you from tampering with the payload. Your web browser saves the token into local storage.

    diagram showing JWT usage

    On subsequent requests, your browser sends the token to the backend server. The server verifies the signature first, and then reads the token payload to authorise you.

    To summarise, with session ID cookies, sessions live on the server, but with JWTs, sessions live on the client.

    The main advantage of JWTs over session ID cookies is that they are easy to scale. Organisations need a way to share sessions across multiple backend servers. When a client switches from using one server or resource to another, that client's session should still work. Furthermore, for large orgs there could be millions of sessions. Since JWTs live on the client, they solve these problems: any backend server can authorise a user just by checking the signature on the token and reading the data inside.

    Unfortunately there are some downsides to JWTs, as they are often configured in an insecure way, and clients are free to modify them and see if the server will still verify them. We'll look at these exploits in the next challenges. For now, the flag is the name of the HTTP header used by the browser to send JWTs to the server.

    You must be logged in to submit your flag.

  • No Way JOSE
    20 pts · 1660 Solves · 5 Solutions

    Let's look at JWT algorithms. The first part of a JWT is the JOSE header, and when you decode it, looks like this:


    This tells the server it's a JWT and which algorithm to use to verify it. Can you see the issue here? The server has to process this untrusted input before it is actually able to verify the integrity of the token! In ideal cryptographic protocols, you verify messages you receive before performing any further operations on them, otherwise in Moxie Marlinspike's words, "it will somehow inevitably lead to doom".

    The "none" algorithm in JWTs is a case in point. The link below takes you to a page where you can interact with a broken session API, which emulates a vulnerability that existed in a lot of JWT libraries. Use it to bypass authorisation and get the flag.

    Play at

    You must be logged in to submit your flag.

  • JWT Secrets
    25 pts · 1499 Solves · 3 Solutions

    The most common signing algorithms used in JWTs are HS256 and RS256. The first is a symmetric signing scheme using a HMAC with the SHA256 hash function. The second is an asymmetric signing scheme based on RSA.

    A lot of guides on the internet recommend using HS256 as it's more straightforward. The secret key used to sign a token is the same as the key used to verify it.

    However, if the signing secret key is compromised, an attacker can sign arbitrary tokens and forge sessions of other users, potentially causing total compromise of a webapp. HS256 makes the secret key harder to secure than an asymmetric keypair, as the key must be available on all servers that verify HS256 tokens (unless better infrastructure with a separate token verifying service is in place, which usually isn't the case). In contrast, with the asymmetric scheme of RS256, the signing key can be better protected while the verifying key is distributed freely.

    Even worse, developers sometimes use a default or weak HS256 secret key.

    Here is a snippet of source code with one function to create a session and another function to authorise a session and check for admin permissions. But there's a strange comment about the secret key. What are you going to do?

    Play at

    You must be logged in to submit your flag.

  • RSA or HMAC?
    35 pts · 1098 Solves · 6 Solutions

    There's another issue caused by allowing attackers to specify their own algorithms but not carefully validating them. Attackers can mix and match the algorithms that are used to sign and verify data. When one of these is a symmetric algorithm and one is an asymmetric algorithm, this creates a beautiful vulnerability.

    The server is running PyJWT with a small patch to enable an exploit that existed in PyJWT versions <= 1.5.0. To create the malicious signature, you will need to downgrade or patch your PyJWT library too. If you want to patch, look at the line that was added in the fix for the vulnerability. Use pip show pyjwt to find the location of the PyJWT library on your computer, and make the edit. For versions of PyJWT > 2.4.0 the code has been changed so you will have to edit jwt/ instead of jwt/

    Play at

    You must be logged in to submit your flag.

  • JSON in JSON
    40 pts · 1011 Solves · 6 Solutions

    We've explored how flawed verification can break the security of JWTs, but it can sometimes be possible to exploit the code to sign unexpected data in the first place.

    Play at

    Challenge contributed by sublevel_1157

    You must be logged in to submit your flag.

  • RSA or HMAC? Part 2
    100 pts · 371 Solves · 7 Solutions

    It is possible to abuse JWT public keys without the public key being public? This challenge takes RSA or HMAC one step further, and now both a deeper knowledge of RSA maths and data formatting is involved. It's more realistic than the first part as web apps usually won't have a route disclosing their public key.

    If you are attempting to implement the solution yourself (which is recommended over using a public script!), but the signature is not validating, take care that your formatting is 100% correct. We've added to the source the commands used to generate the private and public keys.

    The server is running PyJWT with a small patch to enable an exploit that existed in PyJWT versions <= 1.5.0. To create the malicious signature, you will need to patch or downgrade your PyJWT library too. Use pip show pyjwt to find the location of the PyJWT library on your computer, and edit jwt/ to remove the line that was added in the fix for the vulnerability.

    Play at

    You must be logged in to submit your flag.

TLS Part 1: The Protocol

  • Secure Protocols
    5 pts · 414 Solves

    The rest of CryptoHack focusses on cryptographic primitives, low-level building blocks such as symmetric ciphers, public-key algorithms, and hash functions. This section however looks at cryptographic protocols. Cryptographic protocols are what happen when primitives are combined together, enabling two or more parties to communicate securely.

    A good cryptographic protocol addresses the three core ideas of security (the CIA triad):

    1. Confidentiality: keeping secrets

    2. Authenticity: verifying identities

    3. Integrity: ensuring safe transport

    Transport Layer Security (TLS) is the most widespread cryptographic protocol; an average Internet user initiates hundreds of TLS connections every day. TLS aims to provide secure communication, meeting the above three requirements, over the insecure network infrastructure of the Internet. Most commonly TLS is used to secure HTTP traffic from a browser. To achieve this there are multiple major components, including TLS certificates, Certificate Authorities (CAs), a handshake phase, and more that we will cover.

    Some still refer to TLS as SSL, which stands for Secure Sockets Layer, and was the older version of the protocol. The first version of TLS was defined in 1999.

    Providing cryptographic security for Internet HTTP traffic is the core design goal of TLS. However, for TLS to be useful, security could not be the only goal. A wide range of devices communicate using TLS, from underpowered smartphones to powerful webservers, leading to three additional goals:

    - Interoperability: aims to ensure that two devices can communicate even if they are using different TLS implementations which support different sets of algorithms.

    - Extensibility: means TLS can support many extra use-cases through optional extensions without overcomplicating the core protocol.

    - Efficiency: important so that the performance cost of TLS is not too high, especially on low-end devices where cryptographic operations are slow.

    The last main point to cover here is that there have been several versions of TLS, each of which has improved the protocol, and patched known vulnerabilities. Almost all devices in use today can be counted upon to support TLS 1.2 (released 2008), which is still considered reasonably secure, even though the current version TLS 1.3 (released 2018) offers major improvements. A small percentage of servers still support the now-ancient TLS 1.0 and even SSL 3.0 (which are vulnerable to several exploits) due to misconfigurations or the need to allow ancient hardware to connect to them. This shows how interoperability can work against security.

    To get the flag for this challenge, browse to and find the name of the certificate authority organisation which issued the TLS certificate for the domain - this can be done purely within the browser. We'll explore the role of certificate authorities more in future challenges!

      - SSL Labs Statistics

    You must be logged in to submit your flag.

  • Sharks on the Wire
    10 pts · 381 Solves

    The best way to understand a network protocol is to watch real traffic. For this challenge you'll use the incredible Wireshark tool to investigate a TLS connection.

    Wireshark is an open-source networking tool which can be used to easily record and analyse network traffic. It's widely used for troubleshooting so it's useful to know the basics of how to use it. Installation should be straightforward on Linux and macOS, on Windows it can be a little trickier, please check the docs.

    Once you have Wireshark installed, open the file "" linked below. This is a packet capture showing the first 50 packets when we visited in the Firefox browser. A packet is a formatted unit of data transmitted over a network. In the upper pane you can see a list of these packets and Wireshark is smart enough to figure out the network protocols used in each one based on the data inside. When you click on a packet, you get a "dissection" of each field in the data and what it means in the middle pane. In the bottom pane is a view of the raw packet bytes.

    In the next challenges we'll look at what is happening in these packets. For now let's just get the hang of the Wireshark interface.

    By default Wireshark only shows IP addresses in the source and destination columns. Click View > Resolution > Resolve Network Addresses to see some helpful names we added to the source and destination IPs to make the communication clearer. While Wireshark can resolve some public IPs by itself (like becomes "" using the DNS request in the packet capture), Wireshark could not resolve the private IPs in the capture so we annotated those ourselves in the provided file by right-clicking the IPs then Edit Resolve Name.

    The search bar at the top of Wireshark allows the packets to be filtered using powerful expressions. You can also right-click packets on certain columns and click Apply as Filter > Selected to apply the same criteria on the selected column to filter all packets in the capture. For instance, if you right-click and do this for a packet sent by the CryptoHack server in the "Source" column, the ip.src == filter will be applied. To remove the filter clear the search bar and hit enter.

    How many packets were received by the server (i.e. was the destination) in this capture?

    Challenge files:

    You must be logged in to submit your flag.

  • TLS Handshake
    15 pts · 353 Solves · 2 Solutions

    This challenge uses the same packet capture as the previous challenge. Let's describe the communication we see at a high level.

    The TLS communication only begins at packet 10, but what happens before provides important context:

    - Packets 1-2: First, when we typed into the address bar and hit enter, a Domain Name System (DNS) request was made to translate the domain name ( to an IP address (

    - Packets 3-4: The "Safe Browsing" feature in Firefox reached out to a Google server to check that was not a phishing or malicious domain.

    - Packets 5-6: DNS responses to our DNS requests came back, saying that can be reached at IP address

    - Packets 7-9: A TCP three-way handshake (SYN, SYN-ACK, ACK) was initiated between our laptop and port 443 (the TLS port) of the server at This negotiated a stable connection between the two computers over the Internet before the real data transfer could start.

    - Packet 10-11: A TLS ClientHello message was sent from our laptop to the server. The next challenge will expand on this, but for now note this was our laptop sending a bunch of important parameters such as the ciphers it supports. Packet 11 is an ACK TCP packet sent from the server ACKnowledging it received the packet from our laptop.

    - Packet 12-17: The server sent TLS ServerHello, Change Cipher Spec, and Application Data messages. TLS 1.3 is designed to be really fast - the server sends back its own parameters, then signals Change Cipher Spec which means it is switching over to sending encrypted communications from now on. Then the server sends its TLS certificate encrypted.

    - Packets 18-21: An Online Certificate Status Protocol (OCSP) connection was made from our laptop to an OCSP server, to check that the TLS certificate presented by CryptoHack hadn't been revoked... yet another thing we'll explore later!

    - Packets 22-27: Our laptop sent a Change Cipher Spec message to note that it is switching over to sending encrypted data, and it finally made a HTTP request requesting the CryptoHack home page. The actual HTTP content of the connection can't be seen in the packet capture, as it's now encrypted!

    - Packets 28-39: The server started sending the contents of the CryptoHack homepage to our client over HTTP wrapped in TLS.

    - Packets 40-50: Firefox's HTML parser saw that it needed external resources from Content Delivery Networks such as to load JavaScript resources on the page and sent DNS requests to resolve those domains. This isn't relevant to TLS apart from the notable fact that DNS requests on most systems by default are not encrypted (but DNS-over-HTTPS, which fixes this obvious leak, is starting to get more common).

    Wow, that was a lot of packets just to start displaying a relatively simple website (at least by modern Internet standards), and that wasn't even all of them! By spending some time playing around in Wireshark you should gain a better grasp on what data TLS protects as well as what it does not.

    To solve this challenge, find the Random data sent from in the ServerHello message of the packet capture.

    Challenge files:

      - The Illustrated TLS 1.3 connection

    You must be logged in to submit your flag.

  • Saying Hello
    20 pts · 340 Solves · 2 Solutions

    As we've seen, TLS connections begin with a handshake, where the client (normally a browser) and server agree on important parameters that will define the remainder of the connection. The parameters exchanged allow a shared secret to be generated, and after the handshake is complete, the shared secret is used to symmetrically encrypt subsequent application data.

    At a high level TLS messages are called "records". The record format starts with a short header, which contains information about the TLS version, the content type of the message (handshake, change cipher spec, application data, and alert), and the data length. Then the data follows.

    The first message sent is the ClientHello, where the client sends the server the following data:

    - A list of cipher suites it supports

    - The highest TLS version it supports

    - A list of extensions and compression methods it supports

    - A random number (used to provide entropy in the key exchange)

    - A session ID to identify the connection

    The TLS cipher suite that is negotiated is crucial as it specifies the cryptographic primitives that will be used. A cipher suite name is a human-readable representation of a cipher suite, and it looks like this: ECDHE-RSA-AES128-GCM-SHA256:

    - ECDHE is the Elliptic-curve Diffie–Hellman algorithm used for key exchange.

    - RSA is used to authenticate the handshake.

    - AES-128 is used to symmetrically encrypt the application data.

    - GCM is the mode of operation that will be used for AES.

    - SHA256 will be used for message authentication.

    You can check for more information about specific cipher suites.

    Now for the challenge: the server "" speaks both TLS 1.2 and TLS 1.3, and supports only a single TLS 1.2 cipher suite. What is this cipher suite? Give your answer in a similar format to the cipher suite name above (OpenSSL format).

    To avoid a TLS 1.3 handshake, you can use curl or openssl commands with specific flags to specify that TLS 1.2 is the maximum version you support in your ClientHello message, or you can use an online tool like Qualys SSL Labs to get all the TLS information about the server to solve this.

    You must be logged in to submit your flag.

Level Up

level up icon

You are now level Current level