Skip to content

Commit

Permalink
unicornafl: Add UAF chcker to loader (AFLplusplus#2009)
Browse files Browse the repository at this point in the history
* impl uaf chcker

By adding a list of freed chunks, add the chunk to the list during free, check whether the allocated block is in the freed chunk list during malloc, and if so, remove the chunk from the freed chunk list, in __check_mem_access check whether the address is in the freed chunk list. This enables the detection of uaf.

* make uaf_check be configruable
  • Loading branch information
Resery authored Feb 27, 2024
1 parent 9f6d27d commit 1e01ccc
Showing 1 changed file with 22 additions and 1 deletion.
23 changes: 22 additions & 1 deletion unicorn_mode/helper_scripts/unicorn_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,10 @@ def is_buffer_in_chunk(self, addr, size):

_uc = None # Unicorn engine instance to interact with
_chunks = [] # List of all known chunks
_chunks_freed = [] # List of all freed chunks
_debug_print = False # True to print debug information

def __init__(self, uc, debug_print=False):
def __init__(self, uc, debug_print=Falseuaf_check=False):
self._uc = uc
self._debug_print = debug_print

Expand All @@ -111,6 +112,13 @@ def malloc(self, size):
try:
self._uc.mem_map(addr, total_chunk_size, UC_PROT_READ | UC_PROT_WRITE)
chunk = self.HeapChunk(addr, total_chunk_size, size)

if self.uaf_check:
for chunk_freed in self._chunks_freed:
if chunk_freed.is_buffer_in_chunk(chunk.data_addr, 1):
self._chunks_freed.remove(chunk_freed)
break

if self._debug_print:
print(
"Allocating 0x{0:x}-byte chunk @ 0x{1:016x}".format(
Expand Down Expand Up @@ -164,6 +172,10 @@ def free(self, addr):
)
)
self._uc.mem_unmap(chunk.actual_addr, chunk.total_size)

if self.uaf_check:
self._chunks_freed.append(chunk)

self._chunks.remove(chunk)
return True
# Freed an object that doesn't exist. Maybe 'dobule-free' or 'invalid free' vulnerability here.
Expand All @@ -187,6 +199,15 @@ def __check_mem_access(self, uc, access, address, size, value, user_data):
# Force a memory-based crash
uc.force_crash(UcError(UC_ERR_READ_PROT))

if self.uaf_check:
for chunk in self._chunks_freed:
if address >= chunk.actual_addr and (
(address + size) <= (chunk.actual_addr + chunk.total_size)
):
if chunk.is_buffer_in_chunk(address, size):
print("Use-after-free @ 0x{0:016x}".format(address))
uc.force_crash(UcError(UC_ERR_FETCH_UNMAPPED))


# ---------------------------
# ---- Loading function
Expand Down

0 comments on commit 1e01ccc

Please sign in to comment.