├── .github └── workflows │ └── create-release.yml ├── README.md ├── demo.png └── pwndb.go /.github/workflows/create-release.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | # Sequence of patterns matched against refs/tags 6 | tags: 7 | - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 8 | 9 | jobs: 10 | 11 | build: 12 | name: Create Release 13 | runs-on: ubuntu-latest 14 | steps: 15 | 16 | - name: Set up Go 1.x 17 | uses: actions/setup-go@v2 18 | with: 19 | go-version: ^1.13 20 | id: go 21 | 22 | - name: Check out code into the Go module directory 23 | uses: actions/checkout@v2 24 | 25 | - name: Get dependencies 26 | run: | 27 | go get -v -t -d ./... 28 | if [ -f Gopkg.toml ]; then 29 | curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh 30 | dep ensure 31 | fi 32 | 33 | - name: Build Linux 34 | run: env GOOS=linux GOARCH=amd64 go build -o pwndb-linux . 35 | 36 | - name: Build Windows 37 | run: env GOOS=windows GOARCH=amd64 go build -o pwndb-windows . 38 | 39 | - name: Build OSX 40 | run: env GOOS=darwin GOARCH=amd64 go build -o pwndb-osx . 41 | 42 | - name: Create Release 43 | id: create_release 44 | uses: actions/create-release@v1 45 | env: 46 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token 47 | with: 48 | tag_name: ${{ github.ref }} 49 | release_name: Release ${{ github.ref }} 50 | draft: false 51 | prerelease: false 52 | 53 | - name: Upload Linux Release 54 | uses: actions/upload-release-asset@v1 55 | env: 56 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 57 | with: 58 | upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 59 | asset_path: ./pwndb-linux 60 | asset_name: pwndb-linux 61 | asset_content_type: application/octet-stream 62 | 63 | - name: Upload Windows Release 64 | uses: actions/upload-release-asset@v1 65 | env: 66 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 67 | with: 68 | upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 69 | asset_path: ./pwndb-windows 70 | asset_name: pwndb-windows.exe 71 | asset_content_type: application/octet-stream 72 | 73 | - name: Upload OSX Release 74 | id: upload-release-asset 75 | uses: actions/upload-release-asset@v1 76 | env: 77 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 78 | with: 79 | upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 80 | asset_path: ./pwndb-osx 81 | asset_name: pwndb-osx 82 | asset_content_type: application/octet-stream 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pwndb 2 | pwndb is a tool that looks for leaked passwords from a dark web breach database given a user or domain. 3 | 4 | 5 | ### Credit 6 | Tool has been extended from the one made by [PostRequest](https://github.com/postrequest) [here](https://github.com/postrequest/tools/tree/master/pwndb). 7 | 8 | ### Usage 9 | Any number of users and domains can be specified. 10 | ``` 11 | pwndb -user foo -user bar 12 | pwndb -domain foo.com -domain bar.com -domain baz.com 13 | ``` 14 | 15 | If at least one user and domain is specfied, all permutations will be checked but it will return *only* results that contain both. 16 | The below command will check foo@baz.com and bar@baz.com 17 | ``` 18 | pwndb -user foo -user bar -domain baz.com 19 | ``` 20 | 21 | ### Installation 22 | 1. Download and install the go tools. [https://golang.org/dl/](https://golang.org/dl/) 23 | 2. Find the location of your GOPATH. 24 | ``` 25 | go env GOPATH 26 | ``` 27 | 3. Drop pwndb.go in GOPATH/src/pwndb (create any folders that don't exist) 28 | 4. Run the go install command and the binary should be able to run from anywhere. 29 | 30 | ``` 31 | go install pwndb 32 | pwndb 33 | ``` 34 | ### Quick Setup 35 | Download and run the binary for your platform below. (or from [releases](https://github.com/coj337/pwndb/releases)) 36 | [Windows](https://github.com/coj337/pwndb/releases/download/v1.1/pwndb-windows.exe) 37 | [Linux](https://github.com/coj337/pwndb/releases/download/v1.1/pwndb-linux) 38 | [OSX](https://github.com/coj337/pwndb/releases/download/v1.1/pwndb-osx) 39 | 40 | ### Demo 41 |  42 | -------------------------------------------------------------------------------- /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coj337/pwndb/76dff913f545d8bd423327bfd88a68e8b218f6e7/demo.png -------------------------------------------------------------------------------- /pwndb.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io/ioutil" 7 | "log" 8 | "net/http" 9 | "net/url" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | // User is the struct that contains leaked credentials 15 | type User struct { 16 | email string 17 | password string 18 | } 19 | 20 | // CheckDump checks pwndb for leaked credentials 21 | func CheckDump(user string, domain string) string { 22 | postParam := url.Values{ 23 | "luser": {user}, 24 | "domain": {domain}, 25 | "luseropr": {"0"}, 26 | "domainopr": {"0"}, 27 | "submitform": {"em"}, 28 | } 29 | client := http.Client{ 30 | Timeout: 30 * time.Second, 31 | } 32 | resp, err := client.PostForm("https://pwndb2am4tzkvold.onion.ws/", postParam) 33 | if err != nil { 34 | log.Fatalln(err) 35 | } 36 | defer resp.Body.Close() 37 | body, err := ioutil.ReadAll(resp.Body) 38 | if err != nil { 39 | log.Fatalln(err) 40 | } 41 | return string(body) 42 | } 43 | 44 | // ParseDump parses the data returned from CheckDump 45 | func ParseDump(rawData string) (users []User) { 46 | leaks := strings.Split(rawData, "Array")[2:] 47 | for _, leak := range leaks { 48 | username := strings.Split(strings.Split(leak, "[luser] => ")[1], "\n")[0] 49 | domain := strings.Split(strings.Split(leak, "[domain] => ")[1], "\n")[0] 50 | email := username + "@" + domain 51 | password := strings.Split(strings.Split(leak, "[password] => ")[1], "\n")[0] 52 | users = append(users, User{email, password}) 53 | } 54 | return 55 | } 56 | 57 | func GetDump(username string, domain string) (users []User) { 58 | body := CheckDump(username, domain) 59 | 60 | // Error if data not returned correctly after a retry 61 | if !strings.Contains(body, "
") { 62 | body := CheckDump(username, domain) 63 | if !strings.Contains(body, "") { 64 | log.Fatalln("Error contacting pwndb") 65 | } 66 | } 67 | rawData := strings.Split(strings.Split(body, "\n")[1], "")[0] 68 | users = ParseDump(rawData) 69 | return 70 | } 71 | 72 | func GetDumps(usernames []string, domains []string) (users []User) { 73 | //If domains and usernames are specified, only find matching permutations, otherwise find all 74 | if len(usernames) > 0 && len(domains) > 0 { 75 | for i := 0; i < len(domains); i++ { 76 | for j := 0; j < len(usernames); j++ { 77 | usersDump := GetDump(usernames[j], domains[i]) 78 | users = append(users, usersDump...) 79 | } 80 | } 81 | } else if len(usernames) > 0 { 82 | for i := 0; i < len(usernames); i++ { 83 | usersDump := GetDump(usernames[i], "") 84 | users = append(users, usersDump...) 85 | } 86 | } else if len(domains) > 0 { 87 | for i := 0; i < len(domains); i++ { 88 | usersDump := GetDump("", domains[i]) 89 | users = append(users, usersDump...) 90 | } 91 | } 92 | 93 | return 94 | } 95 | 96 | func init() { 97 | log.Println() 98 | fmt.Println(` /$$ /$$ 99 | | $$| $$ 100 | /$$$$$$ /$$ /$$ /$$ /$$$$$$$ /$$$$$$$| $$$$$$$ 101 | /$$__ $$| $$ | $$ | $$| $$__ $$ /$$__ $$| $$__ $$ 102 | | $$ \ $$| $$ | $$ | $$| $$ \ $$| $$ | $$| $$ \ $$ 103 | | $$ | $$| $$ | $$ | $$| $$ | $$| $$ | $$| $$ | $$ 104 | | $$$$$$$/| $$$$$/$$$$/| $$ | $$| $$$$$$$| $$$$$$$/ 105 | | $$____/ \_____/\___/ |__/ |__/ \_______/|_______/ 106 | | $$ 107 | | $$ 108 | |__/ ` + "\n") 109 | } 110 | 111 | type arrayFlags []string 112 | 113 | func (i *arrayFlags) String() string { 114 | return "" 115 | } 116 | 117 | func (i *arrayFlags) Set(value string) error { 118 | *i = append(*i, value) 119 | return nil 120 | } 121 | 122 | func main() { 123 | var users, domains arrayFlags 124 | var totalString string 125 | flag.Var(&users, "user", "Username to check") 126 | flag.Var(&domains, "domain", "Domain to check") 127 | flag.Parse() 128 | 129 | if len(domains) == 0 && len(users) == 0 { 130 | flag.Usage() 131 | fmt.Println(" Example: pwndb -user foo -user bar -domain baz.com") 132 | fmt.Println() 133 | log.Fatalln("Please enter domains or users to check.") 134 | } 135 | 136 | dump := GetDumps(users, domains) 137 | if len(dump) < 1 { 138 | log.Fatalln("No data found") 139 | } else if len(dump) == 1 { 140 | totalString = "[1 User]\n" 141 | } else { 142 | totalString = fmt.Sprintf("[%d Users]\n", len(dump)) 143 | } 144 | fmt.Printf(totalString) 145 | for _, user := range dump { 146 | fmt.Println(user.email + ":" + user.password) 147 | } 148 | } 149 | --------------------------------------------------------------------------------