Jump to content

Get SeDebug privilege.


Manko
 Share

Recommended Posts

Hi!

Yes it's been done before, but I found a shorter variant and thought it should be documented on this site... :mellow:

Func _GetPrivilege_SeDebug()
    $ret=DllCall("ntdll.dll", "int", "RtlAdjustPrivilege", "int", 20, "int", 1, "int", 0, "int*", 0) ; 20 is SeDebug privilege...
    If @error Then
        SetError( 1, @error, False ) ; 1=error dllcall. Set dllcall-error as extended. Return false.
    Else
        if $ret[0] Then SetError( 2, $ret[0], False) ; 2=error RtlAdjustPrivilege. Set it's errorcode as extended. Return False.
        Return( True ) ; Return true if it worked. (RtlAdjustPrivilege returns 0 if it works.)
    EndIf
EndFunc

Or if you like to code dirty like me...

DllCall("ntdll.dll", "int", "RtlAdjustPrivilege", "int", 20, "int", 1, "int", 0, "int*", 0) ; 20 is SeDebug privilege...

...though in this way you won't know but, at best, indirecly if it failed...

/Manko

Yes i rush things! (I sorta do small bursts inbetween doing nothing.) Things I have rushed and reRushed:* ProDLLer - Process manager - Unload viri modules (dll) and moore...* _WinAPI_ProcessListOWNER_WTS() - Get Processes owner list...* _WinAPI_GetCommandLineFromPID() - Get commandline of target process...* _WinAPI_ThreadsnProcesses() Much info if expanded - optional Indented "Parent/Child"-style Processlist. Moore to come... eventually...
Link to comment
Share on other sites

Yes, it makes me think I ought to excavate those systemfiles on a regular basis...

Great table! :mellow:

/Manko

Yes i rush things! (I sorta do small bursts inbetween doing nothing.) Things I have rushed and reRushed:* ProDLLer - Process manager - Unload viri modules (dll) and moore...* _WinAPI_ProcessListOWNER_WTS() - Get Processes owner list...* _WinAPI_GetCommandLineFromPID() - Get commandline of target process...* _WinAPI_ThreadsnProcesses() Much info if expanded - optional Indented "Parent/Child"-style Processlist. Moore to come... eventually...
Link to comment
Share on other sites

I'm completely tired of studying. :mellow:

My head is full of things boring by nature.

...I think I will do some reversing (for learning purposes) to see what RtlAdjustPrivilege do exactly.

Maybe translate it to AutoIt to see if I'll get it right. That should be interesting.

edit: will post it when I'm done.

Edited by trancexx
Link to comment
Share on other sites

Ok, here goes...

I wrote this:

$hModule = _LoadLibraryEx("ntdll.dll", 0)

$pAddress = _GetAddress($hModule, "RtlAdjustPrivilege")
ConsoleWrite("RtlAdjustPrivilege address = " & $pAddress & @CRLF)

$tByteStructure = DllStructCreate("byte[256]", $pAddress) ; 256 bytes (will see if that's enough)
ConsoleWrite(DllStructGetData($tByteStructure, 1) & @CRLF)





;FUNCTIONS:

Func _LoadLibraryEx($sModule, $iFlag)
    Local $aCall = DllCall("kernel32.dll", "handle", "LoadLibraryExW", "wstr", $sModule, "handle", 0, "dword", $iFlag)
    If @error Then Return SetError(1, @error, 0)
    Return $aCall[0]
EndFunc   ;==>_LoadLibraryEx

Func _GetAddress($hModule, $vFuncName)
    Local $sType = "str"
    If IsNumber($vFuncName) Then $sType = "int" ; if ordinal value passed
    Local $aCall = DllCall("kernel32.dll", "ptr", "GetProcAddress", "handle", $hModule, $sType, $vFuncName)
    If @error Or Not $aCall[0] Then
        Return SetError(1, 0, 0)
    EndIf
    Return $aCall[0]
EndFunc   ;==>_GetAddress

The result on my XP SP3 was:

0x8BFF558BEC83EC30807D1001A1C8E0977C8945FC8B45148945D48D45D8500F842A9D00006A286AFFE8743BFEFF85C07C668B45088945F08A450C33C9F6D856C745EC01000000894DF41BC083E0028945F88D45D0508D45DC506A108D45EC5051FF75D8E83934FEFFFF75D88BF0E80F35FEFF81FE060100000F843701020085F67C12837DDC008B4DD40F85BD0300008A450C88018BC65E8B4DFCE86B63FEFFC9C210000FB7C0EB5790909090908BFF558BEC807D1000568B750C668B06578B7D080F8502250200663B47020F871B2502000FB7166A00D1EA59895508894D10742E538B4604668B04486683F84172B46683F85A0F87DC7C00000FB7C083C0208B

So what's that. That's the code at the address of RtlAdjustPrivilege function.

To make it clearer I went byte by byte and tried to make some sense. The result was this formatted code:

8BFF
55
8BEC
83EC30
807D1001
A1C8E0977C
8945FC
8B4514
8945D4
8D45D8
50
0F842A9D0000
6A28
6AFF
E8743BFEFF
85C0
7C66
8B4508
8945F0
8A450C
33C9
F6D8
56
C745EC01000000
894DF4
1BC0
83E002
8945F8
8D45D0
50
8D45DC
50
6A10
8D45EC
50
51
FF75D8
E83934FEFF
FF75D8
8BF0
E80F35FEFF
81FE06010000
0F8437010200
85F6
7C12
837DDC00
8B4DD4
0F85BD030000
8A450C
8801
8BC6
5E
8B4DFC
E86B63FEFF
C9
C21000
...

Then I added interpretation of the code (and comments) to make it human understandable.

Knowing the definitions (hints):

NTSTATUS RtlAdjustPrivilege(
  IN ULONG                Privilege,
  IN BOOLEAN              Enable,
  IN BOOLEAN              CurrentThread,
  OUT PBOOLEAN            Enabled
  )


NtAdjustPrivilegesToken(
  IN HANDLE               TokenHandle,
  IN BOOLEAN              DisableAllPrivileges,
  IN PTOKEN_PRIVILEGES    TokenPrivileges,
  IN ULONG                PreviousPrivilegesLength,
  OUT PTOKEN_PRIVILEGES   PreviousPrivileges OPTIONAL,
  OUT PULONG              RequiredLength OPTIONAL 
  )


NtOpenProcessToken(
  IN HANDLE               ProcessHandle,
  IN ACCESS_MASK          DesiredAccess,
  OUT PHANDLE             TokenHandle 
  )


NtOpenThreadToken(
  IN HANDLE               ThreadHandle,
  IN ACCESS_MASK          DesiredAccess,
  IN BOOLEAN              OpenAsSelf,
  OUT PHANDLE             TokenHandle 
  )


NTSTATUS NtClose(      
  IN HANDLE               Handle
  )

the result is:

---------
    ; BLOCK 10
    ---------
    8BFF                    mov edi, edi                        ;  --NOT RELEVANT--
    55                      push ebp                            ; save the value of ebp
    8BEC                    mov ebp, esp                        ; ebp now points to the top of the stack
    83EC30                  sub esp, 48d                        ; allocate 48 bytes on the stack
    807D1001                cmp byte[ebp+16d], 1d               ; check byte value 16 bytes "into" the ebp. This is third passed parameter (BOOLEAN CurrentThread).
    A1C8B0977C              mov eax, dword[7C97B0C8]            ;   --NOT RELEVANT--    this is some internal handler stuff. Not relevant for what's shown here.
    8945FC                  mov dword[ebp-4d], eax              ;   --NOT RELEVANT--    set some variable to eax value. Again not relevant here.
    8B4514                  mov eax, dword[ebp+20d]             ; set eax to (PBOOLEAN Enabled) parameter.
    8945D4                  mov dword[ebp-44d], eax             ; set another variable to eax value (PBOOLEAN Enabled).
    8D45D8                  lea eax, dword[ebp-40d]             ; load address to eax (at ebp-40 will obviously be TokenHandle on return of below action)
    50                      push eax                            ; push pointer to buffer - TokenHandle parameter of NtOpenThreadToken/NtOpenProcessToken function
    0F841A9D0000            je 40218d                           ; if (BOOLEAN CurrentThread) = 1 then go forward 40218 bytes ; To BLOCK 80
    6A28                    push 40d                            ; push 40 - DesiredAccess parameter of NtOpenProcessToken function - hardcoded value
    6AFF                    push -1d                            ; push -1 - ProcessHandle parameter of NtOpenProcessToken function - hardcoded value
    E8763BFEFF              call -115850d                       ; call function at 115850 bytes back (NtOpenProcessToken coincidently)
    ---------
    ; BLOCK 20
    ---------
    85C0                    test eax, eax                       ; check eax
    7C66                    jl 102d                             ; if (eax) go forward 102 bytes ; To BLOCK 60
    8B4508                  mov eax, dword[ebp+8d]              ; (ULONG Privilege) parameter
    8945F0                  mov dword[ebp-16d], eax             ; set some dword (at -16) to eax (passed ULONG Privilege)
    8A450C                  mov al, byte[ebp+12d]               ; (BOOLEAN Enable) parameter to al (eax effectively)
    33C9                    xor ecx, ecx                        ; ecx = 0
    F6D8                    neg al                              ; change sign of al (eax effectively)
    56                      push esi                            ; pushing esi (purpose will be shown later)
    C745EC01000000          mov dword[ebp-20d], 1d              ; set some dword (at -20) to 1
    894DF4                  mov dword[ebp-12d], ecx             ; set other dword (at -12) to value of ecx (0)
    1BC0                    sbb eax, eax                        ; subtract with borrow
    83E002                  and eax, 2d                         ; add 2 to eax
    8945F8                  mov dword[ebp-8d], eax              ; set third dword (at -8) to eax value (0 or 2)
    8D45D0                  lea eax, dword[ebp-48d]             ; pointer to some dword space
    50                      push eax                            ; push that pointer - RequiredLength parameter of NtAdjustPrivilegesToken function
    8D45DC                  lea eax, dword[ebp-36d]             ; pointer to some other dword space
    50                      push eax                            ; push that pointer - PreviousPrivileges parameter of NtAdjustPrivilegesToken function
    6A10                    push 16d                            ; push 16 - PreviousPrivilegesLength parameter (hardcoded value) of NtAdjustPrivilegesToken function
    8D45EC                  lea eax, dword[ebp-20d]             ; pointer to some space (structure TOKEN_PRIVILEGES filled above)
    50                      push eax                            ; TokenPrivileges pointer parameter of NtAdjustPrivilegesToken function
    51                      push ecx                            ; push ecx (0) - DisableAllPrivileges parameter of NtAdjustPrivilegesToken function
    FF75D8                  push dword[ebp-40d]                 ; TokenHandle parameter (was stored at ebp-40, remenber?)
    E83B34FEFF              call -117701d                       ; call function at 117701 bytes back (NtAdjustPrivilegesToken)
    FF75D8                  push dword[ebp-40d]                 ; again push token handle
    8BF0                    mov esi, eax                        ; save the value of eax to esi. This is why esi was pushed. eax is return value of NtAdjustPrivilegesToken function.
    E81135FEFF              call -117487d                       ; call function at 117487 bytes back (NtClose)
    81FE06010000            cmp esi, 262d                       ; check if NtAdjustPrivilegesToken returned 262 (obviously some special situation)
    0F8427E30100            je 123687d                          ; if for some reason it's 262 then jump forward 123687 bytes ; To BLOCK 90
    ---------
    ; BLOCK 30
    ---------
    85F6                    test esi, esi                       ; check esi
    7C12                    jl 18d                              ; if (esi) then jump forward 18 bytes ; To BLOCK 50
    837DDC00                cmp dword[ebp-36d], 0d              ; check the value of byref-ed PreviousPrivileges value
    8B4DD4                  mov ecx, dword[ebp-44d]             ; set ecx to value at (PBOOLEAN Enabled) parameter - using that variable from the beginning.
    0F85BD030000            jne 957d                            ; if PreviousPrivileges is NOT 0 then jump forward 957 bytes ; To BLOCK 70
    8A450C                  mov al, byte[ebp+12d]               ; set al to (BOOLEAN Enable) parameter
    ---------
    ; BLOCK 40
    ---------
    8801                    mov byte[ecx], al                   ; set boolean at ecx (PBOOLEAN Enabled) to al (BOOLEAN Enable)
    ---------
    ; BLOCK 50
    ---------
    8BC6                    mov eax, esi                        ; set eax to esi
    5E                      pop esi                             ; pop
    ---------
    ; BLOCK 60
    ---------
    8B4DFC                  mov ecx, dword[ebp-4d]              ;   --NOT RELEVANT--  set ecx to the variable from the beginning
    E86B63FEFF              call -105621d                       ;   --NOT RELEVANT--
    C9                      leave                               ; set esp to ebp, then pop ebp (opposite from when the function was starting)
    C21000                  ret 16d                             ; return and clear 16 bytes off the stack
    ---------




    ---------
    ; BLOCK 70
    ---------
    8B45E8                  mov eax, dword[ebp-24d]             ; set eax to value at ebp-24
    D1E8                    shr eax, 1d                         ; shift right (eax, 1)
    2401                    and al, 1d                          ; and (al, 1)
    E93AFCFFFF              jmp -966d                           ; jump 966 bytes back ; To BLOCK 40


    ---------
    ; BLOCK 80
    ---------
    6A00                    push 0d                             ; push 0 - OpenAsSelf parameter of NtOpenThreadToken function - hardcoded value
    6A28                    push 40d                            ; push 40 - DesiredAccess parameter of NtOpenThreadToken function - hardcoded value
    6AFE                    push -2d                            ; push -2 - ThreadHandle parameter of NtOpenThreadToken function - hardcoded value
    E8BA9EFDFF              call -155974d                       ; call function at 155974 bytes back (NtOpenThreadToken)
    E9DF62FFFF              jmp -40225d                         ; jump 40225 bytes back ; To BLOCK 20


    ---------
    ; BLOCK 90
    ---------
    BE610000C0              mov esi, C0000061                   ; set esi to value of  0xC0000061 (STATUS_PRIVILEGE_NOT_HELD)
    E9CF1CFEFF              jmp -123697d                        ; jump 123697 bytes back ; To BLOCK 30

Obviously I had to use calculator to see what's at jumped/called addresses (used functions).

Basically RtlAdjustPrivilege is wrapper function. It calls few other Nt... functions to do the job. Just like AutoIt's UDFs.

Translated to Autoit (literally) it would be:

Func _RtlAdjustPrivilege($iPrivilege, $fEnable, $fCurrentThread, ByRef $fPreviouslyTheSame)

    Local $aCall, $hTokenHandle

    If $fCurrentThread Then
        $aCall = DllCall("ntdll.dll", "long", "NtOpenThreadToken", _
                "handle", -2, _ ; ThreadHandle - hardcoded value
                "dword", 40, _ ; DesiredAccess - hardcoded value
                "boolean", 0, _ ; OpenAsSelf - hardcoded value
                "handle*", 0) ; TokenHandle to collect to
        If @error Or $aCall[0] Then
            Return SetError(1, 0, -1)
        EndIf
        $hTokenHandle = $aCall[4]
    Else
        $aCall = DllCall("ntdll.dll", "long", "NtOpenProcessToken", _
                "handle", -1, _ ; ProcessHandle - hardcoded value
                "dword", 40, _ ; DesiredAccess - hardcoded value
                "handle*", 0) ; TokenHandle to collect to
        If @error Or $aCall[0] Then
            Return SetError(1, 0, -1)
        EndIf
        $hTokenHandle = $aCall[3]
    EndIf

    #cs
        typedef struct _LUID {
        DWORD LowPart;
        LONG  HighPart;
        } LUID, *PLUID;
        
        typedef struct _LUID_AND_ATTRIBUTES {
        LUID  Luid;
        DWORD Attributes;
        } LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES;
        
        typedef struct _TOKEN_PRIVILEGES {
        DWORD               PrivilegeCount;
        LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];
        } TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
    #ce

    Local $tTOKEN_PRIVILEGES = DllStructCreate("dword PrivilegeCount;" & _
            "dword LowPart;" & _ ;...from LUID structure........; from LUID_AND_ATTRIBUTES structure
            "long HighPart;" & _ ;...from LUID structure........; from LUID_AND_ATTRIBUTES structure
            "dword Attributes;") ;..............................; from LUID_AND_ATTRIBUTES structure
    DllStructSetData($tTOKEN_PRIVILEGES, "PrivilegeCount", 1) ; - hardcoded value
    DllStructSetData($tTOKEN_PRIVILEGES, "LowPart", $iPrivilege)
    DllStructSetData($tTOKEN_PRIVILEGES, "HighPart", 0) ; - hardcoded value
    If $fEnable Then
        DllStructSetData($tTOKEN_PRIVILEGES, "Attributes", 2)
    Else
        DllStructSetData($tTOKEN_PRIVILEGES, "Attributes", 0) ; this is redundant in AutoIt but still...
    EndIf

    $aCall = DllCall("ntdll.dll", "long", "NtAdjustPrivilegesToken", _
            "handle", $hTokenHandle, _ ; TokenHandle
            "boolean", 0, _ ; DisableAllPrivileges
            "ptr", DllStructGetPtr($tTOKEN_PRIVILEGES), _ ; TokenPrivileges
            "dword", 16, _ ; PreviousPrivilegesLength - hardcoded value
            "dword*", 0, _ ; PreviousPrivileges
            "dword*", 0) ; RequiredLength

    DllCall("ntdll.dll", "long", "NtClose", "handle", $hTokenHandle) ; close TokenHandle

    If $aCall[0] = 262 Then
        Return SetError(2, 0, -1)
    EndIf

    $fPreviouslyTheSame = Not $aCall[5]

EndFunc   ;==>_RtlAdjustPrivilege

Cool function that RtlAdjustPrivilege.

AutoIt code can be tested like this (you need some tool to monitor privileges status):

Global $fPreviouslyTheSame
_RtlAdjustPrivilege(20, 0, 0, $fPreviouslyTheSame)
ConsoleWrite("- " & $fPreviouslyTheSame & @CRLF)
MsgBox(0, '', $fPreviouslyTheSame)

_RtlAdjustPrivilege(20, 1, 0, $fPreviouslyTheSame)
ConsoleWrite("- " & $fPreviouslyTheSame & @CRLF)
MsgBox(0, '', $fPreviouslyTheSame)
_RtlAdjustPrivilege(20, 1, 0, $fPreviouslyTheSame)
ConsoleWrite("- " & $fPreviouslyTheSame & @CRLF)
MsgBox(0, '', $fPreviouslyTheSame)

_RtlAdjustPrivilege(20, 0, 0, $fPreviouslyTheSame)
ConsoleWrite("- " & $fPreviouslyTheSame & @CRLF)
MsgBox(0, '', $fPreviouslyTheSame)
_RtlAdjustPrivilege(20, 0, 0, $fPreviouslyTheSame)
ConsoleWrite("- " & $fPreviouslyTheSame & @CRLF)
MsgBox(0, '', $fPreviouslyTheSame)

MsgBox(0, '', $fPreviouslyTheSame)



Func _RtlAdjustPrivilege($iPrivilege, $fEnable, $fCurrentThread, ByRef $fPreviouslyTheSame)

    Local $aCall, $hTokenHandle

    If $fCurrentThread Then
        $aCall = DllCall("ntdll.dll", "long", "NtOpenThreadToken", _
                "handle", -2, _ ; ThreadHandle
                "dword", 40, _ ; DesiredAccess
                "boolean", 0, _ ; OpenAsSelf
                "handle*", 0)
        If @error Or $aCall[0] Then
            Return SetError(1, 0, -1)
        EndIf
        $hTokenHandle = $aCall[4]
    Else
        $aCall = DllCall("ntdll.dll", "long", "NtOpenProcessToken", _
                "handle", -1, _ ; ProcessHandle
                "dword", 40, _ ; DesiredAccess 
                "handle*", 0) 
        If @error Or $aCall[0] Then
            Return SetError(1, 0, -1)
        EndIf
        $hTokenHandle = $aCall[3]
    EndIf

    Local $tTOKEN_PRIVILEGES = DllStructCreate("dword PrivilegeCount;" & _
            "dword LowPart;" & _ 
            "long HighPart;" & _ 
            "dword Attributes;") 
    DllStructSetData($tTOKEN_PRIVILEGES, "PrivilegeCount", 1) ; - hardcoded value
    DllStructSetData($tTOKEN_PRIVILEGES, "LowPart", $iPrivilege)
    If $fEnable Then DllStructSetData($tTOKEN_PRIVILEGES, "Attributes", 2)
    
    $aCall = DllCall("ntdll.dll", "long", "NtAdjustPrivilegesToken", _
            "handle", $hTokenHandle, _ ; TokenHandle
            "boolean", 0, _ ; DisableAllPrivileges
            "ptr", DllStructGetPtr($tTOKEN_PRIVILEGES), _ ; TokenPrivileges
            "dword", 16, _ ; PreviousPrivilegesLength - hardcoded value
            "dword*", 0, _ ; PreviousPrivileges
            "dword*", 0) ; RequiredLength

    DllCall("ntdll.dll", "long", "NtClose", "handle", $hTokenHandle) ; close TokenHandle

    If $aCall[0] = 262 Then
        Return SetError(2, 0, -1)
    EndIf

    $fPreviouslyTheSame = Not $aCall[5]

EndFunc   ;==>_RtlAdjustPrivilege

Btw, this shows for example that NtAdjustPrivilegesToken description is somewhere wrong.

Word on:

neg al
sbb eax, eax
and eax, 2d

That's basically (plus irrelevant BitShift):

If $eax Then
    $eax = 2
Else
    $eax = 0
EndIf
Edited by trancexx
Link to comment
Share on other sites

Here's the function I've had around for a while. It's included in some of my UDFs, I guess I never posted the whole thing though:

; #FUNCTION# ;===============================================================================
;
; Name...........: _GetPrivilege_SEDEBUG
; Description ...: Obtains the SE_DEBUG privilege for the running process
; Syntax.........: _GetPrivilege_SEDEBUG()
; Parameters ....:
; Return values .: Success - Returns True
;                  Failure - Returns False and Sets @Error to 1
; Author ........: Erik Pilsits
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........;
; Example .......;
;
; ;==========================================================================================
Func _GetPrivilege_SEDEBUG()
    Local $return = False
    Local $tagLUIDANDATTRIB = "int64 Luid;dword Attributes"
    Local $count = 1
    Local $tagTOKENPRIVILEGES = "dword PrivilegeCount;byte LUIDandATTRIB[" & $count * 12 & "]" ; count of LUID structs * sizeof LUID struct
    Local $TOKEN_ADJUST_PRIVILEGES = 0x20
    Local $SE_PRIVILEGE_ENABLED = 0x2
    Local $curProc = DllCall("kernel32.dll", "ptr", "GetCurrentProcess")
    If @error Then Return False
    Local $call = DllCall("advapi32.dll", "int", "OpenProcessToken", "ptr", $curProc[0], "dword", $TOKEN_ADJUST_PRIVILEGES, "ptr*", 0)
    If (@error Or (Not $call[0])) Then Return False
    Local $hToken = $call[3]
    $call = DllCall("advapi32.dll", "int", "LookupPrivilegeValue", "ptr", 0, "str", "SeDebugPrivilege", "int64*", 0)
    If ((Not @error) And $call[0]) Then
        Local $iLuid = $call[3]
        Local $TP = DllStructCreate($tagTOKENPRIVILEGES)
        Local $LUID = DllStructCreate($tagLUIDANDATTRIB, DllStructGetPtr($TP, "LUIDandATTRIB"))
        DllStructSetData($TP, "PrivilegeCount", $count)
        DllStructSetData($LUID, "Luid", $iLuid)
        DllStructSetData($LUID, "Attributes", $SE_PRIVILEGE_ENABLED)
        $call = DllCall("advapi32.dll", "int", "AdjustTokenPrivileges", "ptr", $hToken, "int", 0, "ptr", DllStructGetPtr($TP), "dword", 0, "ptr", 0, "ptr", 0)
        If Not @error Then $return = ($call[0] <> 0) ; $call[0] <> 0 is success
    EndIf
    DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $hToken)
    Return SetError(Number(Not $return), 0, $return)
EndFunc   ;==>_GetPrivilege_SEDEBUG

And here's the site where I got the table I posted above. It also somewhat explains what RtlAdjustPrivilege is doing (thought not nearly as well as your writeup):

http://forum.sysinternals.com/forum_posts.asp?TID=15745

Edited by wraithdu
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...