
Extracting SSH Private Keys from Windows 10 ssh-agent - vuln
https://blog.ropnop.com/extracting-ssh-private-keys-from-windows-10-ssh-agent/
======
netinstructions
The author of this blog must have uploaded an image without the big red block
to mask the private key, realized their error, and replaced it with an image
of it blocked. However they didn't remove the unblocked image first. Ghost
(the blog engine here) just appends a number to the image when you replace it
without changing the filename, so it's easy to find. See the two URLs below:

[https://blog.ropnop.com/content/images/2018/05/base64_decode...](https://blog.ropnop.com/content/images/2018/05/base64_decode_openssh.png)

[https://blog.ropnop.com/content/images/2018/05/base64_decode...](https://blog.ropnop.com/content/images/2018/05/base64_decode_openssh-1.png)

This is probably a good reason to use burner keys for proof of concepts.

~~~
ropnop
Author here...heh nice find.

All keys used were burner keys anyway.

The only reason I blurred and obfuscated where I could was just for "best
practice" not for real security. I knew if I didn't people would comment that
I should've ;)

~~~
dspillett
_> I knew if I didn't people would comment that I should've ;)_

That and following good practise even when not actually necessary due to other
mitigations, you obviously hint to less experienced readers what good practise
is.

------
meredydd
Just a heads-up - the pixelation used to hide the keys in the final screenshot
is not safe! There aren't that many possible characters in each of those
10x10px blocks, and ~256 levels of average brightness is enough to distinguish
between them. (Here's a simplistic demo:
[https://dheera.net/projects/blur](https://dheera.net/projects/blur))

Stick to the block-of-constant-colour method used in the first few
screenshots. It's ugly but safer!

~~~
discreditable
As I read the article I thought it was more silly they didn't simply use
burner keys as PoC.

~~~
kevin_thibedeau
They are burner keys. The red boxes are pointless.

------
DangerousPie
Am I correct in thinking that this is working as intended, and not actually a
vulnerability? Many people seem to be sharing this as "look at Microsoft
screwing up ssh-agent security", but I can't actually see any evidence of this
in the article.

~~~
EvanAnderson
You are correct. There is no "vulnerability" here. The plaintext of the user's
private keys must be accessible to the CPU performing the cryptographic
operations. DPAPI is a reasonable method to keep the keys encrypted "at rest"
while allowing the keys to be decrypted w/o the requiring password entry each
time the keys are used.

It is helpful for post-exploitation toolkits to have this functionality.

~~~
vesinisa
AFAIK the whole point of ssh-agent is that the private keys are _NOT_
extractable by other processes.

[https://man.openbsd.org/ssh-agent](https://man.openbsd.org/ssh-agent):

> The agent will never send a private key over its request channel. Instead,
> operations that require a private key will be performed by the agent, and
> the result will be returned to the requester. This way, private keys are not
> exposed to clients using the agent.

This sounds like a pretty gaping security hole by Microsoft. I would not
assume loading private keys to an "ssh-agent" means giving any process
(browser, email client etc.) running on the same machine access to the
unencrypted values!

~~~
EvanAnderson
The SSH agent isn't divulging the keys. The OP is decrypting the keys from the
underlying storage. The API used to protect the keys allows the keys to be
decrypted without explicit password entry. The OP has the necessary password
to decrypt the keys, so the API allows it. The SSH agent isn't involved.

~~~
skrause
> _The SSH agent isn 't divulging the keys. The OP is decrypting the keys from
> the underlying storage._

But can't just any program do that as soon as you're logged in? (Since your
login password basically unlocks the DP-API which is protected at rest.)

~~~
JesseWright
A program would need the appropriate level of access (which isn't actually
that high a bar), but at the end of the day the fact of the matter remains:
other processes can potentially access private keys that would otherwise
remain password protected.

------
hirsin
> I have no idea how the original author soleblaze figured out the correct
> format of the binary data, but I am so thankful he did and shared.

Good time to point out that we open sourced [0] all of this so I have some
guesses as to how soleblaze might have "reverse engineered" it :-)

0\. [https://github.com/PowerShell/openssh-
portable](https://github.com/PowerShell/openssh-portable)

------
slrz
From [1], cited and linked to in TFA:

> To do that, we simply start the ssh-agent service (as Administrator) and use
> ssh-add to store our private key.

Did Microsoft do some major surgery on the ssh-agent program or am I missing
something else? If the agent is started as Administrator, why can I connect to
it with my user privileges? And if I do, can other users on the same system do
so, too, accessing the same set of keys?

[1]
[https://blogs.msdn.microsoft.com/powershell/2017/12/15/using...](https://blogs.msdn.microsoft.com/powershell/2017/12/15/using-
the-openssh-beta-in-windows-10-fall-creators-update-and-windows-server-1709/)

~~~
Someone1234
Unprivileged processes can communicate with privileged services.

The service itself sometimes controls which user can access which data, but in
this case since the encrypted keys are stored in the Current User Registry
Hive (NTUSER.DAT) it likely doesn't need to, filesystem permissions handle
that.

Plus even if another user gained access to your registry hive, the data is
encrypted with your context via the Data Protection APIs.

~~~
simias
I'm sure they have a good reason to do it that way but why run a privileged
process when per-user processes could do the job just fine? You'd reduce the
surface of attack tremendously that way.

If somebody finds a flaw in their admin ssh-agent process they potentially
have a way to access other people's key or maybe even escalate their
privileges.

~~~
Someone1234
> I'm sure they have a good reason to do it that way but why run a privileged
> process when per-user processes could do the job just fine?

I actually don't know. I was thinking the same thing. Hopefully they have a
good reason, because you're right about the attack surface issue.

------
janci
So basically the article is saying Windows protects the keys much better than
linux, where the key sits unencrypted in ~/.ssh folder?

~~~
_ikke_
No:

1\. You can choose to have the keys encrypted with a password (same for
Windows as for Linux)

2\. The key, whether encrypted or unencrypted, are for both platforms stored
on disk in the user profile (see first screenshot)

3\. This talks about ssh-agent, which you can use to cache the the unencrypted
key so that you don't have to type the encryption password every time you want
to use the key. On Linux, this is just stored in memory, whereas in Windows,
it's stored (encrypted) in the registry as well.

------
vbezhenar
With Linux if I'm a program running under target user, I can use unlocked ssh-
agent to perform crypto operations with private key, but I can't extract the
key itself. With Windows I can just steal the key itself. I think Windows is
worse here. Am I misunderstanding something? What's the point of password
protection if key is stored unprotected by this password in the registry?

~~~
EvanAnderson
The private key _is_ stored password-protected in the registry. DPAPI, the API
used to protect the private key, encrypted based on the user's Windows account
password, and allows decryption without further password entry by the already-
logged-on user. There isn't an equivalent API in the Unix world that I'm aware
of. When you fire-up the Windows SSH agent no password entry is necessary,
because the password used to logon to Windows is also used to decrypt the
stored private key. In a Unix environment you'd need to enter a passphrase to
allow the SSH agent to decrypt the key.

~~~
bennofs
The equavilent in the unix world is gnome keyring (or any other Secret Service
spec implementation) unlocked by a PAM module on login.

------
a-dub
OT: Does the existence of this openssh port mean that the Windows command
window is now a fully functioning terminal?

~~~
oblio
It depends on what you mean by fully functional.

~~~
Piskvorrr
In other words, no. There's basic functionality though - 80/20 etc.

------
ww520
I assume the author doing these under the Administrator account or had admin
privilege.

~~~
kuroguro
You can read them with or without admin access on the same user. On the other
hand a different user's admin account wouldn't help unless you can dump the
first user's password.

[https://msdn.microsoft.com/en-
us/library/ms995355.aspx#winda...](https://msdn.microsoft.com/en-
us/library/ms995355.aspx#windataprotection-dpapi_topic02)

------
organicmultiloc
So ssh private keys are stored in plain base64 encoding in the windows
registry? How is that even possible?

~~~
jkaplowitz
No, part of this involved using Windows's Data Protection API to decrypt it.

Other non-administrator users can't read these registry keys, it's encrypted
with the login password (as is common with macOS Keychain and GNOME/KDE's
credential stores) so even other administrators can't decrypt it.

On Linux, administrators (root) can extract the keys from ssh-agent. This is
actually no less secure and usually more secure.

This is a cool demo of how to do it on Windows, and there's a reason the
author didn't call it a vulnerability - it's working as designed and this form
of attack is outside the intended threat model.

~~~
simias
>On Linux, administrators (root) can extract the keys from ssh-agent.

I don't understand how the situation is different. Of course you can extract
the keys from a running ssh-agent since the whole point is not having to
provide your password every time so they have to have access to the private
key one way or an other. How is the situation different on Windows? Surely
when the user is logged an administrator with access to the full RAM and
storage will be able to piece everything together (like TFA does for
instance)?

On the other hand if you really can't trust your admin you have a huge problem
anyway, even with a HSM you could be phished very easily.

Actually overall I'd say that this Windows method is _slightly_ less secure
because it means that the Windows keychain thingy is a single point of
failure, if somebody compromises it they have access to everything including
the ssh keys in the registry.

~~~
jkaplowitz
I don't think Windows gives an administrator account unfettered access to the
full RAM, no. And without that or the user's login password, all they could
get from the registry is the encrypted version, just as on disk. The
encryption is separate per-user with that user's password.

Of course there may be ways to get an even more advanced level of access than
administrator, such as the system account, but honestly Windows does lock some
things down really hard at the kernel level and Data Protection decryption
based on in-RAM credentials might be one. I don't know modern Windows
internals to that level.

~~~
simias
>I don't think Windows gives an administrator account unfettered access to the
full RAM, no.

Are you sure? Typically root has access to the full RAM on an un _x system.
Unless this is linked to a hardware TPM module I 'm not sure why and how it
would be protected. Maybe I'm wrong to assume that Windows Administrator ==
un_x root?

Anyway, if the OS has a way to hide some of its state from even the admin then
surely it could use it to hide the unencrypted SSH key in RAM instead of
hiding the key-to-the-registry-key? My main argument is that at some point if
the OS doesn't want to prompt the user for a password it must have access to
the private key one way or an other, so I'm not convinced that Windows is more
(or less) secure than Linux in this situation.

------
e40
So, good reason to use the Cygwin version of ssh-agent? I assume it doesn't
suffer from the same thing.

~~~
EvanAnderson
I don't understand what it "suffers" from. It's performing as-intended. A user
needs to be able to retrieve the plaintext of their SSH private keys.

There's nothing that seems architecturally unsound about how Microsoft
implemented this. DPAPI is a reasonable way to protect the keys "at rest" in
the registry. The OP was able to extract the keys because he has the
credentials for the user from whom he is extracting the keys.

Short of storing the keys in the memory of a dedicated crypto-processor
outside the host computer (and performing the cryptographic operations there)
the plaintext of the private keys will have to be recoverable to the user.

~~~
throwaway2048
the entire point of agents is that they DON'T just hand you key plaintext,
otherwise what would the point of them be compared to just an un-encrypted
file.

ssh-agent signs requests, tokens, etc on your behalf. You never see the
private key.

~~~
Arnavion
... which is why the blog post is about figuring out how to decrypt the
underlying storage that ssh-agent reads from to get to the private key.

Edit: If your point was specifically about this from EvanAnderson's comment

>A user needs to be able to retrieve the plaintext of their SSH private keys.

then the "user" there is the abstract identity used to locate and decrypt the
private key, not the human invoking ssh-agent.

