TUCoPS :: Windows Apps :: sb5966.htm

Preventing buffer exploits discussion
4th Feb 2003 [SBWID-5966]
COMMAND

	Preventing buffer exploits discussion

SYSTEMS AFFECTED

	Windows platforms

PROBLEM

	- see below -

SOLUTION

	David Litchfield [david@ngssoftware.com] suggests :
	
	 http://www.ngssoftware.com/
	
	
	 Defeating Exploits
	 ******************
	
	The ideas in this "paper" present a method for defeating  exploits;  not
	the actual vulnerability. Before getting to the details  let's  consider
	slammer (again).
	
	What made  slammer  so  successful?  The  overriding  factor  that  made
	slammer so successful was it's ability to spread. What made it's  spread
	a  foregone  conclusion  was  the  fact  that   every   vulnerable   SQL
	Server/MSDE had a "jmp esp" instruction at address 0x42B0C9DC. This  was
	the address that was used to gain control of the SQL  Server's  path  of
	execution to a point where the worm's  payload,  the  "arbitrary  code",
	would be executed.
	
	This address is in a dynamic link library (DLL) , sqlsort.dll which  has
	an "image base" of 0x42AE0000.
	
	Every image file, DLL or executable, has an "Image Base" and  this  base
	is the preferred location where the file should be  loaded  into  memory
	by the Windows Loader. [I don't  want  to  digress,  here,  as  to  what
	happens if there's a conflict. See the references at the  end.]  Now  if
	this Image Base on one particular system had been  0x42AF0000  then  the
	worm would have failed to infect this  particular  box;  the  "jmp  esp"
	instruction that should've been at 0x42B0C9DC on this  system  would  be
	found at 0x42B1C9DC so the worm would have  been  off  target.  The  SQL
	Server running on this system, whilst still being  "vulnerable"  to  the
	buffer overflow vulnerability  would  have  been  invulnerable  to  this
	worm. Sure - the SQL Server may have crashed - but  it  would  not  have
	been compromised.
	
	It's like sickle cell. Someone born with the  gene  that  causes  sickle
	cell anaemia, a blood disorder  that  affects  many  people  of  a  West
	African origin, or carriers of the  gene,  sickle  cell  trait,  do  not
	suffer from the ill affects of malaria, a disease caused by  a  parasite
	and most commonly spread by mosquitoes. Whilst someone with sickle  cell
	trait can still catch malaria,  the  gene  mutates  the  haemoglobin  in
	their  blood  in  such  a  way  that  they  are  invulnerable   to   the
	debilitating side effects and syptoms of  the  disease  such  as  mental
	confusion, coma and death. There is an  obvious  evolutionary  advantage
	to sickle cell trait; remember that the evolution of the  species  cares
	not about how long a person lives, only that they live  long  enough  to
	pass on their  genes.  (Those  with  anaemia  may  suffer  from  crises,
	periods of acute pain so the trade off is somewhat questionable.)
	
	In areas where malaria is a common cause of death, being  a  carrier  of
	the sick cell gene can help ensure that this person  lives  long  enough
	to have progeny. This is Darwinian natural selection in progress.
	
	 Rebasing
	 ********
	
	The problem with operating systems is that they  all  have  pretty  much
	the same  "genetic  code"  which  makes  each  and  every  one  of  them
	vulnerable to a new exploit. So we need to make them different and  this
	can be achieved through rebasing. Rebasing is the  process  of  changing
	the Image Base of an image file. By doing this  the  DLL/EXE  is  loaded
	into a different location in the virtual address space.
	
	Going back to Slammer, had I have rebased sqlsort.dll giving  it  a  new
	base of 0x41410000 my box would have been invulnerable to the  worm.  If
	another worm were written, though, that used an address  that  contained
	a "jmp esp" instruction in kernel32.dll then I would be  vulnerable.  So
	I rebase kernel32.dll. But then another  worm  uses  another  DLL  so  I
	rebase that one, too. Eventually I've rebased all of the  DLLs  used  by
	SQL  Server  mutating  it's  "genetic  code",  making  it   considerably
	different to any other SQL Server install on the planet. In  fact  if  I
	rebase every DLL on my system and every executable then I  can  make  my
	box almost invulnerable to a given exploit,  past,  present  or  future.
	It's not that my box is invulnerable to a buffer overflow  vulnerability
	- it's just invulnerable to the exploits for it. To gain  control  of  a
	system protected in such a way would require  that  the  author  of  the
	exploit know the location of loaded DLLs.
	
	So how easy is it to rebase DLLs and executables? Very.  Microsoft  have
	provided  a  function   to   do   this,   ReBaseImage(),   exported   by
	imagehlp.dll. If you rebase an image the new  base  must  be  on  a  64K
	boundary - i.e. if the image base mod 64000 !=0 the base is not valid.
	
	The only other problem is Windows File Protection. Once  you've  rebased
	a copy of the DLL you need to copy the new DLL  over  the  old  one  but
	Windows File Protection won't allow you to do this. To  get  around  the
	problem     use     the     MoveFileEx      and      specifying      the
	MOVEFILE_DELAY_UNTIL_REBOOT flag. Doing this will add a registry  value,
	"PendingFileRenameOperations"                                         to
	HKLM\System\CurrentControlSet\Control\Session Manager\.  You  then  need
	to add another DWORD value "AllowProtectedRenames"  and  set  it  to  1.
	Then restart the system. On reboot the new DLLs, with  their  new  image
	bases, will be loaded. For example - here is sample output  of  listdlls
	after kernel32.dll and ws2_32.dll have been rebased.
	
	
	Copyright (C) 1997-2000 Mark Russinovich
	http://www.sysinternals.com
	
	----------------------------------------------------------------------------
	--
	WINLOGON.EXE pid: 208
	Command line: winlogon.exe
	
	  Base        Size      Version         Path
	  0x01000000  0x2e000                   \??\C:\WINNT\system32\winlogon.exe
	  0x77f80000  0x7b000   5.00.2195.5400  C:\WINNT\System32\ntdll.dll
	  0x78000000  0x46000   6.01.9359.0000  C:\WINNT\system32\MSVCRT.dll
	  0x4a4a0000  0xb1000   5.00.2195.6011  C:\WINNT\system32\KERNEL32.dll
	  0x77db0000  0x5b000   5.00.2195.5992  C:\WINNT\system32\ADVAPI32.dll
	  0x77d30000  0x71000   5.00.2195.5419  C:\WINNT\system32\RPCRT4.dll
	  0x54530000  0x13000   5.00.2195.4874  C:\WINNT\system32\WS2_32.dll
	..
	..
	
	Now all the way through  this  I've  been  saying  things  like  "almost
	invulnerable" etc. Here's the reason. For some  vulnerabilities  it  may
	be sufficient to overwrite a saved return address, function  pointer  or
	whatever by only a few bytes. For example assume a saved return  address
	is 0x44784500 and at address 0x44784536 is a "jmp ebx"  instruction  and
	ebx points to our code. Then we only need to overwrite the saved  return
	address by 1 byte - with 0x36. So knowledge of the DLL load  address  is
	not needed. However, this scenario is going to  happen  so  infrequently
	(if ever) that it does not  detract  from  the  idea  of  rebasing  your
	system. There may other ways to bypass this method.
	
	Some ideas to further help prevent exploits from working.
	
	Use addresses such as 0x**000000 or 0x00**0000 for the new  image  base.
	With there being a NULL in much of the image's address space  this  will
	help. (This of course won't make a difference with unicode overflows)
	
	Ensure at least one (core) DLL has a base  of  0x00119400  .  This  will
	ensure that  a  common  stack  location  0x00120000  has  been  assigned
	forcing the OS to chose another location for  the  stack.  You  get  the
	idea.
	
	MSDN Info ReBaseImage()
	 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/rebaseimage.asp
	
	MoveFileEx()
	 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/movefileex.asp
	
	
	 Update (05 Februrary 2003)
	 ======
	
	Thomas [dullien@gmx.de] comments :
	
	--snip--
	
	Rebasing everything is something you're  not  very  likely  to  achieve.
	Hardly any commercial  software  has  executables  which  still  contain
	valid relocation information -- which means  that  you  can  rebase  all
	DLL's as much as you want, the main  EXE  (which  is  always  mapped  at
	0x00400000 and cannot be remapped) will be present  &  can  be  used
	for exploitation. Unless you  rebase  the  complete  address  space  you
	remain vulnerable. Furthermore, rebasing might  not  be  sufficient,  as
	there's
	
	less than 32k different bases -- if the service restarts  cleanly  brute
	force is definitely an option. So you need full randomization.
	
	Heap corruptions allow an attacker to write arbitrary data to  arbitrary
	locations -- so he can patch his own "jmp ebx" or whatever to  whereever
	he   wishes.   Unless   you    implement    something    PaX-like    for
	writable/executable pages, you're still vulnerable. And the majority  of
	all buffer overruns _are_ heap corruptions.
	
	Oh, and there's always the static mapping of the TEB's under Windows.
	
	So the solution you're proposing
	
	   a) Will only work against a small subset of all
	      closed-source-applications (those with relocatable main .exe)
	
	   b) Will even then only protect you against vanilla stack smashes, and offer 0
	
	      protection against heap corruptions or format string bugs
	
	   c) Will be suspectible to brute-force attacks on your address space
	      (which cannot be more complex than 2^15 ... hardly a "hard"
	      task)
	
	-Also-
	
	Someone points out :
	
	There is a tool called "ReBase"  shipped  with  Visual  C++  and  Visual
	C++.NET.
	
	 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tools/perfutil_2z39.asp
	
	" Rebase is a command-line tool that you can use  to  specify  the  base
	addresses for the DLLs that your application uses. "
	
	" Alternatively, you can use the ReBaseImage function. "
	
	 Update (06 February 2003)
	 ======
	
	Riley Hassell [rhassell@eeye.com], Security Research Associate  of  eEye
	Digital Security argues :
	
	So the course of this  talk  with  most  likely  go  into  generating  a
	totally  dynamic  address  space  and  once  again,   end   in   another
	theoretical solution, to an overly complex problem.
	
	Defeating Rebasing
	-------------------------------------
	
	Many  operating  systems  with  fault  handling  features  and   refined
	multitasking, reference address spaces with  segments  to  permit  these
	features and aid general performance. The majority of this behavior  can
	be studied by following process creation and task switching. Start  from
	the user API and step through until the entry point  of  the  executable
	is reached.
	
	TEB: Thread Environment Block
	TIB: Thread Information Block
	PEB: Process Environment Block
	
	The TEB/TIB fs:[] segment references originated  in  the  OS2  days  and
	have since passed down into 9x client systems, and  of  course,  Windows
	NT. During the process creation the PEB and  TIB  are  initialized  into
	the new virt and can be referenced by  the  fs  segment.  Modifying  the
	address space referenced by fs and how fs is setup  is  possible...  but
	by the time you're done you're designing a new operating system.
	
	As Ryan might say... It's all data ;) The data referenced in this  delta
	can be referenced during a ret. You just need to find  a  set  of  bytes
	that forms the needed instruction. You may be able to modify this  arena
	in a way that you can insert your own instructions. Maybe  some  of  the
	TLS storage can be controlled  by  supplying  malformed  sizes  in  your
	exploit session... ;)
	
	Note: PEB locking pointers can  be  overwritten  with  format  bugs  and
	control structure based heap overflows.
	
	7FFDF000  00010000
	7FFDF004  FFFFFFFF
	7FFDF008  01000000  <- Executable image base ;)
	7FFDF00C  00071E90
	7FFDF010  00020000
	7FFDF014  00000000
	7FFDF018  00070000
	7FFDF01C  77FCF170  <- PEB fast Lock entry point
	7FFDF020  77F8313C  <- PEB lock entry point
	7FFDF024  77F8316D  <- PEB unlock entry point
	
	Brett Moore wrote me several months ago with a very interesting  exploit
	concept using multiple writes. The first write you  insert  your  needed
	instruction into  writeable  memory  somewhere.  The  second  write  you
	overwrite some writeable entry point or hook, with the  address  of  the
	inserted instruction.
	
	There's not much out there if you're interested in  learning  about  the
	TIB and the PEB. If you really want to understand these  structures  and
	general loading behavior, learn Polish and Russian,  then  hit  up  some
	VX'er archives. If you end up talking to any of  them,  tell  them  that
	somebody is trying to stop exploits by rebasing dll's :)
	
	Rebasing... There's a reason why relocation sections exist. While  doing
	your own relocations is  possible,  the  design  of  such  a  system  is
	extremely, and I'll say again, extremely complex.  Just  differentiating
	all the instructions from data is a fairly painful  process.  Maybe  the
	ETCH guys did this at one point but as far as I know  this  has  been  a
	big hurdle in image modifcation for quite some time.
	
	Michal Zalewski provided some  great  examples  of  issue's  you'll  run
	into:
	
	MZ> Also, what if I wanted to pass a value 4325404 (0x42001c) to this
	MZ> function, and it is not a pointer, only looks this way? For example,some
	MZ> FOO_ASYNC flag is defined as 0x400000, FOO_LOCK as 0x020000, and
	voila,OR
	MZ> them and you have "a pointer".
	MZ> In other cases, say, with register calls, it is getting even nastier,
	MZ> because even if, one way or another, you managed to find out how every
	MZ> single function is going to use its parameters (not likely), register
	MZ> calls are still black magic.
	
	GetProcAddress ACL's...
	
	>
	> It is possible to intercept every call to GetProcAddress and determine
	> whether or not the call should be authorized based on a predetermined list
	> of known valid callers (runtime call stack analysis).
	
	Simply rewrite a micro GetProcAddress. GetProcAddress  is  basically  an
	overstuffed RVA engine. This is defeated  by  "The  payload  brings  the
	tools concept".  Most  userland  hooking  schemes  can  also  easily  be
	bypassed by using direct gates "Ex: Interupts  Gates".  You  could  also
	intercept a thread that has the neccesary privelege by snagging  a  hook
	in it's path.
	
	> This list of authorized callers must be constructed through the use of
	forensic profiling
	> tools in the case of other people's binaries, but can be constructed with
	> the help of additional API calls in the case of one's own code. Call a
	> profiling/tracing API before calling GetProcAddress. After compilation but
	> before deployment to production boxes you simply execute the code in
	profile
	> mode to generate a list of authorized callers. This list is then
	configured
	> as a static security setting adhered to by the security layer that sits
	> between GetProcAddress and the rest of the virtual world.
	
	Who's an authorized caller?
	
	Someone who has a "safe" caller address on the stack....
	
	If a the attacker start's offering  instructions  to  your  CPU...  kiss
	your ass goodbye. Research AV/VX trends from the  late  80's  and  early
	90's.
	
	 Update (08 Februrary 2003)
	 ======
	
	Alex Fedotov proposed the following PEB/TEB data structures :
	
	 http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&q=_NT_TEB&btnG=Google+Search
	
	
	typedef struct _CURDIR
	{
	   UNICODE_STRING DosPath;
	   PVOID Handle;
	} CURDIR, *PCURDIR;
	
	typedef struct RTL_DRIVE_LETTER_CURDIR
	{
	   USHORT Flags;
	   USHORT Length;
	   ULONG TimeStamp;
	   UNICODE_STRING DosPath;
	} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
	
	typedef struct _PEB_FREE_BLOCK
	{
	   struct _PEB_FREE_BLOCK* Next;
	   ULONG Size;
	} PEB_FREE_BLOCK, *PPEB_FREE_BLOCK;
	
	/* RTL_USER_PROCESS_PARAMETERS.Flags */
	#define PPF_NORMALIZED (1)
	
	typedef struct _RTL_USER_PROCESS_PARAMETERS
	{
	   ULONG  MaximumLength;  //  00h
	   ULONG  Length;   //  04h
	   ULONG  Flags;   //  08h
	   ULONG  DebugFlags;  //  0Ch
	   PVOID  ConsoleHandle;  //  10h
	   ULONG  ConsoleFlags;  //  14h
	   HANDLE  InputHandle;  //  18h
	   HANDLE  OutputHandle;  //  1Ch
	   HANDLE  ErrorHandle;  //  20h
	   CURDIR  CurrentDirectory; //  24h
	   UNICODE_STRING DllPath;  //  30h
	   UNICODE_STRING ImagePathName;  //  38h
	   UNICODE_STRING CommandLine;  //  40h
	   PWSTR  Environment;  //  48h
	   ULONG  StartingX;  //  4Ch
	   ULONG  StartingY;  //  50h
	   ULONG  CountX;   //  54h
	   ULONG  CountY;   //  58h
	   ULONG  CountCharsX;  //  5Ch
	   ULONG  CountCharsY;  //  60h
	   ULONG  FillAttribute;  //  64h
	   ULONG  WindowFlags;  //  68h
	   ULONG  ShowWindowFlags; //  6Ch
	   UNICODE_STRING WindowTitle;  //  70h
	   UNICODE_STRING DesktopInfo;  //  78h
	   UNICODE_STRING ShellInfo;  //  80h
	   UNICODE_STRING RuntimeInfo;  //  88h
	   RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; // 90h
	} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
	
	#define PEB_BASE        (0x7FFDF000)
	
	typedef struct _PEB_LDR_DATA
	{
	   ULONG Length;
	   BOOLEAN Initialized;
	   PVOID SsHandle;
	   LIST_ENTRY InLoadOrderModuleList;
	   LIST_ENTRY InMemoryOrderModuleList;
	   LIST_ENTRY InInitializationOrderModuleList;
	} PEB_LDR_DATA, *PPEB_LDR_DATA;
	
	typedef VOID STDCALL (*PPEBLOCKROUTINE)(PVOID);
	
	typedef struct _PEB
	{
	   UCHAR InheritedAddressSpace;                     // 00h
	   UCHAR ReadImageFileExecOptions;                  // 01h
	   UCHAR BeingDebugged;                             // 02h
	   UCHAR Spare;                                     // 03h
	   PVOID Mutant;                                    // 04h
	   PVOID ImageBaseAddress;                          // 08h
	   PPEB_LDR_DATA Ldr;                               // 0Ch
	   PRTL_USER_PROCESS_PARAMETERS ProcessParameters;  // 10h
	   PVOID SubSystemData;                             // 14h
	   PVOID ProcessHeap;                               // 18h
	   PVOID FastPebLock;                               // 1Ch
	   PPEBLOCKROUTINE FastPebLockRoutine;              // 20h
	   PPEBLOCKROUTINE FastPebUnlockRoutine;            // 24h
	   ULONG EnvironmentUpdateCount;                    // 28h
	   PVOID* KernelCallbackTable;                      // 2Ch
	   PVOID EventLogSection;                           // 30h
	   PVOID EventLog;                                  // 34h
	   PPEB_FREE_BLOCK FreeList;                        // 38h
	   ULONG TlsExpansionCounter;                       // 3Ch
	   PVOID TlsBitmap;                                 // 40h
	   ULONG TlsBitmapBits[0x2];                        // 44h
	   PVOID ReadOnlySharedMemoryBase;                  // 4Ch
	   PVOID ReadOnlySharedMemoryHeap;                  // 50h
	   PVOID* ReadOnlyStaticServerData;                 // 54h
	   PVOID AnsiCodePageData;                          // 58h
	   PVOID OemCodePageData;                           // 5Ch
	   PVOID UnicodeCaseTableData;                      // 60h
	   ULONG NumberOfProcessors;                        // 64h
	   ULONG NtGlobalFlag;                              // 68h
	   UCHAR Spare2[0x4];                               // 6Ch
	   LARGE_INTEGER CriticalSectionTimeout;            // 70h
	   ULONG HeapSegmentReserve;                        // 78h
	   ULONG HeapSegmentCommit;                         // 7Ch
	   ULONG HeapDeCommitTotalFreeThreshold;            // 80h
	   ULONG HeapDeCommitFreeBlockThreshold;            // 84h
	   ULONG NumberOfHeaps;                             // 88h
	   ULONG MaximumNumberOfHeaps;                      // 8Ch
	   PVOID** ProcessHeaps;                            // 90h
	   PVOID GdiSharedHandleTable;                      // 94h
	   PVOID ProcessStarterHelper;                      // 98h
	   PVOID GdiDCAttributeList;                        // 9Ch
	   PVOID LoaderLock;                                // A0h
	   ULONG OSMajorVersion;                            // A4h
	   ULONG OSMinorVersion;                            // A8h
	   ULONG OSBuildNumber;                             // ACh
	   ULONG OSPlatformId;                              // B0h
	   ULONG ImageSubSystem;                            // B4h
	   ULONG ImageSubSystemMajorVersion;                // B8h
	   ULONG ImageSubSystemMinorVersion;                // C0h
	   ULONG GdiHandleBuffer[0x22];                     // C4h
	
	   PVOID ProcessWindowStation;                      // ???
	} PEB, *PPEB;
	
	typedef struct _GDI_TEB_BATCH
	{
	   ULONG Offset;
	   ULONG HDC;
	   ULONG Buffer[0x136];
	} GDI_TEB_BATCH, *PGDI_TEB_BATCH;
	
	typedef struct _NT_TEB
	{
	   NT_TIB Tib;                         // 00h
	   PVOID EnvironmentPointer;           // 1Ch
	   CLIENT_ID Cid;                      // 20h
	   PVOID ActiveRpcInfo;                // 28h
	   PVOID ThreadLocalStoragePointer;    // 2Ch
	   PPEB Peb;                           // 30h
	   ULONG LastErrorValue;               // 34h
	   ULONG CountOfOwnedCriticalSections; // 38h
	   PVOID CsrClientThread;              // 3Ch
	   PVOID Win32ThreadInfo;              // 40h
	   ULONG Win32ClientInfo[0x1F];        // 44h
	   PVOID WOW32Reserved;                // C0h
	   ULONG CurrentLocale;                // C4h
	   ULONG FpSoftwareStatusRegister;     // C8h
	   PVOID SystemReserved1[0x36];        // CCh
	   PVOID Spare1;                       // 1A4h
	   LONG ExceptionCode;                 // 1A8h
	   ULONG SpareBytes1[0x28];            // 1ACh
	   PVOID SystemReserved2[0xA];         // 1D4h
	   GDI_TEB_BATCH GdiTebBatch;          // 1FCh
	   ULONG gdiRgn;                       // 6DCh
	   ULONG gdiPen;                       // 6E0h
	   ULONG gdiBrush;                     // 6E4h
	   CLIENT_ID RealClientId;             // 6E8h
	   PVOID GdiCachedProcessHandle;       // 6F0h
	   ULONG GdiClientPID;                 // 6F4h
	   ULONG GdiClientTID;                 // 6F8h
	   PVOID GdiThreadLocaleInfo;          // 6FCh
	   PVOID UserReserved[5];              // 700h
	   PVOID glDispatchTable[0x118];       // 714h
	   ULONG glReserved1[0x1A];            // B74h
	   PVOID glReserved2;                  // BDCh
	   PVOID glSectionInfo;                // BE0h
	   PVOID glSection;                    // BE4h
	   PVOID glTable;                      // BE8h
	   PVOID glCurrentRC;                  // BECh
	   PVOID glContext;                    // BF0h
	   NTSTATUS LastStatusValue;           // BF4h
	   UNICODE_STRING StaticUnicodeString; // BF8h
	   WCHAR StaticUnicodeBuffer[0x105];   // C00h
	   PVOID DeallocationStack;            // E0Ch
	   PVOID TlsSlots[0x40];               // E10h
	   LIST_ENTRY TlsLinks;                // F10h
	   PVOID Vdm;                          // F18h
	   PVOID ReservedForNtRpc;             // F1Ch
	   PVOID DbgSsReserved[0x2];           // F20h
	   ULONG HardErrorDisabled;            // F28h
	   PVOID Instrumentation[0x10];        // F2Ch
	   PVOID WinSockData;                  // F6Ch
	   ULONG GdiBatchCount;                // F70h
	   ULONG Spare2;                       // F74h
	   ULONG Spare3;                       // F78h
	   ULONG Spare4;                       // F7Ch
	   PVOID ReservedForOle;               // F80h
	   ULONG WaitingOnLoaderLock;          // F84h
	
	   PVOID StackCommit;                  // F88h
	   PVOID StackCommitMax;               // F8Ch
	   PVOID StackReserve;                 // F90h
	
	   PVOID MessageQueue;                 // ???
	} NT_TEB, *PNT_TEB;
	
	
	 Update (11 Februrary 2003)
	 ======
	
	In Peter Huang whitepaper of compiler security optimization :
	
	 http://members.rogers.com/yinrong/articles/Prevent.htm
	
	For the past few days, I have done a few experiments and  some  research
	on ways to prevent the  buffer  overflow  exploitation.  I  believe  the
	following compiler option (if implemented  and  used)  should  make  the
	exploitation of stack buffer overflow by  "jmp  esp"  method  impossible
	(as far as I know) to execute a piece of malicious code on  Intel-Inside
	PC. The buffer vulnerability, if exists, still overflows to  be  trapped
	by this mechanism if being pumped too much.
	
	For a function like:
	
	Void testVoid (void)
	{
		do something here and the stack overflows such as sprintf in ssnetlib.dll
	in SQL 2000 server (pre-SP3)
	}
	
	The compiler inserts the following opcodes before "ret".
	
	Mov	ecx, [esp]
	Cmp	word ptr [ecx], 0FFE4h	; check for "jmp esp"
	Jnz	realRet
	Mov	byte ptr [esp+4], 0cch	; stack has been overflowed and function
	; will breakpoint (no need to go on anyway)
	RealRet:
		ret
	
	For a function like:
	
	Void testParametered(int I, int i2, int i3 ...)
	{
		do something here and the stack overflows such as sprintf in ssnetlib.dll
	in SQL 2000 server (pre-SP3)
	}
	
	The compiler inserts the following opcode before "ret"
	
		Mov	byte ptr[esp+4], 0cch	; if return address is not overwritten,
		                            ; then this will be discarded by opcode such
	as
		                            ; "add esp, xx" down the execution path.
		                            ; Otherwise, the exploitation code injected
	onto the stack,
		                            ; which happens before this move, will
		                            ; cause a breakpoint trap to happen due to the
		                            ; "jmp esp" method exploited by the buffer
	overflow.
		Ret
	
	Normally, both above functions continue normally. However, if the  stack
	is overflowed due to some software bugs under exploitation attack,  then
	the mechanism  listed  above  will  generate  breakpoint  trap  and  the
	execution of malicious code is stopped.
	
	Unfortunately, it will definitely increase  the  executable  image  size
	and some runtime hit (should not be much because of the cache lines  are
	still valid etc.).  Some  might  think  that  this  creates  some  false
	illusion of security. However, it does dam  the  overflow  to  what  has
	been overflowed and prevent the overflow from spreading so  that  we  do
	not have to hear others say:" dam it".

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH