How Ansible impersonates users on Windows

Recently, I hit an interesting error during a deployment orchestrated by Ansible. One of the deployment steps was to execute a custom .NET application. Unfortunately, the application was failing on each run with an ACCESS DENIED error. After collecting the stack trace, I found that the failing code was ProtectedData.Protect(messageBytes, null, DataProtectionScope.CurrentUser), so a call to the Data Protection API. To pinpoint a problem I created a simple playbook:

- hosts: all
  gather_facts: no
  vars:
    ansible_user: testu
    ansible_connection: winrm
    ansible_winrm_transport: basic
    ansible_winrm_server_cert_validation: ignore
  tasks:
    - win_shell: |
        Add-Type -AssemblyName "System.Security"; \
        [System.Security.Cryptography.ProtectedData]::Protect([System.Text.Encoding]::GetEncoding(
            "UTF-8").GetBytes("test12345"), $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
      args:
        executable: powershell
      register: output

    - debug:
        var: output

When I run it I get the following error:

fatal: [192.168.0.30]: FAILED! => {"changed": true, "cmd": "Add-Type -AssemblyName \"System.Security\"; [System.Security.Cryptography.ProtectedData]::Protect([System.Text.Encoding]::GetEncoding(\n    \"UTF-8\").GetBytes(\"test\"), $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)", "delta": "0:00:00.807970", "end": "2020-05-04 11:34:29.469908", "msg": "non-zero return code", "rc": 1, "start": "2020-05-04 11:34:28.661938", "stderr": "Exception calling \"Protect\" with \"3\" argument(s): \"Access is denied.\r\n\"\r\nAt line:1 char:107\r\n+ ... .Security\"; [System.Security.Cryptography.ProtectedData]::Protect([Sy ...\r\n+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException\r\n    + FullyQualifiedErrorId : CryptographicException", "stderr_lines": ["Exception calling \"Protect\" with \"3\" argument(s): \"Access is denied.", "\"", "At line:1 char:107", "+ ... .Security\"; [System.Security.Cryptography.ProtectedData]::Protect([Sy ...", "+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", "    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException", "    + FullyQualifiedErrorId : CryptographicException"], "stdout": "", "stdout_lines": []}

The workaround to make it always work was to use the Ansible become parameters:

...
  tasks:
    - win_shell: |
        Add-Type -AssemblyName "System.Security"; \
        [System.Security.Cryptography.ProtectedData]::Protect([System.Text.Encoding]::GetEncoding(
            "UTF-8").GetBytes("test12345"), $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
      args:
        executable: powershell
      become_method: runas
      become_user: testu
      become: yes
      register: output
...

Interestingly, the original playbook succeeds if the testu user has signed in to the remote system interactively (for example, by opening an RDP session) and encrypted something with DPAPI before running the script.

It only made me even more curious about what is happening here. I hope it made you too 🙂

Continue reading

Writing network proxies for development purposes in C#

If you are developing, testing, or supporting web applications, you probably encounter situations when you need to record or modify HTTP traffic. Quite often, the browser request viewer might be enough, but what if you need to modify the traffic on the fly? Another challenging task is testing how your application behaves when put behind a load balancer or an edge server. There are many great HTTP proxies available in the market, including mitmproxy, Burp Suite, or Fiddler and they may be perfect in diagnosing/testing your applications. In this post, however, I am encouraging you to write small tools for your specific needs. There are many reasons why you may want to do so, such as the need for complex requests modifications, better control over the request processing, or customizations of the certificate creation. Of course, implementing the HTTP protocol could be demanding so, don’t worry; we won’t do that 🙂 Instead, we will use the open-source Titanium Web Proxy. The code samples in this post are meant to be run in LINQPad, which is my favorite tool for writing and running .NET code snippets, but you should have no difficulties in porting the samples to a C# script or a console application.

Continue reading

Synthetic types and tracing syscalls in WinDbg

Recently at work, I needed to trace several syscalls to understand what SQL Server was doing. My usual tool for this purpose on Windows was API Monitor, but, unfortunately, it hasn’t been updated for a few years already and became unstable for me. Thus, I decided to switch back to WinDbg. In the past, my biggest problem with tracing the system API in WinDbg was the missing symbols for the internal NT objects. Moreover, I discovered some messy ways to work around it. Fortunately, with synthetic types in WinDbg Preview it’s no longer a problem. In this post, I will show you how to create a breakpoint that nicely prints the arguments to a sample NtOpenFile syscall.

Continue reading

A story of fixing a memory leak in MiniDumper

MiniDumper is a diagnostic tool for collecting memory dumps of .NET applications. Dumps created by MiniDumper are significantly smaller than full-memory dumps collected by, for example, procdump. However, they contain enough information to diagnose most of the issues in the managed applications. MiniDumper was initially developed by Sasha Goldstein, and I made few contributions to its code base. You may learn more about this tool from Sasha’s or my blog posts.

Recently, one of MiniDumper users reported a memory leak in the application. The numbers looked scary as there was a 20MB leak on each memory dump. The issue stayed opened a few weeks before I finally found a moment to look at it. As it was quite a compelling case, I decided to share with you the diagnostics steps in the hope it proves useful in your investigations.

Continue reading

Indexing Windows header files with the PowerShell Scour module

Developing system applications in C# requires a lot of PInvoking. Although there are many great PInvoke Nuget libraries, for smaller projects I still prefer to import only the definitions I use. The pinvoke.net site is an excellent source of stub definitions. However, it happens that the online definition does not contain all the needed constants or lacks something. In such a case you have to look into the Windows headers (which btw. contain not only definitions but also a lot of interesting comments). I used to search through those files using Total Commander “Find Files” dialog, but it was slow and inefficient. So I switched to Sublime Text and created a project for the Windows headers folder (C:\Program Files (x86)\Windows Kits\10\Include\10.0.x.x). Once the folder index is cached, Sublime becomes a great tool for analyzing the source code (not only for C++!). However, when you read a lot of code and switch between various projects, Sublime replaces the old cached projects with the new ones to keep the cache at a reasonable size. That triggers the cache rebuilt when you open the “old” project again, which takes time and makes your search inefficient again.

I then started looking for a way to build a permanent index on the folders I regularly scan (such as the Windows headers directory). At first, I was thinking about running a local instance of Elasticsearch or Apache Solr server, but that seemed like overkill. I was looking for something simpler, some kind of a wrapper over the Apache Lucene library, which is the core engine for the servers mentioned above. Then I stumbled upon the Lee Holmes article about Scour, a PowerShell module that wraps the Lucene.Net library and provides cmdlets to create full-text indexes for your folders. After using it for some time, I am happy with the results so I decided to share my simple setup with you.

Continue reading

Limit the execution time of a process tree on Windows

I was recently looking for a tool which would allow me to limit the total execution time of a process and its children. I haven’t found anything, so I decided to implement such a feature in Process Governor, my open-source process-monitoring application. You may download the v2.3 version from GitHub. In this post, I want to present you the new functionality and describe its implementation details.

When we know the PIDs of our running processes, we could use a simple command to wait for the processes to finish (the Wait-Process cmdlet is an ideal example) and kill the remaining ones if they pass the limit. However, what if we only know the PID of the initial process? Tracking processes hierarchy in a script could become problematic. A simple and clear solution would be to assign a job object to the initial process, let it create new processes, wait the specified period and terminate the job if any of the processes is still running (terminating the job exits all the processes). There are, however, few questions we need to answer:

  • How do we know all processes associated with the job finished their execution?
  • What types of process execution time should we measure?

Continue reading

Correlate PIDs with network packets in Wireshark

By default when you record a trace in Wireshark, you won’t find process IDs in it. And sometimes this information is necessary to investigate the problem you are facing. I run into one of such issues this week. I needed to locate a process on a Virtual Machine (local address 10.0.2.5) which was still using TLSv1 to connect to our load balancer. At first, I only recorded traces in Wireshark and filtered them (ssl.record.version == "TLS 1.0"):

initial-tls1-trace

Continue reading

Minidumper – A Better Way to Create Managed Memory Dumps

This is a repost of my article, originally published on CodeProject on 24 May 2016.

The Story of a Memory Dump

Memory dumps are a common way to diagnose various problems with our applications (such as memory leaks or application hangs). You may think of them as photos which allow you to have a look at the past and notice all the details you might have missed. There are different types of memory dumps which we may compare to different types of photos we take:

  • minimal – focus is on one element (such as an exception) and the whole background is blurry, they take very little space on the hardrive (eg. 2MB)
  • minidumps with thread and process data/heaps/stacks/exception data, etc. – depending on how many options we choose, they might be very detailed high-resolution pictures or very blurry ones, the range of space they take can vary from tens of MBs to several GBs
  • full memory dumps – those can be compared to high-resolution pictures, they are as big as the whole process committed virtual memory

Continue reading

Debug.Assert Everyone!

Every developer knows that unit testing improves the quality of the code. We also profit from static code analysis and use tools such as SonarQube in our build pipelines. Yet, I still find that many developers are not aware of a much older way of checking the validity of the code: assertions. In this post, I will present you the benefits of using assertions, as well as some configuration tips for .NET applications. We will also learn how .NET and Windows support them.

Continue reading

Few facts about OutputDebugString and default settings of the System.Diagnostics.Trace

I recently spent some time analyzing OutputDebugString method. For my another experiment I needed a version of OutputDebugString which depends only on Native API. While implementing it, I discovered few interesting facts about OutputDebugString that maybe will interest you too. The title mentions System.Diagnostics.Trace. It is because the default trace configuration in .NET sends trace messages to an instance of the DefaultTraceListener class, which uses OutputDebugString. And if you do not remove it explicitly from the trace listener collection, your logs will always go through it. You will later see why sometimes it might not be a good idea.

Continue reading