Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

display chain bk and fd if corrupted #537

Merged
merged 4 commits into from
Oct 16, 2018

Conversation

GrosQuildu
Copy link
Contributor

fixes #507
Adds check for doubly linked bins corruption.
It's WIP, as idk how we want to print the corruption, currently its:

pwndbg> bins
...
smallbins
0x100 [corrupted]
FD: 0x555555756600 ◂— 0xbeef
BK: 0x555555756400 —▸ 0x555555756600 —▸ 0x7ffff7dd3c48 (main_arena+328) ◂— 0x555555756400
0x130 [corrupted]
FD: 0x555555756a60 —▸ 0x7ffff7dd3c78 (main_arena+376) ◂— 0x555555756a60 /* '`juUUU' */
BK: 0x555555756800 —▸ 0x555555756a60 —▸ 0x7ffff7dd3c78 (main_arena+376) ◂— 0x555555756800
...

File to test:

#include <stdio.h>
#include <stdlib.h>

int main() {
    char* a1 = malloc(0xf0);
    char* a2 = malloc(0xf0);
    char* a3 = malloc(0xf0);
    char* a4 = malloc(0xf0);
    char* a5 = malloc(0xf0);
    char* a6 = malloc(0xf0);
    char* a7 = malloc(0xf0);
    char* a8 = malloc(0xf0);

    free(a1);
    free(a3);
    free(a5);
    free(a7);
    // breakpoint 1 here

    *(size_t*)a1 = 0xdead;
    // breakpoint 2 here

    a3 = malloc(0xe0);
    char *l1 = malloc(0x123);
    char *l2 = malloc(0x123);
    char *l3 = malloc(0x123);
    char *l4 = malloc(0x123);
    free(l1);
    free(l3);
    malloc(0xe0);
    // breakpoint 3 here

    *(size_t*)a7 = 0xbeef;
    *(size_t*)l3 = *(size_t*)(l3+sizeof(size_t));
    // breakpoint 4 here

    return 0;
}

@GrosQuildu GrosQuildu changed the title wip, display chain bk and fd if corrupted [WIP], display chain bk and fd if corrupted Oct 4, 2018
@@ -393,6 +393,7 @@ def fastbin_index(self, size):


def fastbins(self, arena_addr=None):
"""Returns: chain or None"""
Copy link
Member

Choose a reason for hiding this comment

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

Might be good to add when None might be returned (same for the ones below)


is_chain_corrupted = False
chain_fd = pwndbg.chain.get(int(front), offset=fd_offset, hard_stop=current_base, limit=heap_chain_limit, include_start=True)
chain_bk = pwndbg.chain.get(int(back), offset=bk_offset, hard_stop=current_base, limit=heap_chain_limit, include_start=True)
Copy link
Member

Choose a reason for hiding this comment

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

Maybe:

get_chain = lambda bin: pwndbg.chain.get(int(bin), offset=fd_offset, hard_stop=current_base, limit=heap_chain_limit, include_start=True)
chain_fd = get_chain(front)
chain_bk = get_chain(back)

chain_bk = pwndbg.chain.get(int(back), offset=bk_offset, hard_stop=current_base, limit=heap_chain_limit, include_start=True)

# check if bin[index] points to itself (is empty)
if len(chain_fd) == 2 and len(chain_bk) == 2 and chain_fd[0] == chain_bk[0]:
Copy link
Member

@disconnect3d disconnect3d Oct 7, 2018

Choose a reason for hiding this comment

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

as its Python it can be written as if len(chain_fd) == len(chain_bk) == 2 and ...
I don't mind leaving it as it is; it's up to you

@@ -449,6 +451,8 @@ def bin_at(self, index, arena_addr=None):
Bin 1 - Unsorted BiN
Bin 2 to 63 - Smallbins
Bin 64 to 126 - Largebins

Returns: tuple(chain_from_bin_fd, chain_from_bin_bk, is_chain_corrupted) or None
Copy link
Member

Choose a reason for hiding this comment

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

Does it detect all cases of corrupted chains? What if there is a loop in the linked list pointers (I guess there might be one).
Might be good to add some docs about it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i think all cases. Can't get into loop, because pwndbg.chain.get stops when loop is detected.
Docs seems unnecesary, as the check is simple.

Copy link
Member

Choose a reason for hiding this comment

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

The docs could document examples how those commands behave when heap is corrupted (with examples)

@GrosQuildu GrosQuildu changed the title [WIP], display chain bk and fd if corrupted display chain bk and fd if corrupted Oct 13, 2018
@disconnect3d
Copy link
Member

disconnect3d commented Oct 16, 2018

Below results before and after changes, a bit adjusted by adding newlines after each command result.

Result before the changes:

pwndbg> r
Starting program: /home/dominik/playground/a.out

Breakpoint 1, 0x000000000040056a in foo ()
Breakpoint foo

pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x602400 —▸ 0x602200 —▸ 0x602000 —▸ 0x7ffff7dd1b78 (main_arena+88) —▸ 0x602600 ◂— ...
smallbins
empty
largebins
empty

pwndbg> c
Continuing.

Breakpoint 1, 0x000000000040056a in foo ()
Breakpoint foo

pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x602400 —▸ 0x602200 —▸ 0x602000 ◂— 0xdead
smallbins
empty
largebins
empty

pwndbg> c
Continuing.

Breakpoint 1, 0x000000000040056a in foo ()
Breakpoint foo
pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
0x100: 0x602400 —▸ 0x7ffff7dd1c68 (main_arena+328) —▸ 0x602600 ◂— 0x602400
0x130: 0x602800 —▸ 0x7ffff7dd1c98 (main_arena+376) —▸ 0x602a60 ◂— 0x602800
largebins
empty

pwndbg> c
Continuing.

Breakpoint 1, 0x000000000040056a in foo ()
Breakpoint foo
pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
0x100: 0xbeef
0x130: 0x7ffff7dd1c98 (main_arena+376) —▸ 0x602a60 ◂— 0x7ffff7dd1c98
largebins
empty

pwndbg> c
Continuing.
[Inferior 1 (process 25005) exited normally]

After changes:

$ gdb ./a.out -q

pwndbg> b foo
Breakpoint 1 at 0x40056a

pwndbg> r
Starting program: /home/dominik/playground/a.out

Breakpoint 1, 0x000000000040056a in foo ()
Breakpoint foo
pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x602600 —▸ 0x602400 —▸ 0x602200 —▸ 0x602000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— ...
smallbins
empty
largebins
empty

pwndbg> c
Continuing.

Breakpoint 1, 0x000000000040056a in foo ()
Breakpoint foo

pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all [corrupted]
FD: 0x602600 —▸ 0x602400 —▸ 0x602200 —▸ 0x602000 ◂— 0xdead
BK: 0x602000 —▸ 0x602200 —▸ 0x602400 —▸ 0x602600 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— ...
smallbins
empty
largebins
empty

pwndbg> c
Continuing.

Breakpoint 1, 0x000000000040056a in foo ()
Breakpoint foo

pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
0x100: 0x602600 —▸ 0x602400 —▸ 0x7ffff7dd1c68 (main_arena+328) ◂— 0x602600
0x130: 0x602a60 —▸ 0x602800 —▸ 0x7ffff7dd1c98 (main_arena+376) ◂— 0x602a60 /* '`*`' */
largebins
empty

pwndbg> c
Continuing.

Breakpoint 1, 0x000000000040056a in foo ()
Breakpoint foo

pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
0x100 [corrupted]
FD: 0x602600 ◂— 0xbeef
BK: 0x602400 —▸ 0x602600 —▸ 0x7ffff7dd1c68 (main_arena+328) ◂— 0x602400
0x130 [corrupted]
FD: 0x602a60 —▸ 0x7ffff7dd1c98 (main_arena+376) ◂— 0x602a60 /* '`*`' */
BK: 0x602800 —▸ 0x602a60 —▸ 0x7ffff7dd1c98 (main_arena+376) ◂— 0x602800
largebins
empty

pwndbg> c
Continuing.
[Inferior 1 (process 24980) exited normally]

count, is_chain_corrupted = None, False
if len(b) == 1: # fastbin:
chain_fd = b
elif len(b) == 2: # tcachebin:
Copy link
Member

Choose a reason for hiding this comment

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

What is this dictated by?

Can we add a comment with link to some documentation or glibc source code? Or explain this?

Copy link
Member

@disconnect3d disconnect3d left a comment

Choose a reason for hiding this comment

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

LGTM

@disconnect3d disconnect3d merged commit 5b307a2 into pwndbg:dev Oct 16, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

"bins" command shows that small bin is empty but actually it's not
2 participants