4th Dec 2024
Prepared By: 131LL
Challenge Author(s): 131LL
Difficulty: Hard
Classification: Official
Refreshments is a hard difficulty challenge that features:
off-by-one heap overflow- Leak
unsorted binaddresses Aggregatechunks- Fake
vtableobject Remainderthe "tamper" chunkFSOPHouse of Orangeinglibc 2.23
On a blazing summer day in the Shroom Kingdom, beat the heat with our refreshing juice – it's as bright as a Sun Flower! In our Toadstool Stand, you're not just limited to one sip. Try a mix of free samples, or channel your inner alchemist like Toadsworth by blending it with other delightful beverages. The adventure for your taste buds awaits – power up and enjoy! ✨
- Advanced Heap internal,
glibc 2.23.
Remainder,FSOPandHouse of Orange.
First of all, we start with a checksec:
pwndbg> checksec
Arch: amd64
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'./glibc/'
SHSTK: Enabled
IBT: Enabled
Stripped: NoAs we can see:
| Protection | Enabled | Usage |
|---|---|---|
| Canary | ✅ | Prevents Buffer Overflows |
| NX | ✅ | Disables code execution on stack |
| PIE | ✅ | Randomizes the base address of the binary |
| RelRO | Full | Makes some binary sections read-only |
All protections are enabled.
The program's interface
It looks like a heap challenge.
Starting with main():
void main(void)
{
ulong uVar1;
void *pvVar2;
long lVar3;
void **ppvVar4;
long in_FS_OFFSET;
byte bVar5;
char local_81;
void *local_78 [11];
undefined8 local_20;
bVar5 = 0;
local_20 = *(undefined8 *)(in_FS_OFFSET + 0x28);
setup();
banner();
ppvVar4 = local_78;
for (lVar3 = 10; lVar3 != 0; lVar3 = lVar3 + -1) {
*ppvVar4 = (void *)0x0;
ppvVar4 = ppvVar4 + (ulong)bVar5 * -2 + 1;
}
local_81 = '\0';
while( true ) {
while( true ) {
while( true ) {
printf(&DAT_00101898,(ulong)(uint)(int)local_81);
uVar1 = read_num();
if (uVar1 != 2) break;
printf("\nChoose glass to empty: ");
uVar1 = read_num();
if (uVar1 < (ulong)(long)local_81) {
if (local_78[uVar1] == (void *)0x0) {
error("This glass is already empty!");
}
else {
free(local_78[uVar1]);
local_78[uVar1] = (void *)0x0;
puts("\nGlass is empty now!\n");
}
}
else {
error("This glass is unavailable!");
}
}
if (uVar1 < 3) break;
if (uVar1 == 3) {
printf("\nChoose glass to customize: ");
uVar1 = read_num();
if (uVar1 < (ulong)(long)local_81) {
if (local_78[uVar1] == (void *)0x0) {
error("Cannot customize empty glass!");
}
else {
printf("\nAdd another drink: ");
read(0,local_78[uVar1],0x59);
putchar(10);
}
}
else {
error("This glass is unavailable!");
}
}
else {
if (uVar1 != 4) goto LAB_00100faa;
printf("\nChoose glass: ");
uVar1 = read_num();
if (uVar1 < (ulong)(long)local_81) {
if (local_78[uVar1] == (void *)0x0) {
error("Cannot view empty glass!");
}
else {
printf("\nGlass content: ");
write(1,local_78[uVar1],0x58);
putchar(10);
}
}
else {
error("This glass is unavailable!");
}
}
}
if (uVar1 != 1) break;
if ('\x0f' < local_81) {
error("You cannot take any more glasses!");
/* WARNING: Subroutine does not return */
exit(0x45);
}
pvVar2 = calloc(1,0x58);
local_78[(int)local_81] = pvVar2;
if (local_78[(int)local_81] == (void *)0x0) {
error("Something went wrong with the juice!");
}
else {
local_81 = local_81 + '\x01';
printf("\nHere is your juice!\n\n");
}
}
LAB_00100faa:
error("Have a great day!\n");
/* WARNING: Subroutine does not return */
exit(0x45);
}This is the one and only function we will focus on.
-
Call
fill()five times to allocate chunks (0-4). -
Chunk
0is the "tamper" chunk (used for overflow). -
Chunk
1will be freed to place it in the unsorted bin. -
Chunk
2will be used toleak libcaddresses.
-
Use
edit(0)to overflow into chunk1, modifying itsmetadatato merge it with chunk2. -
Set the size to
0xc1to make chunk1appear larger.
-
Free chunk
1to place it in the unsorted bin (empty(1)). -
This allows unsorted bin metadata to overwrite the content of chunk
2.
- Allocate another chunk (
fill(5)) to reuse the tampered chunk. - Use
view(2)to print thelibcaddress from the unsorted bin'smetadata.
- Allocate and free additional chunks to leak the heap address (
view).
- Allocate a chunk and use
editto overwrite the unsorted bin'sbkpointer with_IO_list_all - 0x10.
- Use
editto craft a fake_IO_FILEstructure with avtablepointing tosystem.
- Call
fillto trigger_IO_OVERFLOW, which calls the fakevtableand executessystem("/bin/sh").
Running solver remotely at 0.0.0.0 1337
Libc address: 0x7f6d8f66f000
Heap address: 0x5648321bf000
Tries: 3
Flag --> HTB{XXXXXXXXXXX}

