Add partial overwrite support to find_fake_fast command (#2667)

* Add partial overwrite candidate to test binary

* Add --partial-overwrite option

* Add partial overwrite test case

* Implement partial overwrite feature
pull/2672/head
CptGibbon 11 months ago committed by GitHub
parent 882cd5ad7f
commit 02590b6134
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -804,6 +804,12 @@ parser.add_argument(
default=False,
help="Does the GLIBC fastbin size field bug affect the candidate size field width?",
)
parser.add_argument(
"--partial-overwrite",
"-p",
action="store_true",
help="Consider partial overwrite candidates, default behavior only shows word-size overwrites.",
)
@pwndbg.commands.ArgparsedCommand(parser, category=CommandCategory.PTMALLOC2)
@ -815,6 +821,7 @@ def find_fake_fast(
max_candidate_size: int | None = None,
align: bool = False,
glibc_fastbin_bug: bool = False,
partial_overwrite: bool = False,
) -> None:
"""Find candidate fake fast chunks overlapping the specified address."""
allocator = pwndbg.aglib.heap.current
@ -867,7 +874,11 @@ def find_fake_fast(
max_candidate_size &= ~(allocator.malloc_align_mask)
if partial_overwrite:
search_start = (target_address - max_candidate_size + size_sz) - (size_sz - 1)
else:
search_start = target_address - max_candidate_size + size_sz
search_end = target_address
if pwndbg.aglib.memory.peek(search_start) is None:
@ -916,8 +927,14 @@ def find_fake_fast(
continue
candidate_address = search_start + i
if partial_overwrite:
if (candidate_address + size_field) > target_address:
malloc_chunk(candidate_address - size_sz, fake=True)
else:
if (candidate_address + size_field) >= (target_address + size_sz):
malloc_chunk(candidate_address - size_sz, fake=True)
else:
break

@ -33,7 +33,8 @@ unsigned long target_address;
* Put the value of `size` at `distance` bytes before the address of
* `target_address`
*/
void setup_mem(unsigned long size, unsigned distance) {
void setup_mem(unsigned long size, unsigned distance)
{
memset(buf, 0, sizeof(buf));
target_address = 0;
@ -41,7 +42,8 @@ void setup_mem(unsigned long size, unsigned distance) {
*(unsigned long *)chunk_size_addr = size;
}
int main(void) {
int main(void)
{
assert((unsigned long)&target_address - (unsigned long)buf == sizeof(buf));
/* Test whether the find_fake_fast command can deal with a fake chunk that has a set
@ -133,4 +135,9 @@ int main(void) {
// fastbin size bug, this is still valid
setup_mem(0xAABBCCDD00000020, 0x8);
break_here();
// A fastbin chunk that overlaps only the first byte of the target address
// Used to test the --partial-overwrite option
setup_mem(0x8000, 0x80);
break_here();
}

@ -164,3 +164,10 @@ def test_find_fake_fast_command(start_binary):
result = gdb.execute("find_fake_fast &target_address --glibc-fastbin-bug", to_string=True)
check_result(result, 0xAABBCCDD00000020)
gdb.execute("continue")
# setup_mem(0x8000, 0x80)
result = gdb.execute("find_fake_fast &target_address", to_string=True)
check_no_results(result)
result = gdb.execute("find_fake_fast &target_address --partial-overwrite", to_string=True)
check_result(result, 0x80)

Loading…
Cancel
Save