Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Maximum Attempt Limit to Submit Flag #370

Open
wants to merge 19 commits into
base: multiple_servers
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ site/
ubuntu-bionic-18.04-cloudimg-console.log
target/
.vscode/
vendor
vendor/
2 changes: 1 addition & 1 deletion _examples/web-php/beast.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ name = "web-php"
flag = "BACKDOOR{SAMPLE_WEB_FLAG}"
type = "web:php:7.1:cli"
hints = ["web_hint_1", "web_hint_2"]
failSolveLimit = 3
max_attempt_limit = 3

[challenge.env]
ports = [10002]
Expand Down
2 changes: 1 addition & 1 deletion _examples/xinetd-service/beast.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ flag = "CTF{sample_flag}"
type = "service"
hints = ["xinetd_hint_1", "xinetd_hint_2"]
preReqs = ["simple", "web-php"]
failSolveLimit=2
max_attempt_limit=2

[challenge.env]
apt_deps = ["gcc", "socat"]
Expand Down
10 changes: 4 additions & 6 deletions api/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ func hintHandler(c *gin.Context) {
// If hint already taken, just return the description
c.JSON(http.StatusOK, HTTPPlainResp{
Message: hint.Description,

})
return
}
Expand Down Expand Up @@ -241,7 +240,6 @@ func challengeInfoHandler(c *gin.Context) {
c.Abort()
return
}


autherr := auth.Authorize(values[1], core.ADMIN)

Expand All @@ -255,7 +253,7 @@ func challengeInfoHandler(c *gin.Context) {
Status: challenge.Status,
Ports: challengePorts,
Hints: hintInfos,
FailSolveLimit: challenge.FailSolveLimit,
MaxAttemptLimit: challenge.MaxAttemptLimit,
Desc: challenge.Description,
Assets: strings.Split(challenge.Assets, core.DELIMITER),
AdditionalLinks: strings.Split(challenge.AdditionalLinks, core.DELIMITER),
Expand All @@ -278,7 +276,7 @@ func challengeInfoHandler(c *gin.Context) {
Status: challenge.Status,
Ports: challengePorts,
Hints: hintInfos,
FailSolveLimit: challenge.FailSolveLimit,
MaxAttemptLimit: challenge.MaxAttemptLimit,
Desc: challenge.Description,
Assets: strings.Split(challenge.Assets, core.DELIMITER),
AdditionalLinks: strings.Split(challenge.AdditionalLinks, core.DELIMITER),
Expand Down Expand Up @@ -463,7 +461,7 @@ func challengesInfoHandler(c *gin.Context) {
ID: hint.HintID,
Points: hint.Points,
}
}
}
// Get previous tries for the current user and challenge
previousTries, err := database.GetUserPreviousTries(user.ID, challenge.ID)
if err != nil {
Expand All @@ -481,7 +479,7 @@ func challengesInfoHandler(c *gin.Context) {
Status: challenge.Status,
Ports: challengePorts,
Hints: hintInfos,
FailSolveLimit: challenge.FailSolveLimit,
MaxAttemptLimit: challenge.MaxAttemptLimit,
Desc: challenge.Description,
Points: challenge.Points,
Assets: strings.Split(challenge.Assets, core.DELIMITER),
Expand Down
4 changes: 2 additions & 2 deletions api/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ type ChallengeInfoResp struct {
AdditionalLinks []string `json:"additionalLinks" example:"['http://link1.abc:8080','http://link2.abc:8081']"`
CreatedAt time.Time `json:"createdAt"`
Status string `json:"status" example:"deployed"`
FailSolveLimit int `json:"failSolveLimit" example:"5"`
MaxAttemptLimit int `json:"maxAttemptLimit" example:"5"`
PreReqs []string `json:"preReqs" example:"['web-php','simple']"`
Ports []uint32 `json:"ports" example:[3001, 3002]`
Hints []HintInfo `json:"hints"`
Expand All @@ -137,7 +137,7 @@ type ChallengePreviewResp struct {
Tags []string `json:"tags" example:"['pwn','misc']"`
Assets []string `json:"assets" example:"['image1.png', 'zippy.zip']"`
AdditionalLinks []string `json:"additionalLinks" example:"['http://link1.abc:8080','http://link2.abc:8081']"`
FailSolveLimit int `json:"failSolveLimit" example:"5"`
MaxAttemptLimit int `json:"maxAttemptLimit" example:"5"`
PreReqs []string `json:"preReqs" example:"['web-php','simple']"`
Aryan51203 marked this conversation as resolved.
Show resolved Hide resolved
Ports []uint32 `json:"ports" example:[3001, 3002]`
Desc string `json:"description" example:"A simple web challenge"`
Expand Down
2 changes: 1 addition & 1 deletion api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func initGinRouter() *gin.Engine {
infoGroup.GET("/submissions", submissionsHandler)
infoGroup.GET("/tags", tagHandler)
infoGroup.GET("/hint/:hintID", hintHandler)
infoGroup.POST("/hint/:hintID",hintHandler)
infoGroup.POST("/hint/:hintID", hintHandler)
infoGroup.GET("/download", serveAssets)
}

Expand Down
33 changes: 18 additions & 15 deletions api/submit.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,21 +113,24 @@ func submitFlagHandler(c *gin.Context) {
})
return
}
preReqsStatus, err := database.CheckPreReqsStatus(challenge, user.ID)

if err != nil {
c.JSON(http.StatusInternalServerError, HTTPErrorResp{
Error: "DATABASE ERROR while processing the request.",
})
return
}
if challenge.PreReqs != "" {
preReqsStatus, err := database.CheckPreReqsStatus(challenge, user.ID)

if !preReqsStatus {
c.JSON(http.StatusOK, FlagSubmitResp{
Message: "You have not solved the prerequisites of this challenge.",
Success: false,
})
return
if err != nil {
c.JSON(http.StatusInternalServerError, HTTPErrorResp{
Error: "DATABASE ERROR while processing the request.",
})
return
}

if !preReqsStatus {
c.JSON(http.StatusOK, FlagSubmitResp{
Message: "You have not solved the prerequisites of this challenge.",
Success: false,
})
return
}
}

// If the challenge is dynamic, then the flag is not stored in the database
Expand Down Expand Up @@ -204,7 +207,7 @@ func submitFlagHandler(c *gin.Context) {
return
}

if challenge.FailSolveLimit > 0 {
if challenge.MaxAttemptLimit > 0 {
previousTries, err := database.GetUserPreviousTries(user.ID, challenge.ID)

if err != nil {
Expand All @@ -213,7 +216,7 @@ func submitFlagHandler(c *gin.Context) {
return
}

if previousTries >= challenge.FailSolveLimit {
if previousTries >= challenge.MaxAttemptLimit {
c.JSON(http.StatusOK, FlagSubmitResp{
Message: "You have reached the maximum number of tries for this challenge.",
Success: false,
Expand Down
15 changes: 6 additions & 9 deletions core/config/challenge.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ type ChallengeMetadata struct {
Text string `toml:"text"`
Points uint `toml:"points"`
} `toml:"hints"`
FailSolveLimit *int `toml:"failSolveLimit"`
MaxAttemptLimit int `toml:"max_attempt_limit"`
PreReqs []string `toml:"preReqs"`
DynamicFlag bool `toml:"dynamic_flag"`
Points uint `toml:"points"`
Expand All @@ -157,15 +157,12 @@ func (config *ChallengeMetadata) ValidateRequiredFields() (error, bool) {
return fmt.Errorf("Name and Flag required for the challenge"), false
}

// Checks if fail solve limit is provided and is greater than 0.
if config.FailSolveLimit != nil {
if *config.FailSolveLimit <= 0 {
return fmt.Errorf("fail Solve Limit must be greater than equal to 0"), false
}
} else {
// Checks if fail solve limit is provided and is greater than 0
if config.MaxAttemptLimit < 0 {
return fmt.Errorf("fail solve limit must be greater than equal to 0"), false
} else if config.MaxAttemptLimit == 0 {
Aryan51203 marked this conversation as resolved.
Show resolved Hide resolved
// sets default value to -1 so it means that there is no limit.
defaultLimit := -1
config.FailSolveLimit = &defaultLimit
config.MaxAttemptLimit = -1
}

if !(utils.StringInSlice(config.Sidecar, Cfg.AvailableSidecars) || config.Sidecar == "") {
Expand Down
1 change: 1 addition & 0 deletions core/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ func (config *BeastConfig) ValidateConfig() error {

return nil
}

type AvailableServer struct {
Host string `toml:"host"`
Username string `toml:"username"`
Expand Down
2 changes: 1 addition & 1 deletion core/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const ( //names
ISSUER string = "beast-sds"
DELIMITER string = "::::"
LOCALHOST string = "localhost"
BEAST_REMOTE_GLOBAL_DIR string = "~/.beast" // This should always be used for remote only.
BEAST_REMOTE_GLOBAL_DIR string = "~/.beast" // This should always be used for remote only.
)

const ( //paths
Expand Down
44 changes: 17 additions & 27 deletions core/database/challenges.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type Challenge struct {
DynamicFlag bool `gorm:"not null;default:false"`
Flag string `gorm:"type:text"`
Type string `gorm:"type:varchar(64)"`
FailSolveLimit int `gorm:"default:-1"`
MaxAttemptLimit int `gorm:"default:-1"`
PreReqs string `gorm:"type:text"`
Sidecar string `gorm:"type:varchar(64)"`
Assets string `gorm:"type:text"`
Expand Down Expand Up @@ -185,36 +185,24 @@ func QueryFirstChallengeEntry(key string, value string) (Challenge, error) {

// Check Pre Reqs Status
func CheckPreReqsStatus(challenge Challenge, userID uint) (bool, error) {
if challenge.PreReqs == "" {
return true, nil
}
// Split the PreReqs field to get the list of prerequisite challenge names
preReqChallengeNames := strings.Split(challenge.PreReqs, core.DELIMITER)

// Query the database to get the user's solved challenges
var userChallenges []UserChallenges
err := Db.Where("user_id = ? AND solved = ?", userID, true).Find(&userChallenges).Error
if err != nil {
return false, err
}

// Create a map to quickly check if a challenge is solved
solvedChallenges := make(map[string]bool)
for _, userChallenge := range userChallenges {
if userChallenge.Solved {
var solvedChallenge Challenge
err := Db.Where("id = ?", userChallenge.ChallengeID).First(&solvedChallenge).Error
if err != nil {
return false, err
}
solvedChallenges[solvedChallenge.Name] = true
}
}

// Check if all prerequisite challenges are solved
for _, preReq := range preReqChallengeNames {
if !solvedChallenges[preReq] {
return false, nil
var preReqChallenge Challenge
err := Db.Where("name = ?", preReq).First(&preReqChallenge).Error
if err != nil {
return false, err
}

var userChallenge UserChallenges
err = Db.Where("user_id = ? AND challenge_id = ? AND solved = ?", userID, preReqChallenge.ID, true).First(&userChallenge).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return false, nil
}
return false, err
}
}

Expand Down Expand Up @@ -261,7 +249,9 @@ func UpdateUserChallengeTries(userID uint, challengeID uint) error {
"tries": userChallenges.Tries + 1,
}

return Db.Model(&UserChallenges{}).Where("user_id = ? AND challenge_id = ?", userID, challengeID).Updates(updates).Error
tx := Db.Model(&UserChallenges{}).Where("user_id = ? AND challenge_id = ?", userID, challengeID).Updates(updates)

return tx.Error
}

// Update an entry for the challenge in the Challenge table
Expand Down
10 changes: 5 additions & 5 deletions core/database/hints.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
)

type Hint struct {
HintID uint `gorm:"primaryKey;autoIncrement"`
ChallengeID uint `gorm:"not null"`
HintID uint `gorm:"primaryKey;autoIncrement"`
ChallengeID uint `gorm:"not null"`
Points uint `gorm:"not null"`
Description string `gorm:"size:255"`
Description string `gorm:"size:255"`
}

type UserHint struct {
Expand Down Expand Up @@ -64,7 +64,7 @@ func GetHintByID(hintID uint) (*Hint, error) {
return &hint, nil
}

//checks if user has already taken the hint
// checks if user has already taken the hint
func UserHasTakenHint(userID, hintID uint) (bool, error) {
DBMux.Lock()
defer DBMux.Unlock()
Expand Down Expand Up @@ -117,7 +117,7 @@ func SaveUserHint(userID, challengeID, hintID uint) error {
// Check if user has enough points
if user.Score < hint.Points {
tx.Rollback()
return fmt.Errorf("Not enough points to take this hint")
return fmt.Errorf("not enough points to take this hint")
}

// Deduct points from user
Expand Down
32 changes: 16 additions & 16 deletions core/manager/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -497,20 +497,20 @@ func UpdateOrCreateChallengeDbEntry(challEntry *database.Challenge, config cfg.B
}
*challEntry = database.Challenge{

Aryan51203 marked this conversation as resolved.
Show resolved Hide resolved
Name: config.Challenge.Metadata.Name,
AuthorID: userEntry.ID,
Format: config.Challenge.Metadata.Type,
Status: core.DEPLOY_STATUS["undeployed"],
ContainerId: coreUtils.GetTempContainerId(config.Challenge.Metadata.Name),
ImageId: coreUtils.GetTempImageId(config.Challenge.Metadata.Name),
FailSolveLimit: *config.Challenge.Metadata.FailSolveLimit,
PreReqs: strings.Join(config.Challenge.Metadata.PreReqs, core.DELIMITER),
DynamicFlag: config.Challenge.Metadata.DynamicFlag,
Flag: config.Challenge.Metadata.Flag,
Type: config.Challenge.Metadata.Type,
Sidecar: config.Challenge.Metadata.Sidecar,
Description: config.Challenge.Metadata.Description,
Assets: strings.Join(assetsURL, core.DELIMITER),
Name: config.Challenge.Metadata.Name,
AuthorID: userEntry.ID,
Format: config.Challenge.Metadata.Type,
Status: core.DEPLOY_STATUS["undeployed"],
ContainerId: coreUtils.GetTempContainerId(config.Challenge.Metadata.Name),
ImageId: coreUtils.GetTempImageId(config.Challenge.Metadata.Name),
MaxAttemptLimit: config.Challenge.Metadata.MaxAttemptLimit,
PreReqs: strings.Join(config.Challenge.Metadata.PreReqs, core.DELIMITER),
DynamicFlag: config.Challenge.Metadata.DynamicFlag,
Flag: config.Challenge.Metadata.Flag,
Type: config.Challenge.Metadata.Type,
Sidecar: config.Challenge.Metadata.Sidecar,
Description: config.Challenge.Metadata.Description,
Assets: strings.Join(assetsURL, core.DELIMITER),
AdditionalLinks: strings.Join(config.Challenge.Metadata.AdditionalLinks, core.DELIMITER),
Points: config.Challenge.Metadata.Points,
MinPoints: config.Challenge.Metadata.MinPoints,
Expand Down Expand Up @@ -899,7 +899,7 @@ func UpdateChallenges(defaultauthorpassword string) {
log.Debugf("Challenges updated in Db")
}

func ValidateFlag(flag, challenge_name string) error{
func ValidateFlag(flag, challenge_name string) error {
if challenge_name == "" {
log.Errorf("Challenge name is empty")
return fmt.Errorf("challenge name is empty")
Expand All @@ -912,7 +912,7 @@ func ValidateFlag(flag, challenge_name string) error{

dynamicflag := database.DynamicFlag{
Name: challenge_name,
Flag: flag,
Flag: flag,
}
err := database.CreateDynamicFlagEntry(&dynamicflag)

Expand Down
5 changes: 0 additions & 5 deletions vendor/github.com/BurntSushi/toml/.gitignore

This file was deleted.

15 changes: 0 additions & 15 deletions vendor/github.com/BurntSushi/toml/.travis.yml

This file was deleted.

3 changes: 0 additions & 3 deletions vendor/github.com/BurntSushi/toml/COMPATIBLE

This file was deleted.

Loading