mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-08 01:38:17 -10:00
Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3429f5f88 | ||
|
|
04d8d2aac7 | ||
|
|
b71759f3b2 | ||
|
|
13c68a7f50 | ||
|
|
1f894f50ff | ||
|
|
33ea66de58 | ||
|
|
9a432f583d | ||
|
|
cbcd948c83 | ||
|
|
2ada8bf8ed | ||
|
|
02a4657d14 | ||
|
|
b7cef9a07c | ||
|
|
49606ba753 | ||
|
|
116431a049 |
No files matched your search
+82
-24
@@ -1,3 +1,12 @@
|
||||
#
|
||||
# For production:
|
||||
# docker build --target production -t sliver .
|
||||
# docker run -it --rm -v $HOME/.sliver:/home/sliver/.sliver sliver
|
||||
#
|
||||
# For unit testing:
|
||||
# docker build --target test .
|
||||
#
|
||||
|
||||
# STAGE: base
|
||||
## Compiles Sliver for use
|
||||
FROM --platform=linux/amd64 golang:1.21.4 as base
|
||||
@@ -22,25 +31,10 @@ RUN cp -vv sliver-server /opt/sliver-server
|
||||
## Use `--target test` in the docker build command to run this stage
|
||||
FROM --platform=linux/amd64 base as test
|
||||
|
||||
### Install testing packages
|
||||
RUN apt-get update --fix-missing && apt-get -y install \
|
||||
libxml2 libxml2-dev libxslt-dev locate curl \
|
||||
libreadline6-dev libcurl4-openssl-dev git-core \
|
||||
libssl-dev libyaml-dev openssl autoconf libtool \
|
||||
ncurses-dev bison curl xsel postgresql \
|
||||
postgresql-contrib postgresql-client libpq-dev \
|
||||
libapr1 libaprutil1 libsvn1 \
|
||||
libpcap-dev libsqlite3-dev libgmp3-dev \
|
||||
mingw-w64 binutils-mingw-w64 g++-mingw-w64 \
|
||||
nasm gcc-multilib
|
||||
|
||||
### Install MSF for testing
|
||||
RUN curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall \
|
||||
&& chmod 755 msfinstall \
|
||||
&& ./msfinstall
|
||||
RUN mkdir -p ~/.msf4/ \
|
||||
&& touch ~/.msf4/initial_setup_complete \
|
||||
&& su -l sliver -c 'mkdir -p ~/.msf4/ && touch ~/.msf4/initial_setup_complete'
|
||||
RUN apt-get update --fix-missing \
|
||||
&& apt-get -y upgrade \
|
||||
&& apt-get -y install \
|
||||
curl gcc-multilib build-essential mingw-w64 binutils-mingw-w64 g++-mingw-w64
|
||||
|
||||
RUN /opt/sliver-server unpack --force
|
||||
|
||||
@@ -51,17 +45,81 @@ RUN /go/src/github.com/bishopfox/sliver/go-tests.sh
|
||||
## Final dockerized form of Sliver
|
||||
FROM --platform=linux/amd64 debian:bookworm-slim as production
|
||||
|
||||
### Install production packages
|
||||
RUN apt-get update --fix-missing \
|
||||
&& apt-get -y upgrade \
|
||||
&& apt-get -y install \
|
||||
libxml2 libxml2-dev libxslt-dev locate gnupg \
|
||||
libreadline6-dev libcurl4-openssl-dev git-core \
|
||||
libssl-dev libyaml-dev openssl autoconf libtool \
|
||||
ncurses-dev bison curl xsel postgresql \
|
||||
postgresql-contrib postgresql-client libpq-dev \
|
||||
curl libapr1 libaprutil1 libsvn1 \
|
||||
libpcap-dev libsqlite3-dev libgmp3-dev \
|
||||
mingw-w64 binutils-mingw-w64 g++-mingw-w64 \
|
||||
nasm gcc-multilib
|
||||
|
||||
### Install MSF for stager generation
|
||||
RUN curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall \
|
||||
&& chmod 755 msfinstall \
|
||||
&& ./msfinstall \
|
||||
&& mkdir -p ~/.msf4/ \
|
||||
&& touch ~/.msf4/initial_setup_complete
|
||||
|
||||
### Cleanup unneeded packages
|
||||
RUN apt-get remove -y curl gnupg \
|
||||
&& apt-get autoremove -y \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
### Add sliver user
|
||||
RUN groupadd -g 999 sliver \
|
||||
&& useradd -r -u 999 -g sliver sliver \
|
||||
&& mkdir -p /home/sliver/ \
|
||||
&& chown -R sliver:sliver /home/sliver \
|
||||
&& su -l sliver -c 'mkdir -p ~/.msf4/ && touch ~/.msf4/initial_setup_complete'
|
||||
|
||||
### Copy compiled binary
|
||||
COPY --from=base /opt/sliver-server /opt/sliver-server
|
||||
|
||||
### Add sliver user
|
||||
RUN groupadd -g 999 sliver && useradd -r -u 999 -g sliver sliver
|
||||
RUN mkdir -p /home/sliver/ && chown -R sliver:sliver /home/sliver
|
||||
|
||||
### Unpack Sliver:
|
||||
USER sliver
|
||||
RUN /opt/sliver-server unpack --force
|
||||
|
||||
WORKDIR /home/sliver/
|
||||
VOLUME [ "/home/sliver/.sliver" ]
|
||||
ENTRYPOINT [ "/opt/sliver-server" ]
|
||||
|
||||
|
||||
# STAGE: production-slim (about 1Gb smaller)
|
||||
### Slim production image, i.e. without MSF and assoicated libraries
|
||||
### Still include GCC and MinGW for cross-platform generation
|
||||
FROM --platform=linux/amd64 debian:bookworm-slim as production-slim
|
||||
|
||||
### Install production packages
|
||||
RUN apt-get update --fix-missing \
|
||||
&& apt-get -y upgrade \
|
||||
&& apt-get -y install \
|
||||
build-essential mingw-w64 binutils-mingw-w64 g++-mingw-w64 gcc-multilib
|
||||
|
||||
### Cleanup unneeded packages
|
||||
RUN apt-get autoremove -y \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
### Add sliver user
|
||||
RUN groupadd -g 999 sliver \
|
||||
&& useradd -r -u 999 -g sliver sliver \
|
||||
&& mkdir -p /home/sliver/ \
|
||||
&& chown -R sliver:sliver /home/sliver
|
||||
|
||||
### Copy compiled binary
|
||||
COPY --from=base /opt/sliver-server /opt/sliver-server
|
||||
|
||||
### Unpack Sliver:
|
||||
USER sliver
|
||||
RUN /opt/sliver-server unpack --force
|
||||
|
||||
USER sliver
|
||||
WORKDIR /home/sliver/
|
||||
VOLUME [ "/home/sliver/.sliver" ]
|
||||
ENTRYPOINT [ "/opt/sliver-server" ]
|
||||
+1
-1
@@ -21,7 +21,7 @@ set -e
|
||||
# Creates the static go asset archives
|
||||
|
||||
GO_VER="1.21.4"
|
||||
GARBLE_VER="1.21.4a"
|
||||
GARBLE_VER="1.21.4b"
|
||||
SGN_VER="0.0.3"
|
||||
|
||||
BLOAT_FILES="AUTHORS CONTRIBUTORS PATENTS VERSION favicon.ico robots.txt SECURITY.md CONTRIBUTING.md LICENSE README.md ./doc ./test ./api ./misc"
|
||||
|
||||
@@ -45,7 +45,7 @@ require (
|
||||
github.com/things-go/go-socks5 v0.0.3
|
||||
github.com/xlab/treeprint v1.2.0
|
||||
github.com/yiya1989/sshkrb5 v0.0.0-20201110125252-a1455b75a35e
|
||||
golang.org/x/crypto v0.14.0
|
||||
golang.org/x/crypto v0.15.0
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9
|
||||
golang.org/x/net v0.17.0
|
||||
golang.org/x/sys v0.14.0
|
||||
|
||||
@@ -448,6 +448,8 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
|
||||
+1
-1
@@ -272,7 +272,7 @@ func listenAndServeTLS(srv *http.Server, certPEMBlock, keyPEMBlock []byte) error
|
||||
}
|
||||
config := &tls.Config{}
|
||||
if srv.TLSConfig != nil {
|
||||
*config = *srv.TLSConfig
|
||||
config = srv.TLSConfig
|
||||
}
|
||||
if certs.TLSKeyLogger != nil {
|
||||
config.KeyLogWriter = certs.TLSKeyLogger
|
||||
|
||||
+5
-4
@@ -44,10 +44,11 @@ const (
|
||||
forceFlagStr = "force"
|
||||
|
||||
// Operator flags
|
||||
nameFlagStr = "name"
|
||||
lhostFlagStr = "lhost"
|
||||
lportFlagStr = "lport"
|
||||
saveFlagStr = "save"
|
||||
nameFlagStr = "name"
|
||||
lhostFlagStr = "lhost"
|
||||
lportFlagStr = "lport"
|
||||
saveFlagStr = "save"
|
||||
permissionsFlagStr = "permissions"
|
||||
|
||||
// Cert flags
|
||||
caTypeFlagStr = "type"
|
||||
|
||||
@@ -71,10 +71,10 @@ var daemonCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
func StartPersistentJobs(listenerJobs *[]clientpb.ListenerJob) error {
|
||||
if len(*listenerJobs) > 0 {
|
||||
func StartPersistentJobs(listenerJobs []*clientpb.ListenerJob) error {
|
||||
if len(listenerJobs) > 0 {
|
||||
// StartPersistentJobs - Start persistent jobs
|
||||
for _, j := range *listenerJobs {
|
||||
for _, j := range listenerJobs {
|
||||
listenerJob, err := db.ListenerByJobID(j.JobID)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -117,7 +117,7 @@ func StartPersistentJobs(listenerJobs *[]clientpb.ListenerJob) error {
|
||||
}
|
||||
j.JobID = uint32(id)
|
||||
}
|
||||
db.UpdateHTTPC2Listener(&j)
|
||||
db.UpdateHTTPC2Listener(j)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-11
@@ -33,54 +33,63 @@ var operatorCmd = &cobra.Command{
|
||||
Short: "Generate operator configuration files",
|
||||
Long: ``,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
name, err := cmd.Flags().GetString(nameFlagStr)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse --%s flag %s", nameFlagStr, err)
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
if name == "" {
|
||||
fmt.Printf("Must specify --%s", nameFlagStr)
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
|
||||
lhost, err := cmd.Flags().GetString(lhostFlagStr)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse --%s flag %s", lhostFlagStr, err)
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
if lhost == "" {
|
||||
fmt.Printf("Must specify --%s", lhostFlagStr)
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
|
||||
lport, err := cmd.Flags().GetUint16(lportFlagStr)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse --%s flag %s", lportFlagStr, err)
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
|
||||
save, err := cmd.Flags().GetString(saveFlagStr)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse --%s flag %s", saveFlagStr, err)
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
if save == "" {
|
||||
save, _ = os.Getwd()
|
||||
}
|
||||
|
||||
permissions, err := cmd.Flags().GetStringSlice(permissionsFlagStr)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse --%s flag %s", permissionsFlagStr, err)
|
||||
return
|
||||
}
|
||||
if len(permissions) == 0 {
|
||||
fmt.Printf("Must specify --%s", permissionsFlagStr)
|
||||
return
|
||||
}
|
||||
|
||||
certs.SetupCAs()
|
||||
configJSON, err := console.NewOperatorConfig(name, lhost, lport)
|
||||
configJSON, err := console.NewOperatorConfig(name, lhost, lport, permissions)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed: %s\n", err)
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
|
||||
saveTo, _ := filepath.Abs(save)
|
||||
fi, err := os.Stat(saveTo)
|
||||
if !os.IsNotExist(err) && !fi.IsDir() {
|
||||
fmt.Printf("File already exists: %s\n", err)
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
if !os.IsNotExist(err) && fi.IsDir() {
|
||||
filename := fmt.Sprintf("%s_%s.cfg", filepath.Base(name), filepath.Base(lhost))
|
||||
@@ -89,7 +98,7 @@ var operatorCmd = &cobra.Command{
|
||||
err = os.WriteFile(saveTo, configJSON, 0600)
|
||||
if err != nil {
|
||||
fmt.Printf("Write failed: %s (%s)\n", saveTo, err)
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -86,13 +85,14 @@ func newOperatorCmd(cmd *cobra.Command, _ []string) {
|
||||
lhost, _ := cmd.Flags().GetString("lhost")
|
||||
lport, _ := cmd.Flags().GetUint16("lport")
|
||||
save, _ := cmd.Flags().GetString("save")
|
||||
permissions, _ := cmd.Flags().GetStringSlice("permissions")
|
||||
|
||||
if save == "" {
|
||||
save, _ = os.Getwd()
|
||||
}
|
||||
|
||||
fmt.Printf(Info + "Generating new client certificate, please wait ... \n")
|
||||
configJSON, err := NewOperatorConfig(name, lhost, lport)
|
||||
configJSON, err := NewOperatorConfig(name, lhost, lport, permissions)
|
||||
if err != nil {
|
||||
fmt.Printf(Warn+"%s\n", err)
|
||||
return
|
||||
@@ -108,7 +108,7 @@ func newOperatorCmd(cmd *cobra.Command, _ []string) {
|
||||
filename := fmt.Sprintf("%s_%s.cfg", filepath.Base(name), filepath.Base(lhost))
|
||||
saveTo = filepath.Join(saveTo, filename)
|
||||
}
|
||||
err = ioutil.WriteFile(saveTo, configJSON, 0o600)
|
||||
err = os.WriteFile(saveTo, configJSON, 0o600)
|
||||
if err != nil {
|
||||
fmt.Printf(Warn+"Failed to write config to: %s (%s) \n", saveTo, err)
|
||||
return
|
||||
@@ -117,7 +117,7 @@ func newOperatorCmd(cmd *cobra.Command, _ []string) {
|
||||
}
|
||||
|
||||
// NewOperatorConfig - Generate a new player/client/operator configuration
|
||||
func NewOperatorConfig(operatorName string, lhost string, lport uint16) ([]byte, error) {
|
||||
func NewOperatorConfig(operatorName string, lhost string, lport uint16, permissions []string) ([]byte, error) {
|
||||
if !namePattern.MatchString(operatorName) {
|
||||
return nil, errors.New("invalid operator name (alphanumerics only)")
|
||||
}
|
||||
@@ -127,6 +127,9 @@ func NewOperatorConfig(operatorName string, lhost string, lport uint16) ([]byte,
|
||||
if lhost == "" {
|
||||
return nil, errors.New("invalid lhost")
|
||||
}
|
||||
if len(permissions) == 0 {
|
||||
return nil, errors.New("must specify at least one permission")
|
||||
}
|
||||
|
||||
rawToken := models.GenerateOperatorToken()
|
||||
digest := sha256.Sum256([]byte(rawToken))
|
||||
@@ -134,6 +137,19 @@ func NewOperatorConfig(operatorName string, lhost string, lport uint16) ([]byte,
|
||||
Name: operatorName,
|
||||
Token: hex.EncodeToString(digest[:]),
|
||||
}
|
||||
for _, permission := range permissions {
|
||||
switch permission {
|
||||
case "all":
|
||||
dbOperator.PermissionAll = true
|
||||
break
|
||||
case "builder":
|
||||
dbOperator.PermissionBuilder = true
|
||||
case "crackstation":
|
||||
dbOperator.PermissionCrackstation = true
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid permission: %s", permission)
|
||||
}
|
||||
}
|
||||
err := db.Session().Save(dbOperator).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
func TestRootOnlyVerifyCertificate(t *testing.T) {
|
||||
certs.SetupCAs()
|
||||
|
||||
data, err := NewOperatorConfig("zerocool", "localhost", uint16(1337))
|
||||
data, err := NewOperatorConfig("zerocool", "localhost", uint16(1337), []string{"all"})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to generate test player profile %s", err)
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ func serverOnlyCmds() (commands []*cobra.Command) {
|
||||
newOperator := &cobra.Command{
|
||||
Use: consts.NewOperatorStr,
|
||||
Short: "Create a new operator config file",
|
||||
Long: help.GetHelpFor([]string{consts.NewOperatorStr}),
|
||||
Long: newOperatorLongHelp,
|
||||
Run: newOperatorCmd,
|
||||
GroupID: consts.MultiplayerHelpGroup,
|
||||
}
|
||||
@@ -94,6 +94,7 @@ func serverOnlyCmds() (commands []*cobra.Command) {
|
||||
f.Uint16P("lport", "p", 31337, "listen port")
|
||||
f.StringP("save", "s", "", "directory/file in which to save config")
|
||||
f.StringP("name", "n", "", "operator name")
|
||||
f.StringSliceP("permissions", "P", []string{}, "grant permissions to the operator profile (all, builder, crackstation)")
|
||||
})
|
||||
command.FlagComps(newOperator, func(comp *carapace.ActionMap) {
|
||||
(*comp)["save"] = carapace.ActionDirectories()
|
||||
@@ -115,3 +116,23 @@ func serverOnlyCmds() (commands []*cobra.Command) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const newOperatorLongHelp = `
|
||||
Create a new operator config file, operator configuration files allow
|
||||
remote machines to connect to the Sliver server. They are most commonly
|
||||
used for allowing remote operators to connect in "Multiplayer Mode."
|
||||
|
||||
To generate a profile for a remote operator, you need to specify the
|
||||
the "all" permission to grant the profile access to all gRPC APIs:
|
||||
|
||||
new-operator --name <operator name> --lhost <sliver server> --permissions all
|
||||
|
||||
Operator profiles can also be used to allow remote machines to connect to
|
||||
the Sliver server for other purposes, such as a "Remote Builder" or a
|
||||
"Crackstation."
|
||||
|
||||
You can restrict profiles' permissions by using the --permissions flag, for
|
||||
example, to create a profile that can only be used as a "Remote Builder":
|
||||
|
||||
new-operator --name <operator name> --lhost <sliver server> --permissions builder
|
||||
`
|
||||
@@ -31,11 +31,11 @@ type ImplantConnection struct {
|
||||
ID string
|
||||
Send chan *sliverpb.Envelope
|
||||
RespMutex *sync.RWMutex
|
||||
LastMessageMutex *sync.RWMutex
|
||||
Resp map[int64]chan *sliverpb.Envelope
|
||||
Transport string
|
||||
RemoteAddress string
|
||||
LastMessage time.Time
|
||||
LastMessageMutex *sync.RWMutex
|
||||
Cleanup func()
|
||||
}
|
||||
|
||||
|
||||
@@ -525,15 +525,15 @@ func ListenerByJobID(JobID uint32) (*clientpb.ListenerJob, error) {
|
||||
return listenerJob.ToProtobuf(), err
|
||||
}
|
||||
|
||||
func ListenerJobs() (*[]clientpb.ListenerJob, error) {
|
||||
func ListenerJobs() ([]*clientpb.ListenerJob, error) {
|
||||
listenerJobs := []models.ListenerJob{}
|
||||
err := Session().Where(&models.ListenerJob{}).Find(&listenerJobs).Error
|
||||
pbListenerJobs := []clientpb.ListenerJob{}
|
||||
pbListenerJobs := []*clientpb.ListenerJob{}
|
||||
for _, listenerJob := range listenerJobs {
|
||||
pbListenerJobs = append(pbListenerJobs, *listenerJob.ToProtobuf())
|
||||
pbListenerJobs = append(pbListenerJobs, listenerJob.ToProtobuf())
|
||||
}
|
||||
|
||||
return &pbListenerJobs, err
|
||||
return pbListenerJobs, err
|
||||
}
|
||||
|
||||
func DeleteListener(JobID uint32) error {
|
||||
|
||||
@@ -28,12 +28,15 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Operator - Colletions of content to serve from HTTP(S)
|
||||
// Operator - Collections of content to serve from HTTP(S)
|
||||
type Operator struct {
|
||||
ID uuid.UUID `gorm:"primaryKey;->;<-:create;type:uuid;"`
|
||||
CreatedAt time.Time `gorm:"->;<-:create;"`
|
||||
Name string
|
||||
Token string `gorm:"uniqueIndex"`
|
||||
ID uuid.UUID `gorm:"primaryKey;->;<-:create;type:uuid;"`
|
||||
CreatedAt time.Time `gorm:"->;<-:create;"`
|
||||
Name string
|
||||
Token string `gorm:"uniqueIndex"` // NOTE: This is the SHA256 of the token
|
||||
PermissionAll bool `gorm:"default:false"` // Access all gRPC APIs
|
||||
PermissionBuilder bool `gorm:"default:false"` // Access Builder gRPC APIs
|
||||
PermissionCrackstation bool `gorm:"default:false"` // Access Crackstation gRPC APIs
|
||||
}
|
||||
|
||||
// BeforeCreate - GORM hook
|
||||
|
||||
@@ -283,7 +283,7 @@ func PortInUse(newPort uint32) error {
|
||||
return err
|
||||
}
|
||||
var port uint32
|
||||
for _, job := range *listenerJobs {
|
||||
for _, job := range listenerJobs {
|
||||
listener, err := db.ListenerByJobID(job.JobID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/bishopfox/sliver/server/configs"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
"github.com/bishopfox/sliver/server/db"
|
||||
"github.com/bishopfox/sliver/server/db/models"
|
||||
"github.com/bishopfox/sliver/server/log"
|
||||
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
|
||||
grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
|
||||
@@ -64,6 +65,7 @@ func initMiddleware(remoteAuth bool) []grpc.ServerOption {
|
||||
return []grpc.ServerOption{
|
||||
grpc.ChainUnaryInterceptor(
|
||||
grpc_auth.UnaryServerInterceptor(tokenAuthFunc),
|
||||
permissionsUnaryServerInterceptor(),
|
||||
auditLogUnaryServerInterceptor(),
|
||||
grpc_tags.UnaryServerInterceptor(grpc_tags.WithFieldExtractor(grpc_tags.CodeGenRequestFieldExtractor)),
|
||||
grpc_logrus.UnaryServerInterceptor(logrusEntry, logrusOpts...),
|
||||
@@ -71,6 +73,7 @@ func initMiddleware(remoteAuth bool) []grpc.ServerOption {
|
||||
),
|
||||
grpc.ChainStreamInterceptor(
|
||||
grpc_auth.StreamServerInterceptor(tokenAuthFunc),
|
||||
permissionsStreamServerInterceptor(),
|
||||
grpc_tags.StreamServerInterceptor(grpc_tags.WithFieldExtractor(grpc_tags.CodeGenRequestFieldExtractor)),
|
||||
grpc_logrus.StreamServerInterceptor(logrusEntry, logrusOpts...),
|
||||
grpc_logrus.PayloadStreamServerInterceptor(logrusEntry, deciderStream),
|
||||
@@ -123,23 +126,93 @@ func tokenAuthFunc(ctx context.Context) (context.Context, error) {
|
||||
digest := sha256.Sum256([]byte(rawToken))
|
||||
token := hex.EncodeToString(digest[:])
|
||||
newCtx := context.WithValue(ctx, Transport, "mtls")
|
||||
if name, ok := tokenCache.Load(token); ok {
|
||||
if op, ok := tokenCache.Load(token); ok {
|
||||
mtlsLog.Debugf("Token in cache!")
|
||||
newCtx = context.WithValue(newCtx, Operator, name.(string))
|
||||
newCtx = context.WithValue(newCtx, Operator, op.(*models.Operator))
|
||||
return newCtx, nil
|
||||
}
|
||||
operator, err := db.OperatorByToken(token)
|
||||
if err != nil || operator == nil {
|
||||
mtlsLog.Errorf("Authentication failure: %s", err)
|
||||
mtlsLog.Errorf("Authentication failure: %v", err)
|
||||
return nil, status.Error(codes.Unauthenticated, "Authentication failure")
|
||||
}
|
||||
mtlsLog.Debugf("Valid user token for %s", operator.Name)
|
||||
tokenCache.Store(token, operator.Name)
|
||||
mtlsLog.Debugf("Valid token for %s", operator.Name)
|
||||
tokenCache.Store(token, operator)
|
||||
|
||||
newCtx = context.WithValue(newCtx, Operator, operator.Name)
|
||||
newCtx = context.WithValue(newCtx, Operator, operator)
|
||||
return newCtx, nil
|
||||
}
|
||||
|
||||
var (
|
||||
// Builder - Allowed methods
|
||||
builderMethods = map[string]bool{
|
||||
"/rpcpb.SliverRPC/GetVersion": true,
|
||||
"/rpcpb.SliverRPC/GenerateExternalGetBuildConfig": true,
|
||||
"/rpcpb.SliverRPC/GenerateExternalSaveBuild": true,
|
||||
"/rpcpb.SliverRPC/BuilderRegister": true,
|
||||
"/rpcpb.SliverRPC/BuilderTrigger": true,
|
||||
"/rpcpb.SliverRPC/Builders": true,
|
||||
}
|
||||
// Crackstation - Allowed methods
|
||||
crackstationMethods = map[string]bool{
|
||||
"/rpcpb.SliverRPC/GetVersion": true,
|
||||
"/rpcpb.SliverRPC/CrackstationRegister": true,
|
||||
"/rpcpb.SliverRPC/CrackstationTrigger": true,
|
||||
"/rpcpb.SliverRPC/CrackstationBenchmark": true,
|
||||
"/rpcpb.SliverRPC/Crackstations": true,
|
||||
"/rpcpb.SliverRPC/CrackTaskByID": true,
|
||||
"/rpcpb.SliverRPC/CrackTaskUpdate": true,
|
||||
"/rpcpb.SliverRPC/CrackFilesList": true,
|
||||
"/rpcpb.SliverRPC/CrackFileCreate": true,
|
||||
"/rpcpb.SliverRPC/CrackFileChunkUpload": true,
|
||||
"/rpcpb.SliverRPC/CrackFileChunkDownload": true,
|
||||
"/rpcpb.SliverRPC/CrackFileComplete": true,
|
||||
"/rpcpb.SliverRPC/CrackFileDelete": true,
|
||||
}
|
||||
)
|
||||
|
||||
func permissionsUnaryServerInterceptor() grpc.UnaryServerInterceptor {
|
||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (_ interface{}, err error) {
|
||||
operator := ctx.Value(Operator).(*models.Operator)
|
||||
if operator.PermissionAll {
|
||||
return handler(ctx, req)
|
||||
}
|
||||
if operator.PermissionBuilder {
|
||||
if ok, _ := builderMethods[info.FullMethod]; ok {
|
||||
return handler(ctx, req)
|
||||
}
|
||||
}
|
||||
if operator.PermissionCrackstation {
|
||||
if ok, _ := crackstationMethods[info.FullMethod]; ok {
|
||||
return handler(ctx, req)
|
||||
}
|
||||
}
|
||||
mtlsLog.Warnf("Permission denied for %s attempting to access %s", operator.Name, info.FullMethod)
|
||||
return nil, status.Error(codes.PermissionDenied, "Permission denied")
|
||||
}
|
||||
}
|
||||
|
||||
func permissionsStreamServerInterceptor() grpc.StreamServerInterceptor {
|
||||
return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
|
||||
operator := ss.Context().Value(Operator).(*models.Operator)
|
||||
if operator.PermissionAll {
|
||||
return handler(srv, ss)
|
||||
}
|
||||
if operator.PermissionBuilder {
|
||||
if ok, _ := builderMethods[info.FullMethod]; ok {
|
||||
return handler(srv, ss)
|
||||
}
|
||||
}
|
||||
if operator.PermissionCrackstation {
|
||||
if ok, _ := crackstationMethods[info.FullMethod]; ok {
|
||||
return handler(srv, ss)
|
||||
}
|
||||
}
|
||||
mtlsLog.Warnf("Permission denied for %s attempting to access %s", operator.Name, info.FullMethod)
|
||||
return status.Error(codes.PermissionDenied, "Permission denied")
|
||||
}
|
||||
}
|
||||
|
||||
func deciderUnary(_ context.Context, _ string, _ interface{}) bool {
|
||||
return serverConfig.Logs.GRPCUnaryPayloads
|
||||
}
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.12
|
||||
// +build go1.12
|
||||
|
||||
package acme
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build amd64 && gc && !purego
|
||||
// +build amd64,gc,!purego
|
||||
|
||||
package argon2
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build amd64 && gc && !purego
|
||||
// +build amd64,gc,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !amd64 || purego || !gc
|
||||
// +build !amd64 purego !gc
|
||||
|
||||
package argon2
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.7 && amd64 && gc && !purego
|
||||
// +build go1.7,amd64,gc,!purego
|
||||
|
||||
package blake2b
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.7 && amd64 && gc && !purego
|
||||
// +build go1.7,amd64,gc,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !go1.7 && amd64 && gc && !purego
|
||||
// +build !go1.7,amd64,gc,!purego
|
||||
|
||||
package blake2b
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build amd64 && gc && !purego
|
||||
// +build amd64,gc,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !amd64 || purego || !gc
|
||||
// +build !amd64 purego !gc
|
||||
|
||||
package blake2b
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.9
|
||||
// +build go1.9
|
||||
|
||||
package blake2b
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build 386 && gc && !purego
|
||||
// +build 386,gc,!purego
|
||||
|
||||
package blake2s
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build 386 && gc && !purego
|
||||
// +build 386,gc,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build amd64 && gc && !purego
|
||||
// +build amd64,gc,!purego
|
||||
|
||||
package blake2s
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build amd64 && gc && !purego
|
||||
// +build amd64,gc,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build (!amd64 && !386) || !gc || purego
|
||||
// +build !amd64,!386 !gc purego
|
||||
|
||||
package blake2s
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.9
|
||||
// +build go1.9
|
||||
|
||||
package blake2s
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
package chacha20
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build (!arm64 && !s390x && !ppc64le) || !gc || purego
|
||||
// +build !arm64,!s390x,!ppc64le !gc purego
|
||||
|
||||
package chacha20
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
package chacha20
|
||||
|
||||
|
||||
-1
@@ -20,7 +20,6 @@
|
||||
// due to the calling conventions and initialization of constants.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
package chacha20
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
#include "go_asm.h"
|
||||
#include "textflag.h"
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
package chacha20poly1305
|
||||
|
||||
|
||||
+22
-3
@@ -5,7 +5,6 @@
|
||||
// This file was originally from https://golang.org/cl/24717 by Vlad Krasnov of CloudFlare.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
// General register allocation
|
||||
@@ -184,11 +183,31 @@ GLOBL ·andMask<>(SB), (NOPTR+RODATA), $240
|
||||
#define shiftD1Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xd2; BYTE $0x04 // PALIGNR $4, X10, X10
|
||||
#define shiftD2Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x04 // PALIGNR $4, X11, X11
|
||||
#define shiftD3Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x04 // PALIGNR $4, X15, X15
|
||||
|
||||
// Some macros
|
||||
|
||||
// ROL rotates the uint32s in register R left by N bits, using temporary T.
|
||||
#define ROL(N, R, T) \
|
||||
MOVO R, T; PSLLL $(N), T; PSRLL $(32-(N)), R; PXOR T, R
|
||||
|
||||
// ROL16 rotates the uint32s in register R left by 16, using temporary T if needed.
|
||||
#ifdef GOAMD64_v2
|
||||
#define ROL16(R, T) PSHUFB ·rol16<>(SB), R
|
||||
#else
|
||||
#define ROL16(R, T) ROL(16, R, T)
|
||||
#endif
|
||||
|
||||
// ROL8 rotates the uint32s in register R left by 8, using temporary T if needed.
|
||||
#ifdef GOAMD64_v2
|
||||
#define ROL8(R, T) PSHUFB ·rol8<>(SB), R
|
||||
#else
|
||||
#define ROL8(R, T) ROL(8, R, T)
|
||||
#endif
|
||||
|
||||
#define chachaQR(A, B, C, D, T) \
|
||||
PADDD B, A; PXOR A, D; PSHUFB ·rol16<>(SB), D \
|
||||
PADDD B, A; PXOR A, D; ROL16(D, T) \
|
||||
PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $12, T; PSRLL $20, B; PXOR T, B \
|
||||
PADDD B, A; PXOR A, D; PSHUFB ·rol8<>(SB), D \
|
||||
PADDD B, A; PXOR A, D; ROL8(D, T) \
|
||||
PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $7, T; PSRLL $25, B; PXOR T, B
|
||||
|
||||
#define chachaQR_AVX2(A, B, C, D, T) \
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !amd64 || !gc || purego
|
||||
// +build !amd64 !gc purego
|
||||
|
||||
package chacha20poly1305
|
||||
|
||||
|
||||
-1
@@ -1,7 +1,6 @@
|
||||
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
|
||||
|
||||
//go:build amd64 && gc && !purego
|
||||
// +build amd64,gc,!purego
|
||||
|
||||
package field
|
||||
|
||||
|
||||
-1
@@ -1,7 +1,6 @@
|
||||
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
|
||||
|
||||
//go:build amd64 && gc && !purego
|
||||
// +build amd64,gc,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !amd64 || !gc || purego
|
||||
// +build !amd64 !gc purego
|
||||
|
||||
package field
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build arm64 && gc && !purego
|
||||
// +build arm64,gc,!purego
|
||||
|
||||
package field
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build arm64 && gc && !purego
|
||||
// +build arm64,gc,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !arm64 || !gc || purego
|
||||
// +build !arm64 !gc purego
|
||||
|
||||
package field
|
||||
|
||||
|
||||
+3
-1
@@ -56,7 +56,9 @@ func (f *hkdf) Read(p []byte) (int, error) {
|
||||
|
||||
// Fill the rest of the buffer
|
||||
for len(p) > 0 {
|
||||
f.expander.Reset()
|
||||
if f.counter > 1 {
|
||||
f.expander.Reset()
|
||||
}
|
||||
f.expander.Write(f.prev)
|
||||
f.expander.Write(f.info)
|
||||
f.expander.Write([]byte{f.counter})
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
// Package alias implements memory aliasing tests.
|
||||
package alias
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build purego
|
||||
// +build purego
|
||||
|
||||
// Package alias implements memory aliasing tests.
|
||||
package alias
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !go1.13
|
||||
// +build !go1.13
|
||||
|
||||
package poly1305
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.13
|
||||
// +build go1.13
|
||||
|
||||
package poly1305
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build (!amd64 && !ppc64le && !s390x) || !gc || purego
|
||||
// +build !amd64,!ppc64le,!s390x !gc purego
|
||||
|
||||
package poly1305
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
package poly1305
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
package poly1305
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
package poly1305
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build amd64 && !purego && gc
|
||||
// +build amd64,!purego,gc
|
||||
|
||||
package salsa
|
||||
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build amd64 && !purego && gc
|
||||
// +build amd64,!purego,gc
|
||||
|
||||
// This code was translated into a form compatible with 6a from the public
|
||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
|
||||
|
||||
-1
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !amd64 || purego || !gc
|
||||
// +build !amd64 purego !gc
|
||||
|
||||
package salsa
|
||||
|
||||
|
||||
+9
-4
@@ -141,9 +141,14 @@ const (
|
||||
agentAddSmartcardKeyConstrained = 26
|
||||
|
||||
// 3.7 Key constraint identifiers
|
||||
agentConstrainLifetime = 1
|
||||
agentConstrainConfirm = 2
|
||||
agentConstrainExtension = 3
|
||||
agentConstrainLifetime = 1
|
||||
agentConstrainConfirm = 2
|
||||
// Constraint extension identifier up to version 2 of the protocol. A
|
||||
// backward incompatible change will be required if we want to add support
|
||||
// for SSH_AGENT_CONSTRAIN_MAXSIGN which uses the same ID.
|
||||
agentConstrainExtensionV00 = 3
|
||||
// Constraint extension identifier in version 3 and later of the protocol.
|
||||
agentConstrainExtension = 255
|
||||
)
|
||||
|
||||
// maxAgentResponseBytes is the maximum agent reply size that is accepted. This
|
||||
@@ -205,7 +210,7 @@ type constrainLifetimeAgentMsg struct {
|
||||
}
|
||||
|
||||
type constrainExtensionAgentMsg struct {
|
||||
ExtensionName string `sshtype:"3"`
|
||||
ExtensionName string `sshtype:"255|3"`
|
||||
ExtensionDetails []byte
|
||||
|
||||
// Rest is a field used for parsing, not part of message
|
||||
|
||||
+1
-1
@@ -208,7 +208,7 @@ func parseConstraints(constraints []byte) (lifetimeSecs uint32, confirmBeforeUse
|
||||
case agentConstrainConfirm:
|
||||
confirmBeforeUse = true
|
||||
constraints = constraints[1:]
|
||||
case agentConstrainExtension:
|
||||
case agentConstrainExtension, agentConstrainExtensionV00:
|
||||
var msg constrainExtensionAgentMsg
|
||||
if err = ssh.Unmarshal(constraints, &msg); err != nil {
|
||||
return 0, false, nil, err
|
||||
|
||||
-3
@@ -10,7 +10,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
_ "crypto/sha1"
|
||||
@@ -140,8 +139,6 @@ var supportedPubKeyAuthAlgos = []string{
|
||||
KeyAlgoDSA,
|
||||
}
|
||||
|
||||
var supportedPubKeyAuthAlgosList = strings.Join(supportedPubKeyAuthAlgos, ",")
|
||||
|
||||
// unexpectedMessageError results when the SSH message that we received didn't
|
||||
// match what we wanted.
|
||||
func unexpectedMessageError(expected, got uint8) error {
|
||||
|
||||
+7
@@ -11,6 +11,7 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -50,6 +51,10 @@ type handshakeTransport struct {
|
||||
// connection.
|
||||
hostKeys []Signer
|
||||
|
||||
// publicKeyAuthAlgorithms is non-empty if we are the server. In that case,
|
||||
// it contains the supported client public key authentication algorithms.
|
||||
publicKeyAuthAlgorithms []string
|
||||
|
||||
// hostKeyAlgorithms is non-empty if we are the client. In that case,
|
||||
// we accept these key types from the server as host key.
|
||||
hostKeyAlgorithms []string
|
||||
@@ -141,6 +146,7 @@ func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byt
|
||||
func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport {
|
||||
t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion)
|
||||
t.hostKeys = config.hostKeys
|
||||
t.publicKeyAuthAlgorithms = config.PublicKeyAuthAlgorithms
|
||||
go t.readLoop()
|
||||
go t.kexLoop()
|
||||
return t
|
||||
@@ -649,6 +655,7 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
|
||||
// message with the server-sig-algs extension if the client supports it. See
|
||||
// RFC 8308, Sections 2.4 and 3.1, and [PROTOCOL], Section 1.9.
|
||||
if !isClient && firstKeyExchange && contains(clientInit.KexAlgos, "ext-info-c") {
|
||||
supportedPubKeyAuthAlgosList := strings.Join(t.publicKeyAuthAlgorithms, ",")
|
||||
extInfo := &extInfoMsg{
|
||||
NumExtensions: 2,
|
||||
Payload: make([]byte, 0, 4+15+4+len(supportedPubKeyAuthAlgosList)+4+16+4+1),
|
||||
|
||||
+15
-4
@@ -1232,16 +1232,27 @@ func ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase []byte) (interface{},
|
||||
return nil, fmt.Errorf("ssh: cannot decode encrypted private keys: %v", err)
|
||||
}
|
||||
|
||||
var result interface{}
|
||||
|
||||
switch block.Type {
|
||||
case "RSA PRIVATE KEY":
|
||||
return x509.ParsePKCS1PrivateKey(buf)
|
||||
result, err = x509.ParsePKCS1PrivateKey(buf)
|
||||
case "EC PRIVATE KEY":
|
||||
return x509.ParseECPrivateKey(buf)
|
||||
result, err = x509.ParseECPrivateKey(buf)
|
||||
case "DSA PRIVATE KEY":
|
||||
return ParseDSAPrivateKey(buf)
|
||||
result, err = ParseDSAPrivateKey(buf)
|
||||
default:
|
||||
return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
|
||||
err = fmt.Errorf("ssh: unsupported key type %q", block.Type)
|
||||
}
|
||||
// Because of deficiencies in the format, DecryptPEMBlock does not always
|
||||
// detect an incorrect password. In these cases decrypted DER bytes is
|
||||
// random noise. If the parsing of the key returns an asn1.StructuralError
|
||||
// we return x509.IncorrectPasswordError.
|
||||
if _, ok := err.(asn1.StructuralError); ok {
|
||||
return nil, x509.IncorrectPasswordError
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as
|
||||
|
||||
+18
-2
@@ -64,6 +64,13 @@ type ServerConfig struct {
|
||||
// Config contains configuration shared between client and server.
|
||||
Config
|
||||
|
||||
// PublicKeyAuthAlgorithms specifies the supported client public key
|
||||
// authentication algorithms. Note that this should not include certificate
|
||||
// types since those use the underlying algorithm. This list is sent to the
|
||||
// client if it supports the server-sig-algs extension. Order is irrelevant.
|
||||
// If unspecified then a default set of algorithms is used.
|
||||
PublicKeyAuthAlgorithms []string
|
||||
|
||||
hostKeys []Signer
|
||||
|
||||
// NoClientAuth is true if clients are allowed to connect without
|
||||
@@ -201,6 +208,15 @@ func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewCha
|
||||
if fullConf.MaxAuthTries == 0 {
|
||||
fullConf.MaxAuthTries = 6
|
||||
}
|
||||
if len(fullConf.PublicKeyAuthAlgorithms) == 0 {
|
||||
fullConf.PublicKeyAuthAlgorithms = supportedPubKeyAuthAlgos
|
||||
} else {
|
||||
for _, algo := range fullConf.PublicKeyAuthAlgorithms {
|
||||
if !contains(supportedPubKeyAuthAlgos, algo) {
|
||||
return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if the config contains any unsupported key exchanges
|
||||
for _, kex := range fullConf.KeyExchanges {
|
||||
if _, ok := serverForbiddenKexAlgos[kex]; ok {
|
||||
@@ -524,7 +540,7 @@ userAuthLoop:
|
||||
return nil, parseError(msgUserAuthRequest)
|
||||
}
|
||||
algo := string(algoBytes)
|
||||
if !contains(supportedPubKeyAuthAlgos, underlyingAlgo(algo)) {
|
||||
if !contains(config.PublicKeyAuthAlgorithms, underlyingAlgo(algo)) {
|
||||
authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
|
||||
break
|
||||
}
|
||||
@@ -591,7 +607,7 @@ userAuthLoop:
|
||||
// algorithm name that corresponds to algo with
|
||||
// sig.Format. This is usually the same, but
|
||||
// for certs, the names differ.
|
||||
if !contains(supportedPubKeyAuthAlgos, sig.Format) {
|
||||
if !contains(config.PublicKeyAuthAlgorithms, sig.Format) {
|
||||
authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
|
||||
break
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -736,8 +736,8 @@ go4.org/mem
|
||||
# go4.org/netipx v0.0.0-20230824141953-6213f710f925
|
||||
## explicit; go 1.18
|
||||
go4.org/netipx
|
||||
# golang.org/x/crypto v0.14.0
|
||||
## explicit; go 1.17
|
||||
# golang.org/x/crypto v0.15.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/crypto/acme
|
||||
golang.org/x/crypto/acme/autocert
|
||||
golang.org/x/crypto/argon2
|
||||
|
||||
Reference in new issue
Block a user