Contents
Tripwire
Implement a system to detect file tampering on Linux servers by crackers.
This time, Tripwire, a host-based IDS (IDS=Intrusion Detection System), will be installed as the file tampering detection system.
Tripwire detects file additions/changes/deletions by creating a database of file status at the time of installation and comparing the database with the current status of the file.。
1 Install
|
1 |
# apt install tripwire |
Tripwire requires a site passphrase to secure the "tw.cfg" Tripwire configuration file and the "tw.pol" Tripwire policy file.
Encrypt both files using the specified passphrase. A site passphrase is also required for a single instance of Tripwire.
During the installation process, you will be prompted to enter the "site key passphrase" and the "local key passphrase".




Creating a Site Key Passphrase


Creating a Local Key Passphrase
A local passphrase is required to protect the Tripwire database and report files. The local key used by Tripwire to prevent unauthorized changes to the Tripwire baseline database.


The installation is progressing and will complete.

2. Configuration File Settings
①twcfg.txt Edit
|
1 2 3 4 5 6 7 8 |
# cd /etc/tripwire # vi twcfg.txt Line9 Add "#" at the beginning of the line and "LOOSEDIRECTORYCHECKING =true" on the line below it #LOOSEDIRECTORYCHECKING =false LOOSEDIRECTORYCHECKING =true Line 12:Change as needed (maximum report level: 4) REPORTLEVEL =4 |
② Create a configuration file (encrypted signature version)
|
1 2 3 |
# twadmin -m F -c tw.cfg -S site.key twcfg.txt Please enter your site passphrase: <site pass> Wrote configuration file: /etc/tripwire/tw.cfg |
③ Optimize Policy
Use the following policy optimization scripts to optimize your policy
|
1 |
# vi twpolmake.pl |
Policy Optimization Script Contents
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#!/usr/bin/perl $POLFILE=$ARGV[0]; open(POL,"$POLFILE") or die "open error: $POLFILE" ; my($myhost,$thost) ; my($sharp,$tpath,$cond) ; my($INRULE) = 0 ; while (<POL>) { chomp; if (($thost) = /^HOSTNAME\s*=\s*(.*)\s*;/) { $myhost = `hostname` ; chomp($myhost) ; if ($thost ne $myhost) { $_="HOSTNAME=\"$myhost\";" ; } } elsif ( /^{/ ) { $INRULE=1 ; } elsif ( /^}/ ) { $INRULE=0 ; } elsif ($INRULE == 1 and ($sharp,$tpath,$cond) = /^(\s*\#?\s*)(\/\S+)\b(\s+->\s+.+)$/) { $ret = ($sharp =~ s/\#//g) ; if ($tpath eq '/sbin/e2fsadm' ) { $cond =~ s/;\s+(tune2fs.*)$/; \#$1/ ; } if (! -s $tpath) { $_ = "$sharp#$tpath$cond" if ($ret == 0) ; } else { $_ = "$sharp$tpath$cond" ; } } print "$_\n" ; } close(POL) ; |
Policy File Optimization
|
1 |
# perl twpolmake.pl twpol.txt > twpol.txt.new |
Create a policy file (encrypted and signed version) based on the optimized policy file.
|
1 2 3 |
# twadmin -m P -c tw.cfg -p tw.pol -S site.key twpol.txt.new Please enter your site passphrase: <site pass> Wrote policy file: /etc/tripwire/tw.pol |
Exclude the Tripwire database itself from being checked
|
1 |
# echo ! "/var/lib/tripwire/`hostname`.twd ;" >> /etc/tripwire/twpol.txt.new |
④Database Creation
|
1 2 |
# tripwire -m i -s -c tw.cfg Please enter your local passphrase: <local pass> |
3. Functionality Verification
①Create test file
|
1 |
# echo test > /root/test.txt |
②Check Tripwire operation
|
1 |
# tripwire -m c -s -c /etc/tripwire/tw.cfg |
If successful, the following display appears
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
Open Source Tripwire(R) 2.4.3.7 Integrity Check Report Report generated by: root Report created on: Wed 14 Jan 2026 10:18:54 AM JST Database last updated on: Never =============================================================================== Report Summary: =============================================================================== Host name: Lepard Host IP address: 127.0.1.1 Host ID: None Policy file used: /etc/tripwire/tw.pol Configuration file used: /etc/tripwire/tw.cfg Database file used: /var/lib/tripwire/Lepard.twd Command line used: tripwire -m c -s -c /etc/tripwire/tw.cfg =============================================================================== Rule Summary: =============================================================================== ------------------------------------------------------------------------------- Section: Unix File System ------------------------------------------------------------------------------- Rule Name Severity Level Added Removed Modified --------- -------------- ----- ------- -------- Other binaries 66 0 0 0 Tripwire Binaries 100 0 0 0 * Other libraries 66 0 0 84 Root file-system executables 100 0 0 0 * Tripwire Data Files 100 1 0 0 System boot changes 100 0 0 0 Root file-system libraries 100 0 0 0 (/lib) Critical system boot files 100 0 0 0 * Other configuration files 66 0 0 1 (/etc) Boot Scripts 100 0 0 0 Security Control 66 0 0 0 * Root config files 100 1 0 0 Devices & Kernel information 100 0 0 0 (/dev) Invariant Directories 66 0 0 0 Total objects scanned: 50850 Total violations found: 87 =============================================================================== Object Summary: =============================================================================== ------------------------------------------------------------------------------- # Section: Unix File System ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- Rule Name: Other libraries (/usr/lib) Severity Level: 66 ------------------------------------------------------------------------------- Modified: "/usr/lib/python3/dist-packages/urllib3/__init__.py" "/usr/lib/python3/dist-packages/urllib3/__pycache__" "/usr/lib/python3/dist-packages/urllib3/__pycache__/__init__.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/__pycache__/_base_connection.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/__pycache__/_collections.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/__pycache__/_request_methods.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/__pycache__/_version.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/__pycache__/connection.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/__pycache__/connectionpool.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/__pycache__/exceptions.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/__pycache__/fields.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/__pycache__/filepost.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/__pycache__/poolmanager.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/__pycache__/response.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/_base_connection.py" "/usr/lib/python3/dist-packages/urllib3/_collections.py" "/usr/lib/python3/dist-packages/urllib3/_request_methods.py" "/usr/lib/python3/dist-packages/urllib3/_version.py" "/usr/lib/python3/dist-packages/urllib3/connection.py" "/usr/lib/python3/dist-packages/urllib3/connectionpool.py" "/usr/lib/python3/dist-packages/urllib3/contrib/__init__.py" "/usr/lib/python3/dist-packages/urllib3/contrib/__pycache__" "/usr/lib/python3/dist-packages/urllib3/contrib/__pycache__/__init__.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/contrib/__pycache__/pyopenssl.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/contrib/__pycache__/socks.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/contrib/emscripten/__init__.py" "/usr/lib/python3/dist-packages/urllib3/contrib/emscripten/__pycache__" "/usr/lib/python3/dist-packages/urllib3/contrib/emscripten/__pycache__/__init__.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/contrib/emscripten/__pycache__/connection.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/contrib/emscripten/__pycache__/fetch.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/contrib/emscripten/__pycache__/request.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/contrib/emscripten/__pycache__/response.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/contrib/emscripten/connection.py" "/usr/lib/python3/dist-packages/urllib3/contrib/emscripten/emscripten_fetch_worker.js" "/usr/lib/python3/dist-packages/urllib3/contrib/emscripten/fetch.py" "/usr/lib/python3/dist-packages/urllib3/contrib/emscripten/request.py" "/usr/lib/python3/dist-packages/urllib3/contrib/emscripten/response.py" "/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py" "/usr/lib/python3/dist-packages/urllib3/contrib/socks.py" "/usr/lib/python3/dist-packages/urllib3/exceptions.py" "/usr/lib/python3/dist-packages/urllib3/fields.py" "/usr/lib/python3/dist-packages/urllib3/filepost.py" "/usr/lib/python3/dist-packages/urllib3/http2/__init__.py" "/usr/lib/python3/dist-packages/urllib3/http2/__pycache__" "/usr/lib/python3/dist-packages/urllib3/http2/__pycache__/__init__.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/http2/__pycache__/connection.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/http2/__pycache__/probe.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/http2/connection.py" "/usr/lib/python3/dist-packages/urllib3/http2/probe.py" "/usr/lib/python3/dist-packages/urllib3/poolmanager.py" "/usr/lib/python3/dist-packages/urllib3/py.typed" "/usr/lib/python3/dist-packages/urllib3/response.py" "/usr/lib/python3/dist-packages/urllib3/util/__init__.py" "/usr/lib/python3/dist-packages/urllib3/util/__pycache__" "/usr/lib/python3/dist-packages/urllib3/util/__pycache__/__init__.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/util/__pycache__/connection.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/util/__pycache__/proxy.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/util/__pycache__/request.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/util/__pycache__/response.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/util/__pycache__/retry.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/util/__pycache__/ssl_.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/util/__pycache__/ssl_match_hostname.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/util/__pycache__/ssltransport.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/util/__pycache__/timeout.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/util/__pycache__/url.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/util/__pycache__/util.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/util/__pycache__/wait.cpython-313.pyc" "/usr/lib/python3/dist-packages/urllib3/util/connection.py" "/usr/lib/python3/dist-packages/urllib3/util/proxy.py" "/usr/lib/python3/dist-packages/urllib3/util/request.py" "/usr/lib/python3/dist-packages/urllib3/util/response.py" "/usr/lib/python3/dist-packages/urllib3/util/retry.py" "/usr/lib/python3/dist-packages/urllib3/util/ssl_.py" "/usr/lib/python3/dist-packages/urllib3/util/ssl_match_hostname.py" "/usr/lib/python3/dist-packages/urllib3/util/ssltransport.py" "/usr/lib/python3/dist-packages/urllib3/util/timeout.py" "/usr/lib/python3/dist-packages/urllib3/util/url.py" "/usr/lib/python3/dist-packages/urllib3/util/util.py" "/usr/lib/python3/dist-packages/urllib3/util/wait.py" "/usr/lib/python3/dist-packages/urllib3-2.3.0.dist-info/INSTALLER" "/usr/lib/python3/dist-packages/urllib3-2.3.0.dist-info/METADATA" "/usr/lib/python3/dist-packages/urllib3-2.3.0.dist-info/WHEEL" "/usr/lib/x86_64-linux-gnu/libtasn1.so.6" "/usr/lib/x86_64-linux-gnu/libtasn1.so.6.6.4" ------------------------------------------------------------------------------- Rule Name: Tripwire Data Files (/var/lib/tripwire/Lepard.twd) Severity Level: 100 ------------------------------------------------------------------------------- Added: "/var/lib/tripwire/Lepard.twd" ------------------------------------------------------------------------------- Rule Name: Other configuration files (/etc) Severity Level: 66 ------------------------------------------------------------------------------- Modified: "/etc/ld.so.cache" ------------------------------------------------------------------------------- Rule Name: Root config files (/root) Severity Level: 100 ------------------------------------------------------------------------------- Added: "/root/test.txt" =============================================================================== Error Report: =============================================================================== No Errors ------------------------------------------------------------------------------- *** End of report *** Open Source Tripwire 2.4 Portions copyright 2000-2018 Tripwire, Inc. Tripwire is a registered trademark of Tripwire, Inc. This software comes with ABSOLUTELY NO WARRANTY; for details use --version. This is free software which may be redistributed or modified only under certain conditions; see COPYING for details. All rights reserved. |
Delete the test file.
|
1 |
# rm -f /root/test.txt |
4. Tripwire Autorun
①Create a script (tripwire.sh) for reporting results via email and set it to run automatically.
|
1 2 |
# cd /opt/script # vi tripwire.sh |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#!/bin/bash PATH=/usr/sbin:/usr/bin:/bin:/usr/local/tripwire/sbin # Passphrase Setup LOCALPASS=xxxxx # Local Key Passphrase SITEPASS=xxxxx # Site Key Passphrase #Specify notification email address MAIL="<your mailaddress> " cd /etc/tripwire # Tripwire Check Execution tripwire -m c -s -c tw.cfg|mail -s "Tripwire(R) Integrity Check Report in `hostname`" $MAIL # Policy File Update twadmin -m p -c tw.cfg -p tw.pol -S site.key > twpol.txt perl twpolmake.pl twpol.txt > twpol.txt.new twadmin -m P -c tw.cfg -p tw.pol -S site.key -Q $SITEPASS twpol.txt.new > /dev/null rm -f twpol.txt* *.bak # Database Update rm -f /usr/local/tripwire/lib/tripwire/*.twd* tripwire -m i -s -c tw.cfg -P $LOCALPASS |
②Give execute permission and execute periodically by Cron.
|
1 2 3 |
# chmod 700 tripwire.sh # crontab -e 0 5 * * * /opt/script/tripwire.sh |
Execute the following and verify that the results are delivered to the specified email address.
|
1 |
# /opt/script/tripwire.sh |
Logwatch
Logwatch aggregates various logs and sends them as a daily report via email. It's a useful tool for detecting unauthorized access and issues, as well as monitoring servers.
①Install
|
1 |
# apt -y install logwatch |
②Copy the default configuration file
|
1 |
# cp /usr/share/logwatch/default.conf/logwatch.conf /etc/logwatch/conf/ |
➂Change email address, etc.
|
1 2 3 4 5 6 7 8 |
# vi /etc/logwatch/conf/logwatch.conf ● Line 76 : Add the email address where you want to receive notifications #MailTo = root MailTo = [Email address] ● Line 115 : Set the level of detail for log notifications #Detail = Low Detail = High |
④Creating Directories
|
1 |
# mkdir /var/cache/logwatch |
⑤operation check
When logwatch is installed, cron is registered by default, so you will receive daily report emails.
If you want to check it immediately, do the following
|
1 |
# /etc/cron.daily/00logwatch |
Chkrootkit
chkrootkit is a tool for detecting the presence of rootkits.
Note that chkrootkit is ineffective once the system has already been compromised, so this must be taken into consideration during installation.
Additionally, chkrootkit does not automatically address rootkits upon detection; manual intervention is required after detection.
①chkrootkit Install
|
1 |
# apt -y install chkrootkit |
➁Check for chkrootkit
|
1 2 |
# chkrootkit | grep INFECTED If nothing is displayed, there is no problem. |
④Creating a chkrootkit Scheduled Execution Script and Changing Permissions
Automatically, /etc/cron.daily/chkrootkit is created based on /usr/sbin/chkrootkit-daily and runs automatically every day, so no script creation is necessary.
This ensures that if a rootkit is installed, an email will be sent to root.
Disk Usage Check Script
1. Script creation
|
1 2 |
# cd /opt/script/ # vi disk_capacity_check.sh |
Contents of disk_capacity_check.sh
|
1 2 3 4 5 6 7 8 9 10 |
#!/bin/bash #Specify notification email address MAIL="<your mailaddress> " DVAL=`/bin/df / | /usr/bin/tail -1 | /bin/sed 's/^.* \([0-9]*\)%.*$/\1/'` if [ $DVAL -gt 80 ]; then echo "Disk usage alert: $DVAL %" | mail -s "Disk Space Alert in `hostname`" $MAIL fi |
|
1 |
# chmod 700 disk_capacity_check.sh |
2. Execution Confirmation
①Check the current usage rate
|
1 |
# df -h |
It will be displayed as follows:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
Filesystem Size Used Avail Use% Mounted on tmpfs 336M 1.7M 334M 1% /run /dev/mapper/ubuntu--vg-ubuntu--lv 9.8G 4.5G 4.8G 49% / tmpfs 1.7G 0 1.7G 0% /dev/shm tmpfs 1.7G 64K 1.7G 1% /tmp tmpfs 5.0M 0 5.0M 0% /run/lock tmpfs 1.0M 0 1.0M 0% /run/credentials/systemd-journald.service tmpfs 1.0M 0 1.0M 0% /run/credentials/systemd-resolved.service /dev/sda2 1.8G 121M 1.5G 8% /boot tmpfs 1.0M 0 1.0M 0% /run/credentials/systemd-networkd.service tmpfs 1.0M 0 1.0M 0% /run/credentials/getty@tty1.service tmpfs 336M 8.0K 336M 1% /run/user/1000 |
②Create dummy files to achieve a usage rate of 80% or higher (in this example, a file named dummyfile approximately 4GB in size).
|
1 |
# dd if=/dev/zero of=dummyfile bs=1M count=4000 |
③Reaffirm
|
1 |
# df -h |
Verify that it is running and has reached over 80%.
④Run the disk capacity check script
|
1 |
# /opt/script/disk_capacity_check.sh |
An email with the subject line "Disk usage alert: 91%" will be sent to the specified email address.
⑤Delete the created "dummyfile"
|
1 |
# rm dummyfile |
⑥Scheduled Execution Settings
|
1 2 |
# crontab -e 30 2 * * * /opt/script/disk_capacity_check.sh |
DNS Update
Whenever the internet connection is lost or the router reboots, causing the global IP address to change, you must access the dynamic DNS service to notify it of the new IP address.
Create a dedicated Python file and schedule it for regular execution via Cron.
This time, it's about DNS settings in Valudomain.
|
1 2 |
# cd /opt/script # vi ddnsset.py |
Content of ddnsset.py
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
#setddns.py import requests import ipaddress from datetime import datetime from pathlib import Path # SETTING DATA MY_DOMAIN = "example.jp" ←Self-hosted domain MY_PASS = "xxxxxxxxxx" ←Password MY_HOSTNAME = "xxxx" ←Host name OUT_FILE = Path("/tmp/ipadress") ←IP Address Log File def time_msg(): now = datetime.now() return now.strftime("%Y/%m/%d %H:%M:%S") def is_valid_ip(ip_str): try: ipaddress.ip_address(ip_str) return True except ValueError: return False def main(): # Check Global IP Address url_get_ip = "https://dyn.value-domain.com/cgi-bin/dyn.fcg?ip" try: response = requests.get(url_get_ip, timeout=10) response.raise_for_status() current_ip = response.text.strip() except requests.RequestException as e: print(f"{time_msg()} Failed to get IP: {e}") return # IP check mssg = time_msg() if not current_ip: print(f"{mssg} invalid IP NULL") return if not is_valid_ip(current_ip): print(f"{mssg} invalid IP={current_ip}") return # Read previous IP previous_ip = "" if OUT_FILE.exists(): with open(OUT_FILE, "r") as f: previous_ip = f.read().strip() if current_ip == previous_ip: print(f"{time_msg()} no change IP={current_ip}") return else: print(f"change IP from {previous_ip} to {current_ip}") # Update DDNS mssg = time_msg() print(f"{mssg} access to value-domain") url_set_ddns = ( f"https://dyn.value-domain.com/cgi-bin/dyn.fcg?" f"d={MY_DOMAIN}&p={MY_PASS}&h={MY_HOSTNAME}" ) try: response = requests.get(url_set_ddns, timeout=10) response.raise_for_status() # Convert line breaks to spaces and consolidate consecutive spaces into a single space. result = ' '.join(response.text.strip().split()) except requests.RequestException as e: print(f"{time_msg()} Failed to update DDNS: {e}") return mssg = time_msg() print(f"{mssg} {MY_HOSTNAME}.{MY_DOMAIN} {result} IP={current_ip}") # Only save the IP address if the DDNS update is successful. if "status=0" in result: with open(OUT_FILE, "w") as f: f.write(current_ip) print(f"{mssg} Successfully saved new IP: {current_ip}") else: print(f"{mssg} DDNS update failed, IP not saved") if __name__ == "__main__": main() |
IP Address Log File Creation
|
1 |
# touch /tmp/ipadress |
Run periodically
|
1 2 3 |
# crontab -e * 00 * * * /usr/bin/python3 /var/www/system/ddnsset.py >> /var/log/ddns_updater.log 2>&1 |
