Skip to content

Commit 1672e18

Browse files
author
Craig H. Rowland
committed
Initial 1.0 Commit
Sandfly's Linux stealth rootkit decloaking utility version 1.0 released.
1 parent feb583d commit 1672e18

File tree

3 files changed

+263
-16
lines changed

3 files changed

+263
-16
lines changed

LICENSE

+15-16
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
MIT License
22

3-
Copyright (c) 2022 Sandfly Security
3+
Copyright © 2018-2022 Sandfly Security
4+
Agentless Security for Linux (www.sandflysecurity.com)
45

5-
Permission is hereby granted, free of charge, to any person obtaining a copy
6-
of this software and associated documentation files (the "Software"), to deal
7-
in the Software without restriction, including without limitation the rights
8-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9-
copies of the Software, and to permit persons to whom the Software is
10-
furnished to do so, subject to the following conditions:
6+
Permission is hereby granted, free of charge, to any person obtaining a copy of this
7+
software and associated documentation files (the “Software”), to deal in the Software
8+
without restriction, including without limitation the rights to use, copy, modify, merge,
9+
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
10+
to whom the Software is furnished to do so, subject to the following conditions:
1111

12-
The above copyright notice and this permission notice shall be included in all
13-
copies or substantial portions of the Software.
12+
The above copyright notice and this permission notice shall be included in all copies or
13+
substantial portions of the Software.
1414

15-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-
SOFTWARE.
15+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
17+
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
18+
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20+
DEALINGS IN THE SOFTWARE.

README.md

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# Sandfly File Decloak - Decloak data hidden by a Linux stealth rootkit
2+
3+
This utility helps investigate a host for signs of an active Linux stealth rootkit that may
4+
be hiding data in critical files. It does this by reading in a file using standard file I/O
5+
operations and then doing the same using memory mapped I/O to see if the number of bytes
6+
read are identical.
7+
8+
Any differences detected will generate an alert. Plus, you will see the hidden data
9+
decloaked to instantly see if it is suspicious or not. This utility will work against many
10+
common Loadable Kernel Module (LKM) stealth rootkits that use data hiding techniques.
11+
12+
## Linux Loadable Kernel Module Stealth Rootkit File Hiding Tactics
13+
14+
Loadable Kernel Module rootkits on Linux use a variety of tactics to hide. One method is to
15+
hide processes which can be decloaked using our utility sandlfy-processdecloak
16+
(<https://github.com/sandflysecurity/sandfly-processdecloak>). The other is to hide data
17+
inside critical start-up scripts so it can maintain persistence between reboots but not be
18+
seen by investigators when running.
19+
20+
For instance the files below are commonly targeted to hide data as they are used to insert
21+
kernel modules upon system boot. Or, these files can be used to insert malicious libraries
22+
to intercept system calls in libc, etc. to alter data to callers:
23+
24+
```text
25+
/etc/modules
26+
/etc/ld.so.conf
27+
```
28+
29+
Also directories for module loading on boot such as:
30+
31+
```text
32+
/etc/modules-load.d
33+
/etc/init.d
34+
/etc/rc*.d
35+
/etc/systemd
36+
```
37+
38+
Many more files can also be used for this purpose and often are hidden under /etc as part
39+
of system init scripts.
40+
41+
## Stealth Rootkit Hiding Method
42+
43+
Most LKM rootkits generally accomplish data hiding by hooking common system calls for file
44+
read operations. They will use a special set of tags to mark data to hide. Between the tags
45+
the malicious data will be inserted. When the rootkit sees the start tag it simply does not
46+
show any data present until the end tag is read. By doing this the rootkit can effectively
47+
hide from discovery using common command line tools and even editors on Linux.
48+
49+
For instance, a modified file may have tags inserted like this:
50+
51+
```bash
52+
# malicious content below
53+
#<lkm_tag>
54+
malicious_module
55+
#</lkm_tag>
56+
```
57+
58+
Anything between the *<lkm_tag>* and *</lkm_tag>* will be masked (along with the tags
59+
themselves) when you use tools like cat, echo, vi and so on. It simply won't be shown.
60+
61+
## Detecting LKM rootkits
62+
63+
It is one thing to convince the kernel to hide data, but something else entirely to get
64+
the file system to agree with it. In fact we know the data is there on the file system
65+
and we just need to bypass the hooked calls to see if we can get it to reveal itself. We'll
66+
accomplish this using memory mapped (mmap) file I/O instead of standard file I/O. LKM
67+
rootkits generally do not intercept mmap file I/O which is a significantly harder and
68+
riskier thing to do.
69+
70+
We will read the file using standard system calls, then we read the file using mmap system
71+
calls in a simple Python script. We then compare the two results. If the results show the
72+
same number of bytes the system is likely clean. However if the two results do not match
73+
then data is being hidden and we will use the mmap I/O to show the data difference and
74+
decloak the data it saw that was different.
75+
76+
## Usage
77+
78+
Simply execute the python script on the system in question and the answer will come forth.
79+
80+
```bash
81+
python3 ./sandfly-file-decloak.py -f <file_to_investigate>
82+
```
83+
84+
Below we find a system with cloaked data under /etc/modules.
85+
86+
```text
87+
root@sandflysecurity:/root # python3 ./sandfly-file-decloak.py -f /etc/modules
88+
89+
Sandfly File Decloaking Utility - Version 1.0
90+
Copyright (c) 2018-2022 Sandfly Security
91+
Agentless Security for Linux - https://www.sandflysecurity.com
92+
93+
94+
**************************************
95+
File contents with standard I/O
96+
**************************************
97+
98+
99+
# /etc/modules: kernel modules to load at boot time.
100+
#
101+
# This file contains the names of kernel modules that should be loaded
102+
# at boot time, one per line. Lines beginning with "#" are ignored.
103+
104+
# malicious content below
105+
106+
107+
108+
**************************************
109+
File contents with memory mapped I/O
110+
**************************************
111+
112+
113+
# /etc/modules: kernel modules to load at boot time.
114+
#
115+
# This file contains the names of kernel modules that should be loaded
116+
# at boot time, one per line. Lines beginning with "#" are ignored.
117+
118+
# malicious content below
119+
#<reptile>
120+
malicious_module
121+
#</reptile>
122+
123+
124+
125+
Standard IO file size bytes: 222
126+
MMAP IO file size bytes: 260
127+
128+
********************************************************************************************
129+
ALERT: File sizes do not match. File has cloaked data. Check contents above for hidden data.
130+
********************************************************************************************
131+
```
132+
133+
## Automating with Agentless Linux Endpoint Detection and Response (EDR)
134+
135+
This tool can be built into an automated script to check hosts for signs of compromise.
136+
However, a much easier way is to use Sandfly to do it agentlessly for all your Linux systems
137+
continuously.
138+
139+
We have modules to detect and decloak stealth rootkit activity instantly across all your
140+
Linux systems. Even better, we can do it without the risk of loading any agents on your
141+
endpoints.
142+
143+
You can find out more information and get a free license to use on your Linux systems below:
144+
145+
<https://www.sandflysecurity.com>
146+
147+
## More Linux Forensics
148+
149+
If you liked this utility, please check out our blog where we go into many other Linux
150+
forensic techniques using command line tools and procedures at our website:
151+
152+
<https://www.sandflysecurity.com>

sandfly-file-decloak.py

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# Copyright © 2018-2022 Sandfly Security - Agentless Security for Linux (www.sandflysecurity.com)
2+
#
3+
# A utility to test if a file is hiding cloaked data due to a Loadable Kernel Module (LKM) or
4+
# LD_PRELOAD stealth rootkit on Linux. Simply call the command as follows against a suspect file:
5+
#
6+
# python3 ./sandfly-file-decloak.py -f /etc/modules
7+
#
8+
# Any cloaked data will be reported and decloaked so you can see the contents and investigate if
9+
# it is malicious.
10+
#
11+
# Sandfly produces an agentless Linux endpoint detection and incident response platform (EDR) that can detect
12+
# thousands of compromise tactics against Linux, including stealth rootkits. Sandfly hunts for threats
13+
# against your Linux systems without loading any agents on your endpoints and works against most distributions
14+
# and architectures.
15+
#
16+
# Please see our website for more information or a free trial.
17+
#
18+
# MIT Licensed
19+
# https://www.sandflysecurity.com
20+
# @SandflySecurity
21+
#
22+
# Please see our blog for more detailed information on this tool and other Linux forensics articles and
23+
# techniques.
24+
25+
import getopt
26+
import mmap
27+
import sys
28+
import binascii
29+
30+
VERSION="1.0"
31+
32+
def main():
33+
filename = None
34+
35+
try:
36+
opts, args = getopt.getopt(sys.argv[1:], "f:")
37+
except getopt.GetoptError:
38+
print("Illegal option. Valid option is -f")
39+
sys.exit(-1)
40+
41+
if len(opts) > 0:
42+
for opt, arg in opts:
43+
if opt == '-f':
44+
filename = arg
45+
46+
if not filename:
47+
print("Need to supply filename with -f")
48+
sys.exit(-1)
49+
50+
51+
print("\nSandfly File Decloaking Utility - Version {0}".format(VERSION))
52+
print("Copyright (c) 2018-2022 Sandfly Security")
53+
print("Agentless Security for Linux - https://www.sandflysecurity.com")
54+
55+
print("\n\n**************************************")
56+
print("File contents with standard I/O")
57+
print("**************************************\n\n")
58+
with open(filename, "r+b") as f:
59+
file_size_standard_io = 0
60+
for line in f:
61+
output = line
62+
try:
63+
print(output.decode('utf-8').rstrip())
64+
except UnicodeDecodeError:
65+
print("hex: ", binascii.hexlify(output))
66+
file_size_standard_io += len(output)
67+
68+
print("\n\n**************************************")
69+
print("File contents with memory mapped I/O")
70+
print("**************************************\n\n")
71+
with open(filename, "r+b") as f:
72+
map = mmap.mmap(f.fileno(), 0, access=mmap.PROT_READ)
73+
file_size_mmap = map.size()
74+
file_seek = 0
75+
while file_seek < file_size_mmap:
76+
output = map.readline()
77+
try:
78+
print(output.decode('utf-8').rstrip())
79+
except UnicodeDecodeError:
80+
print("hex: ", binascii.hexlify(output))
81+
file_seek += len(output)
82+
83+
print("\n\n")
84+
print("Standard IO file size bytes: ", file_size_standard_io)
85+
print("MMAP IO file size bytes: ", file_size_mmap)
86+
if file_size_standard_io != file_size_mmap:
87+
print("\n********************************************************************************************")
88+
print("ALERT: File sizes do not match. File has cloaked data. Check contents above for hidden data.")
89+
print("********************************************************************************************\n\n")
90+
else:
91+
print("\nOK: File sizes are same so they are not cloaked.\n\n")
92+
93+
if __name__ == '__main__':
94+
main()
95+
96+

0 commit comments

Comments
 (0)