func resultUpdater(db *sql.DB, updateTimeout time.Duration, darkestTime time.Time) { for { res, err := CollectLastResult(db) if err != nil { log.Println("Collect last result fail:", err) time.Sleep(updateTimeout) continue } lastResult = res if time.Now().Before(darkestTime) { CountScoreAndSort(&res) currentResult = res.ToHTML(false) } else { currentResult = res.ToHTML(true) // hide score } now := time.Now() lastUpdated = fmt.Sprintf("%02d:%02d:%02d", now.Hour(), now.Minute(), now.Second()) r, err := steward.CurrentRound(db) if err != nil { round = 0 } else { round = r.ID } time.Sleep(updateTimeout) } }
func TestRoundWork(t *testing.T) { db, err := openDB() defer db.Close() round_len := time.Minute * 2 _, err = steward.CurrentRound(db.db) if err == nil { log.Fatalln("Current round in empty database already exist") } var i int for i = 1; i < 5; i++ { new_round, err := steward.NewRound(db.db, round_len) if err != nil { log.Fatalln("Start new round fail:", err) } if new_round != i { log.Fatalln("New round number invalid", new_round, i) } current_round, err := steward.CurrentRound(db.db) if err != nil { log.Fatalln("Get current round fail:", err) } if current_round.ID != new_round { log.Fatalln("Current round number invalid") } if current_round.Len != round_len { log.Fatalln("Current round len invalid") } if time.Now().Sub(current_round.StartTime) > 5*time.Second { log.Fatalln("Time must be ~ current:", current_round.StartTime) } } }
func collectTeamResult(db *sql.DB, team steward.Team, services []steward.Service) (tr TeamResult, err error) { tr.ID = team.ID tr.Name = team.Name rr, err := steward.GetLastResult(db, team.ID) if err != nil { // At game start, no result exist rr = steward.RoundResult{AttackScore: 0, DefenceScore: 0} } tr.Attack = rr.AttackScore tr.Defence = rr.DefenceScore advisory, err := steward.GetAdvisoryScore(db, team.ID) if err != nil { tr.Advisory = 0 } else { tr.Advisory = advisory } round, err := steward.CurrentRound(db) if err != nil { // At game start, no round exist return tr, nil } for _, svc := range services { s := steward.Status{round.ID, team.ID, svc.ID, -1} state, err := steward.GetState(db, s) if err != nil { // Try to get status from previous round s.Round-- state, err = steward.GetState(db, s) if err != nil { state = steward.StatusDown } } tr.Status = append(tr.Status, state) } return }
func advisoryHandler(conn net.Conn, db *sql.DB) { addr := conn.RemoteAddr().String() defer conn.Close() round, err := steward.CurrentRound(db) if err != nil { log.Println("Get current round fail:", err) fmt.Fprint(conn, internalErrorMsg) return } roundEndTime := round.StartTime.Add(round.Len) if time.Now().After(roundEndTime) { fmt.Fprintln(conn, "Current contest not runned") return } fmt.Fprint(conn, "IBST.PSU CTF Advisory Receiver\n"+ "Insert empty line for close\n"+ "Input advisory: ") scanner := bufio.NewScanner(conn) var advisory string for scanner.Scan() { advisory += scanner.Text() + "\n" if len(advisory) > 2 { if advisory[len(advisory)-2:len(advisory)-1] == "\n" { // remove last newline advisory = advisory[:len(advisory)-1] break } } } httpGetRoot := "GET / HTTP/1.1" if len(advisory) > len(httpGetRoot) { if advisory[0:len(httpGetRoot)] == httpGetRoot { fmt.Fprintf(conn, "\n\nIt's not a HTTP server! "+ "Use netcat for communication.") return } } r := `[ -~]` if hasUnacceptableSymbols(advisory, r) { fmt.Fprintf(conn, "Accept only %s\n", r) return } team, err := teamByAddr(db, addr) if err != nil { log.Println("\tGet team by ip failed:", err) fmt.Fprint(conn, invalidTeamMsg) return } _, err = steward.AddAdvisory(db, team.ID, advisory) if err != nil { log.Println("\tAdd advisory failed:", err) fmt.Fprint(conn, internalErrorMsg) return } fmt.Fprint(conn, "Accepted\n") }
func handler(conn net.Conn, db *sql.DB, priv *rsa.PrivateKey, attackFlow chan scoreboard.Attack) { addr := conn.RemoteAddr().String() defer conn.Close() fmt.Fprint(conn, greetingMsg) flag, err := bufio.NewReader(conn).ReadString('\n') if err != nil { log.Println("Read error:", err) } flag = strings.Trim(flag, "\n") log.Printf("\tGet flag %s from %s", flag, addr) valid, err := vexillary.ValidFlag(flag, priv.PublicKey) if err != nil { log.Println("\tValidate flag failed:", err) } if !valid { fmt.Fprint(conn, invalidFlagMsg) return } exist, err := steward.FlagExist(db, flag) if err != nil { log.Println("\tExist flag check failed:", err) fmt.Fprint(conn, internalErrorMsg) return } if !exist { fmt.Fprint(conn, flagDoesNotExistMsg) return } flg, err := steward.GetFlagInfo(db, flag) if err != nil { log.Println("\tGet flag info failed:", err) fmt.Fprint(conn, internalErrorMsg) return } captured, err := steward.AlreadyCaptured(db, flg.ID) if err != nil { log.Println("\tAlready captured check failed:", err) fmt.Fprint(conn, internalErrorMsg) return } if captured { fmt.Fprint(conn, alreadyCapturedMsg) return } team, err := teamByAddr(db, addr) if err != nil { log.Println("\tGet team by ip failed:", err) fmt.Fprint(conn, invalidTeamMsg) return } if flg.TeamID == team.ID { log.Printf("\tTeam %s try to send their flag", team.Name) fmt.Fprint(conn, flagYoursMsg) return } round, err := steward.CurrentRound(db) if round.ID != flg.Round { log.Printf("\t%s try to send flag from past round", team.Name) fmt.Fprint(conn, flagExpiredMsg) return } roundEndTime := round.StartTime.Add(round.Len) if time.Now().After(roundEndTime) { log.Printf("\t%s try to send flag from finished round", team.Name) fmt.Fprint(conn, flagExpiredMsg) return } halfStatus := steward.Status{flg.Round, team.ID, flg.ServiceID, steward.StatusUnknown} state, err := steward.GetState(db, halfStatus) if state != steward.StatusUP { log.Printf("\t%s service not ok, cannot capture", team.Name) fmt.Fprint(conn, serviceNotUpMsg) return } err = steward.CaptureFlag(db, flg.ID, team.ID) if err != nil { log.Println("\tCapture flag failed:", err) fmt.Fprint(conn, internalErrorMsg) return } go func() { attack := scoreboard.Attack{ Attacker: team.ID, Victim: flg.TeamID, Service: flg.ServiceID, Timestamp: time.Now().Unix(), } select { case attackFlow <- attack: default: _ = <-attackFlow attackFlow <- attack } }() fmt.Fprint(conn, capturedMsg) }
// Round start new round func (g Game) Round(counters *sync.WaitGroup) (err error) { roundNo, err := steward.NewRound(g.db, g.roundLen) if err != nil { return } log.Println("New round", roundNo) err = checker.PutFlags(g.db, g.priv, roundNo, g.teams, g.services) if err != nil { return } round, err := steward.CurrentRound(g.db) if err != nil { return } roundEnd := round.StartTime.Add(round.Len) for time.Now().Before(roundEnd) { log.Println("Round", round.ID, "check start") err = checker.CheckFlags(g.db, round.ID, g.teams, g.services) if err != nil { return } timeout := RandomizeTimeout(g.timeout, g.timeout/3) if time.Now().Add(timeout).After(roundEnd) { break } log.Println("Round", round.ID, "check end, timeout", timeout) time.Sleep(timeout) } log.Println("Check", round.ID, "over, wait", time.Now().Sub(roundEnd)) for time.Now().Before(roundEnd) { time.Sleep(time.Second / 10) } counters.Add(1) go func() { defer counters.Done() log.Println("Count round", round.ID, "start", time.Now()) err = counter.CountRound(g.db, round.ID, g.teams, g.services) if err != nil { log.Println("Count round", round.ID, "failed:", err) } log.Println("Count round", round.ID, "end", time.Now()) }() return }
func TestReceiver(*testing.T) { db, err := openDB() if err != nil { log.Fatalln("Open database failed:", err) } defer db.Close() priv, err := vexillary.GenerateKey() if err != nil { log.Fatalln("Generate key failed:", err) } addr := "127.0.0.1:65000" flag, err := vexillary.GenerateFlag(priv) if err != nil { log.Fatalln("Generate flag failed:", err) } err = steward.AddFlag(db.db, steward.Flag{-1, flag, 1, 8, 1, ""}) if err != nil { log.Fatalln("Add flag failed:", err) } firstRound, err := steward.NewRound(db.db, time.Minute*2) if err != nil { log.Fatalln("New round failed:", err) } attackFlow := make(chan scoreboard.Attack) go FlagReceiver(db.db, priv, addr, time.Nanosecond, time.Minute, attackFlow) time.Sleep(time.Second) // wait for init listener // The attacker must appear to be a team (e.g. jury cannot attack) testFlag(addr, flag, invalidTeamMsg) t := steward.Team{ID: -1, Name: "TestTeam", Subnet: "127.0.0.1/24", Vulnbox: "1"} // Correct flag must be captured teamID, err := steward.AddTeam(db.db, t) if err != nil { log.Fatalln("Add team failed:", err) } serviceID := 1 // Flag must be captured only if service status ok steward.PutStatus(db.db, steward.Status{firstRound, teamID, serviceID, steward.StatusUP}) testFlag(addr, flag, capturedMsg) // Correct flag must be captured only one testFlag(addr, flag, alreadyCapturedMsg) // Incorrect (non-signed or signed on other key) flag must be invalid testFlag(addr, "1e7b642f2282886377d1655af6097dd6101eac5b=", invalidFlagMsg) // Correct flag that does not exist in database must not be captured newFlag, err := vexillary.GenerateFlag(priv) if err != nil { log.Fatalln("Generate flag failed:", err) } testFlag(addr, newFlag, flagDoesNotExistMsg) // Submitted flag does not belongs to the attacking team flag4, err := vexillary.GenerateFlag(priv) if err != nil { log.Fatalln("Generate flag failed:", err) } err = steward.AddFlag(db.db, steward.Flag{-1, flag4, 1, teamID, 1, ""}) if err != nil { log.Fatalln("Add flag failed:", err) } testFlag(addr, flag4, flagYoursMsg) // Correct flag from another round must not be captured flag2, err := vexillary.GenerateFlag(priv) if err != nil { log.Fatalln("Generate flag failed:", err) } curRound, err := steward.CurrentRound(db.db) err = steward.AddFlag(db.db, steward.Flag{-1, flag2, curRound.ID, 8, 1, ""}) if err != nil { log.Fatalln("Add flag failed:", err) } _, err = steward.NewRound(db.db, time.Minute*2) if err != nil { log.Fatalln("New round failed:", err) } testFlag(addr, flag2, flagExpiredMsg) // Correct flag from expired round must not be captured roundLen := time.Second roundID, err := steward.NewRound(db.db, roundLen) if err != nil { log.Fatalln("New round failed:", err) } flag3, err := vexillary.GenerateFlag(priv) if err != nil { log.Fatalln("Generate flag failed:", err) } err = steward.AddFlag(db.db, steward.Flag{-1, flag3, roundID, 8, 1, ""}) if err != nil { log.Fatalln("Add flag failed:", err) } time.Sleep(roundLen) // wait end of round testFlag(addr, flag3, flagExpiredMsg) // If service status down flag must not be captured roundID, err = steward.NewRound(db.db, time.Minute) if err != nil { log.Fatalln("New round failed:", err) } flag5, err := vexillary.GenerateFlag(priv) if err != nil { log.Fatalln("Generate flag failed:", err) } err = steward.AddFlag(db.db, steward.Flag{-1, flag5, roundID, 8, serviceID, ""}) if err != nil { log.Fatalln("Add flag failed:", err) } steward.PutStatus(db.db, steward.Status{roundID, teamID, serviceID, steward.StatusDown}) testFlag(addr, flag5, serviceNotUpMsg) steward.PutStatus(db.db, steward.Status{roundID, teamID, serviceID, steward.StatusUP}) // If attempts limit exceeded flag must not be captured newAddr := "127.0.0.1:64000" // Start new receiver for test timeouts go FlagReceiver(db.db, priv, newAddr, time.Second, time.Minute, attackFlow) time.Sleep(time.Second) // wait for init listener // Just for take timeout testFlag(newAddr, flag3, flagExpiredMsg) // Can't use testFlag, if attempts limit exceeded server does not send // greeting message, and client has not able to send flag conn, err := net.DialTimeout("tcp", newAddr, time.Second) if err != nil { log.Fatalln("Connect to receiver failed:", err) } msg, err := bufio.NewReader(conn).ReadString('\n') if err != nil { log.Fatalln("Invalid response:", err) } response := attemptsLimitMsg if msg != response { log.Fatalf("Invalid message [%v] instead [%v]", strings.Trim(msg, "\n"), strings.Trim(response, "\n")) } }