[HN Gopher] Named Pipes in .NET 6 with Tray Icon and Service
       ___________________________________________________________________
        
       Named Pipes in .NET 6 with Tray Icon and Service
        
       Author : entrep
       Score  : 126 points
       Date   : 2021-11-23 14:06 UTC (8 hours ago)
        
 (HTM) web link (erikengberg.com)
 (TXT) w3m dump (erikengberg.com)
        
       | bloblaw wrote:
       | Good article, but I wish the author would've addressed securing
       | these named pipes.
       | 
       | Consider that if a user-mode application can send messages to a
       | privileged process (like a Windows service).
       | 
       | What prevents _any_ user-mode application from doing that? And if
       | your Windows service is running as  "NT_AUTHORITY/SYSTEM" and
       | even executes privileged commands, well you might find you've got
       | a simple privilege escalation vuln.
       | 
       | Remember, secure your named pipes...especially when the named
       | pipe server runs as SYSTEM.
       | 
       | - https://stackoverflow.com/a/59983266
       | 
       | - https://versprite.com/blog/security-research/vulnerable-name...
        
         | program9 wrote:
         | I've worked on apps like this, and I didn't know or care which
         | user was going to use the features requiring elevation. So I
         | couldn't manage permissions per user. My approach to security
         | was to simply limit the input (method parameters usually) from
         | the unprivileged process. For example, not letting the client
         | send arbitrary commands to execute, use filesystem path
         | whitelists, only elevate when required, etc. If the privileged
         | code uses a resource, and that resource can be changed/replaced
         | by an unprivileged user, then the privileged code can be
         | manipulated. Like a Registry key in HKCU for example, or a file
         | in a user's AppData folder. Using enums as method parameters
         | for privileged code helped me avoid some obvious vulns I
         | might've otherwise created. I've definitely done it the wrong
         | way before. It can be tough.
        
           | bloblaw wrote:
           | This is generally how I've approached this problem as well. I
           | like using the `ServiceController.ExecuteCommand` method and
           | just send some integer value from the client -> server...and
           | the server maps the integer value to a pre-determined
           | command.
           | 
           | https://docs.microsoft.com/en-
           | us/dotnet/api/system.servicepr...
           | 
           | You've definitely outlined the risk clearly of allowing a
           | client to specify anything arbitrarily.
           | 
           | I once wrote a sudo implementation for Windows Vista /
           | Windows 7 and first attempt used named pipes communicating to
           | a windows service that did some token manipulation to execute
           | things _as_ the user (but with elevated token attached as
           | well). There be (security) dragons.
           | 
           | I like using named pipes and they are a great IPC mechanism
           | for communicating amongst processes of the same privilege
           | level. I would not use them for message passing between
           | processes of different privilege levels.
        
         | merb wrote:
         | I think the package he used, also has some kind of pipe
         | authorization access control.
        
           | entrep wrote:
           | That is correct.
        
         | entrep wrote:
         | Thanks! That's very valid feedback. Could be my next write up.
        
           | bloblaw wrote:
           | You're welcome. An alternative I've used to named pipes among
           | processes of different privilege levels is to build the
           | service to listen for custom commands sent to it. These are
           | just integers, and the service maps those to pre-defined
           | commands.
           | 
           | Then the only thing the user-mode application can send are
           | just flags (integers) that the service has already pre-
           | determined what it will do in response.
           | 
           | Here's an article:
           | https://www.codeproject.com/Articles/24434/How-to-Write-
           | Wind...
           | 
           | And here's a succinct example:
           | https://stackoverflow.com/a/5805700
        
             | entrep wrote:
             | Interesting. Didn't know about it.
        
         | ww520 wrote:
         | Good to address the security aspects of named pipe. However
         | none of those describes how to secure the server.
         | 
         | The server needs to call ImpersonateNamedPipeClient() on the
         | incoming client connection to assume the client's security
         | token, that would lower the server's privilege to the level of
         | the client. That's it!
         | 
         | A guest level client can connect to the server. The server's
         | privilege becomes guest, and cannot access any resources that
         | guest has no permission to access.
         | 
         | [1] https://docs.microsoft.com/en-
         | us/windows/win32/api/namedpipe...
        
           | munchler wrote:
           | FWIW, the project in the article is explicitly intended to
           | allow privilege elevation: "You have an application which
           | runs in user context, without any administrative rights, and
           | you need to perform some tasks which requires higher
           | privileges."
        
             | ww520 wrote:
             | The server can do whatever it needs to do in its higher
             | privilege. Just when it interacts with the client
             | connection, it lowers its privilege to the client's level.
             | It gets the incoming data, sanitizes it, and reverts back
             | to higher privilege to do the work. This minimizes the
             | attack surface to the area dealing with client interaction,
             | not the whole server. The server might link in a 3rd party
             | XML library to sanitizes the incoming data and you don't
             | know what the library can do. Running that in the client
             | privilege level ensures that whatever it does only under
             | the client's privilege.
        
               | monocasa wrote:
               | That thread still has higher privilege write access to
               | it's process's state, including the stacks of other
               | threads that haven't impersonated that client.
               | ImpersonateNamedPipeClient is a very leaky security
               | barrier, and far from the only thing you need to know
               | about when it comes to named pipe security.
        
             | [deleted]
        
       | k8sToGo wrote:
       | I don't know why I expected something more technical for the tray
       | icon part. I mean using a third party library is not really
       | anything .NET 6 specific.
        
         | entrep wrote:
         | I'll guess that will be a separate post.
        
         | comeonseriously wrote:
         | Seems to me, the focus of the article was more on named pipes
         | than the tray icon, so maybe that's why?
        
       | ape4 wrote:
       | Named pipes have been in Windows for many years
       | https://docs.microsoft.com/en-us/windows/win32/api/winbase/n...
        
         | hobs wrote:
         | First thing I do with SQL Server setups - turn off named pipes
         | :)
        
           | giancarlostoro wrote:
           | Is there a reason you do this? Curious, I havent had to setup
           | SQL Server myself in a while so I don't know what a
           | reasonable reason would be.
        
             | tyingq wrote:
             | Named pipes are fast when the database is on the same box,
             | but slower than a normal tcp connection when the database
             | is remote. Something to do with PeekNamedPipe calls having
             | to prepend reads.
        
               | hobs wrote:
               | Yeah one of my favorite SE posters talks a little more
               | about it, generally the benefits are only there if you
               | have app/db/sql server all on the same box.
               | 
               | https://dba.stackexchange.com/a/24176/15642
        
         | zwieback wrote:
         | Been using them since 1992 but at this point I would naturally
         | turn to sockets, even on the same machine. I can't even really
         | say why though. Named pipes are nice because they are really
         | more like a file but at this point sockets feel more natural
         | because they exist and are supported everywhere.
        
           | ziml77 wrote:
           | You can apply permissions to named pipes and, well, they're
           | named which is useful since you can use a unique and
           | deterministic enough name that you don't need an extra band
           | of communication for the client to know what port the server
           | ended up starting on.
        
             | zwieback wrote:
             | Yeah, good point, as opposed to anonymous pipes, which also
             | still exist.
        
           | ww520 wrote:
           | TCP server cannot assume the security context of the client,
           | thus privilege elevation attack can easily happen.
        
             | monocasa wrote:
             | More importantly in a lot of cases, you can ask the kernel
             | for the client's SID as the server, and make decisions
             | knowing that the client couldn't forge it.
        
         | [deleted]
        
       | resoluteteeth wrote:
       | This uses the package H.Pipes which seems to use
       | System.Runtime.Serialization.BinaryFormatter by default; isn't
       | this insecure?
        
         | tonyedgecombe wrote:
         | Why is BinaryFormatter insecure?
         | 
         | Edit: Never mind, see https://docs.microsoft.com/en-
         | us/dotnet/standard/serializati...
        
           | entrep wrote:
           | It's possible to use different formatters for H.Pipes. I will
           | probably update the post to not mislead.
        
       | thrower123 wrote:
       | I think this is the first NamedPipes tutorial in C# that I've
       | ever seen that doesn't do things completely wrong by using a
       | StreamWriter or StreamReader. Of course, that's because it uses
       | another library that wraps all the tricky bits of NamedPipes that
       | everybody always does wrong -> https://github.com/HavenDV/H.Pipes
       | 
       | NamedPipes are sweet for doing same-machine IPC on Windows, that
       | is for sure, but the built-in API is full of footguns.
        
         | jborean93 wrote:
         | Can you elaborate what's wrong with using StreamReader or
         | StreamWriter with a np? I've used them before so wondering what
         | I'm potentially doing wrong here and what's the alternative.
        
           | thrower123 wrote:
           | It becomes an issue if the data you're reading or writing is
           | larger than 1024 bytes and you are in
           | PipeTransmissionMode.Message, because of some implementation
           | details with buffers and how StreamReader/Writer handle
           | Read/Write calls on the underlying
           | NamedPipe(Client/Server)Stream
           | 
           | See https://stackoverflow.com/questions/31936100/namedpipeser
           | ver...
        
             | jborean93 wrote:
             | Thanks for the info, I personally avoid the message mode
             | and just operate on bytes so that could be why I haven't
             | had problems with it.
        
       | thefz wrote:
       | Amazing read and insanely helpful. Thanks a ton both to the
       | author and to who posted it, if different people.
        
         | entrep wrote:
         | We're the same person. Thanks.
        
       | krisrm wrote:
       | Just to clarify something at the start of the article... If you
       | are using full Visual Studio to develop with .NET 6, you will
       | need 2022. If not, (eg. VS Code), will work with the command line
       | sdk.
        
         | philliphaydon wrote:
         | Pretty sure there isn't anything you can't do in Jetbrains
         | Rider EAP.
         | 
         | Edit: would like to know why I'm being downvoted.
        
           | achandlerwhite wrote:
           | Hot reload in Rider only works in debug mode on Windows (to
           | be clear it also works in nondebug sessions on Windows). On
           | Mac trying to use Hot Reload with Rider on a nondebug session
           | errors out, so it's not 100% yet.
        
             | philliphaydon wrote:
             | But the article doesn't require hot reload to achieve the
             | goal right?
        
           | pjmlp wrote:
           | - Debugging across .NET and C++ on the same solution.
           | 
           | - Create a architecture diagram out of .NET and native
           | compiled code.
           | 
           | - Integration with SharePoint and Dynamix SDKs
           | 
           | - SQL Server and Azure SDKs
           | 
           | - Using the Fakes mocking framework for MSIL rewriting
           | 
           | - Debugging the GPU shaders
           | 
           | Just a couple of examples, I can take plenty more out of VS
           | enterprise.
           | 
           | I really don't get how people can think JetBrains does better
           | than platform owners.
           | 
           | They will ever play catch-up with platform capabilities and
           | only offer a subset of the package.
        
             | philliphaydon wrote:
             | So, the parent comment I replied to was in relation to
             | needing VS 2022 for .NET 6, to which I replied that you
             | could use Jetbrains Rider EAP, obviously for .NET 6, to
             | accomplish the task in the linked post.
             | 
             | > They will ever play catch-up with platform capabilities
             | and only offer a subset of the package.
             | 
             | Obviously, they are competing with a 20+yo product.
             | 
             | But atleast I can get all my .NET work done on Linux
             | without needing slow bloated VS with a ton of useless
             | features like 'unit testing for poor code choices or legacy
             | codebases', or 'integration with the 2nd worst
             | collaborative tool after Jira'.
        
               | pjmlp wrote:
               | Sure when it all boils down to the tiny .NET Core subset
               | of ASP.NET MVC applications, instead of those 20 years of
               | history.
               | 
               | Looking forward to see how they deal with MAUI and Blazor
               | integration.
               | 
               | What others call bloat I call productivity features.
        
       | sebazzz wrote:
       | An alternative that comes with built-in dependency injection is
       | using the .NET hosted process model. Much easier to test too.
        
       ___________________________________________________________________
       (page generated 2021-11-23 23:01 UTC)