netspi-logo netspi-white-logo
  • Penetration Testing as a Service
    • Explore Our Technology

      Resolve™ Technology


      IoT Pentesting
      Secure your ATM, automotive, medical, OT, and embedded devices and systems.



      Strategic Advisory
      Build a mature application security program.


    • Pentesting as a Service
      Better manage your vulnerabilities with world-class pentest execution and delivery.



      Network Pentesting
      Secure your internal, external, and wireless networks.



      Red Team Operations
      Test your internal defense teams against our expert hackers.



    • Application Pentesting
      Secure your web, mobile, thick, and virtual applications.



      Blockchain Pentesting
      Uncover and understand blockchain security concerns.



      Social Engineering
      Conduct email, phone, or physical security social engineering tests.



    • Cloud Pentesting
      Secure your AWS, Azure, and Google cloud infrastructures.



      Secure Code Review
      Find application security vulnerabilities in your source code with SAST tools and manual review.
  • Attack Surface Management
  • Breach and Attack Simulation
  • Resources
    • Featured

      Download Blockchain eBook

      5 Blockchain Security
      Fundamentals Every C-Suite
      Needs to Know

      Download the eBook!




    • Blog
      Read the latest technical and business insights.


      Webinars
      Learn from NetSPI’s technical and business experts.


      Cyber Warfare Training
      Hands-on training courses for cybersecurity professionals.



    • Tip Sheets & More
      Checklists, eBooks, infographics, and more.



      Events
      Connect with us at our events or at security conferences.


      Open Source Tools
      Security tools for everyone.



    • Podcast
      Hear from leaders in the industry.



      Case Studies
      How organizations stay secure with NetSPI.
  • About Us



    • About NetSPI
      Learn what makes us the leader in offensive security.



    • Meet the Pentesting Team
      Learn about our expert technical team and vulnerability research.



    • Careers
      Love where you work. NetSPI is hiring!



    • Partner with NetSPI
      Join the NetSPI Partner Program.



    • Newsroom
      Explore our press releases and news articles.



    • Integrations
      Explore how to connect NetSPI with your existing technology stack.
  • Get a Quote
  • Get a Quote
  • Login
  • Get a Quote
Back

Limiting The Exposure of Plain Text Passwords in C#

October 24, 2019 | Austin Altmann
Technical Blog Thick Application Penetration Testing

One vulnerability that we frequently look for when testing thick client applications is plain text passwords that are exposed in memory. Microsoft provides the SecureString to help protect passwords in memory, but what it does not provide is a perfect solution to actually using the SecureString when sending web requests. And as you’ll see below, there is none, but there are some safer ways to operate.

NetworkCredential Might Be Good Enough

If you’re handling passwords in forms other than the login, NetworkCredential won’t be the best tool for the job. But if you want to use an authentication scheme like Basic or Digest, you might be satisfied implementing a CredentialCache and NetworkCredential as seen here. After all, there’s a NetworkCredential constructor with a SecureString password argument. However, the password will be exposed in memory as a string when preparing to send a WebRequest with the credentials. Each authentication scheme makes a call to the NetworkCredential’s InternalGetPassword function which will return the password in plain text.

internal string InternalGetPassword() {
    string decryptedString = UnsafeNclNativeMethods.SecureStringHelper.CreateString(m_password);
    return decryptedString;
}

The String Problem

The entire point of using a SecureString is to limit the exposure of the plain text password in memory (see the blog title). Strings are immutable and therefore cannot be cleared on command. Their values will exist in memory until the garbage collector rolls around. If strings are used to handle the plain text password, it may exist in more addresses and for longer than anticipated.

The String Solution

Don’t use strings. Use a character or byte array – arrays are mutable!

The Code

Below is some of my code to log into the application. The basic idea of it comes from some Microsoft examples as well as this StackOverflow post. SecureStringLogin accepts the username, password (as a SecureString), and the login function itself which accepts the username as a string and the password as a byte array. GCHandle.Alloc is called to pin the byte array of the future plain text password, ensuring that it stays fixed in one memory location.

public static async Task SecureStringLogin(string username, SecureString password, Func<string, byte[], Task> Login)
{
    byte[] plaintext = null;
    GCHandle gcHandle = GCHandle.Alloc(plaintext, GCHandleType.Pinned);

    IntPtr unmanagedPtr = IntPtr.Zero;

    try
    {
        SecureStringToByteArray(unmanagedPtr, password, ref plaintext);
        await Login(username, plaintext);
    }
    finally
    {
        ClearPasswordFromMemory(unmanagedPtr, ref plaintext, password, gcHandle);
    }
}

And to convert the SecureString to a byte array, we’ll need the SecureString password itself,  a reference to the byte array, and to set that IntPtr to the location of the SecureString’s contents.

private static void SecureStringToByteArray(IntPtr ptr, SecureString ciphertext, ref byte[] plaintext) 
{ 
    ptr= Marshal.SecureStringToBSTR(ciphertext);
    plaintext = new byte[ciphertext.Length];
    unsafe
    { 
        // Copy without null bytes
        byte* bstr = (byte*)ptr;
        for (int i = 0; i < plaintext.Length; i++)
        { 
            plaintext[i] = *bstr ++;
            *bstr = *bstr++;
        } 
    } 
}

Once the login is completed, the byte array will need to be cleared and unpinned.

private static void ClearPasswordFromMemory(IntPtr ptr, ref byte[] plaintext, SecureString password, GCHandle gcHandle)
{
    password.Dispose();
    Array.Clear(plaintext, 0, plaintext.Length);
    gcHandle.Free();
    if (ptr != IntPtr.Zero)
        Marshal.ZeroFreeBSTR(ptr);
}

Finally, whether you’re using streams or an HttpClient for your requests, you’ll just need to craft the body as a byte array and remember to clear and dispose of everything as usual. And there you go!

Closing Thoughts

The system that the application is running on could be compromised, and I believe the application should therefore be designed as securely as possible independent of where it is running. But this code is only cutting down on the time the plain text password is in memory and providing control over when it’s cleared rather than depending on the garbage collector. If the password’s value is going to be used for anything on another machine, it will need to be exposed as plain text, and there’s no way around it.
Microsoft says a SecureString is a little better than using a string. But if you’re set on using a PasswordBox in some sort of form, those are your two choices.

Source Code

  • Basic
  • Digest
  • Kerberos
  • Negotiate
  • NTLM
  • NetworkCredential
SHARE [bws_pdfprint display='pdf,print']
Austin Altmann

Recent Posts

Escalating Privileges with Azure Function Apps
Technical BlogCloud Penetration Testing
March 23, 2023

Escalating Privileges with Azure Function Apps

Pivoting Clouds in AWS Organizations – Part 2: Examining AWS Security Features and Tools for Enumeration
Technical BlogCloud Penetration Testing
March 7, 2023

Pivoting Clouds in AWS Organizations – Part 2: Examining AWS Security Features and Tools for Enumeration

Pivoting Clouds in AWS Organizations – Part 1: Leveraging Account Creation, Trusted Access, and Delegated Admin
Technical BlogCloud Penetration Testing
March 6, 2023

Pivoting Clouds in AWS Organizations – Part 1: Leveraging Account Creation, Trusted Access, and Delegated Admin

Need a Quote?
Common Questions
What is Penetration Testing as a Service (PTaaS)?

PTaaS is NetSPI’s delivery model for penetration testing. It enables customers to simplify the scoping of new engagements, view their testing results in real time, orchestrate faster remediation, perform always-on continuous testing, and more - all through the Resolve™ vulnerability management and orchestration platform. Learn More

Why should I use NetSPI?

We help organizations defend against adversaries by being the best at simulating real-world, sophisticated adversaries with the products, services, and training we provide. We know how attackers think and operate, allowing us to help our customers better defend against the threats they face daily.

How does NetSPI ensure quality results?

At NetSPI, we believe that there is simply no replacement for human-led manual deep dive testing. Our Resolve platform delivers automation to ensure our people spend time looking for the critical vulnerabilities that tools miss. We provide automated and manual testing of all aspects of an organization’s entire attack surface, including external and internal network, application, cloud, and physical security.

Our proven methodology ensures that the client experience and our findings aren’t only as good as the latest tester assigned to your project. That consistency gives our customers assurance that if vulnerabilities exist, we will find them.

Services

  • Penetration Testing
  • Attack Surface Management
  • Breach and Attack Simulation
  • What is Penetration Testing?
  • Ransomware Guide
  • Status

Resources

  • Blog
  • Tip Sheets & More
  • Podcast
  • Webinars
  • Events
  • Case Studies
  • Cyber Warfare Training

Company

  • About Us
  • Careers
  • News
  • Partner with NetSPI
  • Glossary
  • Open Source Tools

Get in Touch

  • Contact Us
  • Schedule a Demo
  • 612.465.8880

Sign up for our newsletter

© 2023 NetSPI LLC.
  • Privacy Policy

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Read More

Accept Decline
I consent to the use of following cookies:
Cookie Declaration About Cookies
Necessary (1) Marketing (1) Analytics (0) Preferences (0) Unclassified (0)
Necessary cookies help make a website usable by enabling basic functions like page navigation and access to secure areas of the website. The website cannot function properly without these cookies.
Name Domain Purpose Expiry Type
YSC youtube.com YouTube session cookie. 52 years HTTP
Marketing cookies are used to track visitors across websites. The intention is to display ads that are relevant and engaging for the individual user and thereby more valuable for publishers and third party advertisers.
Name Domain Purpose Expiry Type
VISITOR_INFO1_LIVE youtube.com YouTube cookie. 6 months HTTP
Analytics cookies help website owners to understand how visitors interact with websites by collecting and reporting information anonymously.
We do not use cookies of this type.
Preference cookies enable a website to remember information that changes the way the website behaves or looks, like your preferred language or the region that you are in.
We do not use cookies of this type.
Unclassified cookies are cookies that we are in the process of classifying, together with the providers of individual cookies.
We do not use cookies of this type.
Cookies are small text files that can be used by websites to make a user's experience more efficient. The law states that we can store cookies on your device if they are strictly necessary for the operation of this site. For all other types of cookies we need your permission. This site uses different types of cookies. Some cookies are placed by third party services that appear on our pages.
Cookie Settings