Application Verifier - Tests within Application Verifier
Basics
At a minimum, you should run Application Verifier with the Basics setting selected. Each of these will test for an area that will cause crashes or other negative scenarios, that have a direct and signifcant impact of the customer experience.
- Exceptions - Ensures that applications do not hide access violations using structured exception handling
- Handles - Tests to ensure the application is not attempting to use invalid handles
- Heaps - Checks for memory corruptions issues in the heap
- Leak - Detects leaks by tracking the resources made by a dll that are not freed by the time the dll was unloaded
- Locks - Verifies the correct usage for critical sections
- Memory - Ensures APIs for virtual space manipulations are used correctly (for example, VirtualAlloc, MapViewOfFile)
- SRWLock - verifies the correct usage for slim reader/writer (SRW) locks.
- Threadpool - Ensures correct usage of threadpool APIs and enforces consistency checks on worker-thread-states after a callback such as dirty threadpool threads and other threadpool-related issues.
- TLS - Ensures that Thread Local Storage APIs are used correctly
For information on the stop code exceptions generated by these tests, see Application Verifier - Stop Codes and Definitions. For information on debugging these failures, see Application Verifier - Debugging Application Verifier Stops
Compatibility
Compatibility Verification Layer tests help to identify an application that may have problems with Microsoft Windows operating system. Many of these checks can also be used to test for the logo/certification requirements.
For information on the stop code exceptions generated by these tests, see Application Verifier - Stop Codes and Definitions.
HighVersionLie — Identifies problems for some of the most common application compatibility issues in Windows. Improperly detecting the version of the operating system or using hard-coded version information can cause the application to fail on later operating systems.
Cuzz
The Concurrency Fuzzing (Cuzz) verification layer detects concurrency bugs and data race conditions. Cuzz adjusts thread scheduling by injecting random delays at key points in an application's code. The following scenario illustrates the type of concurrency bug that could be detected by the Cuzz verification layer.
An application has a parent thread and a child thread. The parent thread starts the child thread and then allocates memory for a structure.
// Parent Thread
StartChildThread(...);
g_pointer = ... malloc(...);
The child thread dereferences the pointer.
//Child Thread
LONG value = g_pointer->someMember;
The preceding code has a concurrency bug. If the child thread attempts to dereference the pointer before the parent thread allocates the memory, the pointer will be invalid. The bug is very unlikely to manifest itself, because in most cases, the parent thread will allocate the memory before the child thread gets started. But in rare cases, the child thread could get started and attempt to dereference the pointer before the parent thread has allocated the memory.
The Cuzz verification layer increases the likelihood of finding concurrency bugs like the one illustrated in the preceding example. Cuzz does not perform any additional checks apart from inserting delays. As such, there are no verification stops directly associated with Cuzz. However, if enabling Cuzz results in a concurrency bug manifesting itself, other verification layers will benefit. For instance, if a race condition results in a heap overflow, the Heaps verification layer will not find the error unless the race condition manifests itself at run time. By increasing the probability of the race condition occurring, Cuzz improves the effectiveness of the Heaps layer in identifying the error.
To get the maximum benefit of Cuzz, enable Cuzz on as many tests as possible, and repeat the same test many times. Cuzz can be enabled on all tests, including manual tests, functional tests, and stress tests. Also, enable as many Application Verifier verification layers as possible.
You can increase the probability of reproducing a bug by providing Cuzz with the same random seed (see Properties).
Cuzz inserts delays only on Win32 synchronization API calls.
Cuzz Properties
The following properties are available for the Cuzz verification layer. To set the properties, select the Cuzz layer in the Application Verifier user interface, and open the Property Window.
Property | Description |
---|---|
FuzzingLevel | Controls the fuzzing level for Cuzz. Set this to 1 for time-critical applications and 4 for regular applications. |
RandomSeed | The random seed used by Cuzz at start. If you set this to 0, Cuzz generates a time-based random seed. |
Low Resource Simulation
Low resource simulation tries to simulate an environment under low resources, such as out of memory. This simulation will identify bugs that occur in low memory conditions. This is also referred to as Fault Injection. You can simulate an environment under low resources, whereby you can define a number (0–100) that indicates the fault probability calls of:
- Wait (for example. the WaitForXXXX API).
- Heap_Alloc (Heap Allocation API).
- Virtual_Alloc (Virtual Memory allocation API).
- Registry (Registry API).
- File (File API such as CreateFile).
- Event (Event API such as CreateEvent).
- MapView ( MapView API such as CreateMapView).
- Ole_Alloc (Ole API such as SysAllocString).
Low resource simulation (also known as fault injection) tries to simulate an environment under low resources, for example out of memory. This will identify bug within low memory conditions.
Low Resource Simulation Properties
To edit the properties, check the Low Resource Simulation check box in the Tests area, right click, and select properties:
Property | Description |
---|---|
Include | Limit faults happens only in the specified dlls. One dll name without path per row. If '*' is specified, faults will happen for all the modules. |
Exclude | Exclude faults for the specified modules. One dll name without path per row. |
Timeout | Give a time slot (in millisecond) when there is no fault at process initialization. |
Wait | A number [0 – 1000000] that indicates the fault probability for the WaitForXXXX API. |
Heap_Alloc | A number [0 – 1000000] that indicates the fault probability for the Heap Allocation API. |
Virtual_Alloc | A number [0 – 1000000] that indicates the fault probability for the Virtual Memory allocation API. |
Registry | A number [0 – 1000000] that indicates the fault probability for the Registry API. |
File | A number [0 – 1000000] that indicates the fault probability for the File API such as CreateFile. |
Event | A number [0 – 1000000] that indicates the fault probability for the Event API such as CreateEvent |
MapView | A number [0 – 1000000] that indicates the fault probability for the MapView API such as CreateMapView. |
Ole_Alloc | A number [0 – 1000000] that indicates the fault probability for the Ole API such as SysAllocString. |
Stacks | Each Windows application thread starts with a stack reserve and a stack commit size. Under normal usage, the stack commit grows whenever there is need for more space on the stack. See Creating Threads and Thread Stack Size for more information. If the system is experiencing low memory conditions, the stack commit growth might fail. The thread that fails to grow its stack and the whole application will most likely crash. That kind of crash is unacceptable for important system processes (e.g. for services). The Stacks check will disable any the stack growth for the application that is being verified so it will simulate the stack growth failures without the need to simulate the whole system low memory conditions. Exceptions will be thrown when the application tries to expand the stack. No verifier stops are generated by this. |
LuaPriv
Limited User Account Privilege Predictor (LuaPriv) tests are both Predictive and diagnostic and work to surface issues related to running an application with administrative privilege, and whether that application would work as well if run with less privilege (generally, as a normal user).
Also known as UAC checks, the Limited User Account Privilege Predictor (LuaPriv) has two primary goals:
Predictive: While running an application with administrative privilege, predict whether that application would work as well if run with less privilege (generally, as a normal user). For example, if the application writes to files that only allow Administrators access, then that application will not be able to write to the same file if run as a non-administrator.
Diagnostic: While running with non-administrator privilege, identify potential problems that may already exist with the current run. Continuing the previous example, if the application tries to write to a file that grants only Administrator group members access, the application will get an ACCESS_DENIED error. If the application does not operate correctly, this operation may be the culprit.
LuaPriv identifies the following types of problems:
Potential Issue | Description |
---|---|
Restricted Namespaces | Creating a named synchronization object (Event, Semaphore, Mutex, etc) without a namespace may complicate running without privilege on some operating systems because the operating system may choose to place the object in a restricted namespace. Creating such an object in a restricted namespace (such as the Global namespace) requires SeCreateGlobalPrivilege, which is granted only to administrators. LuaPriv flags both these issues if it detects them. |
Hard Administrator Checks | Some applications interrogate the user's security token to find out how much privilege he/she has. In those cases, the application may change its behavior depending on how much power it thinks the user has. LuaPriv flags API calls that return this information. |
Requesting Privileges | An application may attempt to enable a security-relevant privilege (such as SeTcbPrivilege or SeSecurityPrivilege) prior to performing an operation that requires it. LuaPriv flags attempts to enable security-relevant privileges. |
Missing Privileges | If an application attempts to enable a privilege that the user does not have, it probably signals that the application expects the privilege, which can cause behavior differences. LuaPriv flags failed privilege requests. |
INI-File Operations | Attempts to write to mapped INI files (WritePrivateProfileSection and similar APIs) can fail as a non-administrator user. LuaPriv flags such operations. |
Access Denied | If the application attempts to access an object (File, registry key, etc) but the attempt fails due to insufficient access, then the application probably expects to be running with more privilege than it has. LuaPriv flags object-open attempts that fail with ACCESS_DENIED and similar errors. |
Deny ACEs | If an object has Deny ACEs in its DACL, then it explicitly denies access to specific entities. This is uncommon, and makes prediction difficult, so LuaPriv flags Deny ACEs when it finds them. |
Access Restricted | If an application attempts to open an object for rights that are not granted to normal users (for example, trying to write to a file that is only writeable by administrators), then the application probably will not work the same when run as a normal user. LuaPriv flags such operations. |
MAXIMUM_ALLOWED | If an application opens an object for MAXIMUM_ALLOWED, then the actual access check on the object will occur elsewhere. Most code that does this does not work correctly, and will almost certainly work differently when run without privilege. LuaPriv thus flags all incidents of MAXIMUM_ALLOWED. |
Miscellaneous
Commonly overlooked issues are captured in the Miscellaneous tests.
- Dangerous APIs — Tracks to see if the application is using the following unsafe actions:
- Dangerous call to TerminateThread.
- Potential stack overflow in low memory conditions.
- Exit process called while multiple threads are still running.
- LoadLibrary is called during DllMain.
- FreeLibrary is called during DllMain.
- Dirty Stacks fills (periodically) the unused portion of the stack with a memory pattern. This can help detect uninitialized variables in future function calls in that thread's context.
- TimeRollOver forces the GetTickCount and TimeGetTime APIs to roll over faster than they normally would. This allows applications to test their handling of time rollover more easily.
Miscellaneous Properties
Dangerous APIs check has one property that can be altered:
DllMainCheck - Check LoadLibrary/FreeLibrary calling when DllMain is active.
Networking
The networking tests look for improper use of WinSock APIs. For example, if a Networking API called before a successful WSAStartup() or after a balancing successful WSACleanup() call was made. For more information about WinSock, see winsock.h header and Windows Sockets 2.
Properties
The following properties are available for the Net verification layer. To set the properties, select the Networking provider in the Application Verifier user interface, and open the Property Window.
Property | Description |
---|---|
FragmentsEnabled | Enables the fragmenting of data streams received by TCP IPv4 and IPv6 sockets. |
FragmentSize | Specifies the maximum number of bytes returned into a buffer to any Winsock receive API call. |
The FragmentsEnabled property enables functionality in the Networking verifier provider to facilitate testing and verification of an application parsing TCP streams off of a network. Once enabled, all calls to Winsock to receive data will only receive up to FragmentSize bytes unless the application specifically requires the entire buffer filled before returning (controlled by the MSG_WAITALL flag). Since neither the TCP protocol nor Winsock provide any guarantees about the number of bytes possibly returned into a buffer, enabling this check will facilitate verifying that the code parsing the stream of data off of the network does so correctly, independently of the number of bytes received per call to Winsock. Issues in stream parsers have been a source of high-profile bugs, and these properties are provided to ease verification of correctness, as this is particularly difficult to test. Note: This does not change the data returned – it only slows it down at a specific rate: the application should behave exactly same fashion with this enabled or disabled.
The following command line enables the fragmentation of all incoming TCP streams to all TCP IPv4 and IPv6 sockets created in myApp.exe and all binaries loaded by myApp.exe.
appverif -enable Networking -for myApp.exe -with Networking.FragmentsEnabled=True Networking.FragmentSize=10
!avrf Debugger Extension
!avrf -net -socket count
- displays open and closed socket handle count
!avrf -net -socket dump [-v] [HANDLE]
- displays socket handle(s), verbosely or not.
!avrf -net -wsastacks
- displays the current WSA init count and chronological list of stack traces for WSAStartup/WSACleanup.
!avrf -net -wsastacks count
- displays the current WSA init count.
!avrf -net -socket count
- This command will give the overall number of socket handles that are being tracked, both opened and closed. Note that these are tracked in a circular queue, so there is a ceiling to the total being tracked. Sockets are added to the opened list when one of the Winsock APIs which allocates a socket handle is called. For example, socket(), WSASocket(), accept(). Sockets are moved from the opened list to the closed list when the closesocket() function is called on that socket handle.
!avrf -net -socket dump [-v] [HANDLE]
- This command will enumerate the socket handles. "-socket dump" will list all tracked opened and closed socket handles by their SOCKET values. The optional -v flag will additionally print the open or close call stack immediately after printing each SOCKET value. The optional HANDLE field will list only the specified SOCKET handle and its open or close call stack.
Here are example of the various -socket usage options:
0:008> !avrf -net -socket count
Number of open socket handles = 16
Number of closed socket handles = 12
0:008> !avrf -net -socket dump
CLOSED SOCKET HANDLE - 0x47c
CLOSED SOCKET HANDLE - 0x2cc
CLOSED SOCKET HANDLE - 0x8c4
CLOSED SOCKET HANDLE - 0x6bc
CLOSED SOCKET HANDLE - 0x44c
CLOSED SOCKET HANDLE - 0x578
CLOSED SOCKET HANDLE - 0x6f4
CLOSED SOCKET HANDLE - 0x5b4
CLOSED SOCKET HANDLE - 0x4d8
CLOSED SOCKET HANDLE - 0x3cc
CLOSED SOCKET HANDLE - 0x4fc
CLOSED SOCKET HANDLE - 0x4e0
OPEN SOCKET HANDLE - 0xfd4
OPEN SOCKET HANDLE - 0x7d8
OPEN SOCKET HANDLE - 0xf8c
OPEN SOCKET HANDLE - 0xf88
OPEN SOCKET HANDLE - 0xae0
OPEN SOCKET HANDLE - 0xe58
OPEN SOCKET HANDLE - 0xdfc
OPEN SOCKET HANDLE - 0xcf8
OPEN SOCKET HANDLE - 0xa18
OPEN SOCKET HANDLE - 0x7a0
OPEN SOCKET HANDLE - 0x7b0
OPEN SOCKET HANDLE - 0x534
OPEN SOCKET HANDLE - 0xcdc
OPEN SOCKET HANDLE - 0x1f0
OPEN SOCKET HANDLE - 0x444
OPEN SOCKET HANDLE - 0x8bc
0:008> !avrf -net -socket dump -v 0x47c
The socket handle is closed
vfNet!VfHookclosesocket
WININET!ICSocket::_UnSafeCloseSocket
WININET!ICSocket::Dereference
WININET!CFsm_GetConnection::RunSM
WININET!CFsm::Run
WININET!DoFsm
WININET!HTTP_REQUEST_HANDLE_OBJECT::OpenConnection_Fsm
WININET!CFsm_OpenConnection::RunSM
WININET!CFsm::Run
WININET!DoFsm
WININET!HTTP_REQUEST_HANDLE_OBJECT::OpenConnection
WININET!HTTP_REQUEST_HANDLE_OBJECT::MakeConnection_Fsm
WININET!CFsm_MakeConnection::RunSM
WININET!CFsm::Run
WININET!DoFsm
WININET!HTTP_REQUEST_HANDLE_OBJECT::SendRequest_Fsm
WININET!CFsm_SendRequest::RunSM
WININET!CFsm::Run
WININET!DoFsm
WININET!HTTP_REQUEST_HANDLE_OBJECT::HttpSendRequest_Start
WININET!CFsm_HttpSendRequest::RunSM
WININET!CFsm::Run
WININET!CFsm::RunWorkItem
SHLWAPI!ExecuteWorkItemThreadProc
vfbasics!AVrfpRtlWorkerCallback
ntdll!RtlpTpWorkCallback
ntdll!TppWorkerThread
kernel32!BaseThreadInitThunk
ntdll!__RtlUserThreadStart
ntdll!_RtlUserThreadStart
!avrf -net -wsastacks [count]
Winsock requires application developers to call the WSAStartup() at least once before making any Winsock calls. This is tracked by Winsock process-wide. The initial reference count instructs a Winsock library (ws2_32.dll) to initialize and load the Winsock catalog and providers. Further calls to WSAStartup increments that reference count. Winsock also requires application developers to call WSACleanup() when they have 'finished'calling into Winsock. The calls to WSACleanup must be paired correctly with a prior call to WSAStartup(). The call to WSACleanup() decrements the process-wide reference count. When the reference count falls to zero, Winsock releases its resources and unloads the Winsock catalog and providers.
This command will give the overall reference count value of the current "WSAStartup" initialization routine and lists the call stacks to calls to WSAStartup and WSACleanup made within the process. Note that this is maintained within a fixed circular queue, so it is not guaranteed to be complete - only the N most recent calls.
Here are example of the various -wsastacks usage options:
0:008> !avrf -net -wsastacks count
Current WSARefCount: 1 (WSAStartup call count minus WSACleanup call count for the target process)
0:008> !avrf -net -wsastacks
Current WSARefCount: 1 (WSAStartup call count minus WSACleanup call count for the target process)
THREAD ID: 0xe4c called WSAStartup
vfNet!WSAInitStacks<NetAllocatorViaPrivateHeap>::AddWSAStackTrace
vfNet!VfHookWSAStartup
WININET!LoadWinsock
WININET!GlobalDataInitialize
WININET!InternetSetOptionA
WININET!InternetSetOptionW
IEFRAME!LCIEUpdateSessionStartTime
IEFRAME!LCIETab_ThreadProc
iertutil!_IsoThreadProc
vfbasics!AVrfpStandardThreadFunction
kernel32!BaseThreadInitThunk
ntdll!__RtlUserThreadStart
ntdll!_RtlUserThreadStart
NTLM
This Application Verifier plug-in monitors an individual process’ calls to the authentication APIs AcquireCredentialsHandle and InitializeSecurityContext in order to detect uses of the NTLM protocol. The NTLM is an outdated authentication protocol with flaws that potentially compromise the security of applications and the operating system and should not be used.
NTLM Authentication Risk
The most important shortcoming outdated NTLM authentication protocol is the lack of server authentication, which could allow an attacker to trick users into connecting to a spoofed server. As a corollary of missing server authentication, applications using NTLM can also be vulnerable to a type of attack known as a “reflection” attack. This latter allows an attacker to hijack a user’s authentication conversation to a legitimate server and use it to authenticate the attacker to the user’s computer. NTLM’s vulnerabilities and ways of exploiting them are the target of increasing research activity in the security community.
Although Kerberos has been available for many years, many applications are still written to use NTLM only. This needlessly reduces the security of applications. Kerberos cannot however replace NTLM in all scenarios – principally those where a client needs to authenticate to systems that are not joined to a domain (a home network perhaps being the most common of these). The Negotiate security package allows a backwards-compatible compromise that uses Kerberos whenever possible and only reverts to NTLM when there is no other option. Switching code to use Negotiate instead of NTLM will significantly increase the security for our customers while introducing few or no application compatibilities. Negotiate by itself is not a silver bullet – there are cases where an attacker can force downgrade to NTLM but these are significantly more difficult to exploit. However, one immediate improvement is that applications written to use Negotiate correctly are automatically immune to NTLM reflection attacks.
By way of a final word of caution against use of NTLM: In Windows it is possible to disable the use of NTLM at the operating system level. If applications have a hard dependency on NTLM they will simply fail to authenticate when NTLM is disabled.
What factors cause NTLM to be “hard-coded” in an application?
There are two factors that will cause a hard dependency on NTLM. The first is explicitly selecting NTLM as the authentication package to be used by the application. For some protocols and APIs the choice of NTLM is obvious, such as in the call to the API AcquireCredentialsHandle (). For other protocols, it may not be so obvious. For example, RPC’s default authentication package (RPC_C_AUTHN_DEFAULT) is actually an alias to NTLM when RPC is used over the network and even the explicit flag to select NTLM doesn’t have the NTLM abbreviation anywhere in it (RPC_C_AUTH_WINNT). This kind of construct makes it easier to select NTLM without necessarily knowing you have done so.
In place of NTLM, developers should use, other authentication methods, for example the Negotiate package (this is also sometimes referred to as the SPNEGO or SNEGO package). Package selection needs to match on both client and server components in order for Negotiate to be able to attempt to use Kerberos - so both client and server parts of the application need to use Negotiate. If either side uses NTLM (as might be the case with legacy versions) Negotiate will still work but will always revert to NTLM. How to tell your application to use Negotiate varies by protocol. Some of the most common protocols (RPC, LDAP, DCOM, HTTP) are covered in detail later in topic 5000 – Application Has Explicitly Selected NTLM Package.
The second factor that results in NTLM being used is when the client does not supply a valid server target name to the authentication process. In protocols that support or require mutual authentication (such as Kerberos) the target name is what is used to achieve mutual authentication. Authentication APIs (such as InitializeSecurityContext ) take an optional parameter, usually called something like “TargetName”, “PrincipalName” or “ServerPrincipalName”. This is the identifier used by domain controllers to select the correct domain account for obtaining credentials for the target service. Since NTLM has no concept of server authentication this parameter is not required for NTLM to successfully authenticate. Kerberos, on the other hand, requires that a client obtains a service ticket that is valid for the service that the client is authenticating to. Kerberos authentication will always fail if no target name or an invalid target name is specified. When Negotiate is selected as the package, supplying no target name (or an invalid target name) will cause Kerberos to be skipped altogether and NTLM to be used. Most authentication APIs have the target name as an optional parameter will accept if NULL without error. Unless the developer overrides this and provides an explicit target name, NTLM, (and moreover, reflectable NTLM) is the result.
How the NTLM Plug-in Works
The Verifier plug detects the following errors:
The NTLM package is directly specified in the call to AcquireCredentialsHandle (or higher level wrapper API).
The target name in the call to InitializeSecurityContext is NULL. In this case, Negotiate falls back to NTLM directly.
The target name in the call to InitializeSecurityContext is not a properly-formed SPN, UPN or NetBIOS-style domain name. In this case, the domain controller returns a “principal not found” error, which causes Negotiate to fall back to NTLM.
The plug-in also logs warnings when it detects downgrades to NTLM; for example, when an SPN is not found by the Domain Controller. These are only logged as warnings since they are often legitimate cases – for example, when authenticating to a system that is not domain-joined.
Configuring Plug-in Stop Options
By default all events categorized as Error are set to cause a debug break. All warning events are set to log the event details only.
Error Events cause a Stop/Break:
5000 – Application Has Explicitly Selected NTLM Package
5001 – Negotiate Package List Includes only NTLM
5002 – Negotiate Package List Wrong NTLM Exclusion
5003 – No target name or malformed target name for Server
Warning Events logged:
- 5010 – Downgrade to NTLM Detected
NTLM Stops
5000 – Application Has Explicitly Selected NTLM Package
Severity – Error
The application or subsystem explicitly selects NTLM instead of Negotiate in the call to AcquireCredentialsHandle. Even though it may be possible for the client and server to authenticate using Kerberos this is prevented by the explicit selection of NTLM.
How to Fix this Error
The fix for this error is to select the Negotiate package in place of NTLM. How this is done will depend on the particular Network subsystem being used by the client or server. Some examples are given below. You should consult the documentation on the particular library or API set that you are using.
APIs(parameter) Used by Application | Incorrect Value | Correct Value | Notes |
---|---|---|---|
AcquireCredentialsHandle (pszPackage) | “NTLM” | NEGOSSP_NAME or “Negotiate” | |
RPC Client: RPCBindingSetAuthInfoEx RPCBindingSetAuthInfoEx (AuthnSv) RPC Server: RPCServerRegisterAuthInfo(AuthnSvc) | RPC_C_AUTHN_WINNT or RPC_C_AUTH_DEFAULT | RPC_C_AUTH_GSS_NEGOTIATE | It is not an error for an RPC server to register the NTLM/WINNT package. This is often required to support older clients that only support NTLM. It is an error if only the NTLM package is registered since this forces all clients to use NTLM even if they are capable of using Kerberos. |
DCOM: SetBlanket CoSetProxyBlanket (dwAuthnSvc) CoCreateInstanceEx (passed as dwAuthnSvc member of COAUTHINFO structure, which itself is a member of the COSERVERINFO struct passed to the API) | RPC_C_AUTHN_WINNT | RPC_C_AUTHN_DEFAULT or RPC_C_AUTHN_GSS_NEGOTIATE | Negotiate should only be used if the communication always occurs across a network. If the DCOM call ever occurs between client and server on the same machine you must use DEFAULT and allow DCOM to choose the correct package to use. |
LDAP: ldap_bind_s (method) | LDAP_AUTH_NTLM | LDAP_AUTH_NEGOTIATE | |
HTTP WinHTTPSetCredentials (AuthScheme) | WINHTTP_AUTH_SCHEME_NTLM | WINHTTP_AUTH_SCHEME_NEGOTIATE |
5001 – Negotiate Package List Includes only NTLM
Severity – Error
When using AcquireCredentialsHandle it is possible to supply a list of packages to be used or ignored by Negotiate. Depending on the list specified, this may override the logic built into Negotiate for choosing the most appropriate and secure authentication package. If the package list includes only NTLM or excludes Kerberos the result is identical to bypassing Negotiate altogether and explicitly selecting the NTLM SSP package directly.
Specifying a sub-package list is only possible when calling AcquireCredentialsHandle directly since most higher-layer APIs (such as RPC) do not allow the caller to control the Negotiate package list.
Microsoft does not recommend that applications try to manipulate the Negotiate package list in this way.
How to Fix this Error
Use the Negotiate package without specifying a list of subpackages or ensure that Kerberos is included.
APIs(parameter) Used by Application | Incorrect Value | Correct Value |
---|---|---|
AcquireCredentialsHandle (PackageList member of SEC_WINNT_AUTH_IDENTITY_EX struct passed as pAuthData parameter) | “!Kerberos” or “NTLM” | NULL or “Kerberos, NTLM” or “Kerberos, !NTLM” or “!NTLM” |
5002 – Negotiate Package List Wrong NTLM Exclusion
Severity - Warning
When calling AcquireCredentialsHandle the application has attempted to exclude NTLM from the list of packages supported by Negotiate. However, the wrong syntax has been used to exclude NTLM, so it remains in the list.
How to Fix this Error Use the following syntax to exclude the NTLM package from Negotiate:
APIs(parameter) Used by Application | Incorrect Value | Correct Value |
---|---|---|
AcquireCredentialsHandle (PackageList member of SEC_WINNT_AUTH_IDENTITY_EX struct passed as pAuthData parameter) | “-NTLM” | “!NTLM” |
5003 – No target name or malformed target name for Server
Severity – Error
When using the Negotiate package, supplying a null or invalid target name (sometimes referred to as principal name) will cause Kerberos to fail and NTLM to be used in its place. You should always specify a valid target name when making an authentication call. The target name is a unique identifier that allows a domain controller to obtain the account details of the server that your application is trying to authenticate to. Once the domain controller has this information it can build appropriate Kerberos tickets that will be understood (decryptable) by both the client and the server.
How to Fix this Error
Target names can be specified in three different formats, each of which is can be used by domain controllers to locate the correct server account object. These formats are Service Principal Name (SPN), User Principal Name (UPN) and NetBIOS two-part domain\account name. The SPN is the most common form and the most interoperable with other Kerberos implementations. A full discussion of SPNs is beyond the scope of this document but the simplest and most common SPN form has two parts – a service class and a host name. The service class identifies the type of server application (e.g. specific application type like http or ldap or as generic as host).The second part is either the fully qualified domain name or flat (NetBIOS) name of the server. Windows clients and servers automatically register SPNs for “host” for the FQDN and flat names. Domain controllers will also map around 40 application-specific service classes on to the “host” SPN for things like “http”, “ldap”, “rpc”, “tapi”, etc.
o specify a target name for an application running in the context of the server operating system (e.g. localsystem, network service or localservice) client applications can use the automatically-registered “host” SPN or one of its aliases. To authenticate to an application running in the context of a domain user account you must register an SPN for that account.
For user accounts you can also use the implicit UPN form that built from the user account name and the domain that the account resides in: useraccountname@domain.dom. Although you can create additional UPNs for user account (using the UPN suffixes that can be created for each domain) these will not work as Kerberos targetnames – only the UPN corresponding to the actual logon account name and actual domain where the account lives can be used.
Finally you can still use the NT4-style domain\username (or domain\computername in the case of services running as localsystem, networkservice or localservice). This works for targets that are running in the context of domain user account or computer accounts.
APIs(parameter) Used by Application | Parameter to set target name | Notes |
---|---|---|
InitializeSecurityContext | pszTargetName | |
RPC Client: RPCBindingSetAuthInfoEx RPCBindingSetAuthInfoEx (AuthnSv) | ServerPrincipalName | This should be the target name for the account under which the server/service is running. It does not have to be the same as the value set in RPCServerRegisterAuthInfo |
DCOM: SetBlanket CoSetProxyBlanket (dwAuthnSvc) CoCreateInstanceEx (passed as dwAuthnSvc member of COAUTHINFO structure, which itself is a member of the COSERVERINFO struct passed to the API) | pServerPrincName | Can use COLE_DEFAULT_PRINCIPAL to let COM automatically select name from binding information |
LDAP: none | Automatically generated by LDAP client. | |
HTTP none | WinHTTP and WinInet supply the targetname from the URL server name |
5010 – Downgrade to NTLM Detected
Severity - Warning
Even though the application specific Negotiate and used a correctly-formatted target name something occurred to cause Negotiate to downgrade to NTLM. Depending on what the circumstances were this may indicate an error or expected behavior. For example, when a computer is not part of a domain or is being used in a location where a domain controller is not accessible it is expected that Negotiate will silently downgrade to allow the application to authenticate using NTLM. However, if this stop occurs when a domain controller is available and you would normally expect Kerberos to be used it almost certainly indicates that something is wrong.
How to Fix This Error
Assuming that you have determined that Kerberos should have been used and not NTLM in this circumstance, there are a number of possibilities why the downgrade took place:
• The target name, even though it may have been in the correct format, did not exist in the domain (or forest).
o You should check that you are building the correct target name in the client application. Is the service class correct? Is the host name correct?
o Is the server process running in the context of the computer or another domain account. In the former case SPNs are automatically registered, in the latter case you may have to register the SPN or use an alternative form such as an implicit UPN or a flat name.
o Might there be network connectivity problems preventing communication with a domain controller or DNS server?
o Is the target SPN registered on more than one account? This will cause the domain controller to reject authentication attempts to it.
Printing
The Print Verifier helps find and troubleshoot issues that may result when an application calls the print subsystem. Print Verifier targets the two layers of the print subsystem, the PrintAPI layer and the PrintDriver layer.
Print API Layer
Print Verifier tests the interface between a program and Winspool.drv and prntvpt.dll and tests the interfaces of those DLLs. You can review the rules for calling functions in this interface in the MSDN help section for APIs exported by winspool.drv and prntvpt.dll.
Print Driver Layer
Print Verifier also tests the interface between a core print driver such as UNIDRV.DLL, UNIDRUI.DLL, PSCRIPT5.DLL, PS5UI.DLL, or MXDWDRV.DLL, and the print driver plug-ins. You can find information about this interface in the MSDN and the WDK.
Typically, only debug versions run the Application Verifier, so performance is not generally an issue. If performance issues arise from the use of this, or any other Application Verifier check, run one check at a time until you have performed all needed checks.
WebServices
Windows Webservices API (WWSAPI) Verification Layer
The WWSAPI plug-in allows developers to catch instances of:
A WWSAPI being called which references an invalid intrinsic WWSAPI object.
A WWSAPI being called which references a single threaded object already in use.
An intrinsic object freed with an asynchronous call pending.
Calling blocking APIs from short threads.
Additionally, this plug-in:
Tracks the use of objects from instantiation to deletion.
Force calls that can be completed asynchronously to be completed synchronously. This is to prevent applications depending on a particular behavior from a call taking a WS_ASYNC_CONTEXT.
Provides a human readable description when an API is passed a bad object, or an object is in use using the !avrf –ws –obj debugger extension (shown below)
For channel, service proxy and service host, each call tracked will show the current state of the object.
By default, the following checkers are enabled:
Property NameDescriptionValidateObjectValidates that the intrinsic object is validTrackObjectTracks the use of an object through its lifetime
Other checkers that can be enabled in this provider through the properties UI are:
Property NameDescriptionCheckTimeoutValidates that async functions are completed within the timeout, specified as TimeoutValForceSyncForce, the sync path to be taken when a WS_ASYNC_CONTEXT context is supplied to an API.
A debugger extension is provided (!avrf –ws –obj) which displays opened and closed intrinsic WWSAPI objects. If this extension is suffixed by an object, it will display verbose information about the usage of this object.
!avrf -ws –obj
This command displays the intrinsic WWSAPI objects which are being tracked, both created and closed. Note that the closed objects are stored in a circular queue, so there is a ceiling to the total number of objects tracked.
Objects are added when the following APIs successfully complete: WsCreateChannel(), WsCreateChannelForListener(), WsCreateServiceHost(), WsCreateServiceProxy(), WsCreateServiceProxyFromTemplate(), WsCreateError(), WsCreateHeap(), WsCreateListener(), WsCreateMetadata(), WsCreateMessage(), WsCreateMessageForChannel(), WsCreateReader(), WsCreateWriter(), WsCreateXmlBuffer(), WsReadXmlBuffer(), WsReadXmlBufferFromBytes()
Objects are moved from the created to the freed list when the corresponding WsFree*() function is called and completes.
!avrf –ws –obj [OBJECT]
This command displays the usage of an intrinsic WWSAPI object. The usage information includes the stack when the object was created, used and freed. If the object is a channel, service host or service proxy, it will display the state of the object prior to the API using the object is called.
Here is an example of the !avrf –ws –obj usage options:
0:001> !avrf -ws -obj
Objects dependent on internal objects allocated:
Objects currently allocated:
0x00000000048566C0 (Type=Heap, Thread=0x000001bc, Pending Operations=0)
0x0000000001BE6780 (Type=Error, Thread=0x000001bc, Pending Operations=0)
0x0000000001C13580 (Type=Service Proxy, Thread=0x000001bc, Pending Operations=0)
Freed objects:
0x0000000001C17170 (Type=Service Proxy, Thread=0x000001bc)
0x0000000004856730 (Type=Heap, Thread=0x000001bc)
0x0000000001BE6820 (Type=Error, Thread=0x000001bc)
0:001> !avrf -ws -obj 0x0000000001C13580
Object @ 0x0000000001C13580
Type = Service Proxy
Thread = 0x000001bc
Internal Reference = 0x00000000026C5E80
Created stack:
vfnws!VfHookWsCreateServiceProxy+0x00aa
BLUESTONE!WST_WebServices::WsCreateServiceProxy+0x00d8
BLUESTONE!ServiceProxy::Connect+0x0116
BLUESTONE!ServiceModel_SimpleTest::SimpleClient+0x0607
BLUESTONE!ServiceModelTestGroup_Simple_Test02_Run+0x0041
BLUESTONE!Fnshell2::FnshellConfiguration::RunTest+0x002e
BLUESTONE!Fnshell2::TESTCASE::Run+0x00d6
BLUESTONE!fnsMsgProc+0x02d6
BLUESTONE!fnsRunTestsWorkerThread+0x085f
KERNEL32!BaseThreadInitThunk+0x000d
ntdll!RtlUserThreadStart+0x001d
Last 4 operations
Operation #1 created in thread 0x00000000000001BC
Service proxy state before operation = Created
Callstack:
vfnws!VfHookWsGetServiceProxyProperty+0x0053
BLUESTONE!WST_WebServices::WsGetServiceProxyProperty+0x009b
BLUESTONE!ServiceProxy::GetState+0x004b
BLUESTONE!ServiceProxy::VerifyState+0x001c
BLUESTONE!ServiceProxy::Connect+0x01c7
BLUESTONE!ServiceModel_SimpleTest::SimpleClient+0x0607
BLUESTONE!ServiceModelTestGroup_Simple_Test02_Run+0x0041
BLUESTONE!Fnshell2::FnshellConfiguration::RunTest+0x002e
BLUESTONE!Fnshell2::TESTCASE::Run+0x00d6
BLUESTONE!fnsMsgProc+0x02d6
BLUESTONE!fnsRunTestsWorkerThread+0x085f
KERNEL32!BaseThreadInitThunk+0x000d
ntdll!RtlUserThreadStart+0x001d
Operation #2 created in thread 0x00000000000001BC
Service proxy state before operation = Created
Callstack:
vfnws!VfHookWsOpenServiceProxy+0x0079
BLUESTONE!WST_WebServices::WsOpenServiceProxy+0x0092
BLUESTONE!ServiceProxy::Connect+0x03d3
BLUESTONE!ServiceModel_SimpleTest::SimpleClient+0x0607
BLUESTONE!ServiceModelTestGroup_Simple_Test02_Run+0x0041
BLUESTONE!Fnshell2::FnshellConfiguration::RunTest+0x002e
BLUESTONE!Fnshell2::TESTCASE::Run+0x00d6
BLUESTONE!fnsMsgProc+0x02d6
BLUESTONE!fnsRunTestsWorkerThread+0x085f
KERNEL32!BaseThreadInitThunk+0x000d
ntdll!RtlUserThreadStart+0x001d
Operation #3 created in thread 0x00000000000001BC
Service proxy state before operation = Open
Callstack:
vfnws!VfHookWsGetServiceProxyProperty+0x0053
BLUESTONE!WST_WebServices::WsGetServiceProxyProperty+0x009b
BLUESTONE!ServiceProxy::GetState+0x004b
BLUESTONE!ServiceProxy::VerifyState+0x001c
BLUESTONE!ServiceProxy::Connect+0x0484
BLUESTONE!ServiceModel_SimpleTest::SimpleClient+0x0607
BLUESTONE!ServiceModelTestGroup_Simple_Test02_Run+0x0041
BLUESTONE!Fnshell2::FnshellConfiguration::RunTest+0x002e
BLUESTONE!Fnshell2::TESTCASE::Run+0x00d6
BLUESTONE!fnsMsgProc+0x02d6
BLUESTONE!fnsRunTestsWorkerThread+0x085f
KERNEL32!BaseThreadInitThunk+0x000d
ntdll!RtlUserThreadStart+0x001d
Operation #4 created in thread 0x00000000000001BC
Service proxy state before operation = Open
Callstack:
vfnws!VfHookWsCall+0x00a6
BLUESTONE!DefaultBinding_ICalculator_Add+0x008b
BLUESTONE!ServiceModelTestGroup_Simple_Function+0x010a
BLUESTONE!ServiceModel_SimpleTest::SimpleClient+0x069a
BLUESTONE!ServiceModelTestGroup_Simple_Test02_Run+0x0041
BLUESTONE!Fnshell2::FnshellConfiguration::RunTest+0x002e
BLUESTONE!Fnshell2::TESTCASE::Run+0x00d6
BLUESTONE!fnsMsgProc+0x02d6
BLUESTONE!fnsRunTestsWorkerThread+0x085f
KERNEL32!BaseThreadInitThunk+0x000d
ntdll!RtlUserThreadStart+0x001d
Asynchronous Callback = BLUESTONE!ServiceModelTestGroup_Simple_Callback
Asynchronous CallbackState = 0x0000000005EBDC30
Completed asynchronously with HRESULT=0x00000000 in thread 0x00000000000001BC
Asynchronous callback stack:
vfnws!VfHookWsCall+0x00e3
BLUESTONE!DefaultBinding_ICalculator_Add+0x008b
BLUESTONE!ServiceModelTestGroup_Simple_Function+0x010a
BLUESTONE!ServiceModel_SimpleTest::SimpleClient+0x069a
BLUESTONE!ServiceModelTestGroup_Simple_Test02_Run+0x0041
BLUESTONE!Fnshell2::FnshellConfiguration::RunTest+0x002e
BLUESTONE!Fnshell2::TESTCASE::Run+0x00d6
BLUESTONE!fnsMsgProc+0x02d6
BLUESTONE!fnsRunTestsWorkerThread+0x085f
KERNEL32!BaseThreadInitThunk+0x000d
ntdll!RtlUserThreadStart+0x001d
Closed stack:
0:001>
Services
The services tests, check for the proper use of Windows Services. For example that services are being started and stopped properly. For information on the stop code exceptions generated by these tests, see Application Verifier - Stop Codes - Services.
Perf
The Perf tests check for efficient use of APIs that impact system performance and energy consumption, such as calling a Windows function that uses an incorrect wait period. For information on the stop code exceptions generated by these tests, see Application Verifier - Stop Codes - Perf.
Hangs
The Hangs tests for the use of APIs that cause the system to become unresponsive, for example when the DllMain thread is waiting for another thread that was blocked. For information on the stop code exceptions generated by these tests, see Application Verifier - Stop Codes - Hangs.
ARM64EC Support
The following providers do not support ARM64EC, and therefore will crash a program running in ARM64EC:
See Also
Application Verifier - Overview
Application Verifier - Features
Application Verifier - Testing Applications
Application Verifier - Stop Codes and Definitions