diff --git a/configs/types.go b/configs/types.go index 808378bd..3a5d5338 100644 --- a/configs/types.go +++ b/configs/types.go @@ -53,7 +53,7 @@ type MongoCfg struct { } type FlagCfg struct { - FlagLength uint `toml:"flaglength"` + FlagLength int `toml:"flaglength"` TickPeriod uint `toml:"tickperiod"` SubmissionServicePort string `toml:"submissionport"` } diff --git a/go.mod b/go.mod index c460752c..c3ab6e3d 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/gofiber/fiber/v2 v2.1.0 github.com/golang/protobuf v1.4.3 github.com/googleapis/gnostic v0.5.3 // indirect + github.com/jasonlvhit/gocron v0.0.1 // indirect github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 github.com/sirupsen/logrus v1.6.0 github.com/spf13/cobra v1.0.0 diff --git a/go.sum b/go.sum index 5c4ebe8f..f5131625 100644 --- a/go.sum +++ b/go.sum @@ -107,6 +107,7 @@ github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+ github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-redis/redis v6.15.5+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -201,6 +202,8 @@ github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jasonlvhit/gocron v0.0.1 h1:qTt5qF3b3srDjeOIR4Le1LfeyvoYzJlYpqvG7tJX5YU= +github.com/jasonlvhit/gocron v0.0.1/go.mod h1:k9a3TV8VcU73XZxfVHCHWMWF9SOqgoku0/QlY2yvlA4= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -260,6 +263,7 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -400,6 +404,7 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= diff --git a/lib/mongo/constants.go b/lib/mongo/constants.go index 6a87fb8c..01b4b582 100644 --- a/lib/mongo/constants.go +++ b/lib/mongo/constants.go @@ -20,4 +20,8 @@ const ( ValueKey = "value" IDKey = "id" + + SubmittedBy = "submittedby" + + Flag = "flag" ) diff --git a/lib/mongo/read.go b/lib/mongo/read.go index facfe1e8..6214c368 100644 --- a/lib/mongo/read.go +++ b/lib/mongo/read.go @@ -63,3 +63,63 @@ func FetchChallenge(challengeId int) (*types.Challenge, error) { } return challenge, nil } + +func FetchTeams(ctx context.Context, collectionName string, filter bson.M, opts ...*options.FindOptions) []types.CTFTeam { + collection := link.Collection(collectionName) + var data []types.CTFTeam + + cur, err := collection.Find(ctx, filter, opts...) + if err != nil { + log.Println(err.Error()) + return nil + } + defer cur.Close(ctx) + for cur.Next(ctx) { + var result types.CTFTeam + if err := cur.Decode(&result); err != nil { + log.Println(err.Error()) + return nil + } + data = append(data, result) + } + if err := cur.Err(); err != nil { + log.Println(err) + return nil + } + return data +} + +func FetchChallenges(ctx context.Context, collectionName string, filter bson.M, opts ...*options.FindOptions) []types.Challenge { + collection := link.Collection(collectionName) + var data []types.Challenge + + cur, err := collection.Find(ctx, filter, opts...) + if err != nil { + log.Println(err.Error()) + return nil + } + defer cur.Close(ctx) + for cur.Next(ctx) { + var result types.Challenge + if err := cur.Decode(&result); err != nil { + log.Println(err.Error()) + return nil + } + data = append(data, result) + } + if err := cur.Err(); err != nil { + log.Println(err) + return nil + } + return data +} + +func FetchSubmission(teamId int, flag string) (*types.Submission, error) { + collection := link.Collection(SubmissionsCollection) + submission := &types.Submission{} + ctx := context.Background() + if err := collection.FindOne(ctx, bson.M{SubmittedBy: teamId, Flag: flag}).Decode(submission); err != nil { + return nil, err + } + return submission, nil +} diff --git a/services/flaghandlerservice/controller.go b/services/flaghandlerservice/controller.go index a938c08a..1f39a8a8 100644 --- a/services/flaghandlerservice/controller.go +++ b/services/flaghandlerservice/controller.go @@ -2,7 +2,7 @@ package flaghandlerservice import ( "context" - "log" + "time" "github.com/sdslabs/katana/lib/mongo" "github.com/sdslabs/katana/types" @@ -10,35 +10,39 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" ) +func checkSubmission(submission *types.Submission) bool { + _, err := mongo.FetchSubmission(submission.SubmittedBy, submission.Flag) + return err != nil +} + func submitFlag(value string, team types.CTFTeam) (bool, int) { flag, err := mongo.FetchFlag(value) var points int if err != nil { - if flag.TeamID == team.Index { - return false, 0 - } - submission := &types.Submission{} - submission.ChallengeID = flag.ChallengeID - submission.Flag = flag.Value - submission.Submitter = team.Index //time of submission could also be stored - if res, err := mongo.InsertOne(context.Background(), mongo.SubmissionsCollection, submission); err != nil { - log.Println(err) - return false, 0 - } else { - log.Println(res) - } - if res, err := mongo.FetchChallenge(flag.ChallengeID); err != nil { - log.Println(err) - return false, 0 - } else { - team.Score += res.Points - points = res.Points - } - if err := mongo.UpdateOne(context.Background(), mongo.TeamsCollection, bson.M{"id": team.Index}, team, options.FindOneAndUpdate().SetUpsert(false)); err != nil { - log.Println(err) - return false, 0 - } - return true, points + return false, 0 + } + if flag.TeamID == team.Index { + return false, 0 + } + submission := &types.Submission{} + submission.ChallengeID = flag.ChallengeID + submission.Flag = flag.Value + submission.SubmittedBy = team.Index + submission.Time = time.Now() + if !checkSubmission(submission) { + return false, 0 + } + if res, err := mongo.FetchChallenge(flag.ChallengeID); err != nil { + return false, 0 + } else { + team.Score = team.Score + res.Points + points = res.Points + } + if err := mongo.UpdateOne(context.Background(), mongo.TeamsCollection, bson.M{"id": team.Index}, team, options.FindOneAndUpdate().SetUpsert(false)); err != nil { + return false, 0 + } + if _, err := mongo.InsertOne(context.Background(), mongo.SubmissionsCollection, submission); err != nil { + return false, 0 } - return false, 0 + return true, points } diff --git a/services/flaghandlerservice/cronjob.go b/services/flaghandlerservice/cronjob.go new file mode 100644 index 00000000..ec192841 --- /dev/null +++ b/services/flaghandlerservice/cronjob.go @@ -0,0 +1,51 @@ +package flaghandlerservice + +import ( + "context" + "log" + "sync" + "time" + + "github.com/jasonlvhit/gocron" + "github.com/sdslabs/katana/configs" + "github.com/sdslabs/katana/lib/mongo" + "github.com/sdslabs/katana/types" + "go.mongodb.org/mongo-driver/bson" +) + +func Ticker(wg sync.WaitGroup) { + log.Println("Ticker") + defer wg.Done() + handler() + gocron.Every(uint64(configs.FlagConfig.TickPeriod)).Second().Do(handler) + <-gocron.Start() + // gocron.Every(uint64(configs.FlagConfig.TickPeriod)).Second().Do(flaggetter) todo:trigger setter here + // <-gocron.Start() +} + +func handler() { + log.Print("Handler triggered -> ", time.Now()) + challenges := mongo.FetchChallenges(context.Background(), mongo.ChallengesCollection, bson.M{}) + teams := mongo.FetchTeams(context.Background(), mongo.TeamsCollection, bson.M{}) + time := time.Now() + for _, team := range teams { + for _, challenge := range challenges { + go flagUpdater(challenge, team, time) + } + } +} + +func flagUpdater(challenge types.Challenge, team types.CTFTeam, triggerTime time.Time) { + flagValue := String(configs.FlagConfig.FlagLength) + var flag = &types.Flag{} + flag.Value = flagValue + flag.ChallengeID = challenge.ID + flag.CreatedAt = triggerTime + flag.TeamID = team.Index + if _, err := mongo.InsertOne(context.Background(), mongo.FlagsCollection, flag); err != nil { + log.Println(err) + } else { + log.Println("Trigger setter") + //todo : trigger flag setter here + } +} diff --git a/services/flaghandlerservice/random.go b/services/flaghandlerservice/random.go new file mode 100644 index 00000000..1415f792 --- /dev/null +++ b/services/flaghandlerservice/random.go @@ -0,0 +1,36 @@ +package flaghandlerservice + +import ( + "bytes" + "crypto/rand" + "encoding/binary" +) + +func Bytes(n int) []byte { + b := make([]byte, n) + _, err := rand.Read(b) + if err != nil { + panic(err) + } + return b +} + +var defLetters = []rune("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + +func String(n int, letters ...string) string { + var letterRunes []rune + if len(letters) == 0 { + letterRunes = defLetters + } else { + letterRunes = []rune(letters[0]) + } + + var bb bytes.Buffer + bb.Grow(n) + l := uint32(len(letterRunes)) + // on each loop, generate one random rune and append to output + for i := 0; i < n; i++ { + bb.WriteRune(letterRunes[binary.BigEndian.Uint32(Bytes(4))%l]) + } + return bb.String() +} diff --git a/services/flaghandlerservice/server.go b/services/flaghandlerservice/server.go index 60f5301f..d8186530 100644 --- a/services/flaghandlerservice/server.go +++ b/services/flaghandlerservice/server.go @@ -4,8 +4,9 @@ import ( "fmt" "log" "net" + "regexp" "strconv" - "strings" + "sync" "github.com/sdslabs/katana/configs" "github.com/sdslabs/katana/lib/mongo" @@ -13,12 +14,15 @@ import ( "github.com/sdslabs/katana/types" ) -func server() { - ln, err := net.Listen(configs.FlagConfig.SubmissionServicePort, "tcp") +func Server(wg sync.WaitGroup) { + ln, err := net.Listen("tcp", configs.FlagConfig.SubmissionServicePort) if err != nil { - log.Fatal(ServiceFail) + log.Fatal(ServiceFail, err) } - defer ln.Close() + defer func() { + ln.Close() + wg.Done() + }() log.Println(ServiceSuccess, configs.FlagConfig.SubmissionServicePort) connectedTeam := types.CTFTeam{} @@ -79,42 +83,28 @@ func handleConnection(conn net.Conn, connectedTeam types.CTFTeam) { } } case "exit": + return default: if (types.CTFTeam{}) == connectedTeam { writeToCient(conn, NoLogin) } else if status, points := submitFlag(cmd, connectedTeam); status { - writeToCient(conn, SubmitSuccess+strconv.Itoa(points)+"\n") + connectedTeam.Score = connectedTeam.Score + points + writeToCient(conn, SubmitSuccess+strconv.Itoa(points)+TotalScore+strconv.Itoa(connectedTeam.Score)+"\n") } else { writeToCient(conn, InvalidFlag) } } } } - func parseCommand(cmdLine string) (cmd, param, password string) { - parts := strings.Split(cmdLine, " ") - if len(parts) == 3 { - cmd = strings.TrimSpace(parts[0]) - param = strings.TrimSpace(parts[1]) - password = strings.TrimSpace(parts[2]) - return + r, _ := regexp.Compile("(init|exit|[A-Za-z0-9]+)([[:blank:]]([A-Za-z0-9]+)[[:blank:]]([A-Za-z0-9]+))?") + matched := r.FindStringSubmatchIndex(cmdLine) + if matched[6] == -1 { + return cmdLine[matched[2]:matched[3]], "", "" } - if len(parts) == 2 { - cmd = strings.TrimSpace(parts[0]) - param = strings.TrimSpace(parts[1]) - password = "" - return - } - if len(parts) == 1 { - cmd = strings.TrimSpace(parts[0]) - param = "" - password = "" - return - } - return "", "", "" + return cmdLine[matched[2]:matched[3]], cmdLine[matched[6]:matched[7]], cmdLine[matched[8]:matched[9]] } - func checkTeam(teamName string, password string) (bool, types.CTFTeam) { team := &types.CTFTeam{} if team, err := mongo.FetchSingleTeam(teamName); err == nil { diff --git a/services/flaghandlerservice/errors.go b/services/flaghandlerservice/statements.go similarity index 86% rename from services/flaghandlerservice/errors.go rename to services/flaghandlerservice/statements.go index 1da7a7f2..0828b712 100644 --- a/services/flaghandlerservice/errors.go +++ b/services/flaghandlerservice/statements.go @@ -19,7 +19,7 @@ const ( TeamAlreadyExists = "Team is already Logged in\n" - TeamConnected = "Team successfully connected,\n Enter flags to submit them\n" + TeamConnected = "Team successfully connected,\nEnter flags to submit them\n" InvalidCreds = "Invalid Team Credentials\n" @@ -30,4 +30,6 @@ const ( NoLogin = "Please login Team first \n" WriteError = "Failed To Write" + + TotalScore = " Total Score: " ) diff --git a/types/mongo.go b/types/mongo.go index 097904ed..cd1c7d1a 100644 --- a/types/mongo.go +++ b/types/mongo.go @@ -18,7 +18,6 @@ type CTFTeam struct { type Challenge struct { ID int `json:"id" bson:"id" binding:"required"` - TeamID int `json:"teamid" bson:"teamid" binding:"required"` Name string `json:"name" bson:"name" binding:"required"` Points int `json:"points" bson:"points" binding:"required"` } @@ -31,7 +30,8 @@ type Flag struct { } type Submission struct { - Submitter int `json:"submitter" bson:"submitter" binding:"required"` - ChallengeID int `json:"challengeid" bson:"challengeid" binding:"required"` - Flag string `json:"flag" bson:"flag" binding:"required"` + SubmittedBy int `json:"submittedby" bson:"submittedby" binding:"required"` + ChallengeID int `json:"challengeid" bson:"challengeid" binding:"required"` + Flag string `json:"flag" bson:"flag" binding:"required"` + Time time.Time `json:"time" bson:"time" binding:"required"` }