Overwrite the SEH overflow exploit detection ideas-vulnerability warning-the black bar safety net

ID MYHACK58:62200716733
Type myhack58
Reporter 佚名
Modified 2007-08-30T00:00:00


See Security focus on a review of the stack-based fingerprint detecting a buffer overflow of some ideas, which is in the ShellCode is already running in its call stack(is Hook the sub calls the function LoadLibrary)is detected, some use an overflow overwriting the SEH Handler, and then any programs run, because the overflow destroys the heap or stack, it will certainly appear abnormal, then point to the ShellCode Handler is run, I think this kind of overflow use, since it wants to run, look first to theoperating systemsexception sending this off, if the Assign exception when we are on the SEH Handler conduct some testing, maybe in the ShellCode to run before they found it.

I simply looked at the SEH handling process, always talk to these two functions, because the wrk code is not full, so I selected ReactOS code, but does not affect understanding.

The following code from ReactOS, the copyright belongs to the original author

VOID NTAPI KiUserExceptionDispatcher(PEXCEPTION_RECORD ExceptionRecord, PCONTEXT Context) { EXCEPTION_RECORD NestedExceptionRecord; NTSTATUS Status;

/ call the vectored exception handlers / if(RtlpExecuteVectoredExceptionHandlers(ExceptionRecord, Context) != ExceptionContinueExecution) {//VEH??? ReactOS also is too strong, to achieve a XP VEH, compatible with a high degree of! goto ContinueExecution; } else { / Dispatch the exception and check the result / if(RtlDispatchException(ExceptionRecord, Context)) { ContinueExecution: / Continue executing / Status = NtContinue(Context, FALSE); } else { / Raise an exception / Status = NtRaiseException(ExceptionRecord, Context, FALSE); } }

/ Setup the Exception record / NestedExceptionRecord. ExceptionCode = Status; NestedExceptionRecord. ExceptionFlags = EXCEPTION_NONCONTINUABLE; NestedExceptionRecord. ExceptionRecord = ExceptionRecord; NestedExceptionRecord. NumberParameters = Status;

/ Raise the exception / RtlRaiseException(&NestedExceptionRecord); }

BOOLEAN NTAPI RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT Context) { PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, NestedFrame = NULL; DISPATCHER_CONTEXT DispatcherContext; EXCEPTION_RECORD ExceptionRecord2; EXCEPTION_DISPOSITION Disposition; ULONG_PTR StackLow, StackHigh; ULONG_PTR RegistrationFrameEnd;

/ Get the current stack limits and registration frame / RtlpGetStackLimits(&StackLow, &StackHigh); RegistrationFrame = RtlpGetExceptionList();

/ Now loop every frame / while (RegistrationFrame != EXCEPTION_CHAIN_END) { / Find out where it ends / RegistrationFrameEnd = (ULONG_PTR)RegistrationFrame + sizeof(EXCEPTION_REGISTRATION_RECORD);

/ Make sure the registration frame is located within the stack / if ((RegistrationFrameEnd > StackHigh) || ((ULONG_PTR)RegistrationFrame < StackLow) || ((ULONG_PTR)RegistrationFrame & 0x3)) { / Check if this happened in the DPC Stack / if (RtlpHandleDpcStackException(RegistrationFrame, RegistrationFrameEnd, &StackLow, &StackHigh)) { / Use DPC Stack Limits and restart / continue; }

/ Set invalid stack and return false / ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID; return FALSE; }

/ Check if logging is enabled / RtlpCheckLogException(ExceptionRecord, Context, RegistrationFrame, sizeof(*RegistrationFrame));

/ Call the handler / Disposition = RtlpExecuteHandlerForException(ExceptionRecord, RegistrationFrame, Context, &DispatcherContext, RegistrationFrame-> Handler);

/ Check if this is a nested frame / if (RegistrationFrame == NestedFrame) { / Mask out the flag and the nested frame / ExceptionRecord->ExceptionFlags &= ~EXCEPTION_NESTED_CALL; NestedFrame = NULL; }

/ Handle the dispositions / switch (Disposition) { / Continue searching / case ExceptionContinueExecution:

/ Check if it was non-continuable / if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) { / Set up the exception record / ExceptionRecord2. ExceptionRecord = ExceptionRecord; ExceptionRecord2. ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION; ExceptionRecord2. ExceptionFlags = EXCEPTION_NONCONTINUABLE; ExceptionRecord2. NumberParameters = 0;

/ Raise the exception / RtlRaiseException(&ExceptionRecord2); } else { / Return to caller / return TRUE; }

/ Continue searching / case ExceptionContinueSearch: break;

/ Nested exception / case ExceptionNestedException:

/ Turn the nested flag on / ExceptionRecord->ExceptionFlags |= EXCEPTION_NESTED_CALL;

/ Update the current nested frame / if (DispatcherContext. RegistrationPointer > NestedFrame) { / Get the frame from the dispatcher context / NestedFrame = DispatcherContext. RegistrationPointer; } break;

/ Anything else / default:

/ Set up the exception record / ExceptionRecord2. ExceptionRecord = ExceptionRecord; ExceptionRecord2. ExceptionCode = STATUS_INVALID_DISPOSITION; ExceptionRecord2. ExceptionFlags = EXCEPTION_NONCONTINUABLE; ExceptionRecord2. NumberParameters = 0;

/ Raise the exception / RtlRaiseException(&ExceptionRecord2); break; }

/ Go to the next frame / RegistrationFrame = RegistrationFrame->Next; }

/ Unhandled, return false / return FALSE; }

Then we may be in need of protection process Hook KiUserExceptionDispatcher, where the surface detection Handler is safe, I can think of might not be too safe Handler there are four cases, maybe there are more, I just simply implement the first strategy(that is, the traverse a bit of SEH chain), below is the relevant code fragment.


inline DWORD fastcall GetFsDword(DWORD dwOffset) { asm mov eax,DWORD PTR fs:[ecx] }

//Policy: //1. Handler in the stack area //2. Handler in the stack area //3. Handler in the global data area //4. Handler in the normal code page, but the first instruction is jmp xxx, or Handler of the previous paragraph does not affect the ShellCode instructions, the latter with a jmp xxx jump to the Handler, how to detect it?

BOOL AnyUnsafeHandler(void) { struct SEHChain{ SEHChain pNext; void pHandler; };

SEHChain pChain=(SEHChain)GetFsDword(0); DWORD dwStackBase=GetFsDword(4); DWORD dwStackLimit=GetFsDword(8);


do { bRet=((DWORD)(pChain->pHandler)>=dwStackLimit)&&((DWORD)(pChain->pHandler)<=dwStackBase); pChain=pChain->pNext; }while(! bRet&&(pChain!= (SEHChain*)-1));

return bRet; }

VOID WINAPI HookedUserExceptionDispatcher(PEXCEPTION_RECORD ExceptionRecord, PCONTEXT Context) { if(AnyUnsafeHandler()) { ExitThread(0); }

TrampolineUserExceptionDispatcher(ExceptionRecord,Context); }

Detected in the non-secure Handler when and why should I use ExitThread?, because based on the TIB of the Seh Chain is thread-related, it is not the Final type of the SEH Handler(don't understand the reference to Hume warrior in the classic article<<SEH in ASM>>), so the direct use of ExitThread may appear dangerous thread to back off, if it is the main thread then the process will exit, if required, at the same time record what the log for the administrator to analyze the attack situation.