Skip to content

Adding heap grooming to avoid non contiguous memory blocks#172

Open
x-64 wants to merge 3 commits intopwncollege:mainfrom
x-64:adding_heap_grooming_for_downunderctf2022_babypywn
Open

Adding heap grooming to avoid non contiguous memory blocks#172
x-64 wants to merge 3 commits intopwncollege:mainfrom
x-64:adding_heap_grooming_for_downunderctf2022_babypywn

Conversation

@x-64
Copy link
Contributor

@x-64 x-64 commented Jan 31, 2026

Under standard conditions the two blocks are not contiguous:

Address of buf1: 0x70f19a23c230
Address of buf2: 0x70f19a11f230
Distance: -1167360

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts the babypywn challenge script to “heap groom” by making several early ctypes allocations, aiming to increase the likelihood that the subsequently allocated buffers end up contiguous in memory (as needed by the challenge behavior).

Changes:

  • Pre-allocates a list of 10 ctypes.c_buffer(512) objects before allocating buf1/buf2.
  • Minor edit in the final print(open('/flag', 'r').read()) line (re-touched in the diff).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


from ctypes import CDLL, c_buffer
libc = CDLL('/usr/lib/x86_64-linux-gnu/libc.so.6')
prime = [c_buffer(512) for _ in range(10)]
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new prime allocation list is never referenced, so it reads as unused/accidental. If this is intentional heap grooming, consider renaming it to something descriptive (e.g., heap_groom/groom_allocs) and add a short comment explaining why this allocation count/size is needed to keep the buffers alive and influence layout.

Suggested change
prime = [c_buffer(512) for _ in range(10)]
# Heap grooming: keep these allocations alive to influence buffer layout.
heap_groom = [c_buffer(512) for _ in range(10)]

Copilot uses AI. Check for mistakes.
libc.gets(buf1)
if b'pwn.college' in bytes(buf2):
print(open('/flag', 'r').read()) No newline at end of file
print(open('/flag', 'r').read())
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

open('/flag', 'r').read() leaves the file descriptor open until GC; use a context manager (with open(...) as f:) to ensure the file is closed deterministically.

Suggested change
print(open('/flag', 'r').read())
with open('/flag', 'r') as f:
print(f.read())

Copilot uses AI. Check for mistakes.
Comment on lines 3 to 8
from ctypes import CDLL, c_buffer
libc = CDLL('/usr/lib/x86_64-linux-gnu/libc.so.6')
prime = [c_buffer(512) for _ in range(10)]
buf1 = c_buffer(512)
buf2 = c_buffer(512)
libc.gets(buf1)
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of libc.gets(buf1) with a fixed-size c_buffer(512) is inherently unsafe, because gets does not enforce any length limit and allows an attacker to overflow buf1 and corrupt adjacent memory (including buf2). In this context an attacker can input more than 512 bytes to control buf2 and satisfy the if b'pwn.college' in bytes(buf2) check to read /flag, and depending on layout may also achieve arbitrary memory corruption or code execution. Replace gets with a bounded input API (e.g., one that takes the buffer size and enforces it) and ensure that any low-level reads via ctypes are strictly length-checked.

Suggested change
from ctypes import CDLL, c_buffer
libc = CDLL('/usr/lib/x86_64-linux-gnu/libc.so.6')
prime = [c_buffer(512) for _ in range(10)]
buf1 = c_buffer(512)
buf2 = c_buffer(512)
libc.gets(buf1)
from ctypes import c_buffer
prime = [c_buffer(512) for _ in range(10)]
buf1 = c_buffer(512)
buf2 = c_buffer(512)
# Safely read at most 511 bytes of user input into buf1, leaving room for a null terminator.
user_input = input()
data = user_input.encode('utf-8', errors='ignore')[:511]
buf1.value = data

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants