- mrh1997 / wincred.py
- Как настроить Python Keyring для получения учетных данных из Windows Credential Manager в Windows 7?
- 3 ответа
- RodneyRichardson / wincred.py
- Python – How to Configure Python Keyring to pull credentials from Windows Credential Manager on Windows 7
- Best Solution
- Related Solutions
- New answer, powershell
- TCP
- UDP
- Old answer, cmd
mrh1997 / wincred.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
#!python3 |
«»» |
Access windows credentials |
«»» |
from typing import Tuple |
import ctypes as CT |
import ctypes . wintypes as WT |
CRED_TYPE_GENERIC = 0x01 |
LPBYTE = CT . POINTER ( WT . BYTE ) |
LPWSTR = WT . LPWSTR |
LPCWSTR = WT . LPWSTR |
class CREDENTIAL_ATTRIBUTE ( CT . Structure ): |
_fields_ = [ |
( ‘Keyword’ , LPWSTR ), |
( ‘Flags’ , WT . DWORD ), |
( ‘ValueSize’ , WT . DWORD ), |
( ‘Value’ , LPBYTE )] |
PCREDENTIAL_ATTRIBUTE = CT . POINTER ( CREDENTIAL_ATTRIBUTE ) |
class CREDENTIAL ( CT . Structure ): |
_fields_ = [ |
( ‘Flags’ , WT . DWORD ), |
( ‘Type’ , WT . DWORD ), |
( ‘TargetName’ , LPWSTR ), |
( ‘Comment’ , LPWSTR ), |
( ‘LastWritten’ , WT . FILETIME ), |
( ‘CredentialBlobSize’ , WT . DWORD ), |
( ‘CredentialBlob’ , LPBYTE ), |
( ‘Persist’ , WT . DWORD ), |
( ‘AttributeCount’ , WT . DWORD ), |
( ‘Attributes’ , PCREDENTIAL_ATTRIBUTE ), |
( ‘TargetAlias’ , LPWSTR ), |
( ‘UserName’ , LPWSTR )] |
PCREDENTIAL = CT . POINTER ( CREDENTIAL ) |
advapi32 = CT . WinDLL ( ‘Advapi32.dll’ ) |
advapi32 . CredReadA . restype = WT . BOOL |
advapi32 . CredReadA . argtypes = [ LPCWSTR , WT . DWORD , WT . DWORD , CT . POINTER ( PCREDENTIAL )] |
def GetGenericCredential ( name : str ) -> Tuple [ str , str ]: |
«»» |
Returns a Tuple of Name and Password of a Generic Windows Credential |
Uses bytes in Py3 and str in Py2 for url, name and password. |
«»» |
cred_ptr = PCREDENTIAL () |
if advapi32 . CredReadW ( name , CRED_TYPE_GENERIC , 0 , CT . byref ( cred_ptr )): |
username = cred_ptr . contents . UserName |
cred_blob = cred_ptr . contents . CredentialBlob |
cred_blob_size = cred_ptr . contents . CredentialBlobSize |
cred_str = CT . string_at ( cred_blob , cred_blob_size ) |
password = cred_str . decode ( ‘utf-16le’ , errors = ‘ignore’ ) |
advapi32 . CredFree ( cred_ptr ) |
return username , password |
else : |
raise IOError ( «Failure reading credential» ) |
def main (): |
name , pwd = GetGenericCredential ( ‘git:https://github.com’ ) |
print ( «GITHUB NAME:» , name ) |
print ( «GITHUB PASSWORD:» , pwd ) |
if __name__ == ‘__main__’ : |
main () |
unicodePassword = credPtr.contents.CredentialBlob[:passwordSize:2]
My instinct tells me that this is probably a byte-value representing a text encoded using something other than UTF-8. Maybe UTF-16? Using the step-size «2» and then converting the bytes blindly using the chr builtin is in that case erroneous at best, or even a security risk at worst.
If my feeling is correct, it would be better to find out which encoding is used in the credential store and then simply use credPtr.contents.CredentialBlob.decode()
Actually this code was written for Python 2.7 ignoring Unicode. For real Unicode support there is more to do:
- replace CreadReadA by CreadReadW and thus supporting unicode urls
- replacing all LPTSTR by LPWSTR . This is especially important for UserName as it would be returned as unicode then
- credPtr.contents.CredentialBlob is of type LP_c_byte . Thus you cannot use the method decode .
I updated the code to support unicode correctly (and switched to Python 3 compatibility)
I’m curious as I am not familiar with the Windows API: Why is there a step-size of 2 when retrieving the value from the credentials blob?
Do you have a link to the documentation? Or was this reverse engineered?
And thanks a bunch for updating this! I’ll give it a go 😉
I aligned the code closer to PEP8 and made other things a bit more «pythonic» over at https://gist.github.com/exhuma/a310f927d878b3e5646dc67dfa509b42
In case you agree with the changes, you can merge them back if you like. Unfortunatly it’s not possible to do PRs on gists yet.
Как настроить Python Keyring для получения учетных данных из Windows Credential Manager в Windows 7?
Я потратил много времени на изучение пакета keyring, пытаясь получить простой пример для работы. Я использую python 2.7 на машине Windows 7-x64. Я установил пакет и подтвердил, что файлы находятся в папке Lib/site-packages. В этом фрагменте кода из документации по установке предполагается, что предполагается войти в «систему»?
import keyring keyring.get_password("system", "username")
RuntimeError: рекомендованных бэкэнд не было. Установите пакет keyrings.alt, если вы хотите использовать не рекомендованные серверы.
Похоже, что он не распознает Windows как бэкэнд. Я чувствую, что мне не хватает простого шага. Любая помощь приветствуется, включая простой пример кода для выведения общих учетных данных из диспетчера учетных данных Windows.
У меня точно такая же проблема. Windows 7. Python 3.6. Установлен из конды, IIRC. Вы когда-нибудь решали это?
3 ответа
Наконец, эта работа. Информация от Шона указала мне в правильном направлении с установкой pywin32. Оттуда я пробовал и делал ошибку с созданием тестовых учетных данных в Windows Credential Manager и тестированием функции Python keyring.
Я только получил его работу с Generic Credentials, которая подходит для моих целей. Я установил Интернет или сетевой адрес для «проверки». Имя пользователя было установлено на «test_user». Пароль был установлен на «test123». (Цитаты, включенные здесь для обучения, не включаются при вводе их.
print keyring.get_password («test», «test_user») вернул результат «test123»
Надеюсь, эта информация поможет кому-то другому. Спасибо Шон за направление, необходимое для решения этой проблемы.
RodneyRichardson / wincred.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
«»» |
Access windows credentials |
Credentials must be stored in the Windows Credentials Manager in the Control |
Panel. This helper will search for «generic credentials» under the section |
«Windows Credentials» |
Example usage:: |
result = get_generic_credential(‘foobar’) |
if result: |
print(«NAME:», result.username) |
print(«PASSWORD:», result.password) |
else: |
print(‘No matching credentials found’) |
Based on https://gist.github.com/exhuma/a310f927d878b3e5646dc67dfa509b42 |
which was based on https://gist.github.com/mrh1997/717b14f5783b49ca14310419fa7f03f6 |
«»» |
import ctypes as ct |
import ctypes . wintypes as wt |
from enum import Enum |
from typing import NamedTuple , Optional |
LPBYTE = ct . POINTER ( wt . BYTE ) |
Credential = NamedTuple ( ‘Credential’ , [ |
( ‘username’ , str ), |
( ‘password’ , str ) |
]) |
def as_pointer ( cls ): |
«»» |
Class decorator which converts the class to ta ctypes pointer |
:param cls: The class to decorate |
:return: The class as pointer |
«»» |
output = ct . POINTER ( cls ) |
return output |
class CredType ( Enum ): |
«»» |
CRED_TYPE_* enumeration (wincred.h) |
https://docs.microsoft.com/en-us/windows/win32/api/wincred/ns-wincred-credentialw |
«»» |
GENERIC = 0x01 |
DOMAIN_PASSWORD = 0x02 |
DOMAIN_CERTIFICATE = 0x03 |
DOMAIN_VISIBLE_PASSWORD = 0x04 |
GENERIC_CERTIFICATE = 0x05 |
DOMAIN_EXTENDED = 0x06 |
MAXIMUM = 0x07 |
MAXIMUM_EX = MAXIMUM + 1000 |
@ as_pointer |
class CredentialAttribute ( ct . Structure ): |
«»» |
PCREDENTIAL_ATTRIBUTEW structure (wincred.h) |
https://docs.microsoft.com/en-us/windows/win32/api/wincred/ns-wincred-credential_attributew |
«»» |
_fields_ = [ |
( ‘Keyword’ , wt . LPWSTR ), |
( ‘Flags’ , wt . DWORD ), |
( ‘ValueSize’ , wt . DWORD ), |
( ‘Value’ , LPBYTE )] |
@ as_pointer |
class WinCredential ( ct . Structure ): |
«»» |
CREDENTIALW structure (wincred.h) |
https://docs.microsoft.com/en-us/windows/win32/api/wincred/ns-wincred-credentialw |
«»» |
_fields_ = [ |
( ‘Flags’ , wt . DWORD ), |
( ‘Type’ , wt . DWORD ), |
( ‘TargetName’ , wt . LPWSTR ), |
( ‘Comment’ , wt . LPWSTR ), |
( ‘LastWritten’ , wt . FILETIME ), |
( ‘CredentialBlobSize’ , wt . DWORD ), |
( ‘CredentialBlob’ , LPBYTE ), |
( ‘Persist’ , wt . DWORD ), |
( ‘AttributeCount’ , wt . DWORD ), |
( ‘Attributes’ , CredentialAttribute ), |
( ‘TargetAlias’ , wt . LPWSTR ), |
( ‘UserName’ , wt . LPWSTR )] |
def get_generic_credential ( name : str ) -> Optional [ Credential ]: |
«»» |
Returns a tuple of name and password of a generic Windows credential. |
If no matching credential is found, this will return «None« |
:param name: The lookup string for the credential. |
«»» |
advapi32 = ct . WinDLL ( ‘Advapi32.dll’ ) |
advapi32 . CredReadW . restype = wt . BOOL |
advapi32 . CredReadW . argtypes = [ wt . LPCWSTR , wt . DWORD , wt . DWORD , ct . POINTER ( WinCredential )] |
cred_ptr = WinCredential () |
if advapi32 . CredReadW ( name , CredType . GENERIC . value , 0 , ct . byref ( cred_ptr )): |
try : |
username = cred_ptr . contents . UserName |
cred_blob = cred_ptr . contents . CredentialBlob |
cred_blob_size = cred_ptr . contents . CredentialBlobSize |
password_as_list = [ int . from_bytes ( cred_blob [ pos : pos + 2 ], ‘little’ ) |
for pos in range ( 0 , cred_blob_size , 2 )] |
password = » . join ( map ( chr , password_as_list )) |
return Credential ( username , password ) |
finally : |
advapi32 . CredFree ( cred_ptr ) |
return None |
def main (): |
result = get_generic_credential ( ‘foobar’ ) |
if result : |
print ( «NAME:» , result . username ) |
print ( «PASSWORD:» , result . password ) |
else : |
print ( ‘No matching credentials found’ ) |
if __name__ == ‘__main__’ : |
main () |
Python – How to Configure Python Keyring to pull credentials from Windows Credential Manager on Windows 7
I’ve spent a lot of time researching the keyring package trying to get a simple example to work. I’m using python 2.7 on a windows 7-x64 machine. I’ve installed the package and confirmed that the files are within my Lib/site-packages folder.
In this code snippet from the installation docs what is supposed to go in «system»?
import keyring keyring.get_password("system", "username")
When I run the code i get the following error:
RuntimeError: No recommended backend was available. Install the keyrings.alt package if you want to use the non-recommended backends.
It seems like it’s not recognizing Windows as the backend. I feel like I’m missing a simple step. Any help is appreciated including a simple code example of pulling generic credentials from Windows Credential Manager.
Best Solution
Finally got this working. The information from Shaun pointed me in the right direction with installing pywin32 . From there I did trial and error with creating test credentials in Windows Credential Manager and testing the Python keyring function.
I only got it working with Generic Credentials which is fine for my purposes. I set Internet or network address to «test» . Username was set to «test_user» . Password was set to «test123» . (Quotes included here for instruction, don’t include when entering them.
print keyring.get_password("test","test_user")
returned the result «test123»
Hopefully this information helps somebody else. Thanks to Shaun for the direction needed to solve this.
Related Solutions
Windows – How to you find out which process is listening on a TCP or UDP port on Windows
New answer, powershell
TCP
Get-Process -Id (Get-NetTCPConnection -LocalPort YourPortNumberHere).OwningProcess
UDP
Get-Process -Id (Get-NetUDPEndpoint -LocalPort YourPortNumberHere).OwningProcess
Old answer, cmd
(Add -n to stop it trying to resolve hostnames, which will make it a lot faster.)
Note Dane’s recommendation for TCPView. It looks very useful!
-a Displays all connections and listening ports.
-b Displays the executable involved in creating each connection or listening port. In some cases well-known executables host multiple independent components, and in these cases the sequence of components involved in creating the connection or listening port is displayed. In this case the executable name is in [] at the bottom, on top is the component it called, and so forth until TCP/IP was reached. Note that this option can be time-consuming and will fail unless you have sufficient permissions.
-n Displays addresses and port numbers in numerical form.
-o Displays the owning process ID associated with each connection.
Python – How to execute a program or call a system command
Use the subprocess module in the standard library:
import subprocess subprocess.run(["ls", "-l"])
The advantage of subprocess.run over os.system is that it is more flexible (you can get the stdout , stderr , the «real» status code, better error handling, etc. ).
Even the documentation for os.system recommends using subprocess instead:
The subprocess module provides more powerful facilities for spawning new processes and retrieving their results; using that module is preferable to using this function. See the Replacing Older Functions with the subprocess Module section in the subprocess documentation for some helpful recipes.
On Python 3.4 and earlier, use subprocess.call instead of .run :