0

I'm trying to test the function described here to get RAS Credentials assocciated with the .pbk file to retrieve the data like username, password and pre-shared key. The reason I am doing this is because I lost my pre-shared key and although I have it saved on my laptop I didn't find another way to retrieve it, but also for educational purposes.

Here is the code I'm trying to run. (this is just a demo code from the documentation, I am aware that I need to point to my .pbk file and entry to make it do what I want:

#include <windows.h>
#include "ras.h"
#include <stdio.h>
#include <tchar.h>
#include "strsafe.h"
//#include "pch.h"

#define PHONE_NUMBER_LENGTH 7
#define DEVICE_NAME_LENGTH 5
#define DEVICE_TYPE_LENGTH 5
#define DOMAIN_NAME_LENGTH 9
#define USER_NAME_LENGTH 11

int __cdecl wmain() {

    DWORD dwRet = ERROR_SUCCESS;
    LPCTSTR lpszEntry = L"RasEntryName";
    LPCTSTR lpszPhoneNumber = L"5555555";
    LPCTSTR lpszDeviceName = L"Modem";
    LPCTSTR lpszDeviceType = RASDT_Modem;
    LPCTSTR lpszDomainName = L"RASDomain";
    LPCTSTR lpszUserName = L"RASUserName";
    /***********************************************************************************************/
    // Create a new phone book entry
    /***********************************************************************************************/

    // Allocate heap memory for the RASENTRY structure
    LPRASENTRY lpentry = (LPRASENTRY)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RASENTRY));
    if (lpentry == NULL) {
        wprintf(L"HeapAlloc failed!\n");
        return 0;
    }
    // The RASENTRY->dwSize member has to be initialized or the RRAS RasValidateEntryName() and 
    // RasSetEntryProperties APIs will fail below.
    lpentry->dwSize = sizeof(RASENTRY);
    lpentry->dwFramingProtocol = RASFP_Ppp;
    lpentry->dwfOptions = 0;
    lpentry->dwType = RASFP_Ppp;
    dwRet |= StringCchCopyN(lpentry->szLocalPhoneNumber, RAS_MaxPhoneNumber, lpszPhoneNumber, PHONE_NUMBER_LENGTH);
    dwRet |= StringCchCopyN(lpentry->szDeviceName, RAS_MaxDeviceName, lpszDeviceName, DEVICE_NAME_LENGTH);
    dwRet |= StringCchCopyN(lpentry->szDeviceType, RAS_MaxDeviceType, lpszDeviceType, DEVICE_TYPE_LENGTH);
    if (dwRet != ERROR_SUCCESS) {
        wprintf(L"RASENTRY structure initilization failed!\n");
        HeapFree(GetProcessHeap(), 0, lpentry);
        return 0;
    }

    // Validate the new entry's name
    dwRet = RasValidateEntryName(NULL, lpszEntry);
    if (dwRet != ERROR_SUCCESS) {
        wprintf(L"RasValidateEntryName failed: Error = %d\n", dwRet);
        HeapFree(GetProcessHeap(), 0, lpentry);
        return 0;
    }

    // Create and set the new entry's properties
    dwRet = RasSetEntryProperties(NULL, lpszEntry, lpentry, lpentry->dwSize, NULL, 0);
    if (dwRet != ERROR_SUCCESS) {
        wprintf(L"RasSetEntryProperties failed: Error = %d\n", dwRet);
        HeapFree(GetProcessHeap(), 0, lpentry);
        return 0;
    }

    /******************************************************************************************/
    // Set and get the new entry's credentials
    /******************************************************************************************/

    // Allocate heap memory for the RASCREDENTIALS structure
    LPRASCREDENTIALS lpCred = (LPRASCREDENTIALS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RASCREDENTIALS));
    if (lpCred == NULL) {
        wprintf(L"HeapAlloc failed!\n");
        return 0;
    }
    // The RASCREDENTIALS->dwsize member must be initialized or the RRAS RasSetCredentials() and 
    // RasGetCredentials() APIs will fail below
    lpCred->dwSize = sizeof(RASCREDENTIALS);

    // The entry's credentials must first be set with RasSetCredentials() before they can be 
    // retrieved with RasGetCredentials(). The values below are used to set the new entry's credentials.
    dwRet |= StringCchCopyN(lpCred->szDomain, DNLEN, lpszDomainName, DOMAIN_NAME_LENGTH);
    dwRet |= StringCchCopyN(lpCred->szUserName, UNLEN, lpszUserName, USER_NAME_LENGTH);
    if (dwRet != ERROR_SUCCESS) {
        wprintf(L"RASCREDENTIALS structure initilization failed!\n");
        HeapFree(GetProcessHeap(), 0, lpCred);
        return 0;
    }
    // The username, password, and Domain credentials are valid
    lpCred->dwMask = RASCM_UserName | RASCM_Password | RASCM_Domain;

    // Set the newly created entry's credentials
    dwRet = RasSetCredentials(NULL, lpszEntry, lpCred, FALSE);

    // The same RASCREDENTIALS structure is used to 'set' and 'get' the credentials. Therefore, zero out 
    // its values. (this proves RasGetCredentials works below!) 
    dwRet |= StringCchCopyN(lpCred->szDomain, DNLEN, L"", 0);
    dwRet |= StringCchCopyN(lpCred->szUserName, UNLEN, L"", 0);
    dwRet |= StringCchCopyN(lpCred->szPassword, UNLEN, L"", 0);
    if (dwRet != ERROR_SUCCESS) {
        wprintf(L"RASCREDENTIALS structure reset failed!\n");
        HeapFree(GetProcessHeap(), 0, lpCred);
        HeapFree(GetProcessHeap(), 0, lpentry);
        return 0;
    }

    // Grab the newly created entry's credentials
    dwRet = RasGetCredentials(NULL, lpszEntry, lpCred);
    if (dwRet == ERROR_SUCCESS) {
        wprintf(L"The following credentials were retrieved for the entry: %s\n\tUser name: %s\n\tPassword: %s\n\tDomain: %s\n", lpszEntry, lpCred->szUserName, lpCred->szPassword, lpCred->szDomain);
    }
    else {
        wprintf(L"RasValidateEntryName failed: Error = %d\n", dwRet);
    }

    // Clean up: delete the new entry
    dwRet = RasDeleteEntry(NULL, lpszEntry);
    if (dwRet != ERROR_SUCCESS) {
        wprintf(L"RasDeleteEntry failed: Error = %d\n", dwRet);
    }

    HeapFree(GetProcessHeap(), 0, lpentry);
    HeapFree(GetProcessHeap(), 0, lpCred);
    return 0;
}

However, I am unable to compile the code above in Visual Studio 2017. Here is the error log:

RasCredentials.obj : error LNK2019: unresolved external symbol _RasSetEntryPropertiesW@24 referenced in function _wmain
RasCredentials.obj : error LNK2019: unresolved external symbol _RasDeleteEntryW@8 referenced in function _wmain
RasCredentials.obj : error LNK2019: unresolved external symbol _RasValidateEntryNameW@8 referenced in function _wmain
RasCredentials.obj : error LNK2019: unresolved external symbol _RasGetCredentialsW@12 referenced in function _wmain
RasCredentials.obj : error LNK2019: unresolved external symbol _RasSetCredentialsW@16 referenced in function _wmain

It's like the compiler doesn't see the RAS library even though I included the ras.h header file.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
user3362334
  • 1,980
  • 3
  • 26
  • 58

1 Answers1

0

I solved the problem by adding Rasapi32.lib to the dependencies. I did so by going to Project - > (Project name) Properties -> Linker -> Input -> Additional Dependencies and added Rasapi32.lib.

However, now I have a problem that the password is displayed as a set of *'s instead of plaintext, I guess the same would be the case for the pre-shared key that I need.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
user3362334
  • 1,980
  • 3
  • 26
  • 58
  • "*the password is displayed as a set of `*`'s instead of plaintext*" - as it should be, and is [documented behavior](https://learn.microsoft.com/en-us/windows/win32/api/ras/nf-ras-rasgetcredentialsw): "***RasGetCredentials does not return the actual password. Instead, the szPassword member of the RASCREDENTIALS structure contains a handle to the saved password**. Substitute this handle for the saved password in subsequent calls to RasSetCredentials and RasDial. When presented with this handle, RasDial retrieves and uses the saved password...*" – Remy Lebeau Oct 01 '19 at 22:58
  • "*.. If the dwMask member specifies that a pre-shared key should be used for the credentials, the szPassword member contains the pre-shared key. **If the RASCREDENTIALS structure is used with RasGetCredentials, the value returned is a handle to the pre-shared key as described in the preceding paragraph**.*" – Remy Lebeau Oct 01 '19 at 23:01
  • So as far as I understand, there is no "official" way to pull out the pre-shared key? Because, as I see it, I can use the handle to set the pre-shared key of another entry, but I cannot print out the pre-shared key? I guess there are hacky ways to do this like targeting a pbk file on another machine on the network when calling RasSetCredentials or use some tool to read the process memory and fetch the password from there. However, I want to make sure that I got it correctly. Is this correct? I'm sorry I'm not really familiar with the c++ and the concept of handles – user3362334 Oct 01 '19 at 23:34
  • "*there is no "official" way to pull out the pre-shared key?*" - correct. The password and pre-shared key are stored privately inside of the RAS entry, you can't extract the actual values manually. – Remy Lebeau Oct 01 '19 at 23:42