ACSC 2025: CORPO
A heap overflow challenge where partial RELRO allows overwriting the exit GOT entry to call a hidden launch_shell() function.
TL;DR
When stocks are bought a loop subtracts the price of a single stock once at a time from your balance. If your balance is large enough small prices are too small to be taken into account by single precision floats, making them free essentially. When selling, the total is added to your balance at once. With that you can keep increasing your balance until you can buy the flag.
Objective
The challenge resembles a simple stock market
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
╭──────────────────────────────────────────────────────╮
│ VNO Worth: 1190606667776.00 │ Stonks │
│ │ │
│ /-/- │ FLG 3.661e+14 ↑ │
│ /-- │ KDY 5.109e+04 ↑ │
│ /- │ MLT 455.9 ↑ │
│ /-/- │ TXT 286.9 ↓ │
│ /- │ ARA 198.4 ↑ │
│ /-/- │ KTO 59.35 ↓ │
│ /- │ ZET 30.88 ↓ │
│ /- │ ACSC 12 ↓ │
│ /-/- │ CSCG 13.16 ↓ │
│ /- │ SHC 13.57 ↓ │
│ -/- │ BTA 2.971 ↓ │
│──────────────────────────────────│ DOGE 0.1784 ↓ │
│ > Buy * Sell │ PNY 0.009932 ↓ │
╰──────────────────────────────────────────────────────╯
Vulnerability
1
2
3
4
5
6
7
// CORPO.h
struct user {
char name[4];
float eddies;
float asset;
struct asset assets[];
};
1
2
3
4
5
6
7
8
// CORPO.c
while (shares-- > 0
&& user.eddies > stonk->price
&& stonk->shares > 0) {
user.assets[selected].shares += 1;
stonk->shares -= 1;
user.eddies -= stonk->price;
}
When buying stocks the stock price is subtracted from the users eddies one by one. Because the users eddies is a single precision float a Floating-Point Precision Loss is possible. When eddies is large enough small prices are not able to be subtracted from the float and the stock is practically free.
Exploit Strategy
The useful stocks are a ladder. Each stock is used to grow the balance until the next stock price is also rounded away by float precision:
| Stage | Why |
|---|---|
PNY | 0.01f is already too small to affect the starting balance. |
DOGE | Once the balance is a few million, 0.17f rounds away. |
BTA | The DOGE profit gets us to the range where 3.39f rounds away. |
ZET | BTA profit gets us to the range where 29.95f rounds away. |
MLT | ZET profit gets us to the range where 482.21f rounds away. |
KDY | MLT profit gets us to the range where 50000.0f rounds away. |
After climbing this ladder and buying enough kidneys and selling them again the flag can then simply be bought.
1
2
3
4
5
6
7
8
9
10
11
12
13
[+] Opening connection to vmyshdnj.vuln.gg on port 443: Done
[*] started game with displayed worth 1099073.12
[*] PNY cycle 1: worth 3472754.50
[*] PNY cycle 2: worth 5892334.50
[*] DOGE cycle 1: worth 31612832.00
.
.
.
[*] KDY cycle 12: worth 348848920723456.00, flag price 3.531e+14
[*] KDY cycle 13: worth 378300987867136.00, flag price 3.562e+14
[+] ready to buy flag at displayed worth 378300987867136.00
[+] flag: [flag withheld]
[*] Closed connection to vmyshdnj.vuln.gg port 443