Last active
April 16, 2026 22:51
-
-
Save krushik/a237053c237d921ecf194065ad546852 to your computer and use it in GitHub Desktop.
Bash script to verify the integrity of all installed Debian packages. It compares the metadata stored in the dpkg database with the actual files. In practice, this means checking `/var/lib/dpkg/info/<package>.md5sums` (from `DEBIAN/md5sums` inside the .deb) against the live filesystem via `dpkg --verify`. Mismatches and errors are logged to syslog
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # integrity check script for Debian packages using dpkg metadata vs live files. | |
| # License: MIT | |
| # Copyright (c) 2026 krushik | |
| set -o pipefail | |
| renice -n 19 "$$" >/dev/null || true | |
| ionice -c 2 -n 7 -p "$$" >/dev/null || true | |
| LOG_TAG="dpkg-verify-check" | |
| _errfile=$(mktemp -t dpkg-verify-err.XXXXXX) | |
| trap 'rm -f "$_errfile"' EXIT | |
| output=$(dpkg --verify --verify-format rpm 2>"$_errfile"); rc=$? | |
| (( rc )) && logger -t "$LOG_TAG" -p local6.err "dpkg --verify failed with exit code $rc: $(<"$_errfile")" | |
| set -o noglob # to preserve * in patterns | |
| ignore_patterns=( | |
| /usr/lib/example2ignore/* | |
| /var/ossec/{etc,ruleset/sca,queue}/* | |
| ) | |
| set +o noglob | |
| while IFS= read -r line; do | |
| # verify-format "rpm": ??5?????? [c] pathname | |
| status="${line:0:9}" | |
| attribute="${line:10:1}" | |
| file="${line:12}" | |
| [[ "${status:2:1}" != "5" ]] && continue # skip if no checksum mismatch | |
| [[ "$attribute" == "c" ]] && continue # skip conffiles | |
| for p in "${ignore_patterns[@]}"; do | |
| # shellcheck disable=SC2053 | |
| [[ "$file" == $p ]] && continue 2 | |
| done | |
| package=$(dpkg-query -S -- "$file" 2>/dev/null | head -1) | |
| package=${package%%:*} | |
| current_md5=$(md5sum "$file" 2>/dev/null | awk '{print $1}') | |
| [[ -z "$current_md5" ]] && current_md5="missing" | |
| expected_md5= | |
| if [[ -n "$package" && -f "/var/lib/dpkg/info/${package}.md5sums" ]]; then | |
| expected_md5=$(awk -v f="${file#/}" '$2 == f {print $1; exit}' \ | |
| "/var/lib/dpkg/info/${package}.md5sums") | |
| [[ -z "$expected_md5" ]] && expected_md5="unknown" | |
| fi | |
| logger -t "$LOG_TAG" -p local6.notice "pkg=$package file=$file expected_md5=$expected_md5 current_md5=$current_md5" | |
| done <<< "$output" | |
| exit "$rc" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <decoder name="dpkg-verify"> | |
| <program_name>dpkg-verify-check</program_name> | |
| </decoder> | |
| <decoder name="dpkg-verify-mismatch"> | |
| <parent>dpkg-verify</parent> | |
| <regex>pkg=(\S+) file=(\S+) expected_md5=(\S+) current_md5=(\S+)</regex> | |
| <order>package,file,expected_md5,current_md5</order> | |
| </decoder> | |
| <decoder name="dpkg-verify-error"> | |
| <parent>dpkg-verify</parent> | |
| <regex>failed with exit code (\d+): (.*)</regex> | |
| <order>exit_code,error_message</order> | |
| </decoder> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <group name="dpkg,integrity"> | |
| <rule id="255829" level="10"> | |
| <decoded_as>dpkg-verify</decoded_as> | |
| <description>dpkg checksum mismatch detected</description> | |
| </rule> | |
| <!-- dpkg tampering --> | |
| <rule id="255830" level="10"> | |
| <if_sid>255829</if_sid> | |
| <field name="package">\S+</field> | |
| <description>dpkg tampering: $(package) $(file) expected=$(expected_md5) got=$(current_md5)</description> | |
| </rule> | |
| <!-- missing files --> | |
| <rule id="255831" level="10"> | |
| <if_sid>255830</if_sid> | |
| <field name="current_md5">missing</field> | |
| <description>dpkg file missing: $(file) from $(package)</description> | |
| </rule> | |
| <!-- whitelist --> | |
| <rule id="255832" level="0"> | |
| <if_sid>255830</if_sid> | |
| <field name="file">^/usr/share/doc/</field> | |
| <description>Ignore documentation</description> | |
| </rule> | |
| <!-- dpkg verify failed --> | |
| <rule id="255833" level="10"> | |
| <if_sid>255829</if_sid> | |
| <field name="exit_code">\d+</field> | |
| <description>dpkg verify failed with exit code $(exit_code): $(error_message)</description> | |
| </rule> | |
| </group> |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
also added decoders and rules for wazuh/ossec