![Building](https://res.aon.com/image/fetch/ar_16:9,c_fill,f_auto,g_auto,h_184,w_327/https://assets.aon.com//-/media/images/photos/places/city-dallas-buildings-1288537096.jpg)
Support
During a web application assessment, we encountered ASP.NET’s “Blazor” server for the first time. After attempting a few basic test cases, we realized this was not like any app we’ve tested before. For starters, all the messages transmitted by the application included seemingly random binary characters. You can make out some strings within these messages, but most of the data is not easily readable (Figure 1).
Additionally, any attempts we made to tamper with or replay requests resulted in an error and the connection being renegotiated (Figure 2).
These initial observations proved to be major hindrances for testing a Blazor server application: limited readability and the inability to tamper with data.
Before we dive into addressing these obstacles, we first need to cover some of the basics. Blazor is a framework that comes with a variety of hosting options: WebAssembly (WASM), Server-Side ASP.NET, and Native Client. For the purposes of this blog post, we’ll focus on server-side Blazor, which integrates with SignalR to send browser events and receive pre-rendered page updates. By default, Blazor server applications communicate via WebSockets, though other transports such as Long Polling over HTTP are available as well. Since the end goal here is a Burp Suite extension, we’ll need to use HTTP as the Burp Suite extender APIs previously had little to no WebSockets support.
Note: Since this project began, Portswigger has released newer versions of the Montoya APIs which offer better extension support for WS. Handling Blazor messages over WS is currently under development for the BlazorTrafficProcessor extension.
Forcing a Blazor application to use Long Polling is possible within the negotiation process. When a web browser connects to a Blazor server, the first request is a version negotiation. This specifies the version and transports that will be used by the application.
An example request would look like:
POST /_blazor/negotiate?negotiateVersion=1 HTTP/1.1
Content-Length: 0
[...]
The response is as follows:
HTTP/1.1 200 OK
Content-Length: 316
Content-Type: application/json
[...]
{"negotiateVersion":1,"connectionId":"******","connectionToken"
:"******","availableTransports":[{"transport":"WebSockets","transferFormats":["Text","Binary"]},{"transport":"ServerSentEvents","transferFormats":["Text"]},{"transport":"LongPolling","transferFormats":["Text","Binary"]}]}
Using a Burp match and replace rule, you can remove the WebSockets transport from the response, forcing the browser to fall back to use Long Polling over HTTP. The BlazorTrafficProcessor extension will automatically downgrade any Blazor connections from WS to Long Polling.
After modifying the response to exclude WebSockets the browser console will show a warning to indicate a WebSocket connection failed and Long Polling will be used instead.
Warning: Failed to connect via WebSockets, using the Long Polling fallback transport. This may be due to a VPN or proxy blocking the connection. To trouble shoot this, visit https://aka.ms/blazor-server-using-fallback-long-polling.
By forcing the application to use Long Polling, all Blazor traffic will now occur over HTTP which makes Blazor data more accessible to prospective Burp Suite extensions. However, we still don’t know how the Blazor messages are formatted.
We know that Blazor applications expect messages to be in a particular format and order, with any deviations resulting in an error. If we turn to the documentation, Microsoft identifies this format as MessagePack and outlines how it can be used in ASP.NET applications.
MessagePack is another serialization format used to package structured data, like JSON, XML, etc. The key difference with MessagePack is that it is binary in nature, meaning specific bytes are used to indicate the types and length of serialized data.
While Blazor server uses MessagePack, the traffic is specifically formatted according to Blazor’s own Hub Protocol specification. Therefore, generic MessagePack parsers like the Burp Suite MessagePack extension available from the BApp Store will not work with Blazor traffic. Take the following BlazorPack message for example.
If we use the MessagePack extension on this message, the result is just 25 and the rest of the message is ignored. This is because \x00-\x7f represent positive integers in the MessagePack specification. The extension sees the first \x19, converts it to the decimal value of 25, and fails to parse the rest of the message. We’ll need a customized MessagePack parser to properly read these messages.
Blazor messages are formatted according to the Hub Protocol specification.
([Length] [Body])([Length] [Body])...
Length is a variable-size integer representing the size of Body, which is the actual message. A variable-size integer is one that can occupy a varying number of bytes, depending on the integer’s value. For example, a small integer may occupy a single byte whereas a larger integer may occupy up to five bytes. This value is crucial for parsing messages accurately and is one of the reasons that our tampering attempts failed. If you modify a string to be a different length than the original message, you’d need to update the Length variable-size integer as well. Manually performing these calculations for every request you want to tamper with is tedious and inefficient.
For the Body field, there are different types of messages supported by Blazor (i.e., Invocation, StreamInvocation, Ping, etc.). However, while proxying traffic and testing a sample Blazor application, we rarely saw any other types of messages being used other than Invocation. This is where we’ll focus for an example message breakdown.
The predominant message type observed while testing Blazor applications is an InvocationMessage, used to render page updates and submit data.
Taking a look at the specification, we see that there is the following structure:
[1, Headers, InvocationId, Target, [Arguments], [StreamIds]]
The following request body was sent after modifying a text input field to be foobar:
®•À·BeginInvokeDotNetFromJS•¡1À²DispatchEventAsyncÙx[{
"eventHandlerId":4,"eventName":"change","eventFieldInfo":{"componentId":20,"fieldValue":"foobar"}},{"value":"foobar"}]
Now, taking a look at the bytes:
\xae\x01 \x95 \x01 \x80 \xc0 \xb7 BeginInvokeDotNetFromJS \x95 \xa1 1 \xc0 \xb2 DispatchEventAsync \x01 \xd9\x78 [{"eventHandlerId":4,"eventName":"change","eventFieldInfo":{"componentId":20,"fieldValue":"foobar"}},{"value":"foobar"}]
Each string in a Blazor message is preceded by a MessagePack string header to indicate the size of the string. This adds another layer of complexity to manually tampering with messages; not only do you have to update the Length variable-size integer, but you’d have to update the size headers for each tampered string as well.
In summary, the two biggest obstacles when it comes to testing Blazor applications are:
While some data may be easily readable (i.e., the JSON array above containing user input), any attempt to modify these values will require modification to the preceding size bytes as well. This brings us to our next obstacle:
The BlazorTrafficProcessor (BTP) Burp Suite extension addresses both of these issues by providing testers with the ability to convert request bodies from BlazorPack to JSON and vice versa. JSON is more common in web applications and is easier to read due to being text-based rather than binary-based. By providing both deserialization and serialization functionality, testers can leverage this extension to capture and deserialize a request, modify the desired parameter(s), then serialize back to BlazorPack and submit the request.
The initial version of the extension has two primary features. The first of which is a BTP Request/Response tab that appears on every in-scope BlazorPack message with the ability to convert BlazorPack to JSON. The second is a BTP Burp Suite tab that provides a sandbox for users to serialize/deserialize BlazorPack messages at-will. Any requests/responses that contain BlazorPack serialized data will be highlighted in the HTTP History tab as Cyan.
The BTP tab will appear on every in-scope request and response in your Burp history that is serialized using BlazorPack.
This tab simply displays the BlazorPack body converted into a JSON array of message objects.
Within Blazor server applications, the JSInvokable attribute allows developers to expose DotNet functions to the client-side JavaScript. Take the following snippet for example:
[JSInvokable("CallMe")]
public static void hiddenFunc(String var)
{
Console.WriteLine("Hidden function called!");
Console.WriteLine(var);
}
This is a simple example that just logs some user input to the console, but there are no web pages that allow the user to call this function. Instead, the DotNet.invokeMethodAsync JavaScript function can be used (as outlined here).
After the function has been called from the browser, Burp captured the serialized message that was sent:
Sending the above payload to repeater and using the extension to deserialize yields the following:
The input of foo is contained within a 1-element array, so let’s try tampering and replaying the request. For demo purposes, we’ll change the JSON payload in the BTP tab to include a newline to see if newlines get written to the console output:
[{"Target":"BeginInvokeDotNetFromJS","Headers":0,"Arguments":["3","BlazorServerTestApp","CallMe",0,["Line1\r\nLine2"]],"MessageType":1}]
Clicking on the Raw tab to serialize the data back into MessagePack yields:
Upon sending the request, the response is a simple 200 OK:
HTTP/1.1 200 OK
Content-Length: 0
Connection: close
Content-Type: text/plain
Server: Kestrel
Important note about Blazor server Long Polling: sending any type of invocation POST request will not return data in the response. Instead, Long Polling keeps an open GET request that receives server updates as they become available. As such, if you send a request with malformed input that causes an error, you won’t see that error unless you look at subsequent GET requests.
Checking the console log and we see that the payload did in fact create two distinct lines with our input:
The BTP extension also includes a new tab added to Burp Suite, aptly named BTP. While you can copy and paste data into this tab, it is recommended to use the “Send body to BTP” right-click menu option (Figure 11) to ensure the whole message is copied appropriately. This feature applies to both requests and responses.
The message will then appear in the BTP tab as shown below:
This tab can be used for ad-hoc Blazor conversions with the following steps:
While testing Blazor server applications, you’re likely to run into various Target values such as: BeginInvokeDotNetFromJS, OnRenderCompleted, OnLocationChanged, etc. These functions themselves are not specific to the app that you’re testing. Rather, they are built-in to ASP.NET Core as part of ComponentHub and are used to facilitate communications between the frontend JavaScript and the backend .NET application. For example, OnLocationChanged is used to navigate between pages in the web application. The implementation of these functions can be found in the “aspnetcore” repository on GitHub here.
It is important to distinguish between what’s native and what’s custom in Blazor server applications, since your goal will likely be to find vulnerabilities in the app that you’re testing, not in Blazor itself. As such, focus your testing efforts on fields that contain your input (i.e., arguments to BeginInvokeDotNetFromJS) as opposed to normal Blazor operations (i.e., OnRenderCompleted or EndInvokeJSFromDotNet). With that said, security researchers can also utilize the BTP extension to test Blazor server itself since tampering inputs is now easier.
The following screenshot (Figure 13) displays a deserialized request that updates the value of a text box in the application to be asdf. The highlighted values are potential areas for tampering. The rest of the arguments are native to Blazor and tampering may cause a Blazor error, which would renegotiate your connection.
Consider a case where only client-side JavaScript is used to validate this input field. We could intercept the request, deserialize the message into JSON, enter a value that would otherwise fail validation, reserialize, and fire the request to bypass client-side input validation.
Support
While this extension achieves the base proof-of-concept for a tool to process Blazor server traffic, a feature we believe would be valuable to testers is the ability to fuzz serialized inputs (similar to a Burp Suite intruder attack). However, application data is never returned in response to a POST request when using Long Polling. Instead, the client-side JavaScript polls the server with a GET request and passes an epoch timestamp. The response to these polling requests will contain app data and render updates, making it difficult to deduce which request caused an error or a specific response. For example, if you send a POST request that causes an error, the error would be returned to the next GET (“poll”) request. Sending multiple error-inducing requests could cause the application to return several errors in one response body or spread out across subsequent polling responses. With no clear way to map one input to one response/error, we decided it best to leave out fuzzing for the first iteration of this tool. We are still looking for effective ways to fuzz Blazor applications and a fuzzing feature is on the roadmap for the BlazorTrafficProcessor extension.
BTP is fully dependent on the ability to downgrade a Blazor server connection from WebSockets to Long Polling over HTTP. ASP.NET developers have considered removing Long Polling support altogether, which could render BTP unusable. Ultimately Long Polling was left in the framework due to “unforeseen effects” of removing it, though it remains possible that support will be discontinued in the future.
For BTP to be future proof, it will need WebSockets support eventually. However, Blazor messages can be distributed across different WebSocket frames with a max size of 4096 bytes per frame. In other words, a Blazor message could start in one WebSocket frame and end in another. With limited support for WebSockets in Burp Suite’s Montoya APIs, it was not plausible to include Blazor WebSocket parsing for the initial version of BTP. However, this feature is currently under development as there are new iterations of Burp Suite’s Montoya APIs being released frequently.
You can find the latest version of the extension, as well as setup and usage instructions at our GitHub Repository here: https://github.com/AonCyberLabs/BlazorTrafficProcessor
Thank you for reading and happy Blazor hunting!
Capability Overview
Cyber Resilience
Product / Service
Penetration Testing Services
About Cyber Solutions:
Aon’s Cyber Solutions offers holistic cyber risk management, unsurpassed investigative skills, and proprietary technologies to help clients uncover and quantify cyber risks, protect critical assets, and recover from cyber incidents.
General Disclaimer
This material has been prepared for informational purposes only and should not be relied on for any other purpose. You should consult with your own professional advisors or IT specialists before implementing any recommendation or following the guidance provided herein. Further, the information provided and the statements expressed are not intended to address the circumstances of any particular individual or entity. Although we endeavor to provide accurate and timely information and use sources that we consider reliable, there can be no guarantee that such information is accurate as of the date it is received or that it will continue to be accurate in the future.
Terms of Use
The contents herein may not be reproduced, reused, reprinted or redistributed without the expressed written consent of Aon, unless otherwise authorized by Aon. To use information contained herein, please write to our team.
Our Better Being podcast series, hosted by Aon Chief Wellbeing Officer Rachel Fellowes, explores wellbeing strategies and resilience. This season we cover human sustainability, kindness in the workplace, how to measure wellbeing, managing grief and more.
Expert Views on Today's Risk Capital and Human Capital Issues
Expert Views on Today's Risk Capital and Human Capital Issues
Expert Views on Today's Risk Capital and Human Capital Issues
The construction industry is under pressure from interconnected risks and notable macroeconomic developments. Learn how your organization can benefit from construction insurance and risk management.
Stay in the loop on today's most pressing cyber security matters.
Our Cyber Resilience collection gives you access to Aon’s latest insights on the evolving landscape of cyber threats and risk mitigation measures. Reach out to our experts to discuss how to make the right decisions to strengthen your organization’s cyber resilience.
Our Employee Wellbeing collection gives you access to the latest insights from Aon's human capital team. You can also reach out to the team at any time for assistance with your employee wellbeing needs.
Explore Aon's latest environmental social and governance (ESG) insights.
Our Global Insurance Market Insights highlight insurance market trends across pricing, capacity, underwriting, limits, deductibles and coverages.
How do the top risks on business leaders’ minds differ by region and how can these risks be mitigated? Explore the regional results to learn more.
Our Human Capital Analytics collection gives you access to the latest insights from Aon's human capital team. Contact us to learn how Aon’s analytics capabilities helps organizations make better workforce decisions.
Explore our hand-picked insights for human resources professionals.
Our Workforce Collection provides access to the latest insights from Aon’s Human Capital team on topics ranging from health and benefits, retirement and talent practices. You can reach out to our team at any time to learn how we can help address emerging workforce challenges.
Our Mergers and Acquisitions (M&A) collection gives you access to the latest insights from Aon's thought leaders to help dealmakers make better decisions. Explore our latest insights and reach out to the team at any time for assistance with transaction challenges and opportunities.
How do businesses navigate their way through new forms of volatility and make decisions that protect and grow their organizations?
Our Parametric Insurance Collection provides ways your organization can benefit from this simple, straightforward and fast-paying risk transfer solution. Reach out to learn how we can help you make better decisions to manage your catastrophe exposures and near-term volatility.
Our Pay Transparency and Equity collection gives you access to the latest insights from Aon's human capital team on topics ranging from pay equity to diversity, equity and inclusion. Contact us to learn how we can help your organization address these issues.
Forecasters are predicting an extremely active 2024 Atlantic hurricane season. Take measures to build resilience to mitigate risk for hurricane-prone properties.
Our Technology Collection provides access to the latest insights from Aon's thought leaders on navigating the evolving risks and opportunities of technology. Reach out to the team to learn how we can help you use technology to make better decisions for the future.
Trade, technology, weather and workforce stability are the central forces in today’s risk landscape.
Our Trade Collection gives you access to the latest insights from Aon's thought leaders on navigating the evolving risks and opportunities for international business. Reach out to our team to understand how to make better decisions around macro trends and why they matter to businesses.
With a changing climate, organizations in all sectors will need to protect their people and physical assets, reduce their carbon footprint, and invest in new solutions to thrive. Our Weather Collection provides you with critical insights to be prepared.
Our Workforce Resilience collection gives you access to the latest insights from Aon's Human Capital team. You can reach out to the team at any time for questions about how we can assess gaps and help build a more resilience workforce.
Cyber Labs 3 mins
This client alert provides an overview of the current global IT outage that is related to a CrowdStrike update. We provide an overview of CrowdStrike's response and guidance, and Aon Cyber Solutions' recommendations for affected clients.
Cyber Labs 8 mins
Stroz Friedberg Digital Forensics and Incident Response has observed an uptick in SIM swapping across multiple industries, with several recent incidents targeting crypto and crypto-adjacent companies.