Python Penetration Testing: Extracting Contact Information from Outlook

R. Eric Kiser
System Weakness
Published in
4 min readMar 14, 2023

--

R. Eric Kiser

Imagine you’re conducting a penetration test and you come across users who never log out of their devices or power them down, leaving them exposed to after-hours attacks and lateral movement exploitation. These users can be prime targets for attackers looking to gain access to sensitive information and resources within the organization. As a penetration tester, it’s your job to identify and exploit vulnerabilities in the organization’s security posture. One highly effective way to do this is by gathering comprehensive information about the organization’s users, which is often a requirement for clients.

To obtain this information, you can leverage the organization’s email system using Python and Outlook to extract valuable details like email addresses and phone numbers. This approach not only helps you compile a detailed list of users but also facilitates lateral movement within the organization. If you really want to take things to the next level, you can also retrieve information about users’ access to files and folders but this is another article for another day. In this article, I will show you how to use Python to extract user data from Outlook.

To access Outlook contacts through Python, you would need to use the pywin32 package on the host, which provides access to the Outlook API. Be sure the pywin32 package is installed ( pip install pywin32 ) in your terminal. Now we can import the needed modules

import win32com.client

We can use the current session that the user has running by getting the MAPI namespace object.

# Connect to the running instance of Outlook
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")

We want to extract the default Contacts folder and the Address Book, then gather the book entries. The address book will have more contact information as it is connected to the gal (global address list) in AD (Active Directory).

# Get the default Contacts folder
contacts_folder = outlook.GetDefaultFolder(10)

# Get the address book folder
address_book_folder = outlook.GetDefaultFolder(11)

# Get the address book entries
address_book = address_book_folder.Items

We need to create a for loop that iterates through each contact in the default Contacts folder. We then want the script to do the following:

  1. Check if the contact has a full name. If it does, assign the full name to the full_name variable. Otherwise, skip the current contact using continue. It may be useful to grab these. However, often they are not user accounts.
  2. Check if the contact has an email address. If it does, assign the email address to the email_address variable. Otherwise, assign the string 'N/A' to email_address.
  3. Check if the contact has a business phone number. If it does, assign the phone number to the phone_number variable. Otherwise, assign the string 'N/A' to phone_number.
  4. Check if the contact has a department. If it does, it assign the department to the department variable. Otherwise, assign the string 'N/A' to department.
# Loop through the items in the Contacts folder and extract the desired information
for contact in contacts_folder.Items:

# Check if the contact has a full name
if hasattr(contact, 'FullName'):
full_name = contact.FullName
else:
continue # Skip this contact if full name is not available

# Extract the email address
if hasattr(contact, 'Email1Address'):
email_address = contact.Email1Address
else:
email_address = 'N/A'

# Check if the contact has a phone number
if hasattr(contact, 'BusinessTelephoneNumber'):
phone_number = contact.BusinessTelephoneNumber
else:
phone_number = 'N/A'

# Check if the contact has a department
if hasattr(contact, 'Department'):
department = contact.Department
else:
department = 'N/A'

Now we need to print these details to the screen.

    # Print the contact information to the screen
print(f"Name: {full_name}")
print(f"Email: {email_address}")
print(f"Phone: {phone_number}")
print(f"Department: {department}")
print('-' * 20)

The for loop for the address book entries does the same thing as the first loop, but it iterates through the address book entries instead of the contacts in the default Contacts folder.

# Loop through the address book entries and extract the desired information
for entry in address_book:
# Check if the entry is a contact
if entry.AddressEntryUserType == 0:
# Get the contact object
contact = entry.GetContact()

# Check if the contact has a full name
if hasattr(contact, 'FullName'):
full_name = contact.FullName
else:
continue # Skip this contact if full name is not available

# Extract the email address
if hasattr(contact, 'Email1Address'):
email_address = contact.Email1Address
else:
email_address = 'N/A'

# Check if the contact has a phone number
if hasattr(contact, 'BusinessTelephoneNumber'):
phone_number = contact.BusinessTelephoneNumber
else:
phone_number = 'N/A'

# Check if the contact has a department
if hasattr(contact, 'Department'):
department = contact.Department
else:
department = 'N/A'

# Print the contact information to the screen
print(f"Name: {full_name}")
print(f"Email: {email_address}")
print(f"Phone: {phone_number}")
print(f"Department: {department}")
print('-' * 20)

So, that’s how you can retrieve contact information from both the default Contacts folder and the Address Book folder. Once extracted, the information can be printed to the console or redirected to a txt file, which is what I usually do since the information can be quite extensive. Clap and follow if you like and Happy Hunting!

Conclusion

You can download the script on my GitHub. Clap and follow if you like and Happy Hunting!

--

--

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