-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Swapnil
committed
Jul 28, 2022
0 parents
commit a1ad6b1
Showing
7 changed files
with
683 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2022 FourCore | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
# wintoken | ||
Windows Token Manipulation GOlang Library | ||
|
||
Wintoken abstracts away windows token manipulation functions with functions you are more likely to use. The library exposes easy-to-use functions to steal tokens, enable/disable privileges, and grab interactive and linked tokens. | ||
|
||
## Install | ||
|
||
- Go | ||
- Requires Go to be installed on system. Tested on Go1.16+. | ||
- `go get github.com/fourcorelabs/wintoken` | ||
|
||
## Usage | ||
- To steal a token from a process, you can use OpenProcessToken and supply the PID and the type of token that you want | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"os/exec" | ||
"syscall" | ||
|
||
"github.com/fourcorelabs/wintoken" | ||
) | ||
|
||
func main() { | ||
token, err := wintoken.OpenProcessToken(1234, wintoken.TokenPrimary) //pass 0 for own process | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer token.Close() | ||
|
||
//Now you can use the token anywhere you would like | ||
cmd := exec.Command("/path/to/binary") | ||
cmd.SysProcAttr = &syscall.SysProcAttr{Token: syscall.Token(token.Token())} | ||
} | ||
``` | ||
|
||
- If you want the elevated interactive token for the currently logged in user, you can call GetInteractiveToken with TokenLinked as parameter | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"os/exec" | ||
"syscall" | ||
|
||
"github.com/fourcorelabs/wintoken" | ||
) | ||
|
||
func main() { | ||
//You can get an interactive token(if you are running as a service) | ||
//and specify that you want the linked token(elevated) in the same line | ||
token, err := wintoken.GetInteractiveToken(wintoken.TokenLinked) | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer token.Close() | ||
|
||
//Now you can use the token anywhere you would like | ||
cmd := exec.Command("/path/to/binary") | ||
cmd.SysProcAttr = &syscall.SysProcAttr{Token: syscall.Token(token.Token())} | ||
} | ||
``` | ||
|
||
- Once you have a token, you can query information from this token such as its privileges, integrity levels, associated user details, etc. | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/fourcorelabs/wintoken" | ||
) | ||
|
||
func main() { | ||
token, err := wintoken.OpenProcessToken(1234, wintoken.TokenPrimary) | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer token.Close() | ||
|
||
fmt.Println(token.GetPrivileges()) | ||
fmt.Println(token.GetIntegrityLevel()) | ||
fmt.Println(token.UserDetails()) | ||
} | ||
``` | ||
|
||
- You can Enable, Disable, and Remove privileges in a simple manner | ||
|
||
```go | ||
package main | ||
|
||
import( | ||
"github.com/fourcorelabs/wintoken" | ||
) | ||
|
||
func main(){ | ||
token, err := wintoken.OpenProcessToken(1234, wintoken.TokenPrimary) | ||
if err != nil { | ||
panic(err) | ||
} | ||
//Enable, Disable, or Remove privileges in one line | ||
token.EnableAllPrivileges() | ||
token.DisableTokenPrivileges([]string{"SeShutdownPrivilege", "SeTimeZonePrivilege"}) | ||
token.RemoveTokenPrivilege("SeUndockPrivilege") | ||
} | ||
``` |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
package wintoken | ||
|
||
import ( | ||
"fmt" | ||
"unsafe" | ||
|
||
"golang.org/x/sys/windows" | ||
) | ||
|
||
const ( | ||
WTS_CURRENT_SERVER_HANDLE windows.Handle = 0 | ||
) | ||
|
||
//Open Process Token using PID, pass 0 as PID for self token | ||
func OpenProcessToken(pid int, tokenType tokenType) (*Token, error) { | ||
var ( | ||
t windows.Token | ||
duplicatedToken windows.Token | ||
procHandle windows.Handle | ||
err error | ||
) | ||
|
||
if pid == 0 { | ||
procHandle = windows.CurrentProcess() | ||
} else { | ||
procHandle, err = windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, uint32(pid)) | ||
} | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if err = windows.OpenProcessToken(procHandle, windows.TOKEN_ALL_ACCESS, &t); err != nil { | ||
return nil, err | ||
} | ||
|
||
defer windows.CloseHandle(windows.Handle(t)) | ||
|
||
switch tokenType { | ||
case TokenPrimary: | ||
if err := windows.DuplicateTokenEx(t, windows.MAXIMUM_ALLOWED, nil, windows.SecurityDelegation, windows.TokenPrimary, &duplicatedToken); err != nil { | ||
return nil, fmt.Errorf("error while DuplicateTokenEx: %w", err) | ||
} | ||
case TokenImpersonation: | ||
if err := windows.DuplicateTokenEx(t, windows.MAXIMUM_ALLOWED, nil, windows.SecurityImpersonation, windows.TokenImpersonation, &duplicatedToken); err != nil { | ||
return nil, fmt.Errorf("error while DuplicateTokenEx: %w", err) | ||
} | ||
|
||
case TokenLinked: | ||
if err := windows.DuplicateTokenEx(t, windows.MAXIMUM_ALLOWED, nil, windows.SecurityDelegation, windows.TokenPrimary, &duplicatedToken); err != nil { | ||
return nil, fmt.Errorf("error while DuplicateTokenEx: %w", err) | ||
} | ||
dt, err := duplicatedToken.GetLinkedToken() | ||
windows.CloseHandle(windows.Handle(duplicatedToken)) | ||
if err != nil { | ||
return nil, fmt.Errorf("error while getting LinkedToken: %w", err) | ||
} | ||
duplicatedToken = dt | ||
} | ||
|
||
return &Token{token: duplicatedToken, typ: tokenType}, nil | ||
} | ||
|
||
// Get the Interactive token associated with current logged in user | ||
func GetInteractiveToken(tokenType tokenType) (*Token, error) { | ||
|
||
switch tokenType { | ||
case TokenPrimary, TokenImpersonation, TokenLinked: | ||
default: | ||
return nil, ErrOnlyPrimaryImpersonationTokenAllowed | ||
} | ||
|
||
var ( | ||
sessionPointer uintptr | ||
sessionCount uint32 | ||
interactiveToken windows.Token | ||
duplicatedToken windows.Token | ||
sessionID uint32 | ||
) | ||
|
||
err := windows.WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, (**windows.WTS_SESSION_INFO)(unsafe.Pointer(&sessionPointer)), &sessionCount) | ||
if err != nil { | ||
return nil, fmt.Errorf("error while enumerating sessions: %v", err) | ||
} | ||
defer windows.WTSFreeMemory(sessionPointer) | ||
|
||
sessions := make([]*windows.WTS_SESSION_INFO, sessionCount) | ||
size := unsafe.Sizeof(windows.WTS_SESSION_INFO{}) | ||
|
||
for i := range sessions { | ||
sessions[i] = (*windows.WTS_SESSION_INFO)(unsafe.Pointer(sessionPointer + (size * uintptr(i)))) | ||
} | ||
|
||
for i := range sessions { | ||
if sessions[i].State == windows.WTSActive { | ||
sessionID = sessions[i].SessionID | ||
break | ||
} | ||
} | ||
if sessionID == 0 { | ||
return nil, ErrNoActiveSession | ||
} | ||
|
||
if err := windows.WTSQueryUserToken(sessionID, &interactiveToken); err != nil { | ||
return nil, fmt.Errorf("error while WTSQueryUserToken: %w", err) | ||
} | ||
|
||
defer windows.CloseHandle(windows.Handle(interactiveToken)) | ||
|
||
switch tokenType { | ||
case TokenPrimary: | ||
if err := windows.DuplicateTokenEx(interactiveToken, windows.MAXIMUM_ALLOWED, nil, windows.SecurityDelegation, windows.TokenPrimary, &duplicatedToken); err != nil { | ||
return nil, fmt.Errorf("error while DuplicateTokenEx: %w", err) | ||
} | ||
case TokenImpersonation: | ||
if err := windows.DuplicateTokenEx(interactiveToken, windows.MAXIMUM_ALLOWED, nil, windows.SecurityImpersonation, windows.TokenImpersonation, &duplicatedToken); err != nil { | ||
return nil, fmt.Errorf("error while DuplicateTokenEx: %w", err) | ||
} | ||
case TokenLinked: | ||
if err := windows.DuplicateTokenEx(interactiveToken, windows.MAXIMUM_ALLOWED, nil, windows.SecurityDelegation, windows.TokenPrimary, &duplicatedToken); err != nil { | ||
return nil, fmt.Errorf("error while DuplicateTokenEx: %w", err) | ||
} | ||
dt, err := duplicatedToken.GetLinkedToken() | ||
windows.CloseHandle(windows.Handle(duplicatedToken)) | ||
if err != nil { | ||
return nil, fmt.Errorf("error while getting LinkedToken: %w", err) | ||
} | ||
duplicatedToken = dt | ||
} | ||
|
||
if windows.Handle(duplicatedToken) == windows.InvalidHandle { | ||
return nil, ErrInvalidDuplicatedToken | ||
} | ||
|
||
return &Token{typ: tokenType, token: duplicatedToken}, nil | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module github.com/fourcorelabs/wintoken | ||
|
||
go 1.16 | ||
|
||
require golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= | ||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package wintoken | ||
|
||
import "fmt" | ||
|
||
var ( | ||
ErrNoActiveSession error = fmt.Errorf("no active session found") | ||
ErrInvalidDuplicatedToken error = fmt.Errorf("invalid duplicated token") | ||
ErrOnlyPrimaryImpersonationTokenAllowed error = fmt.Errorf("only primary or impersonation token types allowed") | ||
ErrNoPrivilegesSpecified error = fmt.Errorf("no privileges specified") | ||
ErrTokenClosed error = fmt.Errorf("token has been closed") | ||
) |
Oops, something went wrong.