Hi,

On Wed, Jun 19, 2024 at 10:48 AM Lev Stipakov <lstipa...@gmail.com> wrote:

> At the moment everyone but anonymous are permitted
> to create a pipe with the same name as interactive service creates,
> which makes it possible for malicious process with SeImpersonatePrivilege
> impersonate as local user.
>
> This hardens the security of the pipe, making it possible only for
> processes running as SYSTEM (such as interactive service) create the
> pipe with the same name.
>
> While on it, replace EXPLICIT_ACCESS structures with SDDL string.
>
> CVE: 2024-4877
>
> Change-Id: I35e783b79a332d247606e05a39e41b4d35d39b5d
> Reported by: Zeze with TeamT5 <zez...@gmail.com>
> Signed-off-by: Lev Stipakov <l...@openvpn.net>
> ---
>  v3:
>   - rebase on top of master (replace openvpn_snprintf with snprintf)
>

It's swprintf :)


>  v2:
>   - ensure that sd is freed even if pipe creation failed
>   - added Reported-By
>
>  src/openvpnserv/interactive.c | 81 +++++++++++++----------------------
>  1 file changed, 29 insertions(+), 52 deletions(-)
>
> diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c
> index 294db00a..f06802de 100644
> --- a/src/openvpnserv/interactive.c
> +++ b/src/openvpnserv/interactive.c
> @@ -2140,73 +2140,50 @@ ServiceCtrlInteractive(DWORD ctrl_code, DWORD
> event, LPVOID data, LPVOID ctx)
>  static HANDLE
>  CreateClientPipeInstance(VOID)
>  {
> -    TCHAR pipe_name[256]; /* The entire pipe name string can be up to 256
> characters long according to MSDN. */
> -    HANDLE pipe = NULL;
> -    PACL old_dacl, new_dacl;
> -    PSECURITY_DESCRIPTOR sd;
> -    static EXPLICIT_ACCESS ea[2];
> -    static BOOL initialized = FALSE;
> -    DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
> +    /*
> +     * allow all access for local system
> +     * deny FILE_CREATE_PIPE_INSTANCE for everyone
> +     * allow read/write for authenticated users
> +     * deny all access to anonymous
> +     */
> +    const TCHAR *sddlString =
> TEXT("D:(A;OICI;GA;;;S-1-5-18)(D;OICI;0x4;;;S-1-1-0)(A;OICI;GRGW;;;S-1-5-11)(D;;GA;;;S-1-5-7)");
>
> -    if (!initialized)
> +    PSECURITY_DESCRIPTOR sd = NULL;
> +    if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString,
> SDDL_REVISION_1, &sd, NULL))
>      {
> -        PSID everyone, anonymous;
> -
> -        ConvertStringSidToSid(TEXT("S-1-1-0"), &everyone);
> -        ConvertStringSidToSid(TEXT("S-1-5-7"), &anonymous);
> +        MsgToEventLog(M_SYSERR,
> TEXT("ConvertStringSecurityDescriptorToSecurityDescriptor failed."));
> +        return INVALID_HANDLE_VALUE;
> +    }
>
> -        ea[0].grfAccessPermissions = FILE_GENERIC_WRITE;
> -        ea[0].grfAccessMode = GRANT_ACCESS;
> -        ea[0].grfInheritance = NO_INHERITANCE;
> -        ea[0].Trustee.pMultipleTrustee = NULL;
> -        ea[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
> -        ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
> -        ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
> -        ea[0].Trustee.ptstrName = (LPTSTR) everyone;
> +    /* Set up SECURITY_ATTRIBUTES */
> +    SECURITY_ATTRIBUTES sa = {0};
> +    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
> +    sa.lpSecurityDescriptor = sd;
> +    sa.bInheritHandle = FALSE;
>
> -        ea[1].grfAccessPermissions = 0;
> -        ea[1].grfAccessMode = REVOKE_ACCESS;
> -        ea[1].grfInheritance = NO_INHERITANCE;
> -        ea[1].Trustee.pMultipleTrustee = NULL;
> -        ea[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
> -        ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
> -        ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
> -        ea[1].Trustee.ptstrName = (LPTSTR) anonymous;
> +    DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
>
> +    static BOOL first = TRUE;
> +    if (first)
> +    {
>          flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
> -        initialized = TRUE;
> +        first = FALSE;
>      }
>
> +    TCHAR pipe_name[256]; /* The entire pipe name string can be up to 256
> characters long according to MSDN. */
>      swprintf(pipe_name, _countof(pipe_name), TEXT("\\\\.\\pipe\\" PACKAGE
> "%ls\\service"), service_instance);
> -    pipe = CreateNamedPipe(pipe_name, flags,
> -                           PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE |
> PIPE_REJECT_REMOTE_CLIENTS,
> -                           PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, NULL);
> +    HANDLE pipe = CreateNamedPipe(pipe_name, flags,
> +                                  PIPE_TYPE_MESSAGE |
> PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
> +                                  PIPE_UNLIMITED_INSTANCES, 1024, 1024,
> 0, &sa);
> +
> +    LocalFree(sd);
> +
>      if (pipe == INVALID_HANDLE_VALUE)
>      {
>          MsgToEventLog(M_SYSERR, TEXT("Could not create named pipe"));
>          return INVALID_HANDLE_VALUE;
>      }
>
> -    if (GetSecurityInfo(pipe, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
> -                        NULL, NULL, &old_dacl, NULL, &sd) !=
> ERROR_SUCCESS)
> -    {
> -        MsgToEventLog(M_SYSERR, TEXT("Could not get pipe security info"));
> -        return CloseHandleEx(&pipe);
> -    }
> -
> -    if (SetEntriesInAcl(2, ea, old_dacl, &new_dacl) != ERROR_SUCCESS)
> -    {
> -        MsgToEventLog(M_SYSERR, TEXT("Could not set entries in new acl"));
> -        return CloseHandleEx(&pipe);
> -    }
> -
> -    if (SetSecurityInfo(pipe, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
> -                        NULL, NULL, new_dacl, NULL) != ERROR_SUCCESS)
> -    {
> -        MsgToEventLog(M_SYSERR, TEXT("Could not set pipe security info"));
> -        return CloseHandleEx(&pipe);
> -    }
> -
>      return pipe;
>  }
>
> --
> 2.42.0.windows.2
>

The only change from the 2.6 version is openvpn_swprintf -> swprintf.
I did not retest the build or executable, but looks good to me based on 2.6
tests.

Acked-by: Selva Nair <selva.n...@gmail.com>
_______________________________________________
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to