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

Linux: Address limitations in determining KASLR shifts by introducing VMCoreInfo support #1332

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from

Conversation

gcmoreira
Copy link
Contributor

@gcmoreira gcmoreira commented Nov 4, 2024

This pull request addresses a limitation in the current method for determining KASLR and ASLR shifts by extracting these values from the VMCoreInfo ELF note.
In addition, with the ability to locate the VMCoreInfo ELF note, it became straightforward to also add a plugin to this PR which exports all this information.

The KASLR and ASLR shifts issue

The existing scanning method can inaccurately calculate these shifts in certain situations. For instance, a QEMU memory dump demonstrates this issue.

$ ./vol.py \
    -f ./dump_ubuntu180464bit_4.15.0-213-generic_reptile.core \
    linux.pslist 
Volatility 3 Framework 2.11.0      
OFFSET (V)      PID     TID     PPID    COMM    File output


Volatility was unable to read a requested page:
Page error 0x8c1cbc89b82c in layer layer_name (Page Fault at entry 0x0 in table page directory pointer)

        * Memory smear during acquisition (try re-acquiring if possible)
        * An intentionally invalid page lookup (operating system protection)
        * A bug in the plugin/volatility3 (re-run with -vvv and file a bug)

No further results will be produced

This is because the sample being analyzed has not just one swapper string match, but four, with the last one being the correct match.

$ binwalk -R "swapper/0\x00\x00" ./dump_ubuntu180464bit_4.15.0-213-generic.core

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
346048320     0x14A04740      Raw signature (swapper/0\x00\x00)
1516259136    0x5A604740      Raw signature (swapper/0\x00\x00)
1556105024    0x5CC04740      Raw signature (swapper/0\x00\x00)
1975535424    0x75C04740      Raw signature (swapper/0\x00\x00)

This causes the current find_aslr() scanning implementation to incorrectly calculate the KASLR/ASLR shifts, resulting in the entire analysis failing.

VMCoreInfo

The VMCoreInfo was introduced in Linux kernel 2.6.24 to assist user-space tools such as Crash and makedumpfile in analyzing the kernel's memory layout.
It provides all the essential information and kernel parameters needed to analyze a crash memory dump.

Volatility3 using VMCoreInfo

This PR enhances the Volatility 3 framework by adding support for searching the VMCoreInfo ELF note during initialization. It retrieves the ASLR shift and calculates the physical shift. If the VMCoreInfo ELF note is not found, it gracefully falls back to the traditional method.

Pros

  • Self-Sufficient: Work without reliance on external ISF, enabling early collection of all system parameters during framework initialization. This is especially useful for handling more complex architectures compared to x86-64, like AArch64.
  • Improved Speed: When successful, it delivers faster execution time than the conventional method. However, if VMCoreInfo is missing, there is additional overhead as both methods need to be executed.

Cons

  • Only works when VMCoreInfo is enable in the kernel.
  • It doesn't support kernels < 4.10 ( KERNELOFFSET was added in kernels 3.13, while phys_base as a value was added in 4.10). Given that kernel 4.10 was released in 2017, I think this limitation is relatively manageable.

Demo

$ time python3 ./vol.py \
    -f ./dump_ubuntu180464bit_4.15.0-213-generic_reptile.core \
    linux.pslist
Volatility 3 Framework 2.11.0
OFFSET (V)      PID     TID     PPID    COMM    File output

0x8c1cbc8997c0  1       1       0       systemd Disabled
0x8c1cbc89af80  2       2       0       kthreadd        Disabled
0x8c1cbc898000  3       3       2       kworker/0:0     Disabled
...
0x8c1cb7f897c0  1126    1126    1125    bash    Disabled

real    0m8.990s
user    0m7.880s
sys     0m0.982s

The VMCoreInfo plugin

Additionally, this PR introduces the VMCoreInfo plugin. It's a particular plugin that works without relying on an external ISF symbol file, needing only the elf.json already included with the framework. It supports any architecture, with the only requirement being that it must be little-endian. This can be addressed in future updates.

Demos

x86-64

$ time ./vol.py -r pretty \
    -f ./dump_ubuntu180464bit_4.15.0-213-generic_reptile_infected.core \
    linux.vmcoreinfo
Volatility 3 Framework 2.11.0
  |     Offset |                                    Key |              Value
* | 0x7c9f6000 |                              OSRELEASE | 4.15.0-213-generic
* | 0x7c9f6000 |                               PAGESIZE |               4096
* | 0x7c9f6000 |                    SYMBOL(init_uts_ns) |   ffffffffb1c13280
* | 0x7c9f6000 |                SYMBOL(node_online_map) |   ffffffffb1e60f20
* | 0x7c9f6000 |                 SYMBOL(swapper_pg_dir) |   ffffffffb1c0a000
* | 0x7c9f6000 |                         SYMBOL(_stext) |   ffffffffb0800000
* | 0x7c9f6000 |                 SYMBOL(vmap_area_list) |   ffffffffb1d07bd0
* | 0x7c9f6000 |                    SYMBOL(mem_section) |   ffff96853ff2c000
* | 0x7c9f6000 |                    LENGTH(mem_section) |               2048
* | 0x7c9f6000 |                      SIZE(mem_section) |                 16
* | 0x7c9f6000 |    OFFSET(mem_section.section_mem_map) |                  0
* | 0x7c9f6000 |                             SIZE(page) |                 64
* | 0x7c9f6000 |                      SIZE(pglist_data) |             172864
* | 0x7c9f6000 |                             SIZE(zone) |               1664
* | 0x7c9f6000 |                        SIZE(free_area) |                104
* | 0x7c9f6000 |                        SIZE(list_head) |                 16
* | 0x7c9f6000 |                       SIZE(nodemask_t) |                128
* | 0x7c9f6000 |                     OFFSET(page.flags) |                  0
* | 0x7c9f6000 |                 OFFSET(page._refcount) |                 28
* | 0x7c9f6000 |                   OFFSET(page.mapping) |                  8
* | 0x7c9f6000 |                       OFFSET(page.lru) |                 32
* | 0x7c9f6000 |                 OFFSET(page._mapcount) |                 24
* | 0x7c9f6000 |                   OFFSET(page.private) |                 48
* | 0x7c9f6000 |             OFFSET(page.compound_dtor) |                 40
* | 0x7c9f6000 |            OFFSET(page.compound_order) |                 44
* | 0x7c9f6000 |             OFFSET(page.compound_head) |                 32
* | 0x7c9f6000 |         OFFSET(pglist_data.node_zones) |                  0
* | 0x7c9f6000 |           OFFSET(pglist_data.nr_zones) |             172192
* | 0x7c9f6000 |     OFFSET(pglist_data.node_start_pfn) |             172200
* | 0x7c9f6000 | OFFSET(pglist_data.node_spanned_pages) |             172216
* | 0x7c9f6000 |            OFFSET(pglist_data.node_id) |             172224
* | 0x7c9f6000 |                 OFFSET(zone.free_area) |                192
* | 0x7c9f6000 |                   OFFSET(zone.vm_stat) |               1472
* | 0x7c9f6000 |             OFFSET(zone.spanned_pages) |                112
* | 0x7c9f6000 |            OFFSET(free_area.free_list) |                  0
* | 0x7c9f6000 |                 OFFSET(list_head.next) |                  0
* | 0x7c9f6000 |                 OFFSET(list_head.prev) |                  8
* | 0x7c9f6000 |             OFFSET(vmap_area.va_start) |                  0
* | 0x7c9f6000 |                 OFFSET(vmap_area.list) |                 48
* | 0x7c9f6000 |                 LENGTH(zone.free_area) |                 11
* | 0x7c9f6000 |                        SYMBOL(log_buf) |   ffffffffb1c63ce0
* | 0x7c9f6000 |                    SYMBOL(log_buf_len) |   ffffffffb1c63cdc
* | 0x7c9f6000 |                  SYMBOL(log_first_idx) |   ffffffffb21ab4f8
* | 0x7c9f6000 |                      SYMBOL(clear_idx) |   ffffffffb21ab4c4
* | 0x7c9f6000 |                   SYMBOL(log_next_idx) |   ffffffffb21ab4e8
* | 0x7c9f6000 |                       SIZE(printk_log) |                 16
* | 0x7c9f6000 |             OFFSET(printk_log.ts_nsec) |                  0
* | 0x7c9f6000 |                 OFFSET(printk_log.len) |                  8
* | 0x7c9f6000 |            OFFSET(printk_log.text_len) |                 10
* | 0x7c9f6000 |            OFFSET(printk_log.dict_len) |                 12
* | 0x7c9f6000 |            LENGTH(free_area.free_list) |                  6
* | 0x7c9f6000 |                  NUMBER(NR_FREE_PAGES) |                  0
* | 0x7c9f6000 |                         NUMBER(PG_lru) |                  5
* | 0x7c9f6000 |                     NUMBER(PG_private) |                 12
* | 0x7c9f6000 |                   NUMBER(PG_swapcache) |                  9
* | 0x7c9f6000 |                        NUMBER(PG_slab) |                  8
* | 0x7c9f6000 |                    NUMBER(PG_hwpoison) |                 22
* | 0x7c9f6000 |                   NUMBER(PG_head_mask) |              32768
* | 0x7c9f6000 |      NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE) |               -128
* | 0x7c9f6000 |              NUMBER(HUGETLB_PAGE_DTOR) |                  2
* | 0x7c9f6000 |                      NUMBER(phys_base) |          400556032
* | 0x7c9f6000 |                   SYMBOL(init_top_pgt) |   ffffffffb1c0a000
* | 0x7c9f6000 |                      SYMBOL(node_data) |   ffffffffb1e5c6c0
* | 0x7c9f6000 |                      LENGTH(node_data) |               1024
* | 0x7c9f6000 |                           KERNELOFFSET |           2f800000
* | 0x7c9f6000 |              NUMBER(KERNEL_IMAGE_SIZE) |         1073741824

real    0m4.768s
user    0m3.951s
sys     0m0.779s

aarch64

$ time ./vol.py -r pretty \
    -f ./ram_6.8.0-35-generic_aarch64.raw \
    linux.vmcoreinfo
Volatility 3 Framework 2.11.0
  |     Offset |                                      Key |                                    Value
* | 0x40928000 |                                OSRELEASE |                         6.8.0-35-generic
* | 0x40928000 |                                 BUILD-ID | f0c1677ab8b19cd28c8686a717772df3f8dc6d99
* | 0x40928000 |                                 PAGESIZE |                                     4096
* | 0x40928000 |                      SYMBOL(init_uts_ns) |                         ffffd231dec63400
* | 0x40928000 |               OFFSET(uts_namespace.name) |                                        0
* | 0x40928000 |                  SYMBOL(node_online_map) |                         ffffd231de7dec28
* | 0x40928000 |                   SYMBOL(swapper_pg_dir) |                         ffffd231ddbd8000
* | 0x40928000 |                           SYMBOL(_stext) |                         ffffd231db5c0000
* | 0x40928000 |                   SYMBOL(vmap_area_list) |                         ffffd231de966b28
* | 0x40928000 |                      SYMBOL(mem_section) |                         ffff51957fa0e5c0
* | 0x40928000 |                      LENGTH(mem_section) |                                     8192
* | 0x40928000 |                        SIZE(mem_section) |                                       16
* | 0x40928000 |      OFFSET(mem_section.section_mem_map) |                                        0
* | 0x40928000 |                NUMBER(SECTION_SIZE_BITS) |                                       27
* | 0x40928000 |                 NUMBER(MAX_PHYSMEM_BITS) |                                       48
* | 0x40928000 |                               SIZE(page) |                                       64
* | 0x40928000 |                        SIZE(pglist_data) |                                    23104
* | 0x40928000 |                               SIZE(zone) |                                     1984
* | 0x40928000 |                          SIZE(free_area) |                                      104
* | 0x40928000 |                          SIZE(list_head) |                                       16
* | 0x40928000 |                         SIZE(nodemask_t) |                                        8
* | 0x40928000 |                       OFFSET(page.flags) |                                        0
* | 0x40928000 |                   OFFSET(page._refcount) |                                       52
* | 0x40928000 |                     OFFSET(page.mapping) |                                       24
* | 0x40928000 |                         OFFSET(page.lru) |                                        8
* | 0x40928000 |                   OFFSET(page._mapcount) |                                       48
* | 0x40928000 |                     OFFSET(page.private) |                                       40
* | 0x40928000 |               OFFSET(page.compound_head) |                                        8
* | 0x40928000 |           OFFSET(pglist_data.node_zones) |                                        0
* | 0x40928000 |             OFFSET(pglist_data.nr_zones) |                                    20192
* | 0x40928000 |       OFFSET(pglist_data.node_start_pfn) |                                    20200
* | 0x40928000 |   OFFSET(pglist_data.node_spanned_pages) |                                    20216
* | 0x40928000 |              OFFSET(pglist_data.node_id) |                                    20224
* | 0x40928000 |                   OFFSET(zone.free_area) |                                      256
* | 0x40928000 |                     OFFSET(zone.vm_stat) |                                     1792
* | 0x40928000 |               OFFSET(zone.spanned_pages) |                                      152
* | 0x40928000 |              OFFSET(free_area.free_list) |                                        0
* | 0x40928000 |                   OFFSET(list_head.next) |                                        0
* | 0x40928000 |                   OFFSET(list_head.prev) |                                        8
* | 0x40928000 |               OFFSET(vmap_area.va_start) |                                        0
* | 0x40928000 |                   OFFSET(vmap_area.list) |                                       40
* | 0x40928000 |                   LENGTH(zone.free_area) |                                       14
* | 0x40928000 |                              SYMBOL(prb) |                         ffffd231de821078
* | 0x40928000 |                 SYMBOL(printk_rb_static) |                         ffffd231de821338
* | 0x40928000 |                        SYMBOL(clear_seq) |                         ffffd231decfd168
* | 0x40928000 |                  SIZE(printk_ringbuffer) |                                       88
* | 0x40928000 |      OFFSET(printk_ringbuffer.desc_ring) |                                        0
* | 0x40928000 | OFFSET(printk_ringbuffer.text_data_ring) |                                       48
* | 0x40928000 |           OFFSET(printk_ringbuffer.fail) |                                       80
* | 0x40928000 |                      SIZE(prb_desc_ring) |                                       48
* | 0x40928000 |         OFFSET(prb_desc_ring.count_bits) |                                        0
* | 0x40928000 |              OFFSET(prb_desc_ring.descs) |                                        8
* | 0x40928000 |              OFFSET(prb_desc_ring.infos) |                                       16
* | 0x40928000 |            OFFSET(prb_desc_ring.head_id) |                                       24
* | 0x40928000 |            OFFSET(prb_desc_ring.tail_id) |                                       32
* | 0x40928000 |                           SIZE(prb_desc) |                                       24
* | 0x40928000 |               OFFSET(prb_desc.state_var) |                                        0
* | 0x40928000 |           OFFSET(prb_desc.text_blk_lpos) |                                        8
* | 0x40928000 |                  SIZE(prb_data_blk_lpos) |                                       16
* | 0x40928000 |          OFFSET(prb_data_blk_lpos.begin) |                                        0
* | 0x40928000 |           OFFSET(prb_data_blk_lpos.next) |                                        8
* | 0x40928000 |                        SIZE(printk_info) |                                       88
* | 0x40928000 |                  OFFSET(printk_info.seq) |                                        0
* | 0x40928000 |              OFFSET(printk_info.ts_nsec) |                                        8
* | 0x40928000 |             OFFSET(printk_info.text_len) |                                       16
* | 0x40928000 |            OFFSET(printk_info.caller_id) |                                       20
* | 0x40928000 |             OFFSET(printk_info.dev_info) |                                       24
* | 0x40928000 |                    SIZE(dev_printk_info) |                                       64
* | 0x40928000 |        OFFSET(dev_printk_info.subsystem) |                                        0
* | 0x40928000 |            LENGTH(printk_info_subsystem) |                                       16
* | 0x40928000 |           OFFSET(dev_printk_info.device) |                                       16
* | 0x40928000 |               LENGTH(printk_info_device) |                                       48
* | 0x40928000 |                      SIZE(prb_data_ring) |                                       32
* | 0x40928000 |          OFFSET(prb_data_ring.size_bits) |                                        0
* | 0x40928000 |               OFFSET(prb_data_ring.data) |                                        8
* | 0x40928000 |          OFFSET(prb_data_ring.head_lpos) |                                       16
* | 0x40928000 |          OFFSET(prb_data_ring.tail_lpos) |                                       24
* | 0x40928000 |                      SIZE(atomic_long_t) |                                        8
* | 0x40928000 |            OFFSET(atomic_long_t.counter) |                                        0
* | 0x40928000 |                        SIZE(latched_seq) |                                       24
* | 0x40928000 |                  OFFSET(latched_seq.val) |                                        8
* | 0x40928000 |              LENGTH(free_area.free_list) |                                        6
* | 0x40928000 |                    NUMBER(NR_FREE_PAGES) |                                        0
* | 0x40928000 |                           NUMBER(PG_lru) |                                        5
* | 0x40928000 |                       NUMBER(PG_private) |                                       15
* | 0x40928000 |                     NUMBER(PG_swapcache) |                                       12
* | 0x40928000 |                    NUMBER(PG_swapbacked) |                                       19
* | 0x40928000 |                          NUMBER(PG_slab) |                                       11
* | 0x40928000 |                      NUMBER(PG_hwpoison) |                                       22
* | 0x40928000 |                     NUMBER(PG_head_mask) |                                       64
* | 0x40928000 |        NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE) |                                     -129
* | 0x40928000 |                       NUMBER(PG_hugetlb) |                                        8
* | 0x40928000 |      NUMBER(PAGE_OFFLINE_MAPCOUNT_VALUE) |                                     -257
* | 0x40928000 |                   SYMBOL(kallsyms_names) |                         ffffd231dcf88838
* | 0x40928000 |                SYMBOL(kallsyms_num_syms) |                         ffffd231dcf88830
* | 0x40928000 |             SYMBOL(kallsyms_token_table) |                         ffffd231dd174e88
* | 0x40928000 |             SYMBOL(kallsyms_token_index) |                         ffffd231dd175258
* | 0x40928000 |                 SYMBOL(kallsyms_offsets) |                         ffffd231dd175458
* | 0x40928000 |           SYMBOL(kallsyms_relative_base) |                         ffffd231dd212080
* | 0x40928000 |                          NUMBER(VA_BITS) |                                       48
* | 0x40928000 |                    NUMBER(MODULES_VADDR) |                       0xffff800000000000
* | 0x40928000 |                      NUMBER(MODULES_END) |                       0xffff800080000000
* | 0x40928000 |                    NUMBER(VMALLOC_START) |                       0xffff800080000000
* | 0x40928000 |                      NUMBER(VMALLOC_END) |                       0xfffffbfff0000000
* | 0x40928000 |                    NUMBER(VMEMMAP_START) |                       0xfffffc0000000000
* | 0x40928000 |                      NUMBER(VMEMMAP_END) |                       0xfffffe0000000000
* | 0x40928000 |                   NUMBER(kimage_voffset) |                       0xffffd23178400000
* | 0x40928000 |                      NUMBER(PHYS_OFFSET) |                       0xffffae6b00000000
* | 0x40928000 |                     NUMBER(TCR_EL1_T1SZ) |                                     0x10
* | 0x40928000 |                             KERNELOFFSET |                             52315b5b0000
* | 0x40928000 |                    NUMBER(KERNELPACMASK) |                                      0x0

real    0m4.938s
user    0m4.157s
sys     0m0.780s

@eve-mem
Copy link
Contributor

eve-mem commented Nov 4, 2024

This is extremely interesting! Great work!

It seems like with a little more digging we can use it to get to kallsyms using this method and then get all the symbols for the image.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants