Lessons From Attacking Complex Thick-Client Applications

Security PS performs assessments on a wide variety of software architectures and platforms, some of which cannot be tested effectively using the more standard testing tools and methods. Recently, our team performed an assessment on a more complex application architecture. In this case, a .NET thick-client communicated with a variety of server-side components using either signed SOAP messages or with custom TCP messages. These factors meant our consultants couldn't use a proxy tool to directly manipulate traffic for security testing purposes. This post discusses some of the techniques our application security team used to overcome those challenges and successfully complete the assessment.

Security PS Application Security
Security PS used three techniques to manipulate both the signed SOAP requests and the custom TCP messages:
  • Writing custom code and reusing thick-client libraries
  • Attaching a debugger to the running application and manipulating variables
  • Disassembling, modifying, and reassembling the application
Code is often written in a modular way that makes it easy to reuse existing libraries. In this assessment, Security PS wrote GUI applications that reused the thick-client's libraries to decrypt data or send data to the server. This technique involved creating a new Visual Studio Project, adding the DLLs as a reference, and then writing code that calls functions within those thick-client libraries.

Next, Security PS needed to modify a field within a signed SOAP request to test authorization controls. Our team used a debugger and breakpoints to perform this modification. For .NET thick-clients, this attack is possible after disassembling and reassembling the application with debugging enabled.

Finally, we needed a way to quickly and easily manipulate custom TCP messages to identify vulnerabilities. Use of the debugger and breakpoints was too slow. Use of a custom written testing tool meant having to understand and duplicate some complex interactions that the thick-client managed. So, Security PS chose to directly modify the thick-client to allow interactive modification of TCP messages by consultants. For that to be possible, we needed to disassemble the thick-client, modify the intermediate language code, and then reassemble it.

Using these testing techniques, Security PS identified a number of high impact vulnerabilities. After discussing the vulnerabilities with the client, two of the questions they asked were:
  • Is .NET less secure than other languages since these techniques are possible?
  • How do I stop attackers from manipulating my applications?
The next post will consider these questions more, but the primary message we communicated to our client focused on a critical best practice for secure software design: all security controls must be implemented on a trusted component in the application architecture. In this case, security controls must be implemented on the server-side rather than on the client-side. The client operates on the attacker's computer where everything can be analyzed and modified regardless of the security controls used. The architecture of the application must assume the client environment cannot be trusted.  While additional controls can be applied to increase the difficultly an attacker would have in attempting to manipulate client-side security controls, it is important to recognize that the root of this security weakness is fundamentally a design flaw that would need to be addressed to fully mitigate the risks.

Stay tuned for a follow-up on the questions brought up above.