Skip to content

Commit

Permalink
Merge pull request #695 from aau-network-security/develop
Browse files Browse the repository at this point in the history
File upload feature
  • Loading branch information
Mikkelhost authored Mar 3, 2022
2 parents a435eee + db5ed9a commit 357da4e
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 12 deletions.
5 changes: 5 additions & 0 deletions daemon/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type Config struct {
Rechaptcha string `yaml:"recaptcha-key,omitempty"`
APICreds APICreds `yaml:"api-creds,omitempty"`
DockerRepositories []dockerclient.AuthConfiguration `yaml:"docker-repositories,omitempty"`
FileTransferRoot FileTransferConf `yaml:"file-transfer-root,omitempty"`
}

type APICreds struct {
Expand Down Expand Up @@ -68,3 +69,7 @@ type Files struct {
ExercisesFile string `yaml:"exercises-file,omitempty"`
FrontendsFile string `yaml:"frontends-file,omitempty"`
}

type FileTransferConf struct {
Path string `yaml:"path"`
}
4 changes: 4 additions & 0 deletions daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ func NewConfigFromFile(path string) (*Config, error) {
}

func New(conf *Config) (*daemon, error) {
err := vbox.CreateFileTransferRoot(conf.FileTransferRoot.Path)
if err != nil {
log.Fatal().Msgf("Error while creating file transfer root: %s", err)
}
uf, err := store.NewUserFile(conf.ConfFiles.UsersFile)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("unable to read users file: %s", conf.ConfFiles.UsersFile))
Expand Down
6 changes: 6 additions & 0 deletions daemon/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/aau-network-security/haaukins/virtual/vbox"
"math"
"math/rand"
"net/http"
Expand Down Expand Up @@ -375,6 +376,10 @@ func (d *daemon) StopEvent(req *pb.StopEventRequest, resp pb.Daemon_StopEventSer
}

if (user.NPUser && user.Username == createdBy) || !user.NPUser {
// remove the corrosponding event folder
if err := vbox.RemoveEventFolder(string(evtag)); err != nil {
//do nothing
}
_, err := d.dbClient.SetEventStatus(ctx, &pbc.SetEventStatusRequest{EventTag: string(evtag), Status: Closed})
if err != nil {
return fmt.Errorf("error happened on setting up status of event, err: %v", err)
Expand Down Expand Up @@ -702,6 +707,7 @@ func (d *daemon) closeEvent(ch chan guacamole.Event, wg *sync.WaitGroup) error {
currentTime := strconv.Itoa(int(time.Now().Unix()))
newEventTag := fmt.Sprintf("%s-%s", e.Tag, currentTime)
event, err := d.eventPool.GetEvent(e.Tag)
_ = vbox.RemoveEventFolder(string(e.Tag))
if err != nil {
log.Warn().Msgf("event pool get event error %v ", err)
closeErr = err
Expand Down
4 changes: 2 additions & 2 deletions daemon/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (d *daemon) ResetFrontends(req *pb.ResetFrontendsRequest, stream pb.Daemon_
continue
}

if err := lab.ResetFrontends(stream.Context()); err != nil {
if err := lab.ResetFrontends(stream.Context(), string(evtag), reqTeam.Id); err != nil {
return err
}
stream.Send(&pb.ResetTeamStatus{TeamId: reqTeam.Id, Status: "ok"})
Expand All @@ -61,7 +61,7 @@ func (d *daemon) ResetFrontends(req *pb.ResetFrontendsRequest, stream pb.Daemon_
continue
}

if err := lab.ResetFrontends(stream.Context()); err != nil {
if err := lab.ResetFrontends(stream.Context(), string(evtag), t.ID()); err != nil {
return err
}
stream.Send(&pb.ResetTeamStatus{TeamId: t.ID(), Status: "ok"})
Expand Down
9 changes: 7 additions & 2 deletions lab/lab.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ type Lab interface {
Suspend(context.Context) error
Resume(context.Context) error
Environment() exercise.Environment
ResetFrontends(ctx context.Context) error
ResetFrontends(ctx context.Context, eventTag, teamId string) error
RdpConnPorts() []uint
Tag() string
AddChallenge(ctx context.Context, confs ...store.Exercise) error
Expand Down Expand Up @@ -190,7 +190,7 @@ func (l *lab) Environment() exercise.Environment {
return l.environment
}

func (l *lab) ResetFrontends(ctx context.Context) error {
func (l *lab) ResetFrontends(ctx context.Context, eventTag, teamId string) error {
var errs []error
for p, vmConf := range l.frontends {
err := vmConf.vm.Close()
Expand All @@ -210,6 +210,11 @@ func (l *lab) ResetFrontends(ctx context.Context) error {
errs = append(errs, err)
continue
}

err = vbox.CreateFolderLink(vm.Info().Id, eventTag, teamId)
if err != nil {
log.Logger.Debug().Msgf("Error creating shared folder link after vm reset: %s", err)
}
}

if len(errs) > 0 {
Expand Down
19 changes: 16 additions & 3 deletions svcs/guacamole/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ type labNetInfo struct {
}

func NewEvent(ctx context.Context, e store.Event, hub lab.Hub, flags []store.ChildrenChalConfig, reCaptchaKey string) (Event, error) {
guac, err := New(ctx, Config{}, e.OnlyVPN)
guac, err := New(ctx, Config{}, e.OnlyVPN, string(e.Tag))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -694,6 +694,10 @@ func removeVPNConfigs(confFile string) error {

func (ev *event) createGuacConn(t *store.Team, lab lab.Lab) error {
enableWallPaper := true
enableDrive := true
createDrivePath := true
// Drive path is the home folder inside the docker guacamole
drivePath := "/home/" + t.ID()
rdpPorts := lab.RdpConnPorts()
if n := len(rdpPorts); n == 0 {
log.
Expand All @@ -717,7 +721,6 @@ func (ev *event) createGuacConn(t *store.Team, lab lab.Lab) error {
}

ev.guacUserStore.CreateUserForTeam(t.ID(), u)

hostIp, err := ev.dockerHost.GetDockerHostIP()
if err != nil {
return err
Expand All @@ -736,10 +739,20 @@ func (ev *event) createGuacConn(t *store.Team, lab lab.Lab) error {
Username: &u.Username,
Password: &u.Password,
EnableWallPaper: &enableWallPaper,
EnableDrive: &enableDrive,
CreateDrivePath: &createDrivePath,
DrivePath: &drivePath,
}); err != nil {
return err
}
}

instanceInfo := lab.InstanceInfo()
// Will not handle error below since this is not a critical function
_ = vbox.CreateUserFolder(t.ID(), string(ev.store.Tag))

_ = vbox.CreateFolderLink(instanceInfo[0].Id, string(ev.store.Tag), t.ID())

return nil
}

Expand Down Expand Up @@ -909,7 +922,7 @@ func (ev *event) Handler() http.Handler {
if !ok {
return fmt.Errorf("Not found suitable team for given id: %s", t.ID())
}
if err := teamLab.ResetFrontends(context.Background()); err != nil {
if err := teamLab.ResetFrontends(context.Background(), string(ev.store.Tag), t.ID()); err != nil {
return fmt.Errorf("Reset frontends hook error %v", err)
}
return nil
Expand Down
28 changes: 23 additions & 5 deletions svcs/guacamole/guacamole.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ import (
"net/http/cookiejar"
"net/http/httputil"
"net/url"
"os"
"strings"
"time"

"github.com/aau-network-security/haaukins/virtual/vbox"

"github.com/aau-network-security/haaukins/store"

"github.com/aau-network-security/haaukins/svcs"
Expand Down Expand Up @@ -101,7 +104,7 @@ type Guacamole interface {
ProxyHandler(us *GuacUserStore, klp KeyLoggerPool, am *amigo.Amigo, event Event) svcs.ProxyConnector
}

func New(ctx context.Context, conf Config, onlyVPN int32) (Guacamole, error) {
func New(ctx context.Context, conf Config, onlyVPN int32, eventTag string) (Guacamole, error) {
jar, err := cookiejar.New(nil)
if err != nil {
return nil, err
Expand All @@ -125,7 +128,7 @@ func New(ctx context.Context, conf Config, onlyVPN int32) (Guacamole, error) {
conf: conf,
}
if onlyVPN != docker.OnlyVPN {
if err := guac.create(ctx); err != nil {
if err := guac.create(ctx, eventTag); err != nil {
return nil, err
}
}
Expand All @@ -147,14 +150,23 @@ func (guac *guacamole) GetPort() uint {
return guac.webPort
}

func (guac *guacamole) create(ctx context.Context) error {
func (guac *guacamole) create(ctx context.Context, eventTag string) error {
_ = vbox.CreateEventFolder(eventTag)

user := fmt.Sprintf("%d:%d", os.Getuid(), os.Getgid())
log.Debug().Str("user", user).Msg("starting guacd")

containers := map[string]docker.Container{}
containers["guacd"] = docker.NewContainer(docker.ContainerConfig{
Image: "guacamole/guacd:1.2.0",
UseBridge: true,
Labels: map[string]string{
"hkn": "guacamole_guacd",
},
Mounts: []string{
vbox.FileTransferRoot + "/" + eventTag + "/:/home/",
},
User: user,
})

mysqlPass := uuid.New().String()
Expand Down Expand Up @@ -570,6 +582,7 @@ type createRDPConnConf struct {
SFTPAliveInterval *uint `json:"sftp-server-alive-interval"`
SwapRedBlue *bool `json:"swap-red-blue"`
CreateDrivePath *bool `json:"create-drive-path"`
DrivePath *string `json:"drive-path"`
Username *string `json:"username,omitempty"`
Password *string `json:"password,omitempty"`
}
Expand All @@ -586,6 +599,9 @@ type CreateRDPConnOpts struct {
ResolutionHeight uint
MaxConn uint
ColorDepth uint
EnableDrive *bool
CreateDrivePath *bool
DrivePath *string
}

func (guac *guacamole) CreateRDPConn(opts CreateRDPConnOpts) error {
Expand Down Expand Up @@ -617,7 +633,7 @@ func (guac *guacamole) CreateRDPConn(opts CreateRDPConnOpts) error {
if opts.ColorDepth == 0 {
opts.ColorDepth = 16
}

log.Debug().Str("drive-path", *opts.DrivePath).Msg("Drivepath for user is")
conf := createRDPConnConf{
Hostname: &opts.Host,
Width: &opts.ResolutionWidth,
Expand All @@ -627,6 +643,9 @@ func (guac *guacamole) CreateRDPConn(opts CreateRDPConnOpts) error {
Username: opts.Username,
Password: opts.Password,
EnableWallpaper: opts.EnableWallPaper,
EnableDrive: opts.EnableDrive,
CreateDrivePath: opts.CreateDrivePath,
DrivePath: opts.DrivePath,
}

data := struct {
Expand All @@ -650,7 +669,6 @@ func (guac *guacamole) CreateRDPConn(opts CreateRDPConnOpts) error {

action := func(t string) (*http.Response, error) {
endpoint := guac.baseUrl() + "/guacamole/api/session/data/mysql/connections?token=" + t

req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(jsonData))
if err != nil {
return nil, err
Expand Down
2 changes: 2 additions & 0 deletions virtual/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ type ContainerConfig struct {
PortBindings map[string]string
Labels map[string]string
Mounts []string
User string
Resources *Resources
Cmd []string
DNS []string
Expand Down Expand Up @@ -312,6 +313,7 @@ func (c *container) getCreateConfig() (*docker.CreateContainerOptions, error) {
return &docker.CreateContainerOptions{
Name: uuid.New().String(),
Config: &docker.Config{
User: c.conf.User,
Image: c.conf.Image,
Env: env,
Cmd: c.conf.Cmd,
Expand Down
101 changes: 101 additions & 0 deletions virtual/vbox/vbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ const (
vboxShowVMInfo = "showvminfo"
)

var FileTransferRoot string

func init() {
zerolog.SetGlobalLevel(zerolog.Disabled)
}
Expand Down Expand Up @@ -257,6 +259,11 @@ func SetLocalRDP(ip string, port uint) VMOpt {
return err
}

_, err = VBoxCmdContext(ctx, vboxModVM, vm.id, "--vrdemulticon", "on")
if err != nil {
return err
}

return nil
}
}
Expand Down Expand Up @@ -503,3 +510,97 @@ func VBoxCmdContext(ctx context.Context, cmd string, cmds ...string) ([]byte, er

return out, nil
}

func CreateFileTransferRoot(path string) error {
FileTransferRoot = path
if _, err := os.Stat(path); !os.IsNotExist(err) {
//If path exists
log.Info().Str("transfer-root", path).Msg("File transfer root already exists... Continuing.")
return nil
}
log.Info().Str("transfer-root", path).Msg("File transfer root does not exists... Creating folder")
err := os.MkdirAll(path, 0777)
if err != nil {
log.Warn().Msgf("Error creating file transfer root: %s", err)
return err
}
err = os.Chmod(path, os.ModePerm)
if err != nil {
log.Warn().Msgf("Error setting folder perms on: %s error: %s", path, err)
return err
}
log.Info().Msg("File transfer root succesfully created!")
return nil
}

func CreateEventFolder(tag string) error {
path := FileTransferRoot + "/" + tag
if _, err := os.Stat(path); !os.IsNotExist(err) {
//If path exists
log.Info().Str("event-root", path).Msg("Event root already exists... Continuing.")
return nil
}
log.Info().Str("event-root", path).Msg("Event root does not exists... Creating folder")
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
log.Warn().Msgf("Error creating event root: %s", err)
return err
}
err = os.Chmod(path, os.ModePerm)
if err != nil {
log.Warn().Msgf("Error setting folder perms on: %s error: %s", path, err)
return err
}
log.Info().Msg("Event root succesfully created!")
return nil
}

func RemoveEventFolder(eventTag string) error {
path := FileTransferRoot + "/" + eventTag
if _, err := os.Stat(path); !os.IsNotExist(err) {
//If path exists
log.Info().Str("Event-folder", path).Msg("Event-folder exists... Deleting.")
err := os.RemoveAll(path)
if err != nil {
log.Warn().Msgf("Error deleting event folder: %s with error: %s", path, err)
return err
}
return nil
} else {
log.Info().Str("Event-folder", path).Msg("Event-folder does not exists... Continueing")
return nil
}
}

func CreateUserFolder(teamId string, eventTag string) error {
path := FileTransferRoot + "/" + eventTag + "/" + teamId
if _, err := os.Stat(path); !os.IsNotExist(err) {
//If path exists
log.Info().Str("User-folder", path).Msg("User-folder already exists... Continuing.")
return nil
}
log.Info().Str("User-folder", path).Msg("User-folder does not exists... Creating folder")
err := os.MkdirAll(path, 0777)
if err != nil {
log.Warn().Msgf("Error creating User-folder: %s", err)
return err
}
err = os.Chmod(path, os.ModePerm)
if err != nil {
log.Warn().Msgf("Error setting folder perms on: %s error: %s", path, err)
return err
}
log.Info().Msg("User-folder succesfully created!")
return nil
}

func CreateFolderLink(vm string, eventTag string, teamId string) error {
log.Debug().Msgf("Trying to link shared folder to vm: %s", vm)
//todo Figure out a way to add the new folder and general setup of filetransfer folder and how to manage its content.
_, err := VBoxCmdContext(context.Background(), "sharedfolder", "add", vm, "--name", "filetransfer", "-hostpath", FileTransferRoot+"/"+eventTag+"/"+teamId, "-transient", "-automount")
if err != nil {
log.Warn().Msgf("Error creating shared folder link: %s", err)
return err
}
return nil
}

0 comments on commit 357da4e

Please sign in to comment.