返回顶部

回顾GoEdge投毒事件,附解决方案,附注册机

2024-07-29 15:28

在2024年5月中下旬,GoEdge QQ群聊解散,群主超哥失联于5月20日,在这天上午九点和下午六点都发布了更新

这天上午9点发布的更新版本为1.3.9

节点程序文件 edge-node MD5 8EBAC47C212DBB41CC0B2B9C6D4B32E4
节点程序压缩包 edge-node-linux-amd64-plus-v1.3.9.zip MD5 D6B495249683D981DEA15B5BAD97ACDB

在下午6点左右,上传了新的管理系统,管理系统压缩包中,带有一个节点程序的压缩包,是给edge-api准备的,但是这个节点程序修改日期居然是下午六点,与admin的临近

节点程序文件 edge-node MD5 54D7FDD77A1DBB8431B186BAC03C6429
节点程序压缩包 edge-node-linux-amd64-v1.3.9.zip MD5 88D96C2696C7F842BCEE66B833412571
管理平台压缩包 edge-admin-linux-amd64-plus-v1.3.9.zip MD5 FFDF4E395BE3096787396C46F4B793CF

这显然不对劲,难道是超哥亲自夹杂的私货吗?
带着疑问,我们来静态分析一下,刚修完几十个节点,眼有点花了,这里就不手搓了,直接用微步云沙箱,也方便大家自行查看
首先是早上九点的1.3.9,上传文件到沙箱,根据目前的投毒情况,节点程序文件的字符串中会出现这样一条URL

https://cdn.jsdelivr.vip/jquery.min-3.7.0.js

也就是说,我们只需要看字符串中有没有可以URL就可以了,至于有没有后门,咱也分析不了呀
打开报告,我们看沙箱提取好的URL

然后,是晚上六点的1.3.9,打开报告,看沙箱提取好的URL

此时发现,并没有什么不同,只是域名从cn变成了cloud,这上午还是cn,下午就是cloud了,好神奇,我们先保留这个疑问
根据我的回忆,经过几天的沉寂,在22号,goedge的TG群组回归了

已经编译好发布了好几天,下载下来MD5变了,修改日期居然变5月24号了?报告

节点程序文件 edge-node MD5 54D7FDD77A1DBB8431B186BAC03C6429

近日,有许多GoEdge用户发现,网站页面尾部会插入一段js代码

首先分析一下修改日期为7月10日的1.4.1的节点程序

节点程序文件 edge-node MD5 D08FB882642BC1CD423F44F4F4B0C852
节点程序压缩包 edge-node-linux-amd64-plus-v1.4.1.zip MD5 D7AF8DD45334E7C3EFB8DB7D8D8933C5

查看报告发现,出现了一条逆天的URL

https://cdn.jsdelivr.vip/jquery.min-3.7.0.js

身处澳洲的群主,引用jsdelivr,等等,e呢? 资源,居然还贴心地给我们用了加速?!我真的太感动了啊,就是这链接不太对劲啊,我记得不是这个格式啊,难道是下载服务器ssh密码泄露了,被植入病毒了?

不对呀,这旧版本和新版本编译器咋还换了呢,这不对吧,有人说,说是有人在这汤里下了毒

26日凌晨


群友发现,自己的网站末尾夹杂了私货,经过大家的探讨发现,</body><!—直接就能把这坨东西变成注释,不得不说,这是一个很好的思路

那,这到底是啥呢,为啥要注释掉?
从境内访问,这个网址是一个混淆加密的js文件

从境外访问,不允许访问,这......群主不是说要只给海外用户提供服务嘛


看这个解析,很神奇,使用的是非常好的CDN,不禁让我浮想联翩

接着,有大佬分析出该加密js

不光是分地区分设备跳转,甚至每个时段跳转的概率还不相等,还能根据你的网站分类量身定制,真是贴心啊

经过大家在群里激烈的讨论,位于澳大利亚、比北京晚俩小时的群主,终于在北京时间12:50,悄悄地,上传了一个无毒的版本,试图掩盖一切。然后,随着一声“不信谣,不传谣”,群人数大大减少,大概是大家自己退群了吧

如何解决?

根据我们前面的分析,发现仅在节点程序中夹杂了私货,但是仍建议全部回退5月20日早上的版本,避免后门。如果是在5月21日后安装的,建议立即回退
这里,感谢dv老板分享的谷歌盘存档

首先,我们要在主控屏蔽goedge域名,防止日后出现什么问题,执行下面命令即可

echo "127.0.0.1 goedge.cloud" | sudo tee -a /etc/hosts > /dev/null
echo "127.0.0.1 goedge.cn" | sudo tee -a /etc/hosts > /dev/null
cat /etc/hosts

接着,把主控回退到5月20日版本

首先

cd 主控安装目录

接着

./edge-admin upgrade --url=https://dl.naixi.net/cdn/goedge/goedgecn/edge-admin-linux-amd64-plus-v1.3.9.zip

此处仅演示amd64架构,使用的URL由奶昔提供,感谢!不放心的换成自己的URL即可

前面提到,管理系统压缩包里面带的节点程序是晚上更新的,虽然只是换了个网址,但是仍建议使用早上的版本,所以我们执行一步替换,此处仍使用奶昔提供的下载服务

cd 安装目录,例如 /usr/local/goedge/edge-admin/edge-api/deploy

然后,删除原有的文件

rm -rf edge-node-linux-amd64-plus-v1.3.9.1.zip

获取早上的版本

wget -O edge-node-linux-amd64-v1.3.9.zip https://dl.naixi.net/cdn/goedge/goedgecn/edge-node-linux-amd64-plus-v1.3.9.zip

到这,主控就重装好了,不过要提醒的是,检查一下这个目录/edge-admin/edge-api/deploy
里面有没有比1.3.9更高版本的文件,有的话删掉


只是重装主控可不行,投毒投在节点啊
确保已经安装curl、unzip
看看节点程序装在哪个目录,如果是/root/edge-node,执行如下

rm -rf /usr/local/goedge
cd /root/edge-node
./edge-node/bin/edge-node cache.garbage --delete
curl -L "https://dl.naixi.net/cdn/goedge/goedgecn/edge-node-linux-amd64-plus-v1.3.9.zip" -o edge-node-linux-amd64-plus.zip -C - -#
./edge-node/bin/edge-node stop
rm -rf ./edge-node/data
rm -rf ./edge-node/bin
rm -rf /opt/cache
unzip -o edge-node-linux-amd64-plus.zip
./edge-node/bin/edge-node restart
rm -rf *.zip
mkdir /opt/cache

看看节点程序装在哪个目录,如果是/usr/local/goedge,执行如下

rm -rf /root/edge-node
cd /usr/local/goedge
./edge-node/bin/edge-node cache.garbage --delete
curl -L "https://dl.naixi.net/cdn/goedge/goedgecn/edge-node-linux-amd64-plus-v1.3.9.zip" -o edge-node-linux-amd64-plus.zip -C - -#
./edge-node/bin/edge-node stop
rm -rf ./edge-node/data
rm -rf ./edge-node/bin
rm -rf /opt/cache
unzip -o edge-node-linux-amd64-plus.zip
./edge-node/bin/edge-node restart
rm -rf *.zip
mkdir /opt/cache

需要说明的是,我们先删除了usr下的goedge,因为根据我的经验,节点自动升级的时候有可能会重复安装,具体怎么回事也说不清;我们删除了/opt/cache,这是默认的缓存目录,因为缓存中可能存在投毒后的页面,如果你还有其他缓存目录,需要自行清除,如果体量太大,直接重装系统得了
如果你执行错了,说明你不适合手动操作,直接重装系统得了

网页在线生成激活码:https://fernii.net/goedge

记得安装 pip install pycryptodome

这是现成的打包成.exe的 也可以自己运行.py: https://wormhole.app/4bLp3#d6_tDFR3Aqq3JEX282sJJA

思路来自于奶昔论坛:https://bbs.naixi.net/thread-112-1-1.html

import base64
import json

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

MagicKey = b"41100c93a65cfb71d5b0672c0d60d7ec"
MagicKey2 = b"70ba69d67bf7e61e17ac565c6093a325"[:16]


def create_cipher(key, iv):
    return Cipher(algorithms.AES(key), modes.CFB(iv), backend=default_backend())


def MagicKeyEncode(data):
    cipher = create_cipher(MagicKey, MagicKey2)
    encryptor = cipher.encryptor()
    return encryptor.update(data) + encryptor.finalize()


def MagicKeyDecode(data):
    cipher = create_cipher(MagicKey, MagicKey2)
    decryptor = cipher.decryptor()
    return decryptor.update(data) + decryptor.finalize()


def encrypt():
    _id = input("请输入ID(例如:commercial):")
    hostname = input("请输入主机名(例如:*):")
    company = input("请输入公司/组织名:")
    updated_at = int(input("请输入更新时间戳(例如:4102372799):"))
    nodes = int(input("请输入节点数量(例如:99999):"))
    edition = input("请输入版本(basic/pro/ent/maxsub/ultra):")
    request_code = input("请输入请求代码(例如:F4BuVYEKSnnWucg5IDVzUWRFEJDPkunFObYNtXS4rxj3Bl+5rePM580nbSkizJoP3odKS1TTqWa3DDqaYDC59lhPuH147foFdmUOy6oR3X9dtBafw6cCRPplDaLTJ5RCEVVc4WHv3ja/lKd13HtTEYse3VHR+88KyShNDFBuqaNeSjA474Yb065yKWXNT+qs86/sWnr1GriLkYbSSLf85BHmTGL0qIfSUVzUOOlKg8XiTLsBtcXqdJa5x0Rw0p/9YcMUa/e2aZDvXqcXHP6Tc5pHXA873+wu/3PIiAKkwczD1M2KZ5C89hHlDpYRtNiIwD3wmB5F7f19jOT1ufg0On6xmcxmKiRgUoDbqsgh0x1tCvfYKS6IRKmCiAg2s/4TnheGWTa739sQEG7kJ7d5x3UgVOqy6p31l29AA5qOFkl8QtD2NMGVT21kHQ5f0Z/11z41YTYB1xhUetoxmyeEpAcPTCMB+c+OzDNGq1kZLUExIClGGFth):")

    _json = {
        "id": _id,
        "dayFrom": "1999-01-01",
        "dayTo": "2099-12-31",
        "macAddresses": [],
        "requestCode": request_code,
        "hostname": hostname,
        "company": company,
        "nodes": nodes,
        "updatedAt": updated_at,
        "components": ["*"],
        "edition": edition,
        "email": "",
        "method": "local"
    }

    _json_str = json.dumps(_json, ensure_ascii=False).encode('utf-8')
    encoded = MagicKeyEncode(_json_str)

    print("\n↓原始JSON数据↓")
    print(_json_str.decode('utf-8'))
    print("\n↓注册码↓")
    print(base64.b64encode(encoded).decode())

    input("\n按回车键返回主菜单...")


def decrypt():
    encoded_str = input("请输入加密的注册码:")
    encoded_bytes = base64.b64decode(encoded_str)
    decoded_bytes = MagicKeyDecode(encoded_bytes)
    decoded_str = decoded_bytes.decode('utf-8')

    print("\n↓解密后的原始JSON数据↓")
    print(decoded_str)

    input("\n按回车键返回主菜单...") 


def main():
    while True:
        print("\n请选择操作:")
        print("1. 解密")
        print("2. 加密")
        print("0. 退出")
        choice = input("请输入选项 (1、2 或 0):")

        if choice == "1":
            decrypt()
        elif choice == "2":
            encrypt()
        elif choice == "0":
            print("退出程序。")
            break
        else:
            print("无效的选项,请重新选择。")


if __name__ == "__main__":
    main()



下面是网页版代码(记得在放源码的目录执行:composer require phpseclib/phpseclib

index.php

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>GoEdge Key Hack</title>
    <link rel="icon" href="favicon.ico" type="image/x-icon">
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap');

        body {
            font-family: 'Poppins', sans-serif;
            background: url('background-image.jpg') no-repeat center center fixed;
            background-size: cover;
            margin: 0;
            padding: 40px 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: calc(100vh - 80px);
            overflow: hidden;
        }
        .container {
            background: rgba(0, 0, 0, 0.10);
            padding: 30px;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
            width: 90%;
            max-width: 400px;
            text-align: center;
            backdrop-filter: blur(4px);
        }
        h1 {
            color: #ffffff;
            margin-bottom: 30px;
            font-weight: 600;
            font-size: 24px;
        }
        label {
            display: block;
            font-weight: bold;
            margin-bottom: 10px;
            color: #ffffff;
            font-size: 18px;
        }
        input[type="text"], select, textarea {
            width: calc(100% - 22px);
            padding: 10px;
            margin-bottom: 20px;
            border: 1px solid rgba(255, 255, 255, 1);
            border-radius: 4px;
            box-sizing: border-box;
            font-size: 16px;
            background: rgba(255, 255, 255, 1);
            color: #000000;
            backdrop-filter: blur(4px);
        }
        input[type="text"]::placeholder, textarea::placeholder {
            color: #A9A9A9;
        }
        button {
            background-color: #007BFF;
            color: white;
            padding: 10px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            font-weight: 600;
            margin-top: 20px;
        }
        button:hover {
            background-color: #0056b3;
        }
        .result {
            margin-top: 20px;
            color: #ffffff;
            text-align: left;
        }
        .result code {
            background: rgba(255, 255, 255, 1);
            padding: 10px;
            border-radius: 4px;
            display: block;
            white-space: pre-wrap;
            color: #000000;
            margin-top: 10px;
            cursor: pointer;
            position: relative;
        }
        .back-button-container {
            display: flex;
            justify-content: center;
        }
        .back-button {
            background-color: #007BFF;
            color: white;
            padding: 10px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            font-weight: 600;
            margin-top: 20px;
            display: none;
            text-align: center;
        }
        .back-button:hover {
            background-color: #0056b3;
        }
    </style>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
        $(document).ready(function(){
            $("form").on("submit", function(event){
                event.preventDefault();
                if ($("#operation").val() === "encrypt") {
                    if (!$("#id").val() || !$("#hostname").val() || !$("#company").val() || !$("#updated_at").val() || !$("#nodes").val() || !$("#edition").val()) {
                        alert("请填写所有必填项");
                        return;
                    }
                } else {
                    if (!$("#encoded_str").val()) {
                        alert("请输入加密的注册码");
                        return;
                    }
                }

                $.ajax({
                    url: "process.php",
                    type: "POST",
                    data: $(this).serialize(),
                    success: function(response){
                        $(".result").html(response);
                        $(".form-container").hide();
                        $(".back-button").show();
                    }
                });
            });

            $(".back-button").on("click", function(){
                $(".result").empty();
                $(".form-container").show();
                $(".back-button").hide();
            });

            $(document).on("dblclick", "code", function(){
                var $this = $(this);
                var $temp = $("<input>");
                $("body").append($temp);
                $temp.val($this.text()).select();
                document.execCommand("copy");
                $temp.remove();
                $this.css("color", "blue");
                setTimeout(function(){
                    $this.css("color", "#000000");
                }, 3000);
            });

            $("#encrypt-fields").show();
            $("#decrypt-field").hide();
            $("#encoded_str").prop("required", false);

            $("#operation").on("change", function(){
                if (this.value === 'encrypt') {
                    $("#encrypt-fields").show();
                    $("#decrypt-field").hide();
                    $("#id, #hostname, #company, #updated_at, #nodes, #edition").prop("required", true);
                    $("#encoded_str").prop("required", false);
                } else {
                    $("#encrypt-fields").hide();
                    $("#decrypt-field").show();
                    $("#id, #hostname, #company, #updated_at, #nodes, #edition").prop("required", false);
                    $("#encoded_str").prop("required", true);
                }
            });

            $("#id").val("commercial");
            $("#hostname").val("*");
            $("#updated_at").val(Math.floor(Date.now() / 1000) + (99 * 365 * 24 * 60 * 60));
        });
    </script>
</head>
<body>
    <div class="container">
        <div class="form-container">
            <h1>GoEdge Key Hack</h1>
            <form method="post">
                <label for="operation">请选择操作:</label>
                <select name="operation" id="operation">
                    <option value="encrypt">加密</option>
                    <option value="decrypt">解密</option>
                </select>
                <div id="encrypt-fields">
                    <input type="text" id="id" name="id" placeholder="请输入ID(例如:commercial)" required>
                    <input type="text" id="hostname" name="hostname" placeholder="请输入主机名(例如:*)" required>
                    <input type="text" id="company" name="company" placeholder="请输入公司/组织名" required>
                    <input type="text" id="updated_at" name="updated_at" placeholder="请输入更新时间戳(例如:4102372799)" required>
                    <input type="text" id="nodes" name="nodes" placeholder="请输入节点数量(例如:99999)" required>
                    <select id="edition" name="edition" required>
                        <option value="basic">basic</option>
                        <option value="pro">pro</option>
                        <option value="ent">ent</option>
                        <option value="maxsub">maxsub</option>
                        <option value="ultra">ultra</option>
                    </select>
                    <input type="text" id="request_code" name="request_code" placeholder="请输入请求码的(可为空)">
                </div>
                <div id="decrypt-field">
                    <textarea id="encoded_str" name="encoded_str" placeholder="请输入加密的注册码" required></textarea>
                </div>
                <button type="submit">提交</button>
            </form>
        </div>
        <div class="result"></div>
        <div class="back-button-container">
            <button class="back-button">返回到生成注册码</button>
        </div>
    </div>
</body>
</html>

0

在线客服列表:

电话联系未开放

回到顶部