MemLeak is a caching and heuristic tool for exploiting memory leaks. It can be used as a decorator, around functions of the form: def some_leaker(addr): ... return data_as_string_or_None It will cache leaked memory (which requires either non-randomized stat
| 18 | __all__ = ['MemLeak', 'RelativeMemLeak'] |
| 19 | |
| 20 | class MemLeak(object): |
| 21 | """MemLeak is a caching and heuristic tool for exploiting memory leaks. |
| 22 | |
| 23 | It can be used as a decorator, around functions of the form: |
| 24 | |
| 25 | def some_leaker(addr): |
| 26 | ... |
| 27 | return data_as_string_or_None |
| 28 | |
| 29 | It will cache leaked memory (which requires either non-randomized static |
| 30 | data or a continouous session). If required, dynamic or known data can be |
| 31 | set with the set-functions, but this is usually not required. If a byte |
| 32 | cannot be recovered, it will try to leak nearby bytes in the hope that the |
| 33 | byte is recovered as a side-effect. |
| 34 | |
| 35 | Arguments: |
| 36 | f (function): The leaker function. |
| 37 | search_range (int): How many bytes to search backwards in case an address does not work. |
| 38 | reraise (bool): Whether to reraise call :func:`pwnlib.log.warning` in case the leaker function throws an exception. |
| 39 | |
| 40 | Example: |
| 41 | |
| 42 | >>> import pwnlib |
| 43 | >>> binsh = pwnlib.util.misc.read('/bin/sh') |
| 44 | >>> @pwnlib.memleak.MemLeak |
| 45 | ... def leaker(addr): |
| 46 | ... print("leaking 0x%x" % addr) |
| 47 | ... return binsh[addr:addr+4] |
| 48 | >>> leaker.s(0)[:4] |
| 49 | leaking 0x0 |
| 50 | leaking 0x4 |
| 51 | b'\\x7fELF' |
| 52 | >>> leaker[:4] |
| 53 | b'\\x7fELF' |
| 54 | >>> hex(leaker.d(0)) |
| 55 | '0x464c457f' |
| 56 | >>> hex(leaker.clearb(1)) |
| 57 | '0x45' |
| 58 | >>> hex(leaker.d(0)) |
| 59 | leaking 0x1 |
| 60 | '0x464c457f' |
| 61 | >>> @pwnlib.memleak.MemLeak |
| 62 | ... def leaker_nonulls(addr): |
| 63 | ... print("leaking 0x%x" % addr) |
| 64 | ... if addr & 0xff == 0: |
| 65 | ... return None |
| 66 | ... return binsh[addr:addr+4] |
| 67 | >>> leaker_nonulls.d(0) is None |
| 68 | leaking 0x0 |
| 69 | True |
| 70 | >>> leaker_nonulls[0x100:0x104] == binsh[0x100:0x104] |
| 71 | leaking 0x100 |
| 72 | leaking 0xff |
| 73 | leaking 0x103 |
| 74 | True |
| 75 | |
| 76 | >>> memory = {-4+i: c.encode() for i,c in enumerate('wxyzABCDE')} |
| 77 | >>> def relative_leak(index): |
no outgoing calls
no test coverage detected