about summary refs log tree commit diff
diff options
context:
space:
mode:
authorResery <50428593+Resery@users.noreply.github.com>2024-02-27 02:43:50 -0600
committerGitHub <noreply@github.com>2024-02-27 09:43:50 +0100
commit1e01ccc8fd717b067b697d5b7353a5d587f6a484 (patch)
treeb48222bb8136a40fa2f08fee5a267c1da42833b1
parent9f6d27ddcef43c676985523bb38be2ec292a3227 (diff)
downloadafl++-1e01ccc8fd717b067b697d5b7353a5d587f6a484.tar.gz
unicornafl: Add UAF chcker to loader (#2009)
* 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
-rw-r--r--unicorn_mode/helper_scripts/unicorn_loader.py23
1 files changed, 22 insertions, 1 deletions
diff --git a/unicorn_mode/helper_scripts/unicorn_loader.py b/unicorn_mode/helper_scripts/unicorn_loader.py
index d0995f83..a83e7000 100644
--- a/unicorn_mode/helper_scripts/unicorn_loader.py
+++ b/unicorn_mode/helper_scripts/unicorn_loader.py
@@ -87,9 +87,10 @@ class UnicornSimpleHeap(object):
 
     _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=False, uaf_check=False):
         self._uc = uc
         self._debug_print = debug_print
 
@@ -111,6 +112,13 @@ class UnicornSimpleHeap(object):
             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(
@@ -164,6 +172,10 @@ class UnicornSimpleHeap(object):
                         )
                     )
                 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.
@@ -187,6 +199,15 @@ class UnicornSimpleHeap(object):
                     # 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