> For the complete documentation index, see [llms.txt](https://elijahchia.gitbook.io/ctf-blog/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://elijahchia.gitbook.io/ctf-blog/jelly-ctf-24/the_brewing_secrets-crypto.md).

# the\_brewing\_secrets (crypto)

{% file src="/files/Pve1nZdto3rgm3oneHXz" %}

The main program is made with the following C code:

```c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int runChallenge(int passcodeLength)
{
    int EXTRA_ALLOWANCE = passcodeLength;
    int bitmask = (1 << passcodeLength) - 1;
    int maxTimeout = bitmask;
    int passCode = random() & bitmask;

    printf("WARNING: System will timeout after %d entries\n", maxTimeout + EXTRA_ALLOWANCE);
    printf("Enter %d-digit binary passcode  \n", passcodeLength);

    int timeout = 0;
    int userInput = 0;

    char received;

    while (timeout < maxTimeout + EXTRA_ALLOWANCE)
    {
        scanf(" %c", &received);

        // optimisation with bit shift
        userInput = bitmask & (userInput << 1 | (received != '0'));
        if (userInput == passCode)
        {
            return 1;
        }

        if (timeout % passcodeLength == (passcodeLength - 1))
        {
            printf("Passcode incorrect. Try again!\n");
        }

        timeout++;
    }

    printf("Timeout exceeded\n");

    return 0;
}

int main(int argc, char **argv) {
    srand(time(NULL));

    int PASSCODE_LENGTH = 6;
    int NUM_PHASES = 10;

    int phase_number;
    int result = 0;

    for (phase_number = 1; phase_number <= NUM_PHASES; phase_number++)
    {
        printf("\n\nStarting phase_number %d...\n", phase_number);
        result = runChallenge(PASSCODE_LENGTH);

        // flush stdin
        int c;
        while((c = getchar()) != '\n' && c != EOF);

        printf("Phase number %d - validation result: %d\n", phase_number, result);

        if (result == 0)
        {
            break;
        }
    }

    if (phase_number == NUM_PHASES + 1)
    {
        FILE *f = fopen("flag.txt", "r");
        if(f == NULL){

            printf("Flag not found: please run this on the server\n");
            exit(0);
        }
        char buf[128];
        fgets(buf, 127, f);
        printf("Validation successful. Unlocking garage door: %s\n", buf);
    }

    return 0;
}
```

We are essentially playing a game with 10 phases. In each phase the code calls `runChallenge(6)`, which starts the phase.

In each phase, a random 6-bit integer is generated, and we need to guess it. In each phase we only have `(1 << 6) - 1 + 6 = 69` chances to input characters.&#x20;

`userInput` starts at `0`. For each character we input, `userInput` is shifted left by 1 bit and an OR operation is done with our character. `userInput` is also AND with `bitmask` to ensure that it is always 6 bits. If `userInput` matches `passCode` in 69 tries, we clear the phase. At first glance, 69 tries is not enough to brute-force all `2^6` possible passcodes, since that would require `2^6 * 6 = 384` characters. However, notice that the check `(userInput == passCode)` is done with every character we input, instead of every 6 characters we input. Therefore, we can provide a sequence of characters which, on appending to `userInput`, keeps making `userInput` a different 6-bit integer. This is also a De Brujin Sequence.&#x20;

I found one such sequence online. At each phase, I send characters from the sequence to the server, stopping only when I have cleared the phase. Below is my script:

```python
from pwn import *
de_brujin_sequence = "0000001000011000101000111001001011001101001111010101110110111111" # length of 64
x = de_brujin_sequence[5:]
"""
Verification is done on every bit, rather than on every 5 bits entered. Use De Brujin sequence to 
efficiently bruteforce every possible 5-bit binary string
"""
context.log_level = "debug"

# fill in binary name
elf = context.binary = ELF("./the_brewing_secrets")
if args.REMOTE:
  # fill in remote address
  p = remote("chals.jellyc.tf", 6000)
else:
  p = elf.process()

for phase in range(10):
    # remote changed \n to \r\n :(
    # p.recvuntil(b"passcode  \n") 
    p.recvuntil(b"passcode  \r\n")
    for idx in range(len(x)):
        p.sendline(x[idx].encode())
        res = p.recvline(timeout=0.2)
        if b"Phase number" in res:
            break

p.recvall() # jellyCTF{mad3_w1th_99_percent_l0v3_and_1_percent_sad_g1rl_t3ars}
p.close()
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://elijahchia.gitbook.io/ctf-blog/jelly-ctf-24/the_brewing_secrets-crypto.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
