From 0bad90edb3a1e432b321832575a00c7a7292530c Mon Sep 17 00:00:00 2001 From: Leonard Kugis Date: Sat, 7 Mar 2020 01:06:04 +0100 Subject: IntroSec Added double free attack scenarios. --- .../introduction_to_information_security.md | 54 +++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) (limited to 'en_GB/Introduction to Information Security') diff --git a/en_GB/Introduction to Information Security/introduction_to_information_security.md b/en_GB/Introduction to Information Security/introduction_to_information_security.md index fbdd9ad..d1ce4fb 100644 --- a/en_GB/Introduction to Information Security/introduction_to_information_security.md +++ b/en_GB/Introduction to Information Security/introduction_to_information_security.md @@ -383,7 +383,7 @@ The password is `IntroSec`. so it is likely that there is no new correct char. 4. The attacker continues, learning char by char for each processing time increase, until he got the full password. -## Software Security +## Memory management ### Buffers @@ -391,6 +391,16 @@ Logically, values are assigned to variables. In reality, for every variable, a portion of memory on the call stack gets allocated (*buffer*), and the data gets written to that buffer. Data written to the buffer is written upwards from the address allocated to the buffer. +### Allocation (Doug Lea) + +Memory is divided into chunks. These contain the user and control data (e.g. boundary tags (size, previous size)). +Adjacent free chunks are unified to one free chunk automatically. +Free chunks are stored in *bins*, which are connected in a double linked list, and sorted by size (ascending). +When a chunk is freed, `frontlink(...)` searches the *bins* list from lowest to highest size, and places the chunk in the list whenever +the chunk in the next bin is bigger than the chunk itself, and inserts the chunk in the list in that place. +`unlink(...)` does the opposite. It takes the chunk specified, looks up the chunk in the bin list, +and removes it by rearranging pointers of the next and previous bin. + ## Threat scenarios No security issues without threat models! E.g. a password is considered safe without any provided threat model. @@ -479,3 +489,45 @@ and overrides in wrong memory. - Protect return address using *canaries*. Special instructions placed before actually returning to check for correct return address. - Mark potential shellcode memory as non-executable. + +### Double Free + +#### Dependencies + +When `free(...)` is executed, `frontlink(...)` gets executed at some point transparently. +When `frontlink(...)` finds a place in the *bin* list to put the chunk, it sets the next pointer of the previous chunk +and the back pointer of the next chunk to the inserted chunk. +If this chunk gets added another time, *the previous chunk is already the inserted chunk*! +So the next pointer of the previous chunk gets gets linked to the inserted chunk. +*But with the previous chunk being already the inserted chunk, the next pointer of the inserted chunk gets linked to itself.* +Also, the back pointer of the inserted chunk gets linked to the previous chunk. +*But with the previous chunk being already the inserted chunk, the back pointer of the inserted chunk gets linked to itself.* +Invoking a `malloc(...)` (and eventually an `unlink(...)`) now will result in the chunk *not being removed* from the bin list, +due to the looping pointers on itself. + +#### Free-Free-Malloc-Malloc + +1. Prepare memory. These steps are for target and shellcode preparation. The chunks inbetween ensure, that the chunks dont get unified on `free`. +1.1 Allocate top memory chunk. +1.2 Allocate target chunk from top memory chunk. +1.3 Allocate top memory chunk. +1.4 Allocate shellcode chunk. +2. Perform `free` on target chunk twice. +3. Call `malloc` with size of target chunk. We might get the target junk again, *but it won't get removed from the bin list*. +4. Chunk is now writable. Overwrite *back* pointer with attack target address, and *next* pointer with attack target value. +5. Call `malloc` again. `unlink` algorithm will overwrite memory at *back* with *next*. + +#### Free-Malloc-Free + +1. Allocate memory chunk *A*. +2. `free(A)`, hope that the chunk gets unified with the following chunk. +3. Allocate large chunk *B*, hope to get the chunk just freed. +4. Write ghost chunk data to *B* so, that it appears to be a chunk at *A*, and an unallocated adjacent chunk. +5. Call `free(A)` again. `unlink` is applied to ghost chunk. Unifying will overwrite a target address. + +#### Countermeasure: Canary + +Add *canary* to end of chunk, checksumming the chunks control data, signed with secret key. + +1. On allocation, add calculate checksum over chunk control data and add canary. +2. On `free`, recalculate checksum. If they mismatch, throw error. -- cgit v1.2.1