The Most/Recent Articles

Showing posts with label linux. Show all posts
Showing posts with label linux. Show all posts
yum

Daily Blog #784: Validating linux systems with Yum

Hello Reader,

In the prior posts I've been posting about using rpm to validate packages, but there are other package managers out there. I've decided to look into each package manager individually and then maybe we can make a conditional script to handle all of them. Here is the yum version:

 

#!/bin/bash

# Files to store results
VERIFIED="verified"
FAILURES="failures"
DEBUG="debug"

# Clean previous results
> "$VERIFIED"
> "$FAILURES"
> "$DEBUG"

# Iterate over installed packages managed by yum
for package in $(yum list installed | awk 'NR>1 {print $1}' | cut -d. -f1); do
  echo "Processing package: $package"

  # Find repository URL
  repo_url=$(yumdownloader --urls "$package" 2>/dev/null | head -n 1)

  if [[ -z "$repo_url" ]]; then
    echo "Repository URL not found for package: $package" | tee -a "$FAILURES"
    echo "$repo_url $package" | tee -a "$DEBUG"
    continue
  fi

  # Download RPM package temporarily
  tmp_rpm="/tmp/${package}.rpm"
  curl -s -L "$repo_url" -o "$tmp_rpm"

  if [[ ! -f "$tmp_rpm" ]]; then
    echo "Failed to download RPM - Package: $package" | tee -a "$FAILURES"
    echo "$repo_url $package" | tee -a "$DEBUG"
    continue
  fi

  # Get repository file hashes from the downloaded RPM
  repoquery_hashes=$(rpm2cpio "$tmp_rpm" | cpio -idmv --no-absolute-filenames 2>/dev/null; find . -type f -exec sha256sum {} \;)

  # Verify files
  echo "$repoquery_hashes" | while read -r repo_hash repo_file; do
    local_file="/$repo_file"

    # Check file existence and type
    if [[ ! -x "$local_file" ]] || [[ ! -f "$local_file" ]] || [[ -h "$local_file" ]]; then
      continue
    fi

    # Calculate local disk hash
    disk_hash=$(sha256sum "$local_file" 2>/dev/null | awk '{print $1}')

    if [[ "$disk_hash" == "$repo_hash" ]]; then
      echo "Verified - Package: $package, File: $local_file" >> "$VERIFIED"
    else
      echo "Hash mismatch (Repository) - Package: $package, File: $local_file" | tee -a "$FAILURES"
      echo "$disk_hash $repo_hash $package $local_file" | tee -a "$DEBUG"
    fi
  done

  # Cleanup extracted files and downloaded RPM
  rm -rf ./* "$tmp_rpm"
done

echo "Verification complete. Results are stored in '$VERIFIED' and '$FAILURES'."

Also Read: Automating RPM checks
 

Daily Blog #780: Self validating linux executables

 


Hello Reader,

When I first started doing Digital Forensics and Incident Response (DFIR) back in 2000, one challenge I faced was verifying the integrity of Linux executables. Often, systems didn't record file hashes during installation, and sometimes we didn't even have a reliable set of installation media to compare against.

To solve this problem, I initially wrote a lengthy Perl script. The script went through each installed package on the local system, comparing the file hashes on disk against the original package hashes, and then validating these against the official distribution hashes.

Today, this task is much simpler. On Linux systems using RPM (like RedHat, Fedora, or CentOS), you can quickly verify a file's integrity with a single command:

rpm -Vf /path/to/file

What does this command do?

  • rpm -V (or rpm --verify) checks the integrity of installed packages.
  • -f identifies the installed package that owns the specified file and then verifies the file against the original installed version.

Example Output:

Running the command might give you output like this:

S.5....T.  c /etc/httpd/conf/httpd.conf

Here's what those verification flags mean:

Flag Meaning
S File size differs
M Mode (permissions) differs
5 MD5 checksum differs
D Device number mismatch
L Symlink path differs
U User ownership differs
G Group ownership differs
T Modification time differs
P Capabilities differ
. Test passed (no changes)

If the command produces no output, the file exactly matches what's included in the installed RPM package.

Quick Example:

rpm -Vf /usr/bin/bash

This command verifies the integrity of the bash executable against the installed bash RPM package.

Also Read: Daily Blog #779: Sunday Funday 3/16/25


Daily Blog: #699: Sunday Funday 5/10/20 - Auditd Challenge


Hello Reader.

       We've bounced from Windows to OSX and around the cloud. What we haven't done though is venture in the deep waters of Linux forensics. Today let's help out our fellow examiners who are in the trenches with few landmarks to lead their way in the linux forensics wasteland with this weeks challenge focused on Auditd.


The Prize:

$100 Amazon Giftcard
An apperance on the following week's Forensic Lunch!

The Rules:

  1. You must post your answer before Friday 5/15/20 7PM CST (GMT -5)
  2. The most complete answer wins
  3. You are allowed to edit your answer after posting
  4. If two answers are too similar for one to win, the one with the earlier posting time wins
  5. Be specific and be thoughtful
  6. Anonymous entries are allowed, please email them to dlcowen@gmail.com. Please state in your email if you would like to be anonymous or not if you win.
  7. In order for an anonymous winner to receive a prize they must give their name to me, but i will not release it in a blog post


The Challenge:

On a Linux system with Auditd enabled answer the following quesitons:

1. What new data sources does Auditd create

2. What tools support the data

3. What can an examiner determine from Auditd

4. How long is the data retained for

Daily Blog #682: Linux Kernel Patches for Safe Forensic Imaging

Linux Kernel Patches for Safe Forensic Imaging



Hello Reader,
        Are you using Linux as your DFIR environment of choice? Many are and for good reason. Linux makes many things easy thanks to the wide variety of open source DFIR tools available, premade distributions (SIFT, Paladin, DEFT, etc...) and the ability to quickly turn evidence into mountable file systems.

However for all the good there are some Linux internals that might be silently tripping you up. The first is something a lot of us have known for awhile. If you mount a journaled file system that Linux supports (ext3/ext4 are good examples) the underlying driver may replay the journal even if you tell it read only.

In addition to this Maxim Suhanov (@errno_fail) is now showing that write blockers that make a device appear to be writeable and actively suppress errors to make the device appear to be working can lead to a different set of issues. In this case the in memory cache will replay the journal and record other changes unless you pass into dd the direct iflag value to tell to skip the write cache in memory and look at the disk itself. This was a new one to me and very interesting. In fact I initially thought this was something the write blocker was doing wrong and asked for the firmware revision only to realize when thinking about it again that the issue is with the write cache itself.

The write cache is not unique to Linux, all modern operating systems do it. But I didn't think to find a way to bypass when disk imaging and I'm glad Maxim brought it up. Maxim documented this in his Github project for his Linux write blocker kernel module:

In-memory modifications

Some changes to a mounted file system made by a file system driver can be cached in memory, although they won't reach a physical drive (with the patch enabled and a block device marked as read-only, of course). In this situation, reading a "modified" data block with a userspace program (e.g. dd or md5sum) will result in inconsistency between data received by a userspace program and data actually stored on a drive, i.e. a userspace program will get the bytes from cache (containing modifications from a driver), not from a drive (no modifications here). Unmounting a file system will bring things back to normal.

If you want to make sure your Linux kernel is really treating a disk read only you can use Maxim's kernel model: https://github.com/msuhanov/Linux-write-blocker#in-memory-modifications

If you want to read the original tweets go here:  https://twitter.com/errno_fail/status/1253363615282991105?s=20




Daily Blog #255: RHEL Forensics Part 4: More on mlocate.db

RHEL Forensics Part 4: More on mlocate.db by David Cowen

Hello Reader,
    Today we have something special, a guest post from Hal Pomeranz. One of the best parts of sharing research and information is when others come back and extend their work for the benefit of us all. Today Hal Pomeranz has kindly not only shared back his work in extending the idea of recovering mlocate database's from unallocated space, he's written a tool to do so! I'll be testing Hal's tool on my test image and post those results tomorrow. In the mean time enjoy this very well written post!

If you want to contact Hal go to http://deer-run.com/~hal if you want train with Hal he is an excellent instructor with SANS http://www.sans.org/instructors/hal-pomeranz. Hal is an awesome forensicator and community resource who also is willing to 1099 to those of you like myself that run labs that are looking to extend our capabilities.

You can download the new tool has has made here: https://mega.co.nz/#!TsoTlSjR!BMz7BQqOhCeLGumWu51kaw4v_VFxd6UT3lyqu-ljUdc

With all that said, here is today's guest post from Hal. 

Hal Pomeranz, Deer Run Associates

One of the nice things about our little DFIR community is how researchers build off of each other’s work.  I put together a tool for parsing mlocate.db files for a case I was working on.  David Cowen and I had a conversation about it on his Forensic Lunch. David had some questions about whether we could find previous copies of the mlocate.db in unallocated blocks, and wrote several blog posts on the subject here on HECF blog.  David’s work prompted me to do a little work of my own, and he was kind enough to let me share my findings on his blog.

Hunting mlocate.db Files

In Part 3 of the series, David suggested using block group information to find mlocate.db data in disk blocks.  My thought was, since the mlocate.db files have such a clear start of file signature, we could use the sigfind tool from the Sleuthkit to find mlocate.db files more quickly.
# sigfind -b 4096 006D6C6F /dev/mapper/RD-var
Block size: 4096  Offset: 0  Signature: 6D6C6F
Block: 100736 (-)
Block: 141568 (+40832)
Block: 183808 (+42240)
Block: 232192 (+48384)
Block: 269312 (+37120)
Here I’m running sigfind against my own /var partition.  006D6C6F” is “mlo” in hex, the first four bytes of a mlocate.db file (sigfind only allows a max of 4-byte signatures).  I’m telling sigfind to look for this signature at the start of each 4K block (“-b 4096”).  As you can see, sigfind actually located five different candidate blocks. 
What was interesting to me was the blocks are in multiple different block groups in the file system.  As David suggested in Part 3, the EXT file system normally tries to place files in the same block group as their parent directory.  But when the block group fills up, the file can be placed elsewhere on disk.
I wanted to make sure that these were all legitimate hits and not false-positives.  So I used a couple of other Sleuthkit tools and a little Command-Line Kung Fu:
# for b in 100736 141568 183808 232192 269312; do
    echo ===== $b;
    blkstat /dev/mapper/RD-var $b | grep Allocated;
    blkcat -h /dev/mapper/RD-var $b | head -1;
done
===== 100736
Not Allocated
0    006d6c6f 63617465 00000127 00010000 .mlo cate ...' ....
===== 141568
Not Allocated
0    006d6c6f 63617465 00000127 00010000 .mlo cate ...' ....
===== 183808
Not Allocated
0    006d6c6f 63617465 00000127 00010000 .mlo cate ...' ....
===== 232192
Not Allocated
0    006d6c6f 63617465 00000127 00010000 .mlo cate ...' ....
===== 269312
Allocated
0    006d6c6f 63617465 00000127 00010000 .mlo cate ...' ....
The blkcat output is showing us that these all look like mlocate.db files.  Since block 269312 is “Allocated”, that must be the current mlocate.db file, while the others are previous copies we may be able to recover.

Options for Recovering Deleted Files

Let’s review our options for recovering deleted data in older Linux EXT file systems:
·         For EXT2, use ifind from the Sleuthkit to find the inode that points to the unallocated block that the mlocate.db signature sits in.  Then use icat to recover the file by inode number.

·         For EXT3, the block pointer information in the inode gets zeroed out.  My frib tool uses metadata in the indirect blocks of the file to recover the data (actually, we could use frib in EXT2 as well).
Unfortunately, I’m dealing with an EXT4 file system here, and things are much harder.  Like EXT3, much of the EXT4 inode gets zeroed out when the file is unlinked.  But EXT4 uses extents for addressing blocks, so we don’t have the indirect block metadata to leverage with a tool like frib. You’re left with trying to “carve” the blocks out of unallocated.
However, our carving is going to run into a snag pretty quickly.  Take a look at the istat output from the current mlocate.db file:
# ls -i /var/lib/mlocate/mlocate.db
566 /var/lib/mlocate/mlocate.db
# istat /dev/mapper/RD-var 566
inode: 566
Allocated
[…]

Direct Blocks:
269312 269313 269314 269315 269316 269317 269318 269319
[…]
270328 270329 270330 270331 270332 270333 270334 270335
291840 291841 291842 291843 291844 291845 291846 291847
[…]
The first 1024 blocks of the file are contiguous from block 269312 through 270335. But then there’s a clear gap and we’re starting a new extent with block 291840.  If we had to carve this file, we’d have a significant problem because the file is fragmented.  And unfortunately, all of the mlocate.db files I’ve examined in my testing contained multiple extents.
We could certainly get useful information from the start of the file:
# blkcat /dev/mapper/RD-var 232192 1024 >var-232192-1024
# mlocate-time var-232192-1024
/etc 2014-03-01 09:47:12
/etc/.java 2013-05-09 16:15:05
/etc/.java/.systemPrefs    2013-05-09 16:15:05
/etc/ConsoleKit 2013-05-09 16:15:05
/etc/ConsoleKit/run-seat.d 2013-05-09 16:15:05
/etc/ConsoleKit/run-session.d   2013-05-09 16:15:05
/etc/ConsoleKit/seats.d    2014-01-31 11:11:35
[…]
/home/hal/SANS/framework/data/msfweb/vendor/rails/actionpack/test/fixtures/addresses/.svn/prop-base 2013-05-09 18:52:29
/home/hal/SANS/framework/data/msfweb/vendor/rails/actionpack/test/fixtures/addresses/.svn/props     2013-05-09 18:52:29
/home/hal/SANS/framework/data/msfweb/vendor/rails/actionpack/test/fixtures/addresses/.svn/text-base 2013-05-09 18:52:30
/home/hal/SANS/framework/data/msfweb/vendor/rails/0.556:avahi-daemon
0.564:bluetooth
0.584:ufw
0.586:smbd
[…]
I use blkcat here to dump out 1024 blocks from one of the unallocated mlocate.db signatures, and then hit it with my mlocate-time tool.  Things go great for quite a while, but then we clearly run off the end of the extent and into some unrelated data.  I was able to pull back almost 6,000 individual file entries from this chunk of data, but the current mlocate.db file on my system has over 35,000 entries.

Looking for Another Signature

The fragmentation issue got me wondering if there was some signature I could use to find the other fragments of the file elsewhere on disk.  Here’s a relevant quote from the mlocate.db(5) manual page (emphasis mine):
The  rest  of  the  file until EOF describes directories and their contents.  Each directory starts with a header: 8 bytes for directory time (seconds) in  big  endian, 4 bytes for directory time (nanoseconds) in big endian (0 if unknown, less than 1,000,000,000),  4  bytes  padding, and  a  NUL-terminated  path name of the the directory.  Directory contents, a sequence of file entries sorted by name, follow.
Examining several mlocate.db files, the 4 bytes of padding are nulls, and the directory pathname begins with a slash (“/”).  So “000000002f” is a 5-byte signature we could use to look for directory entries in mlocate.db file fragments.
sigfind doesn’t help us here, because it wants to look for a signature at the start of a block or at a specific block offset.  Since I needed to look for the signature anywhere in a block, I threw together a quick and dirty Perl script for finding our signature in a disk image.  I haven’t done a significant amount of testing, but early indications are:
·         False positives can be a problem—a series of nulls followed by a slash is unfortunately common in data in a typical Linux file system.  In order to combat this, I’ve added a threshold value that requires a block to have a minimum of 6 instances of our signature before being reported as a possible mlocate.db chunk (the threshold value is configurable on the command-line).

·         False-negatives are also an issue.  If a directory contains a large number of files (think /usr/lib), then the directory contents may span multiple blocks.  That means one or two blocks with no instances of our “start of directory entry” signature, even though those blocks actually are part of a mlocate.db fragment.
That being said, the script does do a reasonable job of finding groups of blocks that are part of fragmented mlocate.db files.  With a little manual analyst intervention, it appears that it would be possible to reconstitute a deleted mlocate.db from an EXT4 file system, assuming none of the original blocks had been overwritten.
Frankly, our signature could be a little better too.  It’s not just “four nulls followed by a slash”, it’s “four nulls followed by a Linux path specification”.  Using a regular expression for this would likely reduce the false-positives problem plaguing the current script.

Wrapping Up (For Now)

I’ve had fun getting a deeper understanding of mlocate.db files and some of the challenges in trying to recover this artifact from unallocated.  But I still see some open questions. Can we improve the fidelity of our file signature to eliminate false-positives?  And given that there are chunks of at least five different mlocate.db files scattered around this file system, would we be able to put the correct chunks back together to recover the original file(s)?  Perhaps David or somebody else in the community would like to tackle these issues.

Also Read:

Daily Blog #221: RHEL Forensics Part 3

RHEL Forensics Part 3 by David Cowen HECF Blog

Hello Reader,
        Today we talk about recovering deleted mlocate databases. This was actually harder than I expected as not only did ext3 set the size of the file equal to 0 but the direct block that istat -B came back with was not the first block in our database. So instead I followed the instructions here: http://wiki.sleuthkit.org/index.php?title=FS_Analysis to do a manual recovery of deleted databases. There is still some work to be done here in order to clean up whats been recovered back into parsable databases but I'll leave that bit for next week.

Today let's go through the steps necessary to recover deleted mlocate databases on a RHEL v5 system using Ext3 as the file system. Remember this is necessary as the updatedb command runs daily and deletes the mlocate database before creating a new one.

Step 1. We need to figure out which group of inodes our parent belongs to. You can see in the screenshot below that the parent directory /var/lib/mlocate has inode number 1077298 so that is the group we need to find.

RHEL Forensics Part 3 by David Cowen HECF Blog


Step 2. Run fsstat to find out which group contains our inode, in this case Group 33 contains our inode as shown below. We can use them to determine which blocks to recover for deleted databases.

RHEL Forensics Part 3 by David Cowen HECF Blog


Step 3. Use blkls to recover those unallocated blocks within Group 33 as shown below to a new file:

RHEL Forensics Part 3 by David Cowen HECF Blog

Step 4. Use xxd to parse the recovered blocks and  find the mlocate database signature of 'mlocate'.

RHEL Forensics Part 3 by David Cowen HECF Blog  

This looks like an mlocate database but right now its stuck in the middle of the rest of the unallocated data. So the next thing we need to do next week as we continue this series is to write some code to carve out the mlocate database from this unallocated block chunk. 

Make sure to come back tomorrow for the Forensic Lunch with guests Ian Duffy and Andrew Case!


Daily Blog #220: RHEL Forensics Part 2

RHEL Forensics Part 2 by David Cowen

Hello Reader,
             Yesterday we talked about extending this weeks Sunday Funday answer using the mlocate database on RHEL. Today let's look at what we can determine from the mlocate database using Hal Pomeran'z mlocate-time script and setup tomorrow's entry regarding the recovery of deleted mlocate databases.

mlocate, default on RHEL since v4, queries a database of known files and directories called /var/lib/mlocate/mlocate.db. The database stores the full path to every file and directory it encounters as well as the timestamps of the directories. The timestamp according to the man page will be either the change time or modification time of the directory, whichever is more recent. The timestamp is being kept to determine if during the update process if mlocate should re-index the contents of a directory. This leads to the question, will timestamp manipulation get around mlocate indexing of a file's existence, which is something we can test in this series.

For today's example I have created a file in my home directory called 'secret_file' and then deleted it.

RHEL Forensics Part 2 by David Cowen

Since this filesystem is ext3 the name of the file 'secret_file' is now zero'd out within the directory inode. The only way to know it existed is to hope that there is another recent reference to the file within the ext3 journal to re-associate it or to search the mlocate database. There may be other artifacts but we will focus on those two for the moment.

Searching the mlocate database confirms the file entry still exists:

RHEL Forensics Part 2 by David Cowen

Looking into the parsed database records shows the last time the directory was modified when the file still existed within it:

RHEL Forensics Part 2 by David Cowen

So that's great we can establish a timeframe when the file did exist and we could compare the contents of the current filesystem against the mlocate database to determine which files had been deleted since the last daily cron run. This can be helpful for determining what has changed in the last day in a live response scenario. This does not help though when we want to know what is occurring on a longer term basis.

The mlocate database is updated by default once daily when /etc/cron.daily/mlocate.cron runs and execute updatedb. What Hal pointed out from his tests though is that when that updatedb command runs that it does not overwrite the database but instead unlinks (deletes) it and then creates a new one. We can see that in the following screenshots showing the inode numbers of the mlocate database.

Before updatedb:

RHEL Forensics Part 2 by David Cowen

After updatedb:

RHEL Forensics Part 2 by David Cowen

Notice that the inode number of mlocate.db has changed from 1077692 to 1077693 meaning a new inode has been created and the old inode is still recoverable. As Hal also pointed out the mlocate database has a unique signature that can make determining which deleted inodes contain mlocate databases so tomorow let's do that. Let's see if we can make a quick script that will find and recovery deleted mlocate databases for longer historical comparisons of which files existed on our system.

Also when I'm done with this series I'll be uploading my test image for download so you'll be able to recover the same data! Come back tomorrow and through the rest of this series as we determine:

1. How to identify and recover inodes containing mlocate databases.

2. Examining the possibility of carving mlocate database entries from freespace.

This is a 6-part series. Also Read:

Daily Blog #219: RHEL Forensics Part 1

RHEL Forensics Part 1 by David Cowen - HECF Blog

Hello Reader,
      If you read this weekends Sunday Funday winning answer you learned a lot about how to do forensics on a redhat enterprise linux server. As with anything we do in digital forensics though, there is always more to learn. Today we start a series on what we can do to go beyond this weeks winning answer, which was very good. Let's start by looking into a tool that Hal Pomeranz introduced us to on last weeks Forensic Lunch.

Hal's tool, mlocate-time, allows us to parse the mlocate database for all of the files, directories and timestamps for all files that existed on the system as of the last mlocate database update. By default there is a chron job that is set to run daily to update the mlocate database so the live data will only contain those files that existed since the last daily cron job run. Comparing the files known to exist in the mlocate database to the files live on the current system can reveal files that have been deleted, but what we want to look at is the recovery of past mlocate databases. There are two sources for these:

1. Hope there are backups of the system stored somewhere. From the backups we can extract out all copies of the mlocate database and then parse them with Hal's tool.

2. Recover the deleted inode or carve them out of unallocated space. While on the lunch Hal tested and confirmed that each time the database is updated it deletes the old database and creates a new one. That means that all the old locate databases and their timestamps are either recoverable inodes or carvable data blocks allowing you to bring back the proof of the prior existence of files and timestamps on your system. This is not just true for RHEL but other linux distributions making use of mlocate as well.

Tomorrow let's get into what the data contained with mlocate can do for our investigation and end with some mlocate database reovery. I'm downloading a RHEL v5 evaluation iso tonight to start my tests!

Continue Reading: