├── MacOSThreatTrack.sh └── README.md /MacOSThreatTrack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | getSystemInfo() { 4 | hostname=$(hostname) 5 | uuid=$(system_profiler SPHardwareDataType | awk '/UUID/ {print $3}') 6 | macos_version=$(sw_vers -productVersion) 7 | kernel_version=$(sysctl -n kern.version) 8 | processor_info=$(sysctl -n machdep.cpu.brand_string) 9 | memory_info=$(sysctl -n hw.memsize) 10 | total_memory=$((memory_info/(1024*1024))) 11 | disk_info=$(diskutil list) 12 | network_info=$(ifconfig -a) 13 | echo "" 14 | echo "[*] Hostname: $hostname" 15 | echo "[*] UUID: $uuid" 16 | echo "[*] macOS Version: $macos_version" 17 | echo "[*] Kernel Version: $kernel_version" 18 | echo "[*] Processor: $processor_info" 19 | echo "[*] Total Memory: $total_memory MB" 20 | echo "[*] Disk Info: " 21 | echo "$disk_info" 22 | echo "----------------------------" 23 | echo "[*] Network Info: " 24 | echo "$network_info" 25 | echo "----------------------------" 26 | echo "" 27 | } 28 | 29 | getEnv(){ 30 | echo "" 31 | printenv 32 | } 33 | 34 | getProcessList(){ 35 | pslist=$(ps aux) 36 | echo "" 37 | echo "$pslist" 38 | } 39 | 40 | getUUID() { 41 | ioreg -rd1 -c IOPlatformExpertDevice | grep -E '(UUID)' | awk '{ print $3; }' 42 | } 43 | 44 | getSystemUsers() { 45 | allUsersArray=() 46 | results=$(ls /Users | grep -v '^_') 47 | while read user; do 48 | uuid=$(dscl . -read /Users/$user GeneratedUID | awk '{print $2}') 49 | admin=$(dscl . -read /Groups/admin GroupMembership | grep -w "$user") 50 | allUsersArray+=("username: $user, uuid: $uuid, isAdmin: $admin") 51 | done <<< "$results" 52 | echo "" 53 | printf '%s\n' "${allUsersArray[@]}" 54 | } 55 | 56 | getZshHistory() { 57 | echo "" 58 | users=( $(ls /Users | grep -v '^_') ) 59 | for user in "${users[@]}"; do 60 | path="/Users/$user/.zsh_history" 61 | if [ -f "$path" ]; then 62 | zsh_commands=$(<"$path") 63 | echo "User: $user" 64 | echo "ZSH commands:" 65 | echo "$zsh_commands" 66 | echo "------------------" 67 | fi 68 | done 69 | } 70 | 71 | getBashHistory() { 72 | echo "" 73 | users=( $(ls /Users | grep -v '^_') ) 74 | for user in "${users[@]}"; do 75 | path="/Users/$user/.bash_history" 76 | if [ -f "$path" ]; then 77 | bash_commands=$(<"$path") 78 | echo "User: $user" 79 | echo "Bash commands:" 80 | echo "$bash_commands" 81 | echo "------------------" 82 | fi 83 | done 84 | } 85 | 86 | getShellStartupScripts() { 87 | echo "" 88 | # users=( $(dscl . -list /Users UniqueID | awk '$2 >= 500 { print $1 }') ) 89 | users=( $(ls /Users | grep -v '^_') ) 90 | files=(".bash_profile" ".bashrc" ".profile") 91 | shell_startup_scripts=() 92 | for user in "${users[@]}"; do 93 | for f in "${files[@]}"; do 94 | if [[ -f "/Users/$user/$f" ]]; then 95 | contents=$(cat "/Users/$user/$f") 96 | echo "User: $user" 97 | echo "Shell_startup_filename: $f" 98 | echo "Shell_startup_data:" 99 | echo "$contents" 100 | echo "---------------------------" 101 | fi 102 | done 103 | done 104 | } 105 | 106 | getPeriodic(){ 107 | dirs=("/etc/periodic/daily" "/etc/periodic/weekly" "/etc/periodic/monthly") 108 | daily=() 109 | weekly=() 110 | monthly=() 111 | for i in "${dirs[@]}"; do 112 | files=($(ls "$i")) 113 | if [[ "$i" == "/etc/periodic/daily" ]]; then 114 | daily+=( "${files[@]}" ) 115 | elif [[ "$i" == "/etc/periodic/weekly" ]]; then 116 | weekly+=( "${files[@]}" ) 117 | elif [[ "$i" == "/etc/periodic/monthly" ]]; then 118 | monthly+=( "${files[@]}" ) 119 | fi 120 | done 121 | 122 | periodic_scripts=( 123 | "daily: ${daily[*]}" 124 | "weekly: ${weekly[*]}" 125 | "monthly: ${monthly[*]}" 126 | ) 127 | 128 | echo "" 129 | printf "%s\n" "${periodic_scripts[@]}" 130 | } 131 | 132 | getPfRules(){ 133 | pfrule="/etc/pf.conf" 134 | if [ ! -f "$pfrule" ]; then 135 | echo "Error: /etc/pf.conf not found" 136 | exit 1 137 | fi 138 | contents=$(cat "$pfrule") 139 | echo "" 140 | echo "$contents" 141 | } 142 | 143 | getSIPStatus() { 144 | output=$(csrutil status) 145 | status=$(echo "$output" | grep "System Integrity Protection status" | cut -d ':' -f2 | tr -d '.' | tr -d ' ') 146 | echo "status: $status" 147 | } 148 | 149 | getGateKeeperStatus(){ 150 | gatekeeper_status=$(/usr/sbin/spctl --status) 151 | echo "$gatekeeper_status" 152 | } 153 | 154 | getCronJobs(){ 155 | echo "" 156 | users=( $(ls /Users | grep -v '^_') ) 157 | for user in "${users[@]}"; do 158 | crontab=$(crontab -u "$i" -l) 159 | echo "User: $user" 160 | echo "Crontab: $crontab" 161 | echo "-----------------" 162 | done 163 | } 164 | 165 | getListApps(){ 166 | echo "" 167 | app_path="/Applications/" 168 | apps=$(ls "${app_path}") 169 | for app in $apps; do 170 | app_full_path="${app_path}${app}" 171 | echo "${app_full_path}" 172 | done 173 | } 174 | 175 | getInstallHistory(){ 176 | echo "" 177 | if [ -f "/Library/Receipts/InstallHistory.plist" ]; then 178 | cat "/Library/Receipts/InstallHistory.plist" 179 | fi 180 | } 181 | 182 | getChromeExtensions(){ 183 | users=( $(ls /Users | grep -v '^_') ) 184 | for user in "${users[@]}"; do 185 | base_path="/Users/${user}/Library/Application Support/Google/Chrome/Default/Extensions/" 186 | extensions=$(ls "${base_path}") 187 | if [ $? -eq 0 ]; then 188 | for ext in $extensions; do 189 | full_ext="${base_path}${ext}" 190 | files=$(ls "${full_ext}") 191 | for file in $files; do 192 | if [[ $file == "manifest.json" ]]; then 193 | manifest=$(cat "${full_ext}/${file}") 194 | echo "Extension path: ${full_ext}" 195 | echo "Extension manifest.json content:" 196 | echo "${manifest}" 197 | echo "----------------------" 198 | fi 199 | done 200 | done 201 | fi 202 | done 203 | } 204 | 205 | getActiveNetworkConnections(){ 206 | echo "" 207 | echo "ProcessName ProcessID User FD IPvProtocol UniqueIdentifier TCP/UDP LocalEndpoint RemoteEndpoint" 208 | lsof -i -w | grep "ESTABLISHED" 209 | } 210 | 211 | getLaunchDaemons(){ 212 | launchdaemons=( $(ls /Library/LaunchDaemons/ | grep 'plist') ) 213 | echo "" 214 | for daemon in "${launchdaemons[@]}"; do 215 | echo "LaunchDaemon name: $daemon" 216 | cat $daemon 217 | done 218 | } 219 | 220 | getKernelExtensions(){ 221 | echo "" 222 | if [ -d "/Library/Extensions/" ]; then 223 | for i in /Library/Extensions/*/; do 224 | if [ -f "${i}Contents/Info.plist" ]; then 225 | info_plist_data=$(cat "${i}Contents/Info.plist") 226 | echo "${i}" 227 | echo "$info_plist_data" 228 | echo "--------------------------------" 229 | fi 230 | done 231 | fi 232 | } 233 | 234 | # Run the functions 235 | echo "[+] System info: $(getSystemInfo)" 236 | echo "*****************************************************" 237 | echo "[+] Users list: $(getSystemUsers)" 238 | echo "*****************************************************" 239 | echo "[+] Environment variables: $(getEnv)" 240 | echo "*****************************************************" 241 | echo "[+] Process list: $(getProcessList)" 242 | echo "*****************************************************" 243 | echo "[+] Active network connections: $(getActiveNetworkConnections)" 244 | echo "*****************************************************" 245 | echo "[+] SIP $(getSIPStatus)" 246 | echo "*****************************************************" 247 | echo "[+] GateKeeper $(getGateKeeperStatus)" 248 | echo "*****************************************************" 249 | echo "[+] Zsh history: $(getZshHistory)" 250 | echo "*****************************************************" 251 | echo "[+] Bash history: $(getBashHistory)" 252 | echo "*****************************************************" 253 | echo "[+] Shell startup: $(getShellStartupScripts)" 254 | echo "*****************************************************" 255 | echo "[+] PF rules: $(getPfRules)" 256 | echo "*****************************************************" 257 | echo "[+] Periodic scripts: $(getPeriodic)" 258 | echo "*****************************************************" 259 | echo "[+] CronJobs list: $(getCronJobs)" 260 | echo "*****************************************************" 261 | echo "[+] LaunchDaemons list: $(getLaunchDaemons)" 262 | echo "*****************************************************" 263 | echo "[+] Kernel extensions: $(getKernelExtensions)" 264 | echo "*****************************************************" 265 | echo "[+] Installed applications: $(getListApps)" 266 | echo "*****************************************************" 267 | echo "[+] Installation history: $(getInstallHistory)" 268 | echo "*****************************************************" 269 | echo "[+] Chrome extensions: $(getChromeExtensions)" 270 | echo "*****************************************************" 271 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MacOS ThreatTrack 2 | 3 | > The tool is being tested in the beta phase, and it only gathers MacOS system information at this time. 4 | 5 | > The code is poorly organized and requires significant improvements. 6 | 7 | ## Description 8 | 9 | Bash tool used for proactive detection of malicious activity on macOS systems. 10 | 11 | I was inspired by [Venator-Swift](https://github.com/richiercyrus/Venator-Swift) and decided to create a bash version of the tool. 12 | 13 | ## OneLiner command 14 | 15 | ```bash 16 | curl https://raw.githubusercontent.com/ab2pentest/MacOSThreatTrack/main/MacOSThreatTrack.sh | bash 17 | ``` 18 | 19 | ## Gathered information 20 | 21 | ``` 22 | [+] System info 23 | [+] Users list 24 | [+] Environment variables 25 | [+] Process list 26 | [+] Active network connections 27 | [+] SIP status 28 | [+] GateKeeper status 29 | [+] Zsh history 30 | [+] Bash history 31 | [+] Shell startup scripts 32 | [+] PF rules 33 | [+] Periodic scripts 34 | [+] CronJobs list 35 | [+] LaunchDaemons data 36 | [+] Kernel extensions 37 | [+] Installed applications 38 | [+] Installation history 39 | [+] Chrome extensions 40 | ``` 41 | 42 | ## Todo 43 | 44 | 1) Saving output as JSON instead of printing out the result. 45 | --------------------------------------------------------------------------------