Digital Forensics & Incident Response
  • Welcome
  • General Notes
    • Azure Blob storage with NGINX proxy
    • Install and Configure ZeroTier client
    • S3FS Fuse and MinIO
    • Enable nested VT-X/AMD-V
    • mitm proxy
    • Exploring Volume Shadow Copies Manually
    • Resize VMDK/VDI
    • Resize VMDK on ESXi
    • Convert raw to vmdk
    • Favicon hashing and hunting with Shodan
    • WinRM/RemotePS
    • MinIO/S3/R2 ghost files
    • Mount E01 containing VMDK/XFS from RHEL system
    • Disk images for various filesystems and configurations
      • ext4 with LVM and RAID5 (3 disks)
      • ZFS
      • UFS, FFS, BTRFS, XFS
      • ext4, LVM, and LUKS1/LUKS2
      • NTFS, FAT32, with BitLocker
      • NTFS, FAT32, exFAT with TrueCrypt, VeraCrypt
    • VirtualBox adapters greyed out
    • Exporting SQLite blob data from standalone SQLite database using command line tools
  • Microsoft Defender KQL
    • Introduction to KQL
  • Windows Forensics
    • PsExec
      • PsExec and NTUSER data
    • Security Patch/KB Install Date
  • Linux Forensics
    • Inspecting RPM/DEB packages
    • Common Locations
  • ESXi Forensics
    • Mount external USB device in ESXi hypervisor
    • Understanding ESXi
      • Partitions / Volumes
      • ESXi console / shell
      • Guest Virtual Machines
    • General Notes
    • Triage and Imaging
    • ESXi VMFS Exploration
    • Export OVF from ESXi using OVF Tool
    • Identification, acquisition, and examination of iSCSI LUNs and VMFS datastores
  • Memory Forensics
    • Volatility
      • Volatility3 core commands
      • Build Custom Linux Profile for Volatility
      • Generate custom profile using btf2json
      • Banners, isfinfo, and custom profiles
      • Volatility2 core commands
      • 3rd Party Plugins
    • Acquisition
      • ESXi / VMware Workstation snapshots
      • DumpIt
      • WinPMem
      • Linux / AVML
  • Incident Response
    • Ivanti Connect Secure Auth Bypass and Remote Code Authentication CVE-2024-21887
    • VirusTotal & hash lists
    • Unix-like Artifacts Collector (UAC)
      • Setup MinIO (object storage)
      • Create S3 pre-signed URL
      • UAC and pre-signed URLs
    • Acquiring Linux VPS via SSH
    • AVML dump to SMB / AWS
    • China Chopper webshell
    • Logging Powershell activities
    • Compromised UniFi Controller
    • AnyDesk Remote Access
    • Mounting UFS VMDK from NetScaler/Citrix ADC
  • iOS Forensics
    • Checkm8 / checkra1n acquisitions/extractions
  • CTF / Challenges
    • 13Cubed Linux memory forensics
    • Compromised Windows Server 2022 (simulation)
      • FTK Imager
      • Autopsy Forensics
      • Plaso
      • Events Ripper
      • EZ tools
    • DEFCON 2019 forensics
    • Tomcat shells
    • Magnet Weekly CTF
      • Magnet CTF Week 0
      • Magnet CTF Week 1
    • DFIR Madness CTF
      • Case 001 - Szechuan Sauce
  • Log Files
    • Windows
      • Generating Log Timelines
  • Malware Analysis
    • Identifying UPX packed ELF, decompressing, fixing, and analysing Linux malware
    • PDF Analysis
  • Walking the VAD tree
  • OpenCTI
    • What is CTI/OpenCTI?
    • Setting up OpenCTI
    • Container Management
    • Configure Connectors
  • Vulnerability Management
    • Setting Up Nessus (Essentials)
    • Troubleshooting
  • Privacy
Powered by GitBook
On this page

Was this helpful?

  1. Memory Forensics
  2. Volatility

Generate custom profile using btf2json

How to use btf2json to generate a kernel profile for Volatility 3, without using a virtual machine and entirely within WSL.

PreviousBuild Custom Linux Profile for VolatilityNextBanners, isfinfo, and custom profiles

Last updated 2 months ago

Was this helpful?

My previous guides (and ) have used dwarf2json, fresh virtual machines, and full debugging kernels. This is a somewhat time intensive process and doesn't scale that well - you have to generate multiple fresh virtual machines (depending on flavour/variant), install multiple debugging profiles from slow Canonical debugging repositories, to generate multiple profiles. This assumes you have access to an environment you can (or are allowed to) generate new virtual machines, and doing this in an enterprise environments (with considerations like TLS/SSL inspection, EDR registration, host management, etc etc) becomes an incredibly long winded process.

A few days ago, I saw an announcement from Volatility regarding their plugin contest and btf2json caught my eye.

"Valentin Obst: btf2json

The btf2json project is a very promising effort to ease the burden of large-scale Linux memory analysis. By incorporating information in the readily available vmlinuz file, analysts can create Volatility 3 symbol tables without the need for a full debug kernel. Through acquisition techniques that incorporate filesystem data, it appears that the final version of this project will enable analysis with only information stored within the memory sample – a large shift from the currently difficult method to gather this information across Linux systems and distributions.

Related References: Source:

The tool is great and it works as expected, however the guide/instructions on GitHub are perhaps a little unclear, so I thought I'd write a guide here on how to practically generate a custom profile using btf2json and without access to a virtual machine.

At a high level, this is the process;

  1. Obtain/generate memory sample (DumpIt for Linux, AVML, etc)

  2. Identify full kernel banner (this is important, don't skip this step)

  3. Identify & obtain kernel image and linux modules from relevant repository.

  4. Extract kernel image from package

  5. Decompress kernel image (decompress vmlinuz to vmlinux)

  6. Extract system map from linux modules package

  7. Bring it all together with btf2json

  8. Modify volatility3 schema

  9. Test profile

Let's get started.

  1. Obtain/generate memory sample (DumpIt for Linux, AVML, etc)

  1. Identify full kernel banner (this is important, don't skip this step)

We can use the volatility3 plugin 'banners' to identify banner information. Be mindful that volatility sometimes outputs raw/escape characters in its output. Although the output below is the full value, make sure you remove any prepended/trailing values (like \b for backspace) are removed. Depending on how messy the output is, this may require some trial and error.

python3 vol.py -v -f /mnt/c/13cubed/memory/memory.vmem banners

Linux version 6.5.0-41-generic (buildd@lcy02-amd64-120) (x86_64-linux-gnu-gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #41~22.04.2-Ubuntu SMP PREEMPT_DYNAMIC Mon Jun  3 11:32:55 UTC 2 (Ubuntu 6.5.0-41.41~22.04.2-generic 6.5.13)

  1. Identify & obtain kernel image and Linux modules from relevant repository.

From the above, we can see we have an Ubuntu host with 6.5.0-41-generic.

  1. Extract kernel image from package

We have the kernel package, but it's inside a .deb file (which is an Ubuntu package). We don't want to install it, we want to extract a file from within it. We want to extract vmlinuz-6.5.0-41-generic, but how can we do that? Packages contain data streams and controls streams. If we were to use 7zip (as shown below), you'd be presented with 2 additional zst files (these are compressed with zstd and can't be uncompressed with 7zip)

$ 7z l linux-image-6.5.0-41-generic_6.5.0-41.41_amd64.deb

Scanning the drive for archives:
1 file, 14096990 bytes (14 MiB)

Listing archive: linux-image-6.5.0-41-generic_6.5.0-41.41_amd64.deb

--
Path = linux-image-6.5.0-41-generic_6.5.0-41.41_amd64.deb
Type = Ar
Physical Size = 14096990
SubType = deb

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2024-05-21 01:11:55 .....         2172         2172  control.tar.zst
2024-05-21 01:11:55 .....     14094625     14094625  data.tar.zst
------------------- ----- ------------ ------------  ------------------------
2024-05-21 01:11:55           14096797     14096797  2 files

We can use the dpkg -c command to identify which files we want.

$ dpkg -c linux-image-6.5.0-41-generic_6.5.0-41.41_amd64.deb
drwxr-xr-x root/root         0 2024-05-21 00:11 ./
drwxr-xr-x root/root         0 2024-05-21 00:11 ./boot/
-rw------- root/root  14327304 2024-05-21 00:11 ./boot/vmlinuz-6.5.0-41-generic
[snip]

We can then use dpkg with the fsystarfile option to inspect and ultimately extract the file.

This is the syntax;

dpkg --fsys-tarfile your-downloaded-package.deb | tar xOf - ./path/to/file/inside > dest.file

Using the package above, this would result in the following command (one liner, code block is wrapped)

dpkg --fsys-tarfile linux-image-6.5.0-41-generic_6.5.0-41.41_amd64.deb| tar xOf - ./boot/vmlinuz-6.5.0-41-generic > vmlinuz-6.5.0-41-generic

  1. Decompress kernel image (decompress vmlinuz to vmlinux)

Decompress vmlinuz into vmlinux

./extract-vmlinux.sh vmlinuz-6.5.0-41-generic > vmlinux

  1. Extract system map from linux modules package

Download our corresponding kernel modules package

$ wget http://archive.ubuntu.com/ubuntu/pool/main/l/linux-hwe-6.5/linux-modules-6.5.0-41-generic_6.5.0-41.41~22.04.2_amd64.deb

Perform the same steps as 4, just targeting the System.Map file

$ dpkg -c linux-modules-6.5.0-41-generic_6.5.0-41.41~22.04.2_amd64.deb
drwxr-xr-x root/root         0 2024-06-03 19:39 ./
drwxr-xr-x root/root         0 2024-06-03 19:39 ./boot/
-rw------- root/root   8268513 2024-06-03 19:39 ./boot/System.map-6.5.0-41-generic
-rw-r--r-- root/root    280657 2024-06-03 19:39 ./boot/config-6.5.0-41-generic
drwxr-xr-x root/root         0 2024-06-03 19:39 ./lib/
[snip]

Extract System.map-6.5.0-41-generic (one liner, code block is wrapped)

dpkg --fsys-tarfile linux-modules-6.5.0-41-generic_6.5.0-41.41~22.04.2_amd64.deb| tar xOf - ./boot/System.map-6.5.0-41-generic > System.map-6.5.0-41-generic 
  1. Bring it all together with btf2json

In the same directory, download btf2json

$ wget https://github.com/vobst/btf2json/releases/download/v0.1.0/btf2json

Remember how we identified the banners in step 1? You'll need the full value here.

Linux version 6.5.0-41-generic (buildd@lcy02-amd64-120) (x86_64-linux-gnu-gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #41~22.04.2-Ubuntu SMP PREEMPT_DYNAMIC Mon Jun  3 11:32:55 UTC 2 (Ubuntu 6.5.0-41.41~22.04.2-generic 6.5.13)

The final command;

./btf2json --btf /path/to/vmlinux --map /path/to/System.map-6.5.0-41-generic --banner "Linux version 6.5.0-41-generic (buildd@lcy02-amd64-120) (x86_64-linux-gnu-gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #41~22.04.2-Ubuntu SMP PREEMPT_DYNAMIC Mon Jun  3 11:32:55 UTC 2 (Ubuntu 6.5.0-41.41~22.04.2-generic 6.5.13)" > 13cubed-btfs2json.json

You can see we end up with the profile "13cubed-btfs2json.json" which you'll need to place in volatility3 symbols folder.

  1. Modify volatility3 schema

-          "pattern": "^(dwarf|symtab|system-map)$"
+          "pattern": "^(btf|symdb|dwarf|symtab|system-map)$"

  1. Test Profile

Move your new profile (13cubed-btf2json.json) to your symbols folder.

Check it's registered.

$ mv 13cubed-btf2json.json /path/to/volatility3/symbols
$ python3 vol.py isfinfo

URI     Valid   Number of base_types    Number of types Number of symbols       Number of enums Identifying information

file:///mnt/c/volatility3-2.5.21/volatility3/symbols/13cubed-btf2json.json        True (cached)   19      13317   179428  2441    b'Linux version 6.5.0-41-generic (buildd@lcy02-amd64-120) (x86_64-linux-gnu-gcc-12 (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #41~22.04.2-Ubuntu SMP PREEMPT_DYNAMIC Mon Jun  3 11:32:55 UTC 2 (Ubuntu 6.5.0-41.41~22.04.2-generic 6.5.13)'

Test the profile

$ python3 vol.py -v -f /mnt/c/13cubed/memory/memory.vmem linux.pslist

OFFSET (V)      PID     TID     PPID    COMM    File output

0x9ee0c027b300  1       1       0       systemd Disabled
0x9ee0c0279980  2       2       0       kthreadd        Disabled
0x9ee0c027e600  3       3       2       rcu_gp  Disabled
0x9ee0c0278000  4       4       2       rcu_par_gp      Disabled
0x9ee0c027cc80  5       5       2       slub_flushwq    Disabled
0x9ee0c028cc80  6       6       2       netns   Disabled
0x9ee0c0333300  11      11      2       mm_percpu_wq    Disabled
0x9ee0c0331980  12      12      2       rcu_tasks_kthre Disabled
0x9ee0c0336600  13      13      2       rcu_tasks_rude_ Disabled

[snip]

For this step, we'll use a publicly available sample. recently released an analysis challenge on which involved examination of a memory sample from an Ubuntu machine. The sample is available to .

You'll see that this is important later as btf2json requires you to input this value so it can generate a compatible profile. The variable you provide is going to be converted/encoded in base64, and stored in the profile (as I here)

A quick search gives us a download location; and a direct link;

btf2json doesn't handle compressed linux kernels/images. vmlinuz is the compressed version of vmlinux. The bash script used to extract/decompress the compressed image should be included in your kernel tree (usually /usr/src/kernels/your-kernel-version/scripts/extract-vmlinux). If not, you can .

In \volatility3-2.5.21\volatility3\schemas you'll see a file named 'schema-6.2.0.json'. Open that in your favourite text editor, and here.

here
here
https://github.com/vobst/btf2json https://blog.eb9f.de/2024/11/10/btf2json.html
https://volatilityfoundation.org/the-2024-volatility-plugin-contest-results-are-in/
13Cubed
YouTube
download here
covered
https://launchpad.net/ubuntu/mantic/amd64/linux-image-6.5.0-41-generic/6.5.0-41.41
http://launchpadlibrarian.net/731521331/linux-image-6.5.0-41-generic_6.5.0-41.41_amd64.deb
download it from GitHub
follow the instructions