利用网盘秒传功能,套取他人文件

最近由某些原因,需要下载上古时代的文件,结果找出来的链接要么失效、要么龟速。

然后就想到了用网盘的秒传功能来帮我找文件。

其实这方法在阿里云盘上线的早期已经试过,是可以正常用的,不过后来接口加了密,就没继续跟进了。

这次玩的是天翼云盘,毕竟这个是真的不限速!

话不多说,直接开干。

打开F12,找一个可以被秒传的文件,上传

很容易观察到秒传调用接口分两步:

1

2

https://upload.cloud.189.cn/person/initMultiUpload

https://upload.cloud.189.cn/person/commitMultiUploadFile

根据后来结论得出:initMultiUpload主要是向后台申请空间(因为可能空间不足,也可能每日上传数据量超过上限),申请成功后,会返回一个uploadid,然后再调用commitMultiUploadFile填上这个uploadid来上传。

可以看到GET请求的参数不可读,已经被加密,所以需要定位加解密算法。

XHR断点勾上,上传。

直接断下来了,代码逻辑非常清晰,就是涉及的算法有点多

其中s = n("xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx")相当于一个GUID生成器

其中c = n("xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx").slice(0, 16 + 16 * Math.random() | 0)就是个随机串生成器,这里生成出来的c值将会被当作AES的key来使用,后面RSA算法加密的就是这个c

其中i.default.AES.encrypt就是AES(PKCS7填充模式)

其中b.encrypt就是RSA加密再套一层base64

接下来实现这些算法,由于我只会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

#ifdef _WIN32

#include <sys/timeb.h>

static uint64_t

__timestamp()

{

    struct timeb rawtime;

    ftime(&rawtime);

    return rawtime.time * 1000 + rawtime.millitm;

}

#else

#include <sys/time.h>

static uint64_t

__timestamp()

{

    struct timeval now = {0};

    gettimeofday(&now, NULL);

    unsigned long long u = now.tv_sec;

    u *= 1000;

    u += now.tv_usec / 1000;

    return u;

}

#endif

AES(调用openssl),注意这里要用PKCS7填充:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

static std::vector<uint8_t>

__aes(const char* in, const char* userKey)

{

    std::vector<uint8_t> bytes;

    uint8_t padding = 0x10 - (strlen(in) % 0x10); // PKCS7填充

    bytes.resize(strlen(in) + padding, padding);

    memcpy(bytes.data(), in, strlen(in));

    AES_KEY enc;

    AES_set_encrypt_key((const unsigned char*)userKey, 128, &enc);

    for (size_t i = 0; i < bytes.size(); i += 0x10) {

        AES_ecb_encrypt(bytes.data() + i, bytes.data() + i, &enc, 1);

    }

    return bytes;

}

HMACSHA1:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

static std::vector<uint8_t>

__hmacsha1(const char* in, const char* userKey)

{

    std::vector<uint8_t> bytes;

    bytes.resize(0x14);

    unsigned int outputlength = 0;

    HMAC_CTX* ctx = HMAC_CTX_new();

    HMAC_Init_ex(ctx, userKey, strlen(userKey), EVP_sha1(), NULL);

    HMAC_Update(ctx, (const unsigned char*)in, strlen(in));

    HMAC_Final(ctx, bytes.data(), &outputlength);

    HMAC_CTX_free(ctx);

    return bytes;

}

RSA:

1

2

3

4

5

6

7

static std::vector<uint8_t>

__rsa(const char* in, const char* userKey)

{

    std::vector<uint8_t> bytes;

    // ...自行手搓,hahahahaha~

    return bytes;

}

Base64:

1

2

3

4

5

6

7

static std::string

__base64(const uint8_t* in, size_t len)

{

    std::vector<uint8_t> bytes;

    // ...自行手搓

    return std::string((const char*)bytes.data(), bytes.size());

}

噢对了,还有两个重要的值:

RSA公钥来源:

1

https://cloud.189.cn/api/security/generateRsaKey.action

sessionKey来源:

1

https://cloud.189.cn/api/portal/v2/getUserBriefInfo.action

这俩值随便抓一下,能用几个小时。

/person/initMultiUpload

1

__aes("parentFolderId=-15&fileName=en_win_xp_pro_x64_vl.iso&fileSize=614166528&sliceSize=10485760&lazyCheck=1", c)

parentFolderId=-15这是个固定的文件夹"我的文档"的ID,每个用户都有且无法删除。想用自建的文件夹就稍微麻烦点。

c就是上面随机生成的c值,是个字符串,直接传进去就行

加密结果转成16进制字符串后就是GET参数中的params

HTTP头中的X-Request-ID

随机生成一个GUID填入即可

HTTP头中的X-Request-Date

毫秒级时间戳

HTTP头中的PkId

PkId与RSA公钥是在同一个接口里拿到的,一定要配套使用才行

HTTP头中的Signature

1

__hmacsha1("SessionKey=...&Operate=GET&RequestURI=/person/initMultiUpload&Date=...&params=...", c);

SessionKey来自/api/portal/v2/getUserBriefInfo.action接口

Date毫秒级时间戳,保持与X-Request-Date相同

params就是GET参数中的params

c就是上面随机生成的c

结果转换成16进制字符串后填写到Signature就行

HTTP头中的EncryptionText

1

__base64(__rsa(c, /*RSA公钥*/));

注意外层有个base64

/person/commitMultiUploadFile

加密算法同上,不再赘述

测试

成功!仅通过文件的MD5+filesize完整了文件的秒传。

这里也提醒大家,保护好自己的文件信息,可能一张截图就会导致了你的文件不小心被泄露!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐