reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to the Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by the Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding any notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. Please do not remove or change
|
||||
the license header comment from a contributed file except when
|
||||
necessary.
|
||||
|
||||
Copyright 2026 mukul975
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,370 @@
|
||||
---
|
||||
name: analyzing-linux-elf-malware
|
||||
description: 'Analyze malicious Linux ELF binaries — botnets, cryptominers, ransomware,
|
||||
and rootkits targeting Linux servers, containers, and cloud infrastructure — through
|
||||
static analysis, dynamic tracing, and reverse engineering of x86_64 and ARM samples.
|
||||
Use when investigating Linux malware, triaging a suspicious ELF binary, assessing
|
||||
a compromised Linux server, or analyzing container-targeted malware.
|
||||
|
||||
'
|
||||
domain: cybersecurity
|
||||
subdomain: malware-analysis
|
||||
tags:
|
||||
- malware
|
||||
- Linux
|
||||
- ELF
|
||||
- reverse-engineering
|
||||
- server-malware
|
||||
version: 1.0.0
|
||||
author: mahipal
|
||||
license: Apache-2.0
|
||||
nist_csf:
|
||||
- DE.AE-02
|
||||
- RS.AN-03
|
||||
- ID.RA-01
|
||||
- DE.CM-01
|
||||
mitre_attack:
|
||||
- T1027
|
||||
- T1059.004
|
||||
- T1620
|
||||
- T1574.006
|
||||
mitre_f3:
|
||||
version: '1.1'
|
||||
tactics:
|
||||
- positioning
|
||||
- monetization
|
||||
- reconnaissance
|
||||
techniques:
|
||||
- id: T1219
|
||||
name: Remote Access Tools
|
||||
tactic: positioning
|
||||
source: attack
|
||||
- id: T1555
|
||||
name: Credentials from Password Stores
|
||||
tactic: reconnaissance
|
||||
source: attack
|
||||
- id: F1018
|
||||
name: Convert to Cryptocurrency
|
||||
tactic: monetization
|
||||
source: f3
|
||||
- id: F1047
|
||||
name: Transfer of funds
|
||||
tactic: monetization
|
||||
source: f3
|
||||
---
|
||||
|
||||
# Analyzing Linux ELF Malware
|
||||
|
||||
## When to Use
|
||||
|
||||
- A Linux server or container has been compromised and suspicious ELF binaries are found
|
||||
- Analyzing Linux botnets (Mirai, Gafgyt, XorDDoS), cryptominers, or ransomware
|
||||
- Investigating malware targeting cloud infrastructure, Docker containers, or Kubernetes pods
|
||||
- Reverse engineering Linux rootkits and kernel modules
|
||||
- Analyzing cross-platform malware compiled for Linux x86_64, ARM, or MIPS architectures
|
||||
|
||||
**Do not use** for Windows PE binary analysis; use PEStudio, Ghidra, or IDA for Windows malware.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Ghidra or IDA with Linux ELF support for disassembly and decompilation
|
||||
- Linux analysis VM (Ubuntu 22.04 recommended) with development tools installed
|
||||
- strace, ltrace, and GDB for dynamic analysis and debugging
|
||||
- readelf, objdump, and nm from GNU binutils for static inspection
|
||||
- Radare2 for quick binary triage and scripted analysis
|
||||
- Docker for isolated container-based malware execution
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Identify ELF Binary Properties
|
||||
|
||||
Examine the ELF header and basic properties:
|
||||
|
||||
```bash
|
||||
# File type identification
|
||||
file suspect_binary
|
||||
|
||||
# Detailed ELF header analysis
|
||||
readelf -h suspect_binary
|
||||
|
||||
# Section headers
|
||||
readelf -S suspect_binary
|
||||
|
||||
# Program headers (segments)
|
||||
readelf -l suspect_binary
|
||||
|
||||
# Symbol table (if not stripped)
|
||||
readelf -s suspect_binary
|
||||
nm suspect_binary 2>/dev/null
|
||||
|
||||
# Dynamic linking information
|
||||
readelf -d suspect_binary
|
||||
ldd suspect_binary 2>/dev/null # Only on matching architecture!
|
||||
|
||||
# Compute hashes
|
||||
md5sum suspect_binary
|
||||
sha256sum suspect_binary
|
||||
|
||||
# Check for packing/UPX
|
||||
upx -t suspect_binary
|
||||
```
|
||||
|
||||
```python
|
||||
# Python-based ELF analysis
|
||||
from elftools.elf.elffile import ELFFile
|
||||
import hashlib
|
||||
|
||||
with open("suspect_binary", "rb") as f:
|
||||
data = f.read()
|
||||
sha256 = hashlib.sha256(data).hexdigest()
|
||||
|
||||
with open("suspect_binary", "rb") as f:
|
||||
elf = ELFFile(f)
|
||||
|
||||
print(f"SHA-256: {sha256}")
|
||||
print(f"Class: {elf.elfclass}-bit")
|
||||
print(f"Endian: {elf.little_endian and 'Little' or 'Big'}")
|
||||
print(f"Machine: {elf.header.e_machine}")
|
||||
print(f"Type: {elf.header.e_type}")
|
||||
print(f"Entry Point: 0x{elf.header.e_entry:X}")
|
||||
|
||||
# Check if stripped
|
||||
symtab = elf.get_section_by_name('.symtab')
|
||||
print(f"Stripped: {'Yes' if symtab is None else 'No'}")
|
||||
|
||||
# Section entropy analysis
|
||||
import math
|
||||
from collections import Counter
|
||||
for section in elf.iter_sections():
|
||||
data = section.data()
|
||||
if len(data) > 0:
|
||||
entropy = -sum((c/len(data)) * math.log2(c/len(data))
|
||||
for c in Counter(data).values() if c > 0)
|
||||
if entropy > 7.0:
|
||||
print(f" [!] High entropy section: {section.name} ({entropy:.2f})")
|
||||
```
|
||||
|
||||
### Step 2: Extract Strings and Indicators
|
||||
|
||||
Search for embedded IOCs and functionality clues:
|
||||
|
||||
```bash
|
||||
# ASCII strings
|
||||
strings suspect_binary > strings_output.txt
|
||||
|
||||
# Search for network indicators
|
||||
grep -iE "(http|https|ftp)://" strings_output.txt
|
||||
grep -iE "([0-9]{1,3}\.){3}[0-9]{1,3}" strings_output.txt
|
||||
grep -iE "[a-zA-Z0-9.-]+\.(com|net|org|io|ru|cn)" strings_output.txt
|
||||
|
||||
# Search for shell commands
|
||||
grep -iE "(bash|sh|wget|curl|chmod|/tmp/|/dev/)" strings_output.txt
|
||||
|
||||
# Search for crypto mining indicators
|
||||
grep -iE "(stratum|xmr|monero|pool\.|mining)" strings_output.txt
|
||||
|
||||
# Search for SSH/credential theft
|
||||
grep -iE "(ssh|authorized_keys|id_rsa|shadow|passwd)" strings_output.txt
|
||||
|
||||
# Search for persistence mechanisms
|
||||
grep -iE "(crontab|systemd|init\.d|rc\.local|ld\.so\.preload)" strings_output.txt
|
||||
|
||||
# FLOSS for obfuscated strings (if available)
|
||||
floss suspect_binary
|
||||
```
|
||||
|
||||
### Step 3: Analyze System Calls and Library Usage
|
||||
|
||||
Identify what system calls and libraries the malware uses:
|
||||
|
||||
```bash
|
||||
# List imported functions (dynamically linked)
|
||||
readelf -r suspect_binary | grep -E "socket|connect|exec|fork|open|write|bind|listen"
|
||||
|
||||
# Trace system calls during execution (in isolated VM only)
|
||||
strace -f -e trace=network,process,file -o strace_output.txt ./suspect_binary
|
||||
|
||||
# Trace library calls
|
||||
ltrace -f -o ltrace_output.txt ./suspect_binary
|
||||
|
||||
# Key system calls to watch:
|
||||
# Network: socket, connect, bind, listen, accept, sendto, recvfrom
|
||||
# Process: fork, execve, clone, kill, ptrace
|
||||
# File: open, read, write, unlink, rename, chmod
|
||||
# Persistence: inotify_add_watch (file monitoring)
|
||||
```
|
||||
|
||||
### Step 4: Dynamic Analysis with GDB
|
||||
|
||||
Debug the malware to observe runtime behavior:
|
||||
|
||||
```bash
|
||||
# Start GDB with the binary
|
||||
gdb ./suspect_binary
|
||||
|
||||
# Set breakpoints on key functions
|
||||
(gdb) break main
|
||||
(gdb) break socket
|
||||
(gdb) break connect
|
||||
(gdb) break execve
|
||||
(gdb) break fork
|
||||
|
||||
# Run and analyze
|
||||
(gdb) run
|
||||
(gdb) info registers # View register state
|
||||
(gdb) x/20s $rdi # Examine string argument
|
||||
(gdb) bt # Backtrace
|
||||
(gdb) continue
|
||||
|
||||
# For stripped binaries, break on entry point
|
||||
(gdb) break *0x400580 # Entry point from readelf
|
||||
(gdb) run
|
||||
|
||||
# Monitor network connections during execution
|
||||
# In another terminal:
|
||||
ss -tlnp # List listening sockets
|
||||
ss -tnp # List established connections
|
||||
```
|
||||
|
||||
### Step 5: Reverse Engineer with Ghidra
|
||||
|
||||
Perform deep code analysis on the ELF binary:
|
||||
|
||||
```
|
||||
Ghidra Analysis for Linux ELF:
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
1. Import: File -> Import -> Select ELF binary
|
||||
- Ghidra auto-detects ELF format and architecture
|
||||
- Accept default analysis options
|
||||
|
||||
2. Key analysis targets:
|
||||
- main() function (or entry point if stripped)
|
||||
- Socket creation and connection functions
|
||||
- Command dispatch logic (switch/case on received data)
|
||||
- Encryption/encoding routines
|
||||
- Persistence installation code
|
||||
- Self-propagation/scanning functions
|
||||
|
||||
3. For Mirai-like botnets, look for:
|
||||
- Credential list for brute-forcing (telnet/SSH)
|
||||
- Attack module selection (UDP flood, SYN flood, ACK flood)
|
||||
- Scanner module (port scanning for vulnerable devices)
|
||||
- Killer module (killing competing botnets)
|
||||
|
||||
4. For cryptominers, look for:
|
||||
- Mining pool connection (stratum protocol)
|
||||
- Wallet address strings
|
||||
- CPU/GPU utilization functions
|
||||
- Process hiding techniques
|
||||
```
|
||||
|
||||
### Step 6: Analyze Linux-Specific Persistence
|
||||
|
||||
Check for persistence mechanisms:
|
||||
|
||||
```bash
|
||||
# Check for LD_PRELOAD rootkit
|
||||
strings suspect_binary | grep "ld.so.preload"
|
||||
# Malware writing to /etc/ld.so.preload can hook all dynamic library calls
|
||||
|
||||
# Check for crontab persistence
|
||||
strings suspect_binary | grep -i "cron"
|
||||
|
||||
# Check for systemd service creation
|
||||
strings suspect_binary | grep -iE "systemd|\.service|systemctl"
|
||||
|
||||
# Check for init script creation
|
||||
strings suspect_binary | grep -iE "init\.d|rc\.local|update-rc"
|
||||
|
||||
# Check for SSH key injection
|
||||
strings suspect_binary | grep -i "authorized_keys"
|
||||
|
||||
# Check for kernel module (rootkit) loading
|
||||
strings suspect_binary | grep -iE "insmod|modprobe|init_module"
|
||||
|
||||
# Check for process hiding
|
||||
strings suspect_binary | grep -iE "proc|readdir|getdents"
|
||||
```
|
||||
|
||||
## Key Concepts
|
||||
|
||||
| Term | Definition |
|
||||
|------|------------|
|
||||
| **ELF (Executable and Linkable Format)** | Standard binary format for Linux executables, shared libraries, and core dumps containing headers, sections, and segments |
|
||||
| **Stripped Binary** | ELF binary with debug symbols removed, making reverse engineering more difficult as function names are lost |
|
||||
| **LD_PRELOAD** | Linux environment variable specifying shared libraries to load before all others; abused by rootkits to intercept system library calls |
|
||||
| **strace** | Linux system call tracer that logs all system calls and signals made by a process, revealing file, network, and process operations |
|
||||
| **GOT/PLT** | Global Offset Table and Procedure Linkage Table; ELF structures for dynamic linking that can be hijacked for function hooking |
|
||||
| **Statically Linked** | Binary compiled with all library code included; common in IoT malware to run on systems without matching shared libraries |
|
||||
| **Mirai** | Prolific Linux botnet targeting IoT devices via telnet brute-force; source code leaked, leading to many variants |
|
||||
|
||||
## Tools & Systems
|
||||
|
||||
- **Ghidra**: NSA reverse engineering tool with full ELF support for x86, x86_64, ARM, MIPS, and other Linux architectures
|
||||
- **Radare2**: Open-source reverse engineering framework with command-line interface for quick binary analysis and scripting
|
||||
- **strace**: Linux system call tracing tool for observing binary behavior including file, network, and process operations
|
||||
- **GDB**: GNU Debugger for setting breakpoints, examining memory, and stepping through Linux binary execution
|
||||
- **pyelftools**: Python library for parsing ELF files programmatically for automated analysis pipelines
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
### Scenario: Analyzing a Cryptominer Found on a Compromised Linux Server
|
||||
|
||||
**Context**: A cloud server shows 100% CPU usage. Investigation reveals an unknown binary running from /tmp with a suspicious name. The binary needs analysis to confirm it is a cryptominer and identify the attacker's wallet and pool.
|
||||
|
||||
**Approach**:
|
||||
1. Copy the binary to an analysis VM and compute SHA-256 hash
|
||||
2. Run `file` and `readelf` to identify architecture and linking type
|
||||
3. Extract strings and search for mining pool addresses (stratum+tcp://) and wallet addresses
|
||||
4. Run with strace in a sandbox to observe network connections (mining pool connection)
|
||||
5. Import into Ghidra to identify the mining algorithm and configuration extraction
|
||||
6. Check for persistence mechanisms (crontab, systemd service, SSH keys)
|
||||
7. Document all IOCs including pool address, wallet, C2 for updates, and persistence artifacts
|
||||
|
||||
**Pitfalls**:
|
||||
- Running `ldd` on malware outside a sandbox (ldd can execute code in the binary)
|
||||
- Not checking for ARM/MIPS architecture before attempting x86_64 execution
|
||||
- Missing companion scripts (.sh files) that may handle persistence and cleanup
|
||||
- Ignoring the initial access vector (how the miner was deployed: SSH brute force, web exploit, container escape)
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
LINUX ELF MALWARE ANALYSIS REPORT
|
||||
====================================
|
||||
File: /tmp/.X11-unix/.rsync
|
||||
SHA-256: e3b0c44298fc1c149afbf4c8996fb924...
|
||||
Type: ELF 64-bit LSB executable, x86-64
|
||||
Linking: Statically linked (all libraries embedded)
|
||||
Stripped: Yes
|
||||
Size: 2,847,232 bytes
|
||||
Packer: UPX 3.96 (unpacked for analysis)
|
||||
|
||||
CLASSIFICATION
|
||||
Family: XMRig Cryptominer (modified)
|
||||
Variant: Custom build with C2 update mechanism
|
||||
|
||||
FUNCTIONALITY
|
||||
[*] XMR (Monero) mining via RandomX algorithm
|
||||
[*] Stratum pool connection for work submission
|
||||
[*] C2 check-in for configuration updates
|
||||
[*] Process name masquerading (argv[0] = "[kworker/0:0]")
|
||||
[*] Competitor process killing (kills other miners)
|
||||
[*] SSH key injection for re-access
|
||||
|
||||
NETWORK INDICATORS
|
||||
Mining Pool: stratum+tcp://pool.minexmr[.]com:4444
|
||||
C2 Server: hxxp://update.malicious[.]com/config
|
||||
Wallet: 49jZ5Q3b...Monero_Wallet_Address...
|
||||
|
||||
PERSISTENCE
|
||||
[1] Crontab entry: */5 * * * * /tmp/.X11-unix/.rsync
|
||||
[2] SSH key added to /root/.ssh/authorized_keys
|
||||
[3] Systemd service: /etc/systemd/system/rsync-daemon.service
|
||||
[4] Modified /etc/ld.so.preload for process hiding
|
||||
|
||||
PROCESS HIDING
|
||||
LD_PRELOAD: /usr/lib/.libsystem.so
|
||||
Hook: readdir() to hide /tmp/.X11-unix/.rsync from ls
|
||||
Hook: fopen() to hide from /proc/*/maps reading
|
||||
```
|
||||
@@ -0,0 +1,119 @@
|
||||
# API Reference: Linux ELF Malware Analysis Tools
|
||||
|
||||
## readelf - ELF Binary Inspection
|
||||
|
||||
### Syntax
|
||||
```bash
|
||||
readelf -h <binary> # ELF header
|
||||
readelf -S <binary> # Section headers
|
||||
readelf -l <binary> # Program headers (segments)
|
||||
readelf -s <binary> # Symbol table
|
||||
readelf -d <binary> # Dynamic section
|
||||
readelf -r <binary> # Relocation entries
|
||||
readelf -n <binary> # Notes section
|
||||
```
|
||||
|
||||
### Key ELF Header Fields
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `Class` | 32-bit or 64-bit |
|
||||
| `Machine` | Architecture (x86-64, ARM, MIPS) |
|
||||
| `Type` | EXEC (executable), DYN (shared object) |
|
||||
| `Entry point` | Code execution start address |
|
||||
|
||||
## pyelftools - Python ELF Parsing
|
||||
|
||||
### Usage
|
||||
```python
|
||||
from elftools.elf.elffile import ELFFile
|
||||
|
||||
with open("binary", "rb") as f:
|
||||
elf = ELFFile(f)
|
||||
elf.elfclass # 32 or 64
|
||||
elf.little_endian # True/False
|
||||
elf.header.e_machine # Architecture
|
||||
elf.header.e_entry # Entry point
|
||||
elf.num_sections() # Section count
|
||||
elf.get_section_by_name(".symtab") # Symbol table
|
||||
```
|
||||
|
||||
## strings - String Extraction
|
||||
|
||||
### Syntax
|
||||
```bash
|
||||
strings <binary> # ASCII strings (default min 4)
|
||||
strings -n 8 <binary> # Minimum 8 characters
|
||||
strings -e l <binary> # 16-bit little-endian (Unicode)
|
||||
strings -t x <binary> # Print offset in hex
|
||||
```
|
||||
|
||||
## strace - System Call Tracing
|
||||
|
||||
### Syntax
|
||||
```bash
|
||||
strace -f ./binary # Follow forks
|
||||
strace -e trace=network ./binary # Network calls only
|
||||
strace -e trace=file ./binary # File operations only
|
||||
strace -e trace=process ./binary # Process operations
|
||||
strace -o output.txt ./binary # Log to file
|
||||
strace -c ./binary # Summary statistics
|
||||
```
|
||||
|
||||
### Key System Calls
|
||||
| Call | Category |
|
||||
|------|----------|
|
||||
| `socket`, `connect`, `bind` | Network |
|
||||
| `fork`, `execve`, `clone` | Process |
|
||||
| `open`, `read`, `write`, `unlink` | File I/O |
|
||||
| `ptrace` | Anti-debug/injection |
|
||||
|
||||
## ltrace - Library Call Tracing
|
||||
|
||||
### Syntax
|
||||
```bash
|
||||
ltrace -f ./binary # Follow child processes
|
||||
ltrace -e malloc+free ./binary # Specific functions
|
||||
ltrace -o output.txt ./binary # Log to file
|
||||
```
|
||||
|
||||
## GDB - GNU Debugger
|
||||
|
||||
### Syntax
|
||||
```bash
|
||||
gdb ./binary
|
||||
(gdb) break main
|
||||
(gdb) break *0x400580 # Break at address
|
||||
(gdb) run
|
||||
(gdb) info registers
|
||||
(gdb) x/20s $rdi # Examine string at RDI
|
||||
(gdb) x/10i $rip # Disassemble at RIP
|
||||
(gdb) bt # Backtrace
|
||||
```
|
||||
|
||||
## UPX - Packer Detection/Unpacking
|
||||
|
||||
### Syntax
|
||||
```bash
|
||||
upx -t <binary> # Test if packed
|
||||
upx -d <binary> # Decompress/unpack
|
||||
upx -l <binary> # List compression details
|
||||
```
|
||||
|
||||
## objdump - Disassembly
|
||||
|
||||
### Syntax
|
||||
```bash
|
||||
objdump -d <binary> # Disassemble .text
|
||||
objdump -D <binary> # Disassemble all sections
|
||||
objdump -M intel -d <binary> # Intel syntax
|
||||
objdump -t <binary> # Symbol table
|
||||
```
|
||||
|
||||
## nm - Symbol Listing
|
||||
|
||||
### Syntax
|
||||
```bash
|
||||
nm <binary> # List symbols
|
||||
nm -D <binary> # Dynamic symbols only
|
||||
nm -u <binary> # Undefined (imported) symbols
|
||||
```
|
||||
@@ -0,0 +1,230 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Linux ELF malware static analysis agent using pyelftools and binary inspection."""
|
||||
|
||||
import hashlib
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
from collections import Counter
|
||||
|
||||
try:
|
||||
from elftools.elf.elffile import ELFFile
|
||||
HAS_ELFTOOLS = True
|
||||
except ImportError:
|
||||
HAS_ELFTOOLS = False
|
||||
|
||||
|
||||
def compute_hashes(filepath):
|
||||
"""Compute MD5, SHA1, and SHA256 hashes of a file."""
|
||||
md5 = hashlib.md5()
|
||||
sha1 = hashlib.sha1()
|
||||
sha256 = hashlib.sha256()
|
||||
with open(filepath, "rb") as f:
|
||||
for chunk in iter(lambda: f.read(65536), b""):
|
||||
md5.update(chunk)
|
||||
sha1.update(chunk)
|
||||
sha256.update(chunk)
|
||||
return {"md5": md5.hexdigest(), "sha1": sha1.hexdigest(), "sha256": sha256.hexdigest()}
|
||||
|
||||
|
||||
def calculate_entropy(data):
|
||||
"""Calculate Shannon entropy of binary data."""
|
||||
if not data:
|
||||
return 0.0
|
||||
counter = Counter(data)
|
||||
length = len(data)
|
||||
return -sum((c / length) * math.log2(c / length) for c in counter.values())
|
||||
|
||||
|
||||
def analyze_elf_header(filepath):
|
||||
"""Parse ELF header and extract key properties."""
|
||||
if not HAS_ELFTOOLS:
|
||||
return {"error": "pyelftools not installed: pip install pyelftools"}
|
||||
with open(filepath, "rb") as f:
|
||||
elf = ELFFile(f)
|
||||
symtab = elf.get_section_by_name(".symtab")
|
||||
info = {
|
||||
"class": f"{elf.elfclass}-bit",
|
||||
"endian": "Little" if elf.little_endian else "Big",
|
||||
"machine": elf.header.e_machine,
|
||||
"type": elf.header.e_type,
|
||||
"entry_point": f"0x{elf.header.e_entry:X}",
|
||||
"stripped": symtab is None,
|
||||
"num_sections": elf.num_sections(),
|
||||
"num_segments": elf.num_segments(),
|
||||
}
|
||||
return info
|
||||
|
||||
|
||||
def analyze_sections(filepath):
|
||||
"""Analyze ELF sections for entropy and suspicious characteristics."""
|
||||
if not HAS_ELFTOOLS:
|
||||
return []
|
||||
sections = []
|
||||
with open(filepath, "rb") as f:
|
||||
elf = ELFFile(f)
|
||||
for section in elf.iter_sections():
|
||||
data = section.data()
|
||||
if len(data) == 0:
|
||||
continue
|
||||
entropy = calculate_entropy(data)
|
||||
sections.append({
|
||||
"name": section.name,
|
||||
"type": section["sh_type"],
|
||||
"size": len(data),
|
||||
"entropy": round(entropy, 4),
|
||||
"high_entropy": entropy > 7.0,
|
||||
"flags": section["sh_flags"],
|
||||
})
|
||||
return sections
|
||||
|
||||
|
||||
def extract_strings(filepath, min_length=6):
|
||||
"""Extract ASCII strings from the binary and categorize by type."""
|
||||
stdout, _, rc = subprocess.run(
|
||||
["strings", "-n", str(min_length), filepath],
|
||||
capture_output=True, text=True, timeout=120
|
||||
).stdout, "", 0
|
||||
if not stdout:
|
||||
return {}
|
||||
all_strings = stdout.strip().splitlines()
|
||||
categorized = {
|
||||
"urls": [], "ips": [], "domains": [], "shell_commands": [],
|
||||
"crypto_mining": [], "persistence": [], "ssh_related": [],
|
||||
"total": len(all_strings),
|
||||
}
|
||||
for s in all_strings:
|
||||
s_lower = s.lower()
|
||||
if any(proto in s_lower for proto in ["http://", "https://", "ftp://"]):
|
||||
categorized["urls"].append(s)
|
||||
if any(p in s_lower for p in ["stratum", "xmr", "monero", "pool.", "mining"]):
|
||||
categorized["crypto_mining"].append(s)
|
||||
if any(p in s_lower for p in ["crontab", "systemd", "init.d", "rc.local",
|
||||
"ld.so.preload", "systemctl"]):
|
||||
categorized["persistence"].append(s)
|
||||
if any(p in s_lower for p in ["ssh", "authorized_keys", "id_rsa", "shadow", "passwd"]):
|
||||
categorized["ssh_related"].append(s)
|
||||
if any(p in s_lower for p in ["bash", "wget", "curl", "chmod", "/tmp/", "/dev/"]):
|
||||
categorized["shell_commands"].append(s)
|
||||
import re
|
||||
if re.match(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", s):
|
||||
categorized["ips"].append(s)
|
||||
if re.match(r"[a-zA-Z0-9.-]+\.(com|net|org|io|ru|cn|xyz)", s):
|
||||
categorized["domains"].append(s)
|
||||
return categorized
|
||||
|
||||
|
||||
def check_packing(filepath):
|
||||
"""Check if the binary is packed with UPX or other packers."""
|
||||
with open(filepath, "rb") as f:
|
||||
data = f.read(4096)
|
||||
indicators = []
|
||||
if b"UPX!" in data:
|
||||
indicators.append("UPX packer detected (UPX! magic)")
|
||||
if b"UPX0" in data or b"UPX1" in data:
|
||||
indicators.append("UPX section names found")
|
||||
stdout, _, _ = subprocess.run(["upx", "-t", filepath],
|
||||
capture_output=True, text=True,
|
||||
stderr=subprocess.STDOUT, timeout=120).stdout, "", 0
|
||||
if stdout and "packed" in stdout.lower():
|
||||
indicators.append("UPX verification confirms packing")
|
||||
return indicators
|
||||
|
||||
|
||||
def analyze_dynamic_linking(filepath):
|
||||
"""Analyze dynamic linking information and imported functions."""
|
||||
stdout, _, rc = subprocess.run(["readelf", "-d", filepath],
|
||||
capture_output=True, text=True, timeout=120).stdout, "", 0
|
||||
dynamic_info = {"libraries": [], "rpath": None}
|
||||
if stdout:
|
||||
for line in stdout.splitlines():
|
||||
if "NEEDED" in line:
|
||||
lib = line.split("[")[-1].rstrip("]") if "[" in line else ""
|
||||
dynamic_info["libraries"].append(lib)
|
||||
if "RPATH" in line or "RUNPATH" in line:
|
||||
dynamic_info["rpath"] = line.split("[")[-1].rstrip("]")
|
||||
|
||||
readelf_proc = subprocess.run(
|
||||
["readelf", "-r", filepath],
|
||||
capture_output=True, text=True,
|
||||
timeout=120,
|
||||
)
|
||||
import re as _re
|
||||
suspicious_funcs = _re.compile(r'socket|connect|exec|fork|open|write|bind|listen|send|recv')
|
||||
stdout2 = "\n".join(
|
||||
line for line in (readelf_proc.stdout or "").splitlines()
|
||||
if suspicious_funcs.search(line)
|
||||
)
|
||||
dynamic_info["suspicious_imports"] = [
|
||||
line.strip() for line in (stdout2 or "").splitlines() if line.strip()
|
||||
]
|
||||
return dynamic_info
|
||||
|
||||
|
||||
def detect_malware_type(strings_data):
|
||||
"""Classify malware type based on extracted strings."""
|
||||
classifications = []
|
||||
if strings_data.get("crypto_mining"):
|
||||
classifications.append("Cryptominer")
|
||||
if any("flood" in s.lower() or "ddos" in s.lower()
|
||||
for s in strings_data.get("shell_commands", [])):
|
||||
classifications.append("DDoS Botnet")
|
||||
if strings_data.get("ssh_related") and strings_data.get("persistence"):
|
||||
classifications.append("Backdoor/Trojan")
|
||||
if any("insmod" in s or "modprobe" in s or "init_module" in s
|
||||
for s in strings_data.get("shell_commands", [])):
|
||||
classifications.append("Rootkit")
|
||||
if any("ransom" in s.lower() or "encrypt" in s.lower() or "bitcoin" in s.lower()
|
||||
for cat in strings_data.values() if isinstance(cat, list) for s in cat):
|
||||
classifications.append("Ransomware")
|
||||
return classifications or ["Unknown"]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=" * 60)
|
||||
print("Linux ELF Malware Analysis Agent")
|
||||
print("Static analysis with pyelftools, strings, readelf")
|
||||
print("=" * 60)
|
||||
|
||||
target = sys.argv[1] if len(sys.argv) > 1 else None
|
||||
|
||||
if target and os.path.exists(target):
|
||||
print(f"\n[*] Analyzing: {target}")
|
||||
print(f"[*] Size: {os.path.getsize(target)} bytes")
|
||||
|
||||
hashes = compute_hashes(target)
|
||||
print(f"[*] MD5: {hashes['md5']}")
|
||||
print(f"[*] SHA256: {hashes['sha256']}")
|
||||
|
||||
elf_info = analyze_elf_header(target)
|
||||
print(f"\n--- ELF Header ---")
|
||||
for k, v in elf_info.items():
|
||||
print(f" {k}: {v}")
|
||||
|
||||
packing = check_packing(target)
|
||||
if packing:
|
||||
for p in packing:
|
||||
print(f"[!] {p}")
|
||||
|
||||
sections = analyze_sections(target)
|
||||
high_ent = [s for s in sections if s.get("high_entropy")]
|
||||
if high_ent:
|
||||
print(f"\n[!] High entropy sections (possible packing/encryption):")
|
||||
for s in high_ent:
|
||||
print(f" {s['name']}: entropy={s['entropy']}, size={s['size']}")
|
||||
|
||||
strings_data = extract_strings(target)
|
||||
print(f"\n--- Strings Analysis ({strings_data.get('total', 0)} total) ---")
|
||||
for category in ["urls", "ips", "domains", "crypto_mining", "persistence", "ssh_related"]:
|
||||
items = strings_data.get(category, [])
|
||||
if items:
|
||||
print(f" {category}: {len(items)}")
|
||||
for item in items[:5]:
|
||||
print(f" - {item}")
|
||||
|
||||
classification = detect_malware_type(strings_data)
|
||||
print(f"\n[*] Classification: {', '.join(classification)}")
|
||||
else:
|
||||
print(f"\n[DEMO] Usage: python agent.py <elf_binary>")
|
||||
print("[*] Provide a Linux ELF binary for analysis.")
|
||||
Reference in New Issue
Block a user