Acquire RAM and disk images from a suspect Linux server safely
For developers handling an incident on a Linux server, this guide gives exact commands to capture volatile memory and a forensically useful disk image with minimal extra writes. You will finish with timestamped image files, hashes, and logs you can hand to responders or analyze offline.
TL;DR — On a suspect Linux server, collect RAM first, then collect a disk image, and write both to external storage or over SSH to another host. The most common mistake is imaging the wrong block device or writing the image onto the suspect disk, which destroys evidence and can fill the filesystem mid-capture. Reading time: ~5 min
Goal
When you are done, you will have a RAM image, a disk image, SHA-256 hashes for both, and a command log stored off the suspect server or on an attached destination disk, with enough metadata to prove what was captured and from which device.
Prerequisites
- Root shell on the suspect Linux server — check with
id -uand expect0 - A second storage target with free space at least equal to RAM size plus used disk size; either:
- an attached external disk mounted read-write, or
- SSH access to a separate collector host with enough space
- Linux tools present on the suspect server:
bash,lsblk,dd,sha256sum,dmesg,mount,journalctl; check versions with:
bash --version | head -1
lsblk --version
dd --version | head -1
sha256sum --version | head -1
- For memory capture on Linux: one of these available now:
- LiME kernel module source already approved for your kernel, or
- AVML binary compatible with the host
- Kernel version and architecture — check with:
uname -r
uname -m
- The exact destination path or collector host details, for example
/mnt/forensics/case-042/orir@collector.example:/srv/cases/case-042/
Steps
Step 1: Start a command log and identify the source disks
⚠️ Every command you run changes the system a little. Keep it minimal, and do not install packages on the suspect host unless your incident process explicitly allows it.
export CASE_ID=case-042
export TS=$(date -u +%Y%m%dT%H%M%SZ)
mkdir -p /root/$CASE_ID
exec > >(tee -a /root/$CASE_ID/acquisition-$TS.log) 2>&1
set -o pipefail
printf 'UTC start: %s\n' "$TS"
hostnamectl || hostname
uname -a
lsblk -e7 -o NAME,PATH,SIZE,TYPE,FSTYPE,MOUNTPOINT,MODEL,SERIAL
findmnt -rno SOURCE,TARGET /
Success looks like a timestamped log file and lsblk output that clearly shows the root disk, for example /dev/nvme0n1 mounted at /.
Step 2: Mount or validate the destination storage
If using an attached destination disk:
mkdir -p /mnt/forensics
lsblk -e7 -o NAME,PATH,SIZE,TYPE,FSTYPE,MOUNTPOINT
mount /dev/sdb1 /mnt/forensics
mkdir -p /mnt/forensics/$CASE_ID
findmnt /mnt/forensics
df -h /mnt/forensics
If using a remote collector over SSH:
export COLLECTOR=ir@collector.example
ssh -o BatchMode=yes $COLLECTOR "mkdir -p /srv/cases/$CASE_ID && df -h /srv/cases/$CASE_ID"
Success looks like findmnt showing /mnt/forensics mounted from the destination device, or SSH returning free space on the collector.
Step 3: Capture volatile memory first
⚠️ RAM capture is kernel-sensitive. If your memory tool does not match the running kernel, stop and use the correct build. Forcing it can fail noisily or destabilize the host.
If AVML is already present at /usr/local/bin/avml and executable:
/usr/local/bin/avml /mnt/forensics/$CASE_ID/${HOSTNAME:-host}-$TS-memory.lime
sha256sum /mnt/forensics/$CASE_ID/${HOSTNAME:-host}-$TS-memory.lime | tee /mnt/forensics/$CASE_ID/${HOSTNAME:-host}-$TS-memory.lime.sha256
If writing to a remote collector instead:
/usr/local/bin/avml /dev/stdout | ssh $COLLECTOR "cat > /srv/cases/$CASE_ID/${HOSTNAME:-host}-$TS-memory.lime"
ssh $COLLECTOR "sha256sum /srv/cases/$CASE_ID/${HOSTNAME:-host}-$TS-memory.lime" | tee /root/$CASE_ID/${HOSTNAME:-host}-$TS-memory.lime.sha256
If you must use LiME and already have lime.ko built for uname -r:
insmod ./lime.ko "path=/mnt/forensics/$CASE_ID/${HOSTNAME:-host}-$TS-memory.lime format=lime"
lsmod | grep -i lime
sha256sum /mnt/forensics/$CASE_ID/${HOSTNAME:-host}-$TS-memory.lime | tee /mnt/forensics/$CASE_ID/${HOSTNAME:-host}-$TS-memory.lime.sha256
Success looks like the memory image file growing to roughly RAM size and sha256sum printing a 64-hex digest.
Step 4: Acquire the disk image from the correct block device
⚠️ This step can cause severe damage if you reverse
if=andof=or choose the wrong source device. Re-runlsblkand verify the root disk path before pressing Enter.
Local destination disk image:
export SRC_DISK=/dev/nvme0n1
export OUT=/mnt/forensics/$CASE_ID/${HOSTNAME:-host}-$TS-$(basename $SRC_DISK).img
blockdev --getsize64 $SRC_DISK
nohup dd if=$SRC_DISK of=$OUT bs=16M iflag=fullblock,direct conv=noerror,sync status=progress 2> /root/$CASE_ID/dd-$TS.log &
echo $! > /root/$CASE_ID/dd-$TS.pid
Remote collector disk image:
export SRC_DISK=/dev/nvme0n1
nohup dd if=$SRC_DISK bs=16M iflag=fullblock,direct conv=noerror,sync status=progress 2> /root/$CASE_ID/dd-$TS.log | ssh $COLLECTOR "cat > /srv/cases/$CASE_ID/${HOSTNAME:-host}-$TS-$(basename $SRC_DISK).img" &
echo $! > /root/$CASE_ID/dd-$TS.pid
Check progress:
tail -f /root/$CASE_ID/dd-$TS.log
Typical progress output shape:
10737418240 bytes (11 GB, 10 GiB) copied, 38 s, 282 MB/s
21474836480 bytes (21 GB, 20 GiB) copied, 77 s, 279 MB/s
Success looks like steadily increasing byte counts and no repeating I/O errors.
Step 5: Hash the disk image and record source metadata
After dd finishes, hash the image and save source-disk details.
For a local image:
sha256sum $OUT | tee ${OUT}.sha256
fdisk -l $SRC_DISK | tee /mnt/forensics/$CASE_ID/${HOSTNAME:-host}-$TS-$(basename $SRC_DISK)-fdisk.txt
blkid $SRC_DISK | tee /mnt/forensics/$CASE_ID/${HOSTNAME:-host}-$TS-$(basename $SRC_DISK)-blkid.txt
For a remote image:
ssh $COLLECTOR "sha256sum /srv/cases/$CASE_ID/${HOSTNAME:-host}-$TS-$(basename $SRC_DISK).img" | tee /root/$CASE_ID/${HOSTNAME:-host}-$TS-$(basename $SRC_DISK).img.sha256
fdisk -l $SRC_DISK | tee /root/$CASE_ID/${HOSTNAME:-host}-$TS-$(basename $SRC_DISK)-fdisk.txt
blkid $SRC_DISK | tee /root/$CASE_ID/${HOSTNAME:-host}-$TS-$(basename $SRC_DISK)-blkid.txt
Success looks like a completed hash, plus fdisk showing the exact partition table for the imaged device.
Step 6: Capture minimal acquisition notes and unmount cleanly
printf 'UTC end: %s\n' "$(date -u +%Y%m%dT%H%M%SZ)"
dmesg | tail -100 | tee /root/$CASE_ID/dmesg-tail.txt
journalctl -n 100 --no-pager | tee /root/$CASE_ID/journal-tail.txt
sync
umount /mnt/forensics
Success looks like umount returning no output and exit code 0 from echo $?.
Verify it works
Run these checks against the final artifacts.
For local storage:
ls -lh /mnt/forensics/$CASE_ID
sha256sum -c /mnt/forensics/$CASE_ID/*.sha256
For a remote collector:
ssh $COLLECTOR "ls -lh /srv/cases/$CASE_ID && sha256sum -c /srv/cases/$CASE_ID/*.sha256"
Expected result shape:
host-20261030T141500Z-memory.lime: OK
host-20261030T141500Z-nvme0n1.img: OK
Also verify the disk image size is plausible:
lsblk -b -dn -o NAME,SIZE $SRC_DISK
ls -lh /mnt/forensics/$CASE_ID/${HOSTNAME:-host}-$TS-$(basename $SRC_DISK).img
The image should be close to the source disk size for a raw dd capture.
Common pitfalls
Imaging the destination disk instead of the suspect disk
Mistake: choosing /dev/sdb because it was the last disk attached, when /dev/sdb is actually the external evidence drive. Symptom: the image file is tiny, the destination mount disappears, or the external disk becomes unreadable. Fix: stop immediately, run lsblk -o NAME,PATH,SIZE,TYPE,MOUNTPOINT,SERIAL, and set SRC_DISK to the device backing / from findmnt -rno SOURCE /.
Writing the image onto the suspect server's root filesystem
Mistake: of=/var/tmp/server.img on the same disk you are imaging. Symptom: dd: error writing ... No space left on device, services fail, or the host crashes from a full root filesystem. Fix: write to /mnt/forensics/... on an attached disk or stream over SSH to a collector.
Reversing if= and of= in dd
Mistake: dd if=/mnt/forensics/case.img of=/dev/nvme0n1 .... Symptom: immediate data destruction on the suspect disk; no safe in-place recovery. Fix: do not retry; disconnect the host and escalate. Before running dd, read the command left-to-right and confirm if= is the source block device and of= is the image file.
Using a memory capture tool that does not match the kernel
Mistake: loading a LiME module built for a different uname -r. Symptom: insmod: ERROR: could not insert module ./lime.ko: Invalid module format or kernel taint/oops messages in dmesg. Fix: use an AVML binary compatible with the host or a LiME module built exactly for the running kernel and architecture.
Assuming dd hung because there is no output
Mistake: running dd without status=progress and killing it early. Symptom: no terminal output for minutes while the process is actually reading. Fix: use status=progress and watch /root/$CASE_ID/dd-$TS.log, or send USR1 to dd on systems where that is supported.
Hashing before writes are flushed
Mistake: starting sha256sum immediately after a backgrounded capture without waiting for completion. Symptom: hash changes between runs or sha256sum -c later reports FAILED. Fix: wait for dd to exit, run sync, then hash the final file once.
This article was written by an AI system and published pending human review. Verify anything you intend to act on.
Have a project in mind?
Get an instant AI price estimate for it, or talk directly to our team.
One email a month on what we learn building with AI