> For the complete documentation index, see [llms.txt](https://kabinet.gitbook.io/ctf-writeup/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kabinet.gitbook.io/ctf-writeup/2024/greyctf-2024/fearless-concurrency.md).

# Fearless Concurrency

## Challenge Description

Rust is the most safest, fastest and bestest language to write web app! The code compiles, therefore it is impossible for bugs! PS: This is my first rust project (real) 🦀🦀🦀🦀🦀 Comment Suggest edit

Author: jro

<http://challs.nusgreyhats.org:33333>

<https://storage.googleapis.com/greyctf-challs/dist-fearless-concurrency.zip>

***

## Code Analysis

The web application has a registration function which generates a Random UID.

```rust
async fn register(State(state): State<AppState>) -> impl IntoResponse {
    let uid = rand::random::<u64>();
    let mut users = state.users.write().await;
    let user = User::new();
    users.insert(uid, user);
    uid.to_string()
}
```

\
We are also able to craft query

```rust
async fn query(State(state): State<AppState>, Json(body): Json<Query>) -> axum::response::Result<String> {
    let users = state.users.read().await;
    let user = users.get(&body.user_id).ok_or_else(|| "User not found! Register first!")?;
    let user = user.clone();

    // Prevent registrations from being blocked while query is running
    // Fearless concurrency :tm:
    drop(users);

    // Prevent concurrent access to the database!
    // Don't even try any race condition thingies
    // They don't exist in rust!
    let _lock = user.lock.lock().await;
    let mut conn = state.pool.get_conn().await.map_err(|_| "Failed to acquire connection")?;

    // Unguessable table name (requires knowledge of user id and random table id)
    let table_id = rand::random::<u32>();
    let mut hasher = Sha1::new();
    hasher.update(b"fearless_concurrency");
    hasher.update(body.user_id.to_le_bytes());
    let table_name = format!("tbl_{}_{}", hex::encode(hasher.finalize()), table_id);

    let table_name = dbg!(table_name);
    let qs = dbg!(body.query_string);

    // Create temporary, unguessable table to store user secret
    conn.exec_drop(
        format!("CREATE TABLE {} (secret int unsigned)", table_name), ()
    ).await.map_err(|_| "Failed to create table")?;

    conn.exec_drop(
        format!("INSERT INTO {} values ({})", table_name, user.secret), ()
    ).await.map_err(|_| "Failed to insert secret")?;


    // Secret can't be leaked here since table name is unguessable!
    let res = conn.exec_first::<String, _, _>(
        format!("SELECT * FROM info WHERE body LIKE '{}'", qs),
        ()
    ).await;

    // You'll never get the secret!
    conn.exec_drop(
        format!("DROP TABLE {}", table_name), ()
    ).await.map_err(|_| "Failed to drop table")?;

    let res = res.map_err(|_| "Failed to run query")?;

    // _lock is automatically dropped when function exits, releasing the user lock

    if let Some(result) = res {
        return Ok(result);
    }
    Ok(String::from("No results!"))
}
```

Looking at this function, we can see that it is vulerable to SQL Injection.

```rust
    let res = conn.exec_first::<String, _, _>(
        format!("SELECT * FROM info WHERE body LIKE '{}'", qs),
        ()
    ).await;

```

***

## Exploit

I used SQL Map, and was able to perform the sql injection

<figure><img src="/files/6y7cGtBO51yFvGQ61IV3" alt=""><figcaption></figcaption></figure>

Next, I attempted to dump the table.

<figure><img src="/files/mCrGHqgQEtCJimEAN9Rn" alt=""><figcaption></figcaption></figure>

Looking at the source code, I was able to identify how they created the random strings for the table.

```rust
    // Unguessable table name (requires knowledge of user id and random table id)
    let table_id = rand::random::<u32>();
    let mut hasher = Sha1::new();
    hasher.update(b"fearless_concurrency");
    hasher.update(body.user_id.to_le_bytes());
    let table_name = format!("tbl_{}_{}", hex::encode(hasher.finalize()), table_id);

```

I then copied the code, to create the hash of my current user with a simple rust script.

```rust
use sha1::{Digest, Sha1};
use hex;

fn main() {
    let mut hasher = Sha1::new();
    hasher.update(b"fearless_concurrency");
    hasher.update(2629577642326695728u64.to_le_bytes());
    let table_name = format!("tbl_{}", hex::encode(hasher.finalize()));
    println!("{}", table_name);
}

```

<figure><img src="/files/gqdmTIVp6nfMjCK1pV78" alt=""><figcaption></figcaption></figure>

Upon inspecting the dumped table, I noticed that my current user's table is not being deleted for some reason. To gain a better understanding, I proxied my SQL Map to Burp Suite.

<figure><img src="/files/MU1cu500ykj59t0Hoj46" alt=""><figcaption><p>SQL Injection payload generated by SQLMap</p></figcaption></figure>

It appears that there were multiple tables containing my user hashes. I attempted to retrieve the secret from the last table on the list.

<figure><img src="/files/DkKr5Sw0vNBvxrhdCM0p" alt=""><figcaption><p>SQL Injection payload generated by SQLMap</p></figcaption></figure>

With the retrieved secret, I was able to get the flag from the `/flag` endpoint.

<figure><img src="/files/bb9MzjfdXze5enVch2i4" alt=""><figcaption></figcaption></figure>

Flag: grey{ru57\_c4n7\_pr3v3n7\_l061c\_3rr0r5}

***

## Further Discussion

However, this is definitely not the intended solution. Looking at the source code, it will attempt to drop the table after the query ran.

```rust
    // You'll never get the secret!
    conn.exec_drop(
        format!("DROP TABLE {}", table_name), ()
    ).await.map_err(|_| "Failed to drop table")?;
```

The challenge name Fearless Concurrency also hinted at it being a Race Condition or something similar, where you have 2 payload running concurrently.

After the CTF, while discussing solution in the discord server, the author revealed that the intended solution was to inject a sleep, and use a seperate user account to perform the SQLI to leak the secret.

<figure><img src="/files/xtVhRRtLH2uSMxcq5Pt1" alt=""><figcaption><p>#web in the Grey Cat The Flag discord server</p></figcaption></figure>

Lorenz has also kindly shared his proof of concept script in the message linked below.

<https://discord.com/channels/969232688521281606/969232688911360035/1231460020412223589>


---

# 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://kabinet.gitbook.io/ctf-writeup/2024/greyctf-2024/fearless-concurrency.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.
