Attacking
Attacking
COM
Attacking .NET
· May 20, 2024 · 31 min read
Table of contents
Code Access Security (CAS)
1. Overly Permissive Policies
2. Insecure Code Execution
3. Misconfigured Evidence-Based Security
AllowPartiallyTrustedCaller attribute (APTCA)
1. Elevation of Privilege
2. Data Leakage
Distributed Component Object Model (DCOM)
1. Authentication and Authorization
2. Data Integrity and Confidentiality
3. Denial of Service (DoS) Attacks
Using DCOMCNFG Utility
Programmatic Configuration in .NET
Timing vulnerabilities with CBC-mode symmetric
Encrypt-then-HMAC Implementation
Secure Encryption and Decryption Example
Race Conditions
Race Conditions in the Dispose Method
Race Conditions in Constructors
Race Conditions with Cached Objects
Race Conditions in Finalizers
App Secrets
Environment Variables
Secret Manager
Enable Secret Storage
Set, Access, and Manage Secrets
XML Processing
.NET Framework Options:
Win32 and COM-based Options:
Timing attacks
ViewState is love
Formatter Attacks
TemplateParser
ObjRefs
Leaking ObjRefs
Trust Issues
Known Suspects
Exploitation
Resources
Show less
Attacking .NET applications often involves exploiting weaknesses in the code or the
runtime environment. One common attack vector is through input validation flaws,
where an attacker inputs malicious data into an application, potentially leading to
issues like SQL injection or cross-site scripting (XSS). For example, if a .NET
application does not properly sanitize user inputs before executing database queries,
an attacker could inject SQL commands that manipulate the database, retrieve
sensitive information, or cause data loss. Similarly, XSS attacks can occur if the
application fails to properly encode user inputs before rendering them in the web
browser, allowing attackers to execute malicious scripts in the context of other users’
sessions.
Another significant aspect of attacking .NET applications involves reverse engineering
and tampering with the compiled code. .NET applications are typically compiled into
an intermediate language (IL) which can be decompiled back into readable source
code with tools like ILSpy or dotPeek. This makes it easier for attackers to understand
the application logic, discover hardcoded secrets, or modify the code to change its
behavior. Additionally, attackers might exploit vulnerabilities in the .NET runtime itself,
such as through deserialization attacks, where untrusted data is deserialized into
objects, leading to arbitrary code execution. Securing .NET applications requires
thorough input validation, proper use of cryptography, and adopting secure coding
practices to mitigate these risks.
One common issue is the creation of overly permissive security policies. Granting too
many permissions to code, especially third-party or less trusted components, can
expose your application to various attacks.
COPY
using System;
using System.Security.Permissions;
class OverlyPermissiveExample
{
public static void Main()
{
try
{
// This grants unrestricted access, which is dangerous
PermissionSet allPerms = new
PermissionSet(PermissionState.Unrestricted);
allPerms.Demand();
Mitigation: Always grant the minimum permissions necessary for the code to
function. Use PermissionSetobjects to precisely control the granted permissions.
COPY
using System;
using System.Security;
using System.Security.Permissions;
class LeastPrivilegeExample
{
public static void Main()
{
try
{
// Grant only the necessary permissions
PermissionSet perms = new
PermissionSet(PermissionState.None);
perms.AddPermission(new
FileIOPermission(FileIOPermissionAccess.Read, @"C:\example.txt"));
perms.Demand();
Improper use of CAS can lead to insecure code execution, allowing attackers to
execute arbitrary code with higher privileges.
Example of insecure execution:
COPY
using System;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
class InsecureReflectionExample
{
public static void Main()
{
try
{
// Execute a method using reflection without proper
permission checks
Type type = Type.GetType("System.IO.File, mscorlib");
MethodInfo method = type.GetMethod("Delete", new Type[] {
typeof(string) });
method.Invoke(null, new object[] { @"C:\example.txt" });
using System;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
class SecureReflectionExample
{
[ReflectionPermission(SecurityAction.Demand, Flags =
ReflectionPermissionFlag.RestrictedMemberAccess)]
public static void Main()
{
try
{
// Restrict reflection permissions
Type type = Type.GetType("System.IO.File, mscorlib");
MethodInfo method = type.GetMethod("Delete", new Type[] {
typeof(string) });
// Ensure only authorized code can perform the action
if (method != null && method.IsPublic)
{
method.Invoke(null, new object[] { @"C:\example.txt"
});
Console.WriteLine("File deleted using secure
reflection.");
}
}
catch (SecurityException se)
{
Console.WriteLine($"SecurityException: {se.Message}");
}
}
}
using System;
using System.Security;
using System.Security.Policy;
using System.Security.Permissions;
class MisconfiguredEvidenceExample
{
public static void Main()
{
try
{
// Incorrectly assigning evidence
Evidence evidence = new Evidence();
evidence.AddHostEvidence(new
Url("http://untrustedsource.com"));
using System;
using System.Security;
using System.Security.Policy;
using System.Security.Permissions;
class SecureEvidenceExample
{
public static void Main()
{
try
{
// Properly validate and assign evidence
Evidence evidence = new Evidence();
evidence.AddHostEvidence(new Zone(SecurityZone.Intranet));
Allowing partially trusted callers can lead to an elevation of privilege if the assembly is
not designed to handle untrusted input securely. This can happen if internal methods
assume that all callers are fully trusted and therefore do not perform necessary
security checks.
Example of a vulnerability:
COPY
using System;
using System.Security;
[assembly: AllowPartiallyTrustedCallers]
using System;
using System.Security;
[assembly: AllowPartiallyTrustedCallers]
2. Data Leakage
Partially trusted callers may exploit exposed APIs to access sensitive data that should
be restricted.
Example of data leakage:
COPY
using System;
using System.Security;
[assembly: AllowPartiallyTrustedCallers]
using System;
using System.Security;
[assembly: AllowPartiallyTrustedCallers]
To manage and inspect the APTCA settings for assemblies, developers can use tools
like the .NET Framework Configuration Tool ( caspol ) or PowerShell.
Inspecting APTCA Settings:
Using caspol :
COPY
caspol -listgroups
[System.Reflection.Assembly]::LoadFile("C:\path\to\your\assembly.dll")
.GetCustomAttributes($true) | Where-Object { $_ -is
[System.Security.AllowPartiallyTrustedCallersAttribute] }
DCOM allows remote procedure calls over a network, which can be intercepted or
exploited if proper authentication and authorization mechanisms are not in place.
Without proper security, unauthorized users can gain access to sensitive operations
or data.
Mitigation:
Use strong authentication methods such as NTLM or Kerberos.
Implement role-based access control (RBAC) to ensure that only authorized users
can invoke methods on DCOM objects.
2. Data Integrity and Confidentiality
DCOM services can be susceptible to DoS attacks, where an attacker sends a large
number of requests to overwhelm the server, making it unavailable to legitimate
users.
Mitigation:
Implement rate limiting to restrict the number of requests a client can make in a
given period.
Use network firewalls and intrusion detection/prevention systems to detect and
block malicious traffic.
DCOM security settings can be configured using the DCOMCNFG utility or
programmatically through .NET code.
Using DCOMCNFG Utility
1. Launch DCOMCNFG:
COPY
dcomcnfg
You can use .NET to programmatically configure DCOM security settings for a specific
application. Below is an example demonstrating how to configure DCOM settings:
COPY
using System;
using System.Runtime.InteropServices;
class DcomSecurityExample
{
// Constants for DCOM security settings
const int RPC_C_AUTHN_LEVEL_DEFAULT = 0;
const int RPC_C_IMP_LEVEL_IDENTIFY = 2;
const int EOAC_NONE = 0;
[DllImport("ole32.dll")]
private static extern int CoInitializeSecurity(
IntPtr pSecDesc,
int cAuthSvc,
IntPtr asAuthSvc,
IntPtr pReserved1,
int dwAuthnLevel,
int dwImpLevel,
IntPtr pAuthList,
int dwCapabilities,
IntPtr pReserved3
);
if (result != 0)
{
throw new Exception($"CoInitializeSecurity failed with
error code {result}");
}
using System;
using System.IO;
using System.Security.Cryptography;
try
{
using (ICryptoTransform decryptor =
aes.CreateDecryptor(aes.Key, aes.IV))
using (MemoryStream ms = new MemoryStream(cipherText))
using (CryptoStream cs = new CryptoStream(ms,
decryptor, CryptoStreamMode.Read))
using (StreamReader reader = new StreamReader(cs))
{
return reader.ReadToEnd();
}
}
catch (CryptographicException)
{
return null; // Invalid padding
}
}
}
}
In this example, if an attacker can detect whether the padding is valid or not based on
the response time or an error message, they can perform a padding oracle attack.
To prevent padding oracle attacks, it is essential to use an HMAC (Hash-based
Message Authentication Code) to verify the integrity of the encrypted data before
attempting decryption. This approach ensures that any tampered data is rejected
before decryption, making timing attacks infeasible.
Encrypt-then-HMAC Implementation
COPY
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
Buffer.BlockCopy(cipherTextWithHmac, 0, cipherText, 0,
cipherText.Length);
Buffer.BlockCopy(cipherTextWithHmac, cipherText.Length, hmac,
0, hmac.Length);
Race Conditions
Race conditions in .NET applications, particularly concerning security vulnerabilities,
can arise in various scenarios. Let's explore these race conditions and their potential
impacts, along with best practices to mitigate them.
Race Conditions in the Dispose Method
void Dispose()
{
if (myObj != null)
{
Cleanup(myObj);
myObj = null;
}
}
Without proper synchronization, it's possible for multiple threads to enter the Dispose
method simultaneously, leading to Cleanup being called more than once. This can
result in improper disposal of resources, potentially causing security vulnerabilities,
especially with resource handles like files.
Race Conditions in Constructors
In scenarios where other threads might access class members before constructors
complete, race conditions can arise. It's essential to review all class constructors to
ensure there are no security concerns if this occurs. Synchronizing threads may be
necessary to prevent such issues.
Race Conditions with Cached Objects
Code that caches security information or utilizes code access security operations can
be vulnerable to race conditions if not properly synchronized. Consider the following
example:
COPY
void SomeSecureFunction()
{
if (SomeDemandPasses())
{
fCallersOk = true;
DoOtherWork();
fCallersOk = false;
}
}
void DoOtherWork()
{
if (fCallersOK)
{
DoSomethingTrusted();
}
else
{
DemandSomething();
DoSomethingTrusted();
}
}
If DoOtherWork can be called from another thread with the same object, an untrusted
caller might bypass a security demand. This highlights the importance of proper
synchronization, especially when caching security-related information.
Race Conditions in Finalizers
Objects with finalizers that reference static or unmanaged resources can encounter
race conditions. If multiple objects share a resource manipulated in a class's finalizer,
all access to that resource must be synchronized to prevent race conditions.
App Secrets
When developing ASP.NET Core applications, managing sensitive data like passwords
and API keys is crucial. Storing such information directly in code or configuration files
is insecure and not recommended. Instead, ASP.NET Core provides mechanisms for
safely managing app secrets during development. Let's explore how to handle app
secrets securely in ASP.NET Core applications.
Environment Variables
Environment variables are commonly used to store sensitive data, as they override
configuration values from other sources. However, it's important to note that
environment variables are generally stored in plain text, which could pose a security
risk if the system is compromised.
Secret Manager
The Secret Manager tool in ASP.NET Core provides a way to store sensitive data
securely during development. This tool stores app secrets in a separate location from
the project tree and ensures they are not checked into source control. However, it's
essential to understand that the Secret Manager tool doesn't encrypt the stored
secrets and should only be used for development purposes.
The Secret Manager tool operates on project-specific configuration settings stored in
the user profile directory. It hides implementation details and stores values in a JSON
configuration file. However, developers should not rely on the location or format of
data saved by the Secret Manager tool, as these details may change in the future.
Enable Secret Storage
To enable secret storage using the Secret Manager tool, developers can use either
the .NET CLI or Visual Studio. The dotnet user-secrets init command initializes the
Secret Manager for the project and adds a UserSecretsId element to the project file.
Visual Studio also provides a convenient way to manage user secrets through its UI.
Set, Access, and Manage Secrets
Once secret storage is enabled, developers can set, access, and manage secrets
using commands like dotnet user-secrets set , dotnet user-secrets list , and dotnet
user-secrets remove . Secrets can be accessed in code using the Configuration API,
In the non-compliant code above, sensitive data such as the database connection
string is hardcoded directly into the source code, which poses a security risk.
COPY
XML Processing
When processing XML in .NET applications, it's important to consider security issues
to prevent vulnerabilities such as XML External Entity (XXE) attacks and denial of
service attacks. Let's discuss the various XML processing options available in .NET
and their security implications:
.NET Framework Options:
Console.WriteLine(xml);
}
}
COPY
Console.WriteLine(xml);
}
}
2. System.Xml.XmlReader:
Processing Type: Stream-based
Description: XmlReader provides a fast, non-cached, forward-only way to
access XML data.
Security Considerations: XmlReader is vulnerable to XXE attacks if not
configured properly. Developers should disable external entities and DTD
processing when parsing untrusted XML data to mitigate this risk.
COPY
while (reader.Read())
{
// Process XML data
Console.WriteLine(reader.Name);
}
reader.Close();
}
}
COPY
while (reader.Read())
{
// Process XML data
Console.WriteLine(reader.Name);
}
reader.Close();
}
}
3. System.Xml.XmlWriter:
Processing Type: Stream-based
Description: XmlWriter provides a fast, non-cached, forward-only way to
generate XML data.
Security Considerations: XmlWriter itself doesn't pose significant security
risks. However, care should be taken to ensure that the generated XML
doesn't contain sensitive information or vulnerabilities.
COPY
writer.WriteStartElement("root");
writer.WriteElementString("name", "John");
writer.WriteElementString("age", "30");
writer.WriteEndElement();
writer.Close();
}
}
COPY
writer.WriteStartElement("root");
writer.WriteElementString("name", "John");
writer.WriteElementString("age", "30");
writer.WriteEndElement();
writer.Close();
}
}
4. System.Xml.XmlDocument:
Processing Type: In-memory
Description: XmlDocument implements the W3C Document Object Model
(DOM) and allows for creation, insertion, removal, and modification of nodes
using familiar DOM methods and properties.
Security Considerations: XmlDocument is susceptible to XXE attacks if
untrusted XML is parsed without proper configuration. Developers should
disable external entities and DTD processing to mitigate this risk.
COPY
Console.WriteLine(node.SelectSingleNode("name").InnerText);
Console.WriteLine(node.SelectSingleNode("age").InnerText);
}
}
}
COPY
Console.WriteLine(node.SelectSingleNode("name").InnerText);
Console.WriteLine(node.SelectSingleNode("age").InnerText);
}
}
}
5. System.Xml.XPath.XPathNavigator:
Processing Type: In-memory
Description: XPathNavigator offers editing options and navigation
capabilities using a cursor model.
Security Considerations: Similar to XmlDocument, XPathNavigator is
vulnerable to XXE attacks if not configured securely. Developers should
follow best practices to prevent XXE vulnerabilities.
COPY
while (nodes.MoveNext())
{
// Process XML data
Console.WriteLine(nodes.Current.SelectSingleNode("name").Value);
Console.WriteLine(nodes.Current.SelectSingleNode("age").Value);
}
}
}
COPY
// Compliant code: XPathNavigator with secure settings
using System;
using System.Xml;
using System.Xml.XPath;
while (nodes.MoveNext())
{
// Process XML data
Console.WriteLine(nodes.Current.SelectSingleNode("name").Value);
Console.WriteLine(nodes.Current.SelectSingleNode("age").Value);
}
}
}
6. XslCompiledTransform:
Processing Type: In-memory
Description: XslCompiledTransform provides options for transforming XML
data using XSL transformations.
Security Considerations: XslCompiledTransform can be vulnerable to XXE
attacks if untrusted XML is transformed without proper precautions.
Developers should ensure that input XML is sanitized to prevent injection
attacks.
Win32 and COM-based Options:
1. XmlLite:
Description: XmlLite is a fast, secure, non-caching, forward-only XML parser
suitable for building high-performance XML apps. It works with any language
that can use dynamic link libraries (DLLs).
Security Considerations: XmlLite is relatively safe, but developers should
handle XML data securely to prevent injection attacks.
2. MSXML:
Description: MSXML is a COM-based technology included with the Windows
operating system for processing XML. It provides a native implementation of
the DOM with support for XPath and XSLT.
Security Considerations: MSXML is prone to various security vulnerabilities if
not used carefully. Developers should keep MSXML updated and apply
security patches regularly to mitigate risks.
When working with XML processing options in .NET, developers should always
validate and sanitize input XML data, disable external entities and DTD processing,
and follow best practices to prevent security vulnerabilities. Additionally, staying
updated on security advisories and patches for XML-related libraries is essential to
ensure the security of .NET applications.
Timing attacks
In .NET, timing attacks are a concern in security where attackers exploit variations in
the execution time of cryptographic algorithms to gain information about secret data,
such as passwords or encryption keys. Here's how you can address timing attacks in
.NET:
1. Implementing Fixed-Time String Comparison:
COPY
int result = 0;
return result == 0;
}
COPY
[MethodImpl(MethodImplOptions.NoInlining |
MethodImplOptions.NoOptimization)]
public bool Equals(string str1, string str2)
{
// Implementation remains the same
}
This ensures that the method is not inlined or optimized, maintaining a consistent
execution time.
3. Using CryptographicOperations.FixedTimeEquals (since .NET Core 2.1):
.NET Core provides a built-in method for fixed-time comparison of byte arrays:
COPY
This method compares two byte arrays in constant time, mitigating timing attacks.
ViewState is love
ViewState attacks in .NET can be a serious concern for web application security.
Attackers can exploit ViewState deserialization vulnerabilities to execute arbitrary
code and gain unauthorized access to the application. Here's an overview of
ViewState attacks and how they can be mitigated:
1. Understanding ViewState Deserialization: ViewState is a mechanism in ASP.NET
that allows state information to be persisted across postbacks. It serializes the
state of server-side controls and sends it to the client as a hidden field in the web
form. The client sends the ViewState back to the server on subsequent requests,
where it is deserialized and used to restore the control's state.
2. Exploiting ViewState Deserialization: Attackers can manipulate the ViewState
parameter to execute arbitrary code on the server. They can modify the serialized
ViewState data to include malicious code, such as remote code execution
payloads or WebShell logic. By submitting the manipulated ViewState, the
attacker can trigger the deserialization process on the server and execute the
injected code.
3. Mitigating ViewState Attacks: To mitigate ViewState attacks, consider the
following measures:
Validate and Sanitize Input: Implement strict input validation and data
sanitization to prevent malicious input from being processed by the server.
Use Secure ViewState Encryption: Encrypt ViewState data using strong
encryption algorithms and secure keys to prevent tampering and
manipulation by attackers.
Apply Strict Deserialization Controls: Use .NET framework features like
ActivitySurrogateSelectorFromFile to control the deserialization process and
The attacker crafts a malicious ViewState payload containing serialized data with
injected code. When submitted to the server, the ViewState is deserialized, and
the injected code is executed, allowing the attacker to gain unauthorized access
or execute arbitrary commands.
COPY
// Non-compliant Code:
// Compliant Code:
TemplateParser
The exploitation of ASP.NET TemplateParser, as described in the provided excerpt,
illustrates a sophisticated attack vector that targets the deserialization process in
ASP.NET applications, particularly focusing on SharePoint environments. Let's break
down the key points and issues discussed in the text:
1. Introduction to SharePoint Custom .aspx Pages:
SharePoint allows users to upload and create custom .aspx pages within the
system.
There's a fundamental assumption that untrusted users can create these
pages but are restricted from adding server-side code.
2. Security Measures in SharePoint:
SharePoint implements the SPPageParserFilter class, extending ASP.NET's
PageParserFilter, to validate server control types against a Safe Controls list
during the tokenization step in TemplateParser.ProcessBeginTag() method.
This validation aims to prevent untrusted users from adding unauthorized
server-side code.
3. Challenges and Ideas with TemplateParser:
The TemplateParser has certain policies:
Control over types is limited to custom server controls and the @
Register directive.
<%@ Register
TagPrefix="x"
Assembly="System.Data.Services, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"
Namespace="System.Data.Services.Internal.ExpandedWrapper`1[[System.Dat
eTime,mscorlib]]�"
%>
<x:y
runat="server"
ExpandedElement="foobar"
/>
Explanation:
This non-compliant code snippet attempts to exploit the ASP.NET
TemplateParser.
It uses the @ Register directive to register a custom server control type
( ExpandedWrapper<DateTime> ) from the System.Data.Services assembly.
By appending � to the Namespace attribute, it tricks .NET into ignoring parts
of the server control type, allowing arbitrary code execution.
The ExpandedElement property is set to "foobar", potentially triggering a
TypeConverter or method associated with the DateTime type.
COPY
<%@ Register
TagPrefix="x"
Assembly="MyAssembly"
Namespace="MyNamespace"
%>
<x:MyCustomControl
runat="server"
MyProperty="safeValue"
/>
Explanation:
This compliant code snippet demonstrates the secure usage of the ASP.NET
TemplateParser.
It registers a custom server control ( MyCustomControl ) from a trusted assembly
( MyAssembly ) and namespace ( MyNamespace ).
The properties of the control are set to safe values, avoiding any potential
security vulnerabilities.
This code adheres to best practices for input validation and secure coding,
mitigating the risk of exploitation.
ObjRefs
When .NET Remoting services are exposed via HTTP, they can be provided using
either a standalone listener or integrated into an ASP.NET web application via IIS. In
the latter scenario, the call stack involves components like
HttpRemotingHandlerFactory , HttpRemotingHandler , and HttpHandlerTransportSink .
Leaking ObjRefs
A critical vulnerability arises from the limited exception handling in the call stack,
particularly in SoapServerFormatterSink and BinaryServerFormatterSink . These
components handle exceptions by creating and serializing a ReturnMessage object,
which includes the current LogicalCallContext .
To exploit this, two conditions must be met:
1. Exception handling in SoapServerFormatterSink or BinaryServerFormatterSink is
reached.
2. A class instance deriving from MarshalByRefObject is stored in the
LogicalCallContext .
Trust Issues
It's possible to overwrite trusted values from the HttpRequest with values from
corresponding HTTP headers, such as __RequestVerb and __requestUri . By
manipulating these headers, attackers can pass validation and trigger exception
handling in SoapServerFormatterSink or BinaryServerFormatterSink .
Known Suspects
ObjRefs.
Exploitation
With a leaked ObjRef, attackers can exploit deserialization in .NET Remoting via HTTP.
While default configurations restrict direct remote code execution, bypass techniques
exist to achieve it.
COPY
COPY
In the compliant code, the application checks whether late HTTP header parsing is
enabled before populating the base transport headers. If it's enabled, the code
prevents overwriting of trusted values from the HttpRequest with untrusted ones from
HTTP headers, thus mitigating the vulnerability.
Resources
code-white
OWASP
Sonarsource
DevSecOps Guides
Written by
Reza Rashidi Follow
Published on
DevSecOpsGuides Follow
MORE ARTICLES
Reza Rashidi Reza Rashidi
Attacking Rust Attacking Java
"Attacking Rust" delves into the Attacking Java applications requires a
intricacies of identifying and mitigating nuanced understanding of both the
security vulnerabilities … language's intricacies and …
Reza Rashidi
Attacking PHP
In modern PHP applications, attackers
exploit various vulnerabilities to
compromise systems, steal d…
©2024 DevSecOpsGuides
Archive · Privacy policy · Terms
Write on Hashnode