Пример #1
0
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)
	}
}
Пример #2
0
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)
		}
	}
}
Пример #3
0
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
}
Пример #4
0
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")
}
Пример #5
0
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)
}
Пример #6
0
// 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
}
Пример #7
0
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"))
	}
}