命令行上传文件到SkyDrive的研究

2012-12-26 21:06:21 35 10045 3


0x01 背景
我比较怕被查水表,所以常年混迹在国外的网络。但是从国外拖数据回来时特别痛苦,下载速度只有几十K每秒,碰到几个G的数据就需要挂通宵了,而且根据个人的经验,你和目标的连接时间越长,被Kick Out的风险就越大。
于是乎就想是否可以将数据先快速转移到某个地方,然后再从那个地方慢慢拖回来,这样风险就小很多了,比如先弄到网盘上。这个想法在国外的可行性是很高的,他们的网速上行和下行是一样的,也就是说下载速度有2M/s时,上传也是这个速度,而不是像国内下载2M/s,上传只有可怜的50K/s(这里要强烈的谴责腐朽落后的美帝国主义)。而且碰到大型的网络,上行速度甚至可以到几十M/s,这样几个G的数据可以在短短几分钟就转移走。
一开始我在Google开始找相关的资料,看是否有人做过相同的事情,要是有现成的我就懒得自己去动手了,我一直认为重复解决别人已经解决的问题就是在浪费时间。一番搜索还真找到个相关的东西,是DropBox命令行上传的bash脚本,传送门:http://www.andreafabrizi.it/?dropbox_uploader
这个脚本是在linux下面使用的,可以利用CURL来上传、下载DropBox上面的文件,最主要的是完全在命令行界面下面操作。
我分析了下脚本,是利用了DropBox开放的REST API进行操作。
这里关系到OAUTH和REST两个东西,想了解的可以去看看相关的原理。而且我个人也建议在看这篇文章之前或之后去了解下OAuth和REST。OAuth 2.0有份中文译本:http://wenku.baidu.com/view/b37ed7260722192e4536f66e.html
简单来讲OAUTH提供了一个用户资源授权的标准,然后REST通过HTTP方法GET、POST、PUT和DELETE来操作资源。
GET,PUT和POST这种动作用CURL.exe就可以实现,所以我们完全可以用CURL.exe来进行REST的相关操作,这样我们就可以在命令行下面操作网盘了,可以上传、下载和删除网盘上的文件
DropBox的相关的操作可以直接参照那份bash脚本,我是把它改写成了C语言版本的,可以在windows下面使用。

本着探索的精神,我想研究看看SkyDrive能不能这样使用,找了一些资料后开始实验。

0x02 SkyDrive的OAuth认证

首先注册个live账号,[email protected] 注意注册的时候年龄一定要大,最好大于18岁,出生年份选早点,不然需要监管人同意上网神马的
注册好后登陆开发者网站:https://manage.dev.live.com/

创建应用
创建一个应用,名字随便填,我这里填cli-uploader,然后进入到应用设置:

注意这里有个重定向域,随便填一个域名,不需要是存在的域名,但是要记住这个域名,后面要用来获取授权code,这里我填http://twi1ight.com ,其他设置保存不变,保存
每个应用都有一个客户端ID(CLIENT_ID)和客户端密钥(CLIENT_SECRET)
我这里创建的应用信息:
CLIENT_ID:00000000400E8C58
CLIENT_SECRET:T9282s1TDT29O5HeBsZu30KGqYDXd90l

获取授权code
根据live SDK 开发人员指南:http://msdn.microsoft.com/zh-cn/library/live/hh243641.aspx  
REST进行登录的方式为:
https://login.live.com/oauth20_authorize.srf?client_id=CLIENT_ID&scope=SCOPES&response_type=RESPONSE_TYPE&redirect_uri=REDIRECT_URL
其中CLIENT_ID是之前创建应用时有的。SCOPE是操作域,指明需要操作的对象,详细的操作域信息可以参考这里:
http://msdn.microsoft.com/zh-cn/library/live/hh243646.aspx#wlskydriveupdate
由于我们是要上传文件到skydrive中,需要写的权限,所以这里SCOPE指定为wl.skydrive_update,而不是wl.skydrive。
RESPONSE_TYPE 参数的值被设置为 code,它会请求授权code,这个code后面用来申请ACCESS TOKEN。REDIRECT_URI 参数的值是在用户登录之后,Live Connect 将用户返回到的 URL,这个URL必须和之前应用中的重定向域名一致!

这样一来我的应用中获取授权code的URL将被构造成如下格式:
https://login.live.com/oauth20_authorize.srf?client_id=00000000400E8C58&scope=wl.skydrive_update&response_type=code&redirect_uri=http://twi1ight.com
访问后跳出对话框需要登录,输入账号密码登录成功后需要进行授权
授权后浏览器会跳转到一个URL形如:http://twi1ight.com/?code=7727a82a-600e-b7df-f2c7-03fd6515fb96

后面那一串7727a82a-600e-b7df-f2c7-03fd6515fb96就是这次申请的授权code
当然如果你被电信可耻的劫持了,会跳到114so.cn,那么结果就会是这样的一串:
http://sh.114so.cn/dnsA.aspx?AIMT=http%3A//twi1ight.com/%3Fcode%3D7727a82a-600e-b7df-f2c7-03fd6515fb96&host=twi1ight.com&refer=&server=161&pre=1356073772258
仔细看看还是能找到那串授权code的,从%3D后面到&符号为止。

获取ACCESS TOKEN
根据live SDK 开发人员指南,获取ACCESS_TOKEN的格式需要POST数据包,格式如下:
POST https://login.live.com/oauth20_token.srf

Content-type: application/x-www-form-urlencoded

client_id=CLIENT_ID&redirect_uri=REDIRECT_URL&client_secret=CLIENT_SECRET&code=AUTHORIZATION_CODE&grant_type=authorization_code
这个很好解决,CURL可以直接POST数据包,将各个数据代入里面,由于CURL在POST数据时,Conten-type默认就是application/x-www-form-urlencoded这种形式,所以就不需要指定--header了,构造的命令格式如下(因为是https,所以加上-k)
curl -k --data "client_id=00000000400E8C58&redirect_uri=http://twi1ight.com&client_secret=T9282s1TDT29O5HeBsZu30KGqYDXd90l&code=7727a82a-600e-b7df-f2c7-03fd6515fb96&grant_type=authorization_code" https://login.live.com/oauth20_token.srf
可以直接在命令行下执行这个,就获得了一个ACCESS_TOKEN:

但是这样复制出来的文字是断行的,我推荐直接输出到一个文件中,那样是不断行的。
OK,绕了这么久,终于搞到最终的ACCESS_TOKEN,这样我们就可以开始上传文件了

0x03 上传文件

根据MSDN:http://msdn.microsoft.com/zh-cn/library/live/hh826531.aspx#uploading_files
REST上传文件的格式如下:
PUT https://apis.live.net/v5.0/me/skydrive/files/HelloWorld.txt?access_token=ACCESS_TOKEN

Hello, World!
其中HelloWorld.txt是上传的文件名字,"Hello, World!"是文件内容
根据这个格式,我先用BurpSuite试一下,构造的数据包与结果如图:


上传成功,SkyDrive上面有了Twi1ight.txt这个文件

但是有个问题,这里是上传的TXT,那如果是个压缩包或者图片什么的,就没办法用BurpSuite上传。
这时候就该CURL出场了。
根据CURL的使用说明:http://curl.haxx.se/docs/httpscripting.html  
curl的--upload-file选项用的就是PUT方式,于是乎结合起来用CURL上传文件到SkyDrive应该是这样:

curl --progress-bar -k -i --upload-file T00ls.Net-Twi1ight.txt  https://apis.live.net/v5.0/me/skydrive/files/T00ls.Net-Twi1ight.txt?access_token=ACCESS_TOKEN

去SkyDrive的WEB界面看看结果:

OK,上传成功!
测试压缩包也是成功的,而且不会损坏压缩包。
这就说明用CURL在命令行下操作SkyDrive是可行的

0x04 存在的问题

DropBox的ACCESS TOKEN配置好后可以一直使用,是不会过期的,所以程序配置好后就可以终生使用了。
但是Skydrive不像DropBox,SkyDrive的ACCESS TOKEN是会过期的,有效期默认只有1个小时;不单如此,连授权code都是会过期的,这样的话每次要上传文件都必须要重新进行一系列的认证:获取授权码,登陆web授权,获取ACCESS TOKEN……特别麻烦

根据MSDN以及OAuth标准中的相关信息,我发现其实是有个REFRESH TOKEN存在的,而且REFRESH TOKEN 是长期有效的,当我们的ACCESS TOKEN过期时,可以直接使用REFRESH TOKEN来获取一个新的ACCESS TOKEN,就不需要再去获取授权code,然后用授权code获取ACCESS TOKEN这样了。
根据OAuth认证流程:http://msdn.microsoft.com/zh-cn/library/live/hh243647.aspx#authcodegrant
如果我们在获取授权code的时候指定了wl.offline_access 作用域,则还会返回一个刷新令牌(REFRESH TOKEN)。

那么现在我们需要申请一个REFRESH TOKEN时,就要指定两个作用域:wl.skydrive_update和wl.offline_access,多个作用域之前用空格分开,获取授权code时的URL就会变成这样:
https://login.live.com/oauth20_authorize.srf?client_id=00000000400E8C58&scope=wl.skydrive_update%20wl.offline_access&response_type=code&redirect_uri=http://twi1ight.com

访问这个URL,登陆后跳出来对话框,需要授权:

注意:这里是随时访问,可以和之前那个授权比较一下,是不一样的!

确定后同样可以获得一个授权code。
然后利用这个授权code和之前一样的步骤去申请ACCESS TOKEN.


注意这时候的结果,有一个ACESS TOKEN,同时也有一个REFRESH TOKEN,注意保存好这个REFRESH TOKEN,这样以后就不用这样麻烦的认证了。

然后我们尝试用这个REFRESH TOKEN去获取一个ACCESS TOKEN,根据OAuth认证流程:http://msdn.microsoft.com/zh-cn/library/live/hh243647.aspx#authcodegrant
用刷新令牌获取访问令牌(ACCESS TOKEN)的HTTP包格式如下:
POST https://login.live.com/oauth20_token.srf

Content-type: application/x-www-form-urlencoded

client_id=CLIENT_ID&client_secret=CLIENT_SECRET&redirect_uri=REDIRECT_URI&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
所以CURL命令格式就是:
curl -k --data “client_id=CLIENT_ID&client_secret=CLIENT_SECRET&redirect_uri=REDIRECT_URI&grant_type=refresh_token&refresh_token=REFRESH_TOKEN”  https://login.live.com/oauth20_token.srf



返回了一个ACCESS TOKEN,同时还有一个新的REFRESH TOKEN
这里我也疑惑这个新的RESFRESH TOKEN,是不是这样老的就不能用了,然后Google查了一下,得到这个结果:
http://social.msdn.microsoft.com/Forums/en-US/messengerconnect/thread/5f9bfda7-98d7-45b1-a1e4-2da9195b085e
这就是说新的老的都能用,但是每个REFRESH TOKEN实际上还是有有效期的,是一年,当老的REFRESH TOKEN快要到期时你可以使用新的,或者你可以每次都记录新的REFRESH TOKEN然后把老的丢掉。

0x05 自动化

由前面的内容可以看到,要在命令行下面进行这些动作还是很麻烦的,需要动态的构造各种URL,各种长,各种麻烦。
为了不要每次都做这么多繁杂的事情,所以我就写了个简单的bat来自动干这些事情。

提供三个选项:-g -f -m
-g是通过REFRESH TOKEN来获取ACCESS TOKEN
-f是上传单个文件
-m是上传指定后缀的文件,比如rar
有个限定就是指定的文件必须和这个bat处在同一目录

获取ACCESS TOKEN


上传单个文件的截图:


0x06 杂谈

SkyDrive的单个文件上传大小限制是100M,所以在压缩文件时注意要指定分卷压缩。
DropBox的大小限制是300M,但是当网速不够快,300M的上传时间就会比较久,而REST是无状态的,有可能会导致服务器认为这个上传已经取消了,当你用CURL上传完毕时可能服务器已经不处理这个文件了,就导致上传失败,所以DropBox的上传我一般也会分卷压缩100M或者150M,防止意外。
这个东西对于像我这种常年在国外的网络混的人可能用处更大一些,比如有时候我需要离线抓取域的hash,ntds.dit数据库可能会有几百M甚至几个G,下载回来的话需要的时间太久,我就会用RAR在命令行下面分卷压缩,上传到DropBox,也就几分钟的事情,然后再挂个VPN,从DropBox把数据下载回来。
我手头的一个棒子的vpn在DropBox的下载速度可以达到2M/s,单个文件的下载速度可以到750k/s左右,为了防止vpn服务器被我拖垮,我一般同时下载两个文件,速度在1.5M/s上下,这样中转一下,一般1个G的文件我这里10分钟多一点就下载好了,如果是直接从国外下载就可能需要好几个小时了。


我看到国内百度和腾讯也有OAuth和REST相关的API开放,本来也想去试试看的,无奈百度的开发者身份需要申请,腾讯的也需要填一堆什么实名认证的东西,相当之麻烦,遂放弃。不过就国内这上传速度,估计真搞出来了也是理论性强于实用性,聊表安慰吧。


T00ls-Skydrive:

关于作者

评论35次

要评论?请先  登录  或  注册