吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 17369|回复: 218
上一主题 下一主题
收起左侧

[Web逆向] 阿里云盘签名算法探究及可用 PoC

    [复制链接]
跳转到指定楼层
楼主
t00t00 发表于 2023-2-14 00:50 回帖奖励
本帖最后由 t00t00 于 2023-2-16 09:11 编辑

前言

先放文件 https://github.com/kazutoiris/ali_ecc。
通过 Python 实现的模拟阿里云盘签名算法。可以通过云盘`x-device-id` 和 `x-signature` 校验,妈妈再也不用担心  `invalid X-Device-Id` 了。
欢迎 Star、Issue、Pull Requests!!!

(施工完毕,请放心阅读)



背景

自从阿里云盘2023年2月13日一波大更新,直接把原来调网页版接口的第三方网盘客户端给干爆了。像小白羊、Clouddrive、AList都出现了`invalid X-Device-Id`。其中,Clouddrive通过官方申请API招安的方式勉强能用,其他俩都不能下载文件了。

这使得复习高数的我直接傻眼了,第三方客户端只能上传不能下载,而网页版的在线视频播放功能一坨,只好全部缓存下来再看。。。

这波操作属实有点逆天,晚饭吃撑了研究一下。



分析

STEP1

通过报错可以发现,阿里云盘请求时候主要使用 `x-device-id` 和 `x-signature` 来进行校验。像列目录之类的可以不用校验,但是取下载链接一定要校验。
(P.S. 这里发现一个小小的漏洞,在列文件目录的时候会携带下载链接,这似乎是油猴脚本至今可用的原因)



如果不带的话就只能收到 `invalid X-Device-Id` 的错误提示了。

STEP2

貌似在不同浏览器上登录,这个 `x-device-id` 会不同。暂时不清楚是怎样随机生成的(准确来说是懒得调了,又不是不能用)。

(( 补充一下:84楼大佬已经分析了一下 x-device-id 的生成过程,只是普通的 UUID 随机字符串。 ))
这样, x-device-id 就可以指定随机数种子 userId,随机且唯一地生成一个 UUID 字符串,避免风控。
privateKey 则可以对 userId 做 SHA256,所得值用于私钥生成,同理可以保证随机且唯一。

综上所述,唯一要生成的就是 `x-signature`。






STEP1

首先就是要确定 `x-signature` 啥时候生成的。因为在前几条请求中都没有涉及到 `x-signature`,只有在请求目录后,所有的请求都带上了 `x-signature`。
(这里发现一个小小的细节:用开发者工具的”编辑并重新发送“,可以发现,即使是删掉了 `x-signature`,发送时也会自动带上。)

STEP2



随机挑一个请求,查看发起的程序。这个一目了然,发送逻辑必定在 `bundle.js` 中!



一个搜索,一个回车,直达要害!这证明了之前的猜想没错。


STEP3

看了一下请求记录,没有 WASM,那估计不是 WASM,是纯 JS 加密算法。

悲,纯 JS 没得下硬件访问断点,WASM 调试起来可方便多了。。

不管了,直接一个断,一个刷新,欸,直接就断下了。



这不比调 WASM 爽,环境不用补,连反调试都没有。

仔细观察,createSession 中 `x-signature` 是通过外部调用传参进来的,并不是这个函数内部产生的。
所以,这就需要根据调用堆栈来找是谁生成了这个值,是哪个函数传递进来的。

但是看了一圈,似乎在调用前就有了签名值。这就意味着必须要换一种方法了。

STEP4

直接开搜 `createSession`,很快啊,就找到了引用位置。



看了一下,整体代码似乎是状态机结构,总的来说还是通俗易懂的,比起恶心的 ollvm 确实正常了不少。

整体代码是自上而下运行的,是一种流水线式的运行方式。打个比方,A切肉,B把切完的肉拿去腌,C把腌完的肉拿去烤,D把烤完的拿去出餐。

这个函数先生成签名,然后生成会话。生成会话过程的签名就是上一级产生的。
当然,这里有很多其他函数,用以处理不同流水线段之间的数据传递,感兴趣的可以研究下,不感兴趣的倒也没啥关系,毕竟不影响抽象实现。
所以这个函数两个部分既可以分成多段运行,也可以直接合并起来。

而这种流水线的方式会导致前面找堆栈的时候,没有办法找到原始签名字符串是啥时候传进来的,就像是写在了全局变量一样(这也是没办法下硬件写入断点的槽点,不然早找到了)。

STEP5

找准了函数,下一步就简单了。创建签名是在 `genSignature` 中,直接一个 Ctrl+F 直达。



整体就很清晰了:
  • 先生成字符串 appId:deviceId:userId:nonce,然后 sha256 编码一下。
  • 交付给下一段流水线,用 privateKey 去签名。
  • 签名值后面加上 01。(这里的 1 是代码中 concat(u),因为 u 来自 recovered 的值,也就是图上蓝色的下一行。这个 1 的来源后续慢慢讲)


STEP6

签名是找到了,但是是拿啥算法签名的呢?



可以看到,阿里云盘有请求一个 `get_public_key` 的地址,而且返回了一个 RSA 密钥。前面代码又有公私钥加密的,这不就是 RSA 签名嘛!

哎哎哎,可别高兴太早,RSA 签名有个显著的特点,就是 e 基本都是 65537。但是调了这么久,似乎从来也没看到过 65537?
而且,根据上面的代码,这个私钥可以直接转换成公钥?RSA 双向转换都是不可以的。就算是调用私钥,最起码也得带上俩个数吧。

[JavaScript] 纯文本查看 复制代码
this.secp.utils.bytesToHex(this.secp.getPublicKey(this.dbMemData.privateKey))


这波属实是半场开香槟——给爷整笑了。

STEP7

兄弟们,干就完事了。

现在有两种可能,一是魔改的 RSA 算法,存在一个常数,这样就只需要提供另一个数就行了;二是,这压根不是 RSA 算法。

不过这两种路子殊途同归,直接一个断点,打到 `getPublicKey` 里面。如果是魔改,必定有常数,如果不是,那也有提示。






可以看到这是一个乘法运算。RSA 中我怎么记得是没有乘法的呢?

放狗搜一下常数,哦哦哦哦哦哦.jpg



来了兄弟们,ecc-secp256k1 算法,也是非对称算法。这是用椭圆曲线做的,难怪怎么只需要一个常数就可以了。

一把梭,直接开搞。

[Python] 纯文本查看 复制代码
private_key = [175, 87, 171, 214, 222, 196, 127, 36, 25, 50, 237, 179, 71, 81, 49, 196,
               250, 103, 115, 203, 138, 179, 192, 182, 43, 175, 233, 72, 200, 14, 64, 254]
private_key = int.from_bytes(private_key, byteorder='big')
ecc_pri = ecdsa.SigningKey.from_secret_exponent(
    private_key, curve=ecdsa.SECP256k1)
ecc_pub = ecc_pri.get_verifying_key()
print(ecc_pub.to_string().hex())


STEP8


别高兴太早。

出来的是 3e2a3bbd2dfe8675bc40b0b0af6a558421b827b5ad022c8d305eb861b9bfdcc48aea1243df77a6298dfd5cf692a407852b3fd996ea5a13ae213c4380bb7b8d0d,
而发送的却是 043e2a3bbd2dfe8675bc40b0b0af6a558421b827b5ad022c8d305eb861b9bfdcc48aea1243df77a6298dfd5cf692a407852b3fd996ea5a13ae213c4380bb7b8d0d

奇怪,算法搞错了?

别急,这不还没调完嘛。。。



[JavaScript] 纯文本查看 复制代码
t ? `${this.y & o ? "03" : "02"}${e}` : `04${e}${A(this.y)}`


是吧,04 是后续转 HEX 的时候手动加上的。这证明算法已经掌握了。

(( 经坛友提醒,04 指的是未压缩 ECC 公钥,细节可以看这篇文章 https://asecuritysite.com/ecc/js_ethereum2 ))

STEP9


算法搞完了,回过头看看公私钥对是咋生成的,这玩意不会有啥稀奇古怪的限制吧。

现在有两点已经掌握:
  • 只需要提供私钥,就可以求解得到公钥。
  • 私钥每次登陆时都会变。


大致可以分析出来,只需要生成私钥就可以了,而且是在初始化的时候。



没有限制,随机生成,完美收官。

STEP10

搞完了生成、算法,但是签名呢?哎,没想到吧,前面已经提到了哦!

  • 先生成字符串 appId:deviceId:userId:nonce,然后 sha256 编码一下。
  • 交付给下一段流水线,用 privateKey 去签名。
  • 签名值后面加上 01。(这里的 1 是代码中 concat(u),因为 u 来自 recovered 的值,也就是图上蓝色的下一行。这个 1 的来源后续慢慢讲)


那你肯定要问了,楼主楼主,nonce 一开始是 0,后面会不会变捏?

简单,友谊手套,Ctrl + F 一搜 nonce 赋值,很快奥,就定位到了。



目测是超时后生成新的 nonce。



更新时间随机的。



这里 nonce 只起限位作用,每次更新 +1,初始值为零,更新时间随机。

那你肯定又要问了,楼主楼主,appId、deviceId、userId 捏?
自己去 GitHub 项目看一下捏,这个抓包都有的,这里就不多做解释了,写文章太累了。。。



把前面导完的东西积一下,首先生成密钥对,发送公钥至阿里云盘,后续则使用这个密钥对进行签名。


STEP1 生成密钥对


[Python] 纯文本查看 复制代码
private_key = random.randint(1, 2**256-1)
ecc_pri = ecdsa.SigningKey.from_secret_exponent(
    private_key, curve=ecdsa.SECP256k1)


STEP2 生成并处理公钥

[Python] 纯文本查看 复制代码
ecc_pub = ecc_pri.get_verifying_key()
public_key = "04"+ecc_pub.to_string().hex()


STEP3 签名

[Python] 纯文本查看 复制代码
def sign(appId, deviceId, userId, nonce) -> str:
    sign_dat = ecc_pri.sign(r(appId, deviceId, userId, nonce).encode('utf-8'), entropy=None,
                            hashfunc=hashlib.sha256)
    return sign_dat.hex()+"01"


至于发送这种小事,完整代码直接见仓库吧,贴完文章太长没眼看了。

这里有个坑点,非对称签名每次签同样的内容产生的签名是不一样的,但是似乎阿里云盘直接简单处理了。
create_session 时候用的 `x-signature` 必须原封不动的传递到其他 API 的调用上,否则就算是密钥对一致、内容一致,也只会报无效。



后记

  • 似乎油猴脚本下载不受影响。
  • AList通过分享创建的也不受影响。
  • 盲猜一波断更小白羊估计这次应该是彻底淘汰了,作者不管,第三方作者也不太好做,不知道有没有接盘侠接个盘。
  • 有啥问题建议直接 GitHub 项目下提交 Issue,秒级回复。论坛估计是得按天起步了。。。
  • Star、Follow、CB 任一大于 1145,胱速整个有意思小活。

免费评分

参与人数 116吾爱币 +112 热心值 +99 收起 理由
bnuzgn + 1 + 1 谢谢@Thanks!
PawnSaruto + 1 + 1 热心回复!
cfsxy + 1 热心回复!
m2kar + 1 我很赞同!
3303B + 1 用心讨论,共获提升!
PDX123 + 1 + 1 我很赞同!
ly6565 + 1 + 1 我很赞同!
dujiangfu + 1 + 1 谢谢@Thanks!
Diamondzl + 1 + 1 谢谢@Thanks!
hejinpu + 1 用心讨论,共获提升!
WuBot + 1 + 1 用心讨论,共获提升!
SPT + 1 + 1 热心回复!
15851920426 + 1 + 1 热心回复!
leaf0125 + 1 用心讨论,共获提升!
K9i + 1 用心讨论,共获提升!
elongcn + 1 谢谢@Thanks!
N1san + 1 + 1 谢谢@Thanks!
zhouTz + 1 完了,根本看不懂,刚开始的小白一枚
wuxiuxin + 1 热心回复!
lizi867 + 1 热心回复!
wk99 + 1 + 1 热心回复!
rocm1828 + 1 + 1 谢谢@Thanks!
WinBoard + 1 + 1 谢谢@Thanks!终于找到了alist上阿里云盘无法使用的解决办法,虽然alist官.
celestialpivot + 1 + 1 谢谢@Thanks!
mzbgf + 1 我很赞同!
xingzhigege + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
FantasyOS + 1 + 1 谢谢@Thanks!
2731784043 + 1 + 1 用心讨论,共获提升!
gaosld + 1 + 1 谢谢@Thanks!
可及 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
苏半仙儿 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
zfpapio + 1 + 1 谢谢@Thanks!
西装佩奇 + 1 + 1 我很赞同!
allspark + 1 + 1 用心讨论,共获提升!
Chenda1 + 1 + 1 我很赞同!
victos + 1 + 1 谢谢@Thanks!
xlwllm + 1 + 1 谢谢@Thanks!
aabbcc123123 + 1 + 1 用心讨论,共获提升!
vnmaj + 1 用心讨论,共获提升!
dincia + 1 谢谢@Thanks!
xuqi + 1 + 1 谢谢@Thanks!
gqdsc + 1 + 1 大佬就是大,厉害
Coocle + 1 谢谢@Thanks!
ddistupid + 1 用心讨论,共获提升!
Courser + 1 + 1 用心讨论,共获提升!
science2011 + 1 我很赞同!
nnzhs + 1 + 1 谢谢@Thanks!
765382553 + 1 + 1 谢谢@Thanks!
fengbu401 + 1 + 1 谢谢@Thanks!
Higher-Stark + 1 用心讨论,共获提升!
soyiC + 1 + 1 用心讨论,共获提升!
a1140314368 + 2 + 1 给1145添把柴
瞄帕斯 + 2 + 1 用心讨论,共获提升!
安尼大大 + 1 + 1 我很赞同!
宅の士 + 1 + 1 用心讨论,共获提升!
Jackrong_ + 1 谢谢@Thanks!
asksea + 1 + 1 谢谢@Thanks!
5omggx + 1 + 1 用心讨论,共获提升!
small_天 + 1 用心讨论,共获提升!
Valar_Dohearis + 1 我很赞同!
1MajorTom1 + 1 热心回复!
笙若 + 1 + 1 谢谢@Thanks!
抱歉、 + 1 用心讨论,共获提升!
jiuli + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
billet-doux + 1 热心回复!
佩可莉姆 + 1 + 1 谢谢@Thanks!
被遗弃的泪水 + 1 + 1 谢谢@Thanks!
codeaftercode + 1 + 1 谢谢@Thanks!
wbem5 + 1 感谢分享
gkroot + 1 + 1 我很赞同!
蹭的累死 + 1 + 1 我很赞同!
Assimov + 1 + 1 谢谢@Thanks!
超鑫戏 + 1 + 1 用心讨论,共获提升!
festallo + 1 + 1 我很赞同!
hoeel + 1 + 1 谢谢@Thanks!
吾之名翎 + 1 谢谢@Thanks!
peeeee + 1 + 1 谢谢@Thanks!
he1a2s0 + 1 + 1 谢谢 @Thanks!
Xin88 + 1 谢谢@Thanks!
aliez114 + 1 + 1 我很赞同!
czz404 + 1 + 1 谢谢@Thanks!
mscsky + 1 + 1 我很赞同!
9324 + 1 + 1 我很赞同!
Makerlife + 1 + 1 用心讨论,共获提升!
uzcool + 3 + 1 热心回复!
From52pojie + 1 + 1 谢谢@Thanks!
liuyuan1114 + 1 + 1 热心回复!
osszoq44 + 1 + 1 谢谢@Thanks!
抱薪风雪雾 + 1 + 1 谢谢@Thanks!
auqhjjqdo + 1 + 1 用心讨论,共获提升!
mayiwan + 1 + 1 热心回复!
zhczf + 1 我很赞同!
四哥! + 1 + 1 谢谢@Thanks!
CyberW + 1 + 1 谢谢@Thanks!
wuai_V + 1 + 1 用心讨论,共获提升!
SouperGeng + 1 + 1 我很赞同!
雷欧库珀 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
aif + 1 + 1 鼓励转贴优秀软件安全工具和文档!
1254qwer + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
川辣布丁 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

来自 30#
 楼主| t00t00 发表于 2023-2-14 10:34 |楼主
本帖最后由 t00t00 于 2023-2-14 11:36 编辑

施工完毕,请放心阅读。

有问题请去 GitHub 下面提交 Issue,秒级回复,论坛回复有点慢。。。

Star、Follow、CB 任一大于 1145,胱速整个有意思小活

有需要的网页截图、仓库 Fork 保存一下哦,年后实习还要投阿里,万一删帖了懂得都懂。。。
推荐
ogli324 发表于 2023-2-15 21:34
本帖最后由 ogli324 于 2023-2-15 21:39 编辑

emem..这会儿空闲,看了下 x-device-id 生成来源过程,就是uuid,这把xx云盘更新了个寂寞。。我还以为上了浏览器指纹相关的设备id呢。。。 下面是相关分析大致流程,有想分析学习的可以看看。

var u = function(e, t, n) {
    var r = (e = e || {}).random || (e.rng || o)();
    if (r[6] = 15 & r[6] | 64,
    r[8] = 63 & r[8] | 128,
    t) {
        n = n || 0;
        for (var i = 0; i < 16; ++i)
            t[n + i] = r[i];
        return t
    }
    return function(e) {
        var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 0
          , n = (l[e[t + 0]] + l[e[t + 1]] + l[e[t + 2]] + l[e[t + 3]] + "-" + l[e[t + 4]] + l[e[t + 5]] + "-" + l[e[t + 6]] + l[e[t + 7]] + "-" + l[e[t + 8]] + l[e[t + 9]] + "-" + l[e[t + 10]] + l[e[t + 11]] + l[e[t + 12]] + l[e[t + 13]] + l[e[t + 14]] + l[e[t + 15]]).toLowerCase();
        if (!s(n))
            throw TypeError("Stringified UUID is invalid");
        return n
    }(r)
};

function d() {
    return u();
}

function f(e) {
    // 实现逻辑,主要以先查询cookie和localStorage是否保存有cna设备id值,如果没有再创建,
    // 目的是在如果用户不主动清理时可以设备id不变,但这种基于随机生成的设备id其实是可变的,
    // 可以用于普通的登录状态标记,无法用于风控相关。
    return r || (r = s.p.get(e) || function(e) {   // s.p.get ==> cookie;
        var t = localStorage.getItem(e);
        return t || (t = (0,
        a.O)(),  // (0,a.O)() ==> d();
        localStorage.setItem(e, t)),
        t
    }(e)),
    r
}

// Bt = "cna";
// w = (0,St.Zw)(Bt); ==>f();
// "x-device-id": w

// x-device-id ==> uuid 

// python实现,其他语言类似。

deviceId = uuid.uuid4()

免费评分

参与人数 2吾爱币 +3 热心值 +2 收起 理由
gaoyanchen + 1 + 1 谢谢@Thanks!
t00t00 + 2 + 1 用心讨论,共获提升!

查看全部评分

推荐
 楼主| t00t00 发表于 2023-2-14 09:39 |楼主
lesliewindy 发表于 2023-2-14 09:22
我在家里路由器装了阿里云webdav,然后在电视上用kodi播放器挂载,看电视电影感觉没受任何影响,这是什么原 ...

有些是通过分享方式创建的,这种是不受影响的。

还有一种是列文件目录的时候,下载地址有泄露,所以不需要调用升级接口。不过这个后门估计过俩天就封了。
推荐
anwen 发表于 2023-2-14 10:21
周小雨 发表于 2023-2-14 01:13
看issue小白羊作者送外卖去了好像

早不去了 现在似乎是会计
推荐
 楼主| t00t00 发表于 2023-2-14 08:09 |楼主
kiseyzed 发表于 2023-2-14 01:19
好歹弄完再发出来吧……

急急国王可以直接先用成品哦,在文章第一行。文章还有大概 90% 没写,正在努力写
推荐
fly1397 发表于 2023-2-16 17:24
感谢大佬,整了js版来用
推荐
djmingge 发表于 2023-2-18 19:42
xddc 发表于 2023-2-18 11:52
是哦,有没有大佬写成PHP

没有这个ecc库
沙发
周小雨 发表于 2023-2-14 01:13
看issue小白羊作者送外卖去了好像
3#
kiseyzed 发表于 2023-2-14 01:19
好歹弄完再发出来吧……
4#
jzx765 发表于 2023-2-14 07:08
前排&#128014;一下
5#
zw0476sky 发表于 2023-2-14 07:30
期待更新后的结果,目前已知的第三方全都不能播放视频了,看不鸟,是真失落。
6#
sqemail 发表于 2023-2-14 07:36
先mark下,等待楼主的续篇
7#
zzk19358590281 发表于 2023-2-14 07:53
期待更新
8#
mosou 发表于 2023-2-14 08:03
github 挂了
9#
 楼主| t00t00 发表于 2023-2-14 08:07 |楼主

现在已开源,醒来继续更新文章
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-14 14:34

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表