回顾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>
电话联系未开放