VMware Workstation: Attack surface through Virtual Printer

In this article, I will introduce an approach to find bugs on closed source applications using the fuzzing method. VMware Workstation is an interesting example to do, please go through each part I present below to better understand this target.


Enhanced metafile format (EMF) is a file format that is used to store portable representations of graphical images. EMF metafiles contain sequential records that are parsed and processed to render the stored image on any output device.

Enhanced metafile spool format (EMFSPOOL) is a file format used to store portable definitions of print jobs that output graphical images. EMFSPOOL metafiles contain a sequence of records that are parsed and processed to run the print job on any output device.

To understand this format, can refer to Microsoft document [1] [2] as well as the whitepaper of j00ru [3].

EMF is used a lot in print spooling, with its use in print spooling leading to a lot of attack surfaces because it combines many file formats stored in records such as images, fonts,…

During my research, I noticed that EMFSPOOL was used in VMware Workstation.

Virtual Printer

This is a feature that allows guest machines to print documents using available printers on the host machine (basically printer sharing). By sending data from the guest machine to the host machine, this can be seen as a way to attack the VM escape.

In the past, in 2015 a series of bugs were reported by Kostya Kortchinsky including the stack overflow bug and he built the exploit successfully [4]. By 2016, j00ru continued to use fuzzing to find out a series of bugs related to image formats JPEG2000, EMF, fonts,… [5] [6]

Virtual Printer is not enabled by default on VMware Workstation. To turn it on we need the following settings:

Enable Virtual Printer on VMware Workstation

About the architecture as well as how it works, the attack surface of the Virtual Printer, we can see the picture below:

Architecture, attack surface of Virtual Printer

The process we are interested in is vprintproxy.exe which is launched on the host machine. Data is sent from the guest machine to the vprintproxy.exe process on the host machine via port COM1. Data sent from the guest machine does not require any permissions, meaning any user can send data. Data sent to the host machine is defined in the format EMFSPOOL. With this format it allows you to attach other file formats to records such as images, EMFs, fonts,…


By taking advantage of the POCs made by j00ru public from before [5] [6], I made a little tweaking to fit the current version, using it and debugging the Virtual Printer’s data processing flow, I found that:

  • The data processing is in TPView.dll
  • Data transmitted from the guest machine to the host machine is only processed at TPView.dll, on the data transmission line, it is not affected by any object to change.

When analyzing TPView.dll, I saw the virtual printer handling some records with file formats such as JPEG2000, OTF, TTF,…


For jpeg2000 record, this is a record added by TPView.dll to EMFSPOOL. j00ru discovered that Irfanview’s jpeg2000 image processing library has the same code base for image processing in TPView.dll. He ported Irfanview’s library to Linux and did fuzz on it. It’s a smart way to do it and greatly improve the performance. However, I have no experience port DLL to Linux (although there are quite a few examples such as LoadLibrary from Taviso [7] or harness fuzz TTF of j00ru [8]), so I decided to reverse and build harness around TPView.dll.

During reverse and debug I see function sub_100584CE will process the JPEG2000 record sent from the guest machine. In the sub_100584CE function, the program decompresses the data and checks the fields in that data (because the data transferred from the guest machine has been compressed by zlib).

Decompress the data in jpeg2000 record and check its availability in the function sub_100584CE

The results of the decompressdata function are as follows:

The address of the data after the decompress is stored in the esi register

I check the function check_record (this will check the fields in the data after decompress) and recreate the struct record_jp2k and the struct header contains the following fields:

Struct record_jp2k and header I initialized

When the decompress data and check the fields are finished, the program continues to compute and get the values in struct record_jp2k and header to process the jpeg2000 image.

The code initializes record_jp2k v20 to store the processing results of the process_jp2k function

We observe from line 84 to line 110 the program creates a record_jp2k v20 to store jpeg2000 data after processing. And process_jp2k function is parsing/process image jpeg2000.

We see the function process_jp2k takes the following parameters:

  • header->data_jp2k: jpeg2000 image file data
  • header: struct header
  • record->len_jp2k: file size jpeg2000
  • v20->hdr: struct saves data after processing of jpeg2000 images
  • val_0x328: The size of the output record with the value 0x328

I have found that the function process_jp2k can be completely used as the entry point of a harness. Since the input data is very similar to the data of the jpeg2000 image and it does not depend much on other values in EMFSPOOL.

Below is a harness that I built to fuzz EMFSPOOL with a record of jpeg2000 image file

The harness uses the fuzz jpeg2000 format of TPView.dll


For font records, TPView.dll supports the full processing of 5 records that EMFSPOOL is available:

  • EMRI_ENGINE_FONT: Defines a font in TrueType format.
  • EMRI_TYPE1_FONT: Defines a font in PostScript Type 1 font format.
  • EMRI_DESIGNVECTOR: Contains a font’s design vector, which characterizes a font’s appearance in 16 properties.
  • EMRI_SUBSET_FONT: Contains a partial font in TrueType format, with enough glyph outlines for pages up to the current page.
  • EMRI_DELTA_FONT: Contains new glyphs to be merged with data from a preceding EMRI_SUBSET_FONT record.

For each record, TPView.dll will have different handlers. However, we can refer to the Microsoft document [2] about these records.

After debugging the TPView’s font record processing flow, I found the sub_10013B06 function would be the function that takes the font data sent from the guest machine and processes it.

The sub_10013B06 function processes the font record

This function takes the following 5 parameters:

flag is the first parameter of the function, with each flag value representing a particular record:

The flag values that TPView.dll can handle

The remaining parameters I check via WinDbg, set a breakpoint at function sub_10013B06. The second argument I see is that this parameter contains a 12-byte memory area and is initialized with NULL. We can check that value in the figure below, the ecx register stores the second parameter:

The second parameter value is stored in the ecx register

The remaining 3 parameters as shown below, we can see that the memory address 0x4453DD8 (argv3) is the memory that contains the font record, the fourth parameter (argv4) is the size of this memory. The 5th parameter (argv5) is 1 byte in size and I check it through a number of runs, this value is always 1.

Represents the remaining 3 parameters of the function sub_10013B06

For the third parameter (argv3) is the font’s record data, for each record we have a different structure, but we can completely refer to Microsoft’s document [9] to understand more about that structure. I take an example of an EMRI_ENGINE_FONT record, the following figure describes the fields in the structure of an EMRI_ENGINE_FONT record. However in this case the record stored in parameter 3 will start from the Type1ID field onwards.

Example of the structure of an EMRI_ENGINE_FONT record

The meanings of each field in the image above are as follows:

  • Type1ID (4 bytes): A 32-bit unsigned integer. The value MUST be 0x00000000, to indicate a TrueType.
  • NumFiles (4 bytes): A 32-bit unsigned integer that specifies the number of files attached to this record.
  • FileSizes (variable): Variable number of 32-bit unsigned integers that define the sizes of the files attached to this record.
  • AlignBuffer (variable): Up to 7 bytes, to make the data that follows 64-bit aligned.
  • FileContent (variable): Variable-size, 32-bit aligned data that represents the definitions of glyphs in the font. The content is in TrueType format.

In my case, I will only use 1 TTF file per record so the EMRI_ENGINE_FONT struct I initialize as follows:

Struct EMRI_ENGINE_FONT that I initialized

Check this parameter on WinDbg we have corresponding fields as follows:

The struct fields of EMRI_ENGINE_FONT respectively

At this point, we can completely build a harness to fuzz this font record by calling the sub_10013B06 function. Based on the information I have above, the following is a sample harness fuzz EMRI_ENGINE_FONT record, other records are similar, just change the flag parameter.

Sample harness used to fuzz EMRI_ENGINE_FONT records


In addition to the JPEG2000 records and fonts, TPView.dll also handles the EMRI_METAFILE record, which is the EMF file format. After receiving data from the guest machine, TPView.dll processes the data containing the contents of the EMF file. It basically writes that data to the %temp% directory as a file and calls the Windows APIs to handle this file as: GetEnhMetaFileW, EnumEnhMetaFile, PlayEnhMetaFileRecord, GetEnhMetaFileHeader, GetEnhMetaFilePaletteEntries,…

However, we will be interested in the EnumEnhMetaFile API:

EnumEnhMetaFile API and parameters

This is a commonly used API to process the records contained in the EMF file through a callback that is the third parameter of this API. This API is used in the sub_10042BB6 function of the TPView.dll library. After reviewing this callback, I decided to choose this callback as the function I want to fuzz because this function is the function that will parsing/process the records in the EMF file.

The code calls the EnumEnhMetaFile API to process the EMF file

As in the picture above, we can see that the callback is the proc function, but I had difficulty finding the 4th parameter, i.e. the param for the callback function. Since the param is a local variable, it takes a long time to trace back to recover the fields in the param. In cases like this, I usually have to reverse static a bit and guess the fields and debug to check it.

Let’s first guess its size.

The section defines the parameters of the sub_10042BB6 function

Looking at the local variables defined in function sub_10042BB6, we notice that the param variable starts at ebp+0h followed by a series of variables. The EnumEnhMetaFile API used in the function has the 5th parameter being a struct RECT, the corresponding in the function sub_10042BB6 is the variable xDest located at ebp+98h. Thereby, I realized that the size of the largest param variable could only be 0x98 because if it exceeds this size it will override the xDest variable (5th parameter of the EnumEnhMetaFile API).

Struct param_s that I initialized

I create a struct param_s with size 0x98 including the fields as above. Continue to recover the remaining fields in the struct.

The code initializes two fields v23 and v26 in struct param_s

Lines 75 and 101 in function sub_10042BB6 proceed to initialize the variables v23 and v26 using the GetDeviceCaps API. This leads to 2 values v23 and v26 in the struct, which is an int devcap value.

The code initializes fields v13, v21, v24, v25 in struct param_s

Next, we pay special attention to 4 fields v13, v21, v24, v25 in the struct, I will go through these 4 fields in turn:

1. Field v13

This field is passed to the function sub_100A68D2:

The sub_100A68D2 function initializes CStringList

This is the function that initializes the CStringList structure, look at the sub_100A68D2 function, I recreate struct CStringList as follows:

Struct CStringList I created

This CStringList struct has size 0x1C, so the field v13 -> v19 in struct param_s are the memory area of struct CStringList. Now my struct param_s is updated as follows:

Struct param_s is updated

 We can initialize CStringList with the following code:

The code initializes struct CStringList

2. Field v21

Unlike field v13, field v21 is copied from another place through the sub_1000F8EA function. The function sub_1000F8EA copies a memory area of 8 bytes in size:

The function sub_1000F8EA assigns values to fields v21 and v22

Therefore, this function will initialize 2 fields in struct param, v21 and v22. Because it is assigned a value from another memory area, it is difficult to see when doing static. I debug, set breakpoints before calling the EnumEnhMetaFile API.

Breakpoint before the EnumEnhMetaFile API and checks for the values v21, v22

We see struct param_s located at address 0x4AAF57C, fields v21 and v22 have sizes 0x1c and 0x10 respectively at the addresses shown in the figure. Check the tpview!TPRenderW+221858 and tpview!TPRenderW+2228cc addresses I know function sub_1001B7FD will initialize the memory assigned to v21 and function sub_1004559D will initialize the memory into field v22. I reverse the two functions sub_1001B7FD and sub_1004559D to determine the fields of the memory it creates. Through that, my param_s struct is updated as follows: (The struct names I set according to liking and habit)

Struct param_s is updated

I initialize the above struct as follows:

The code that initializes 2 structs is assigned to v21 and v22

3. Fields v24, v25

Similar to v21, I also debug and check the initialization functions v24 and v25, the results I get are as follows:

The last struct param_s I have

And here is the code I use to initialize two fields v24 and v25:

The code initializes two fields v24 and v25

At this point, I was able to generate the param (4th parameter) for the EnumEnhMetaFile API. Now, simply call API EnumEnhMetaFile and pass parameters to complete the harness:

The code calls the proc function to complete the harness

Here I have shown how to create harnesses to fuzz the TPView.dll library. With the harnesses I introduced above, it is possible to apply Winafl, pe-afl, or Tiny-afl (a tool I built based on TinyInst [10] [11]) to fuzz. Corpus to fuzz for jpeg2000 format, fonts are plentiful on the internet (refer to j00ru’s font creation tool). For EMF file I create a program to generate EMF files containing some popular records such as bitmap, control, comment, clipping,…


JPEG2000 record: 1 bug memory corruption.

Font Record: 2 integer overflow bugs (CVE-2020-3989 and CVE-2020-3990)

Also in the reverse process, I discovered some issues that are not security bugs like:

  • The EMRI_TYPE1_FONT record’s processing flow is incorrect due to the incorrect field checking
  • Hits int 3 due to exception handling when bad EMF file parsing leads to DOS.


Through this article, I have introduced to everyone an approach to building harness fuzzing for closed source applications. Here’s a good example for beginners to learn fuzz to try. What I am showing above is just a part of the TPView.dll I know of. The codebase of TPView.dll is huge, I still do not fully understand, there might be some attack surface I don’t know (there may still be many bugs, everyone can try). Hopefully, this article can help people approach fuzzing more easily and soon have bugs.


[1] https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-emf/91c257d7-c39d-4a36-9b1f-63e3f73d30ca
[2] https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-emfspool/3d8cd6cc-5287-42e8-925f-4a53afd04534
[3] https://j00ru.vexillium.org/talks/pacsec-windows-metafiles-an-analysis-of-the-emf-attack-surface-and-recent-vulnerabilities/
[4] https://bugs.chromium.org/p/project-zero/issues/detail?id=287&q=VMware&can=1
[5] https://bugs.chromium.org/p/project-zero/issues/detail?id=850&q=VMware&can=1
[6] https://bugs.chromium.org/p/project-zero/issues/detail?id=848&q=VMware&can=1
[7] https://github.com/taviso/loadlibrary
[8] https://github.com/googleprojectzero/BrokenType/tree/master/fontsub-dll-on-linux
[9] https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-emfspool/ed79f9d8-31fb-46cb-950e-ea7682f50c70
[10] https://github.com/googleprojectzero/BrokenType/tree/master/truetype-generator
[11] https://github.com/googleprojectzero/BrokenType/tree/master/ttf-otf-mutator

IoT vulnerabilities research series – Virtualizing devices with QEMU

1. Introduction

In the previous article, we have mentioned that IoT devices such as Router, Access Point, and IP Camera can be compromised and turned into botnets. There are several existing hacking techniques could help attackers implement this kind of attack, and exploiting vulnerabilities enduring in IoT devices is one of them. This research series aims to provide readers with in-depth knowledge and objective perception of different IoT vulnerabilities that hackers can exploit.

In this article, we would like to introduce about QEMU, which stands for Quick EMUlator, can perform hardware virtualization. Using QEMU, researchers can set up virtual environments simulating Router, Access Point and IP Camera to facilitate vulnerability research processes. Studies carried out with QEMU can help security researchers explore unrevealed vulnerabilities hiding inside devices so that manufacturers can patch them.

Why should we use virtual devices instead of real devices?

There are several advantages, namely, cost & time effectiveness and user-friendliness that virtual devices possess when comparing to real physical ones:

  • Cost-saving: There is no need to spend a significant amount of money purchasing expensive devices when utilizing virtual devices.
  • Time-saving: It is incontrovertible that installing virtual devices takes much less time than ordering, shipping, and installing physical devices.
  • User friendly: It is easier for us to work in virtual machines than in physical ones.

However, we can meet some struggles when working with virtual devices because some are not comprehensively similar to physical devices, and some are hard or impossible to be implemented in simulative environments.

2. Virtualizing processes

Environment setup

In this experiment, we are going to use the tools listed below:

For the Linux virtual machine, we recommend using Ubuntu Server 16.04. Please note that you must select the option “Enable hypervisor application in this virtual machine” when configuring the Linux virtual machine. Below are some minimum required specifications for the Linux machine:

  • MEMORY: >= 1GB
  • CORES: >= 2
  • HARD DISK: >= 30GB
Figure 1 – Virtual machine specs

After successfully installing the Linux machine, download the setting script setup.sh and run.

Virtualizing experiment

In this part, an actual experiment is demonstrated so that readers can have a better insight into how all the virtualizing processes take place. We select Router DIR-882 manufactured by D-Link in this experiment since it contains quite comprehensively enough information and requirements to generate virtualizing.

First of all, go to https://support.dlink.com/ProductInfo.aspx?m=DIR-882-US and then download the Firmware of the router.

Step 1: Find the device’s rootfs

After downloading the firmware, we need to perform firmware extracting to obtain rootfs. However, this process’s details are beyond this article’s scope, so they are not presented here. You can find the instruction on implementing this step in this ZDI’s blog post.

Step 2: Examine the device’s architecture

After extracting the device’s rootfs, we need to know the router’s architecture to virtualize it by QEMU. We can run the command $ file rootfs/bin/busybox to obtain this piece of information.

Figure 2 – Obtain architecture information

It is shown in the result that this device uses mipsel architecture (Little-endian), and we need a machine that has the capability of analyzing this architecture. In this experiment, we will utilize a pre-built mipsel virtual machine to facilitate the process. To ease the installation of the mipsel virtual machine, we have prepared a setup script named emumipsel.sh that you can find at this link.

Figure 3 – Running emulator.sh

After installing the mipsel virtual machine, you can log in with the username/password combination root/root.

Step 3: Get rootfs into the QEMU virtual device

It was in step 2 that we succeeded in obtaining rootfs, and now we will copy that into QEMU.

Zip all the rootfs data:

  • $ tar -czvf rootfs.tar.gz rootfs/

Use scp in the Linux machine to copy the created tar file:

Unzip the tar file:

  • $ tar -xvf rootfs.tar.gz

Step 4: Virtualize nvram

NOTE: It is unnecessary to apply this step to virtualize devices that do not encompass nvram.

On exploring the router DIR-882, we recognized the appearance of nvram; however, QEMU does not support the virtualization of nvram, so we must employ another tool to perform this action.

Figure 4 – nvram appears in the router

Wandering around the Internet, we figured out a pretty excellent tool called libnvram that could support virtualizing NVRAM in this case. To build a libnvram, we need to use a cross compiler; therefore, if you do not have a cross compiler in your machine, please download a suitable one following this link:

After building a libnvram, you can use the command scp to copy it to the QEMU virtual machine.

Step 5: Configure the QEMU virtual machine

Before proceeding, we must consider the below points:

  • The simulating router will use virtual hardware devices provided by QEMU, so mounting or unmounting those devices can cause an operating problem.
  • The router will utilize the QEMU virtual machine’s network adapter directly, so there stands a chance that the router’s configurations damage the connection between the QEMU machine (guest) and the Linux machine (host).

We must alter some startup configurations of the router so that its operation will not negatively affect the QEMU machine’s functions. 

When reading content inside the file inittab, we saw that the file /etc_ro/rcS is started when the device is on boot, which proves that /etc_ro/rcS is the startup file of the router.

Figure 5 – Finding the startup file

On examining rcS and other files called by rcS, we recognized that the script file makedevlinks.sh was called to execute mount and mknod. We commented out the line of code in rcS that called makedevlinks.sh so that it would not affect the QEMU machine when booting.

Figure 6 – Content of rcS

Step 6: Start visualizing

First, we need to mount some resources so that they can be shared between the QEMU virtual machine and the router.

  • mount -o bind /proc rootfs/proc/
  • mount -o bind /dev rootfs/dev
  • mount -o bind /sys rootfs/sys

In the next step, we move the libvram instance to the rootfs folder and configure it:

  • mv path/libnvram.so rootfs/libnvram.so
  • mkdir rootfs/firmadyne

Perform virtualizing by chroot command:

  • chroot rootfs /bin/sh

Inside the chroot environment, run below commands:

  • export LD_PRELOAD=/libnvram.so
  • /etc_ro/rcS

Wait until the command finishes running.

Figure 7 – Result of the virtualizing process

Step 7: Fix errors (if exist)

Problem: lighttpd service does not appear when checking the system.

Figure 8 – Services running during the virtualizing process (lighttpd does not exist)

By examining events happening after /etc_ro/rcS was executed, we found out that lighttpd should have been started by /bin/init_system, but there was a problem with this process.

Figure 9 – lighttpd is started by init_system

By reverse engineering the file init_system,we figured out that the problem lied in the fact that /var/run/nvramd.pid did not exist in the system.

Figure 10 – Reverse engineer init_system

We tried to run the command executed in init_system to see if the problem could be solved:

  • lighttpd -f /etc_ro/lighttpd/lighttpd.conf -m /etc_ro/lighttpd/lib
Figure 11 – Result of running the command

After running the command, we still saw an error that might have been caused by lighttpd itself. We tried to comment out all lines in the file /etc_ro/lighttpd/lighttpd.conf to see if the error still occurred.

Figure 12 – Comment lines in /etc_ro/lighttpd/lighttpd.conf

After doing that, we finally succeeded in starting lighttpd.

Figure 13 – Successfully start lighttpd
Figure 14 – Website served by lighttpd server

Even though the simulating router could not provide all the features like a real device, we could still take advantage of it to debug lighttpd or other services running on the device.

This writing is quite long up to this point; therefore, we hope that in the future, we can present to you the detailed procedure of setting up an environment for debugging.

3. Conclusion

In essence, creating a virtual device by QEMU is not too hard. However, this process requires the implementers to be knowledgeable about different aspects and carefully understand the machine they want to virtualize. The first attempt of virtualizing a device will cost you time and effort, but you will be familiar with this task when performing it more often.

In the future, we will deliver to you more writings on this topic and other exciting issues. Thank you so much for spending your time with us. Please share and comment if you find this post beneficial.

Credit: @chung96vn

Nghiên cứu lỗ hổng bảo mật trên thiết bị IoT – Ảo hóa thiết bị bằng QEMU

Mở đầu

Xin chào, chúng tôi lại quay trở lại rồi đây.

Trong bài viết trước của nhóm, có lẽ nhiều bạn đọc vẫn còn thắc mắc là tại sao một thiết bị Router, Access Point, Camera IP lại có thể bị thỏa hiệp và biến thành một máy trạm trong một hệ thống Botnet. Có thể bài viết này và một số bài viết sau của chúng tôi sẽ giúp bạn đọc có cái nhìn khách quan hơn về lỗ hổng bảo mật trong các thiết bị IoT, đó là một trong những nguyên nhân chính dẫn đến việc các thiết bị IoT bị tấn công và trở thành một phần của mạng Botnet.

Trong bài viết dưới đây, mình sẽ chia sẻ về kỹ thuật sử dụng QEMU trong việc ảo hóa các thiết bị Router, Access Point, Camera IP nhằm đơn giản hóa quá trình nghiên cứu. Qua đó giúp quá trình tìm kiếm, phát hiện các lỗ hổng bảo mật trở nên đơn giản và hiệu quả hơn.

Những nghiên cứu này nhằm mục đích tìm và phát hiện các lỗ hổng bảo mật trên các nhóm thiết bị nêu trên, qua đó giúp cho nhà cung cấp có thể sửa đổi, khắc phục để nâng cao chất lượng cũng như đảm bảo an toàn thông tin cho người dùng.

Tại sao tôi lại chọn ảo hóa thiết bị mà không phải là nghiên cứu trên các thiết bị thật?

Với những dòng thiết bị tôi đang nghiên cứu thông thường có giá bán trên thị trường cao hoặc không tìm mua được ở Việt Nam mà phải đặt mua ở nước ngoài về, đó chính là những rào cản trong việc sở hữu một thiết bị thật để nghiên cứu. Chính vì thế tôi chọn việc ảo hóa thiết bị để có thể thực hiện được công việc của mình, và đây là những ưu điểm mà tôi thấy được từ việc sử dụng ảo hóa:

  • Tiết kiệm chi phí nghiên cứu
  • Tiết kiệm thời gian không phải chờ mua thiết bị
  • Tương tác với môi trường ảo hóa dễ dàng hơn tương tác với thiết bị thật

Ngoài ra ảo hóa cũng có những nhược điểm nhất định như sau:

  • Không giống hoàn toàn thiết bị thực tế
  • Một số thiết bị khó ảo hóa và tốn nhiều thời gian để thực hiện hoặc không thể thực hiện được ảo hóa

Ảo hóa thiết bị

Cài đặt môi trường?

Ở đây tôi sử dụng những công cụ sau:

  • Một máy ảo linux (nên dùng ubuntu server)
  • QEMU
  • binwalk
  • squashfs-tools
  • jefferson
  • pwndbg
  • gdb-multiarch

Đầu tiên cần phải cài một máy ảo linux, ở đây tôi khuyến khích mọi người sử dụng ubuntu server 16.04.

Lưu ý đối với cấu hình máy ảo cần được tích chọn “Enable hypervisor application in this virtual machine”.

Yêu cầu cấu hình máy ảo:

  • MEMORY: >= 1GB
  • CORES: >= 2
  • HARD DISK: >= 30GB
Cấu hình được dùng cho máy ảo linux

Sau khi cài đặt thành công máy ảo, download file cài đặt setup.sh và khởi chạy.

Ảo hóa thiết bị như nào?

Trong phần này tôi sẽ làm một ví dụ cụ thể để mọi người có cái nhìn cụ thể hơn về hướng mà tôi đã làm để có thể ảo hóa thiết bị. Ở đây tôi chọn Router DIR-882 của nhà cung cấp D-Link bởi tôi thấy nó có đầy đủ các thông tin cũng như các bước cần thiết để có thể thực hiện được ảo hóa đối với nhiều thiết bị khác.

Việc đầu tiên cần làm là tải về firmware của thiết bị đó về.

Bước 1: Phân tích tìm rootfs của thiết bị

Sau đó thực hiện extract firmware vừa tải được để lấy được rootfs của thiết bị. Tôi xin phép không nói cụ thể về việc này bởi việc này đã được hướng dẫn trong một blog của ZDI từ những kỹ thuật mà tôi đã đính kèm trong những báo cáo lỗ hổng bảo mật. Mọi người có thể tham khảo thêm thông tin tại blog của zdi.

Bước 2: Xác định kiến trúc của thiết bị

Sau khi có được rootfs của thiết bị, cần kiểm tra xem thiết bị sử dụng kiến trúc nào? Thông thường tôi thực hiện chạy lệnh $ file rootfs/bin/busybox để xem xem file này thuộc kiến trúc nào.

Có thể thấy thiết bị sử dụng kiến trúc mipsel (little endian)

Sau khi biết được thiết bị sử dụng kiến trúc gì, ta cần chạy một máy ảo chạy kiến trúc đó bằng QEMU. Ở đây tôi sử dụng một máy ảo mipsel được build sẵn và chia sẻ ở trên mạng.

Mình có viết một script hỗ trợ việc chạy máy ảo mipsel, mọi người có thể tải file cài đặt emumipsel.sh về và chạy chúng.

Lần đầu chạy file emumipsel.sh

Sau khi máy ảo QEMU đã chạy thành công, mọi người có thể thực hiện đăng nhập với username/password là root/root.

Bước 3: Đưa rootfs vào trong máy ảo QEMU

Ở bước 1 chúng ta đã có được rootfs của thiết bị này. Ở bước này chúng ta thực hiện đưa toàn bộ file trong này lên máy ảo QEMU.

Đầu tiên nén rootfs thành một tập tin bằng câu lệnh sau:

  • tar -czvf rootfs.tar.gz rootfs/

Sử dụng scp trong máy ảo QEMU để đưa rootfs vào trong máy ảo QEMU:

Giải nén tập tin tại máy ảo QEMU bằng câu lệnh sau:

  • tar -xvf rootfs.tar.gz

Bước 4: Ảo hóa nvram

Lưu ý: Với những thiết bị không sử dụng nvram thì không cần làm bước này.

Nhận thấy thiết bị có sử dụng nvram tuy nhiên máy ảo QEMU không hỗ trợ nvram, chính vì thế cần phải có một công cụ giúp hỗ trợ ảo hóa nvram cho trường hợp này. Sau khi tìm kiếm trên mạng và phát hiện được một công vụ giúp hỗ trợ ảo hóa nvram khá ổn là libnvram của firmadyne.

Thiết bị có sử dụng nvram

Để tạo được một libnvram ta cần phải sử dụng cross compiler để có thể build được một libnvram với kiến trúc mipsel để sử dụng được bên trong máy ảo QEMU. Các bạn có thể tải về cross compiler phù hợp từ đường dẫn sau:

Sau khi build được libnvram thì đưa chúng vào trong máy ảo QEMU bằng câu lệnh scp.

Bước 5: Chỉnh sửa cấu hình để chạy ảo hóa.

Ở bước này chúng ta cần phải chỉnh sửa một số nội dung các file khởi chạy ban đầu để phù hợp với điều kiện chạy trong máy ảo. Cần có một số chú ý như sau:

  • Thiết bị sẽ sử dụng các device có sẵn của máy ảo QEMU và việc mount hay unmount các device khác là không phù hợp và có thể không tương thích dẫn đến máy ảo bị crash và dừng lại.
  • Thiết bị sử dụng card mạng của máy ảo QEMU, chính vì thế các cấu hình mạng mặc định của thiết bị có thể làm hỏng cấu hình mạng của máy chủ dẫn đến việc kết nối từ máy ảo QEMU (guest) đến máy ảo linux (host) bị hỏng.

Từ những lưu ý trên, chúng ta cần phải sửa những câu lệnh có ảnh hưởng đến các device hoặc các cấu hình liên quan đến card mạng. Trước tiên cần tìm được file khởi chạy ban đầu của thiết bị, đọc nội dung trong file inittab cho thấy file /etc_ro/rcS được khởi chạy ngay sau khi thiết bị được bật.

Cấu hình khởi động của thiết bị

Đọc nội dung của file rcS và các file được rcS gọi tới chúng tôi phát hiện tập tin makedevlinks.sh trong đó có chạy các lênh mount, mknod. Để không ảnh hưởng đến máy ảo QEMU trong quá trình chạy ảo hóa thiết bị, tôi đã thực hiện comment dòng lệnh này.

Nội dung file khởi động của thiết bị

Bước 6: Bắt đầu chạy ảo hóa

Việc đầu tiên cần làm là thực hiện chia sẻ tài nguyên giữa máy ảo QEMU với thiết bị sẽ được ảo hóa bằng các lệnh mount:

  • mount -o bind /proc rootfs/proc/
  • mount -o bind /dev rootfs/dev
  • mount -o bind /sys rootfs/sys

Sau đó thực hiện đưa libnvram vào thư mục rootfs và cấu hình ảo hóa nvram:

  • mv path/libnvram.so rootfs/libnvram.so
  • mkdir rootfs/firmadyne

Thực hiện ảo hóa bằng câu lệnh chroot:

  • chroot rootfs /bin/sh

Bên trong môi trường chroot thực hiện chạy những câu lệnh sau:

  • export LD_PRELOAD=/libnvram.so
  • /etc_ro/rcS

Chờ câu lệnh chạy xong và xem các kết quả hiển thị ra để xác định các lỗi có thể gặp phải.

Kết quả chạy ảo hóa thiết bị

Bước 7: Fix các lỗi gặp phải khi chạy (nếu có)

Kiểm tra các tiến trình đã được chạy của thiết bị ảo hóa thì không thấy có dịch vụ lighttpd (dịch vụ web service).

Các tiến trình được chạy bởi ảo hóa thiết bị

Tìm kiếm dựa vào những gì hiển thị sau khi chạy /etc_ro/rcS tôi tìm được dịch vụ lighttpd được chạy bởi /bin/init_system

lighttpd được chạy bởi init_system

Thực hiện dịch ngược file init_system tôi tìm được nguyên nhân dẫn đến lighttpd không được chạy là do file /var/run/nvramd.pid không tồn tại trong hệ thống.

Dịch ngược file init_system

Sau khi dịch ngược tập tin init_system tôi thấy để chạy được lighttpd chỉ cần chạy câu lệnh được sử dụng trong file: lighttpd -f /etc_ro/lighttpd/lighttpd.conf -m /etc_ro/lighttpd/lib

Chạy lighttpd

Thực hiện chạy câu lệnh trên và xem kết quả nhận được, có thể thấy lỗi xảy ra do một số cấu hình của lighttpd chưa được đẩy đủ. Để khắc phục vấn đề này, tôi thực hiện comment hết những dòng không cần thiết trong file /etc_ro/lighttpd/lighttpd.conf để có thể khởi chạy được lighttpd.

Những nội dung cần comment lại
lighttpd server đã được chạy thành công
Truy cập vào web page

Có thể thấy dịch vụ lighttpd đã chạy thành công tuy nhiên không hoàn chỉnh được như một thiết bị thật. Dẫu vậy ta vẫn có thể sử dụng phiên bản emulator này để debug dịch vụ lighttpd hoặc các dịch vụ khác đang được chạy trên thiết bị.

Do bài viết đã dài nên tôi xin phép không chia sẻ thêm về cách cài đặt để có thể debug được ứng dụng mà sẽ nói trong bài viết tiếp theo.

Kết Luận

Như vậy có thể thấy được để ảo hóa một thiết bị bằng QEMU không quá khó, tuy nhiên nó đòi hỏi nhiều kiến thức cũng như am hiểu về các thiết bị mà mình muốn ảo hóa. Thông thường lần đầu tiên thực hiện sẽ tốn nhiều thời gian còn những lần tiếp theo sẽ tốn ít thời gian hơn.

Chúng tôi sẽ còn chia sẻ thêm nhiều những bài viết, những chia sẻ về kỹ thuật hữu ích đến các bạn trong thời gian sắp tới. Trong bài viết tiếp theo có thể tôi sẽ chia sẻ cách để debug dịch vụ lighttpd được chạy trên thiết bị DIR-882 được sử dụng trong ví dụ trên.

Xin cảm ơn các bạn đã dành thời gian để đọc. Hãy chia sẻ nếu thấy hay và để lại những bình luận góp ý phía bên dưới nhé!

Credit: @chung96vn

Tản mạn về một cuộc điều tra tấn công DDoS

Xin chào, sau một thời gian chống chọi Covid, Zepto team chúng tôi đã quay trở lại rồi đây =]]

Hôm nay chúng tôi sẽ chia sẻ về quá trình điều tra, truy vết nguồn gốc của một chiến dịch tấn công DDoS mà hệ thống giám sát ghi nhận được. Qua điều tra, chúng tôi đã phát hiện đây là một cuộc tấn công DDoS đến từ một hệ thống botnet của một tổ chức chuyên bán các dịch vụ tấn công từ chối dịch vụ. Quá trình điều tra và truy vết như thế nào sẽ được chúng tôi chia sẻ cụ thể ở bên dưới, hi vọng mọi người sẽ cảm thấy hữu ích với bài viết này.

Let’s go

Sau khi nhận được thông tin từ hệ thống giám sát rằng hệ thống đang có hiện tượng bị tấn công từ chối dịch vụ, chúng tôi đã ngay lập tức cử người đến để phối hợp ứng cứu sự cố và điều tra về tấn công này. Việc xử lý và ngăn chặn tấn công DDoS đã được thực hiện ngay sau đó và hệ thống đã quay trở lại hoạt động bình thường. Tuy nhiên mục tiêu chúng tôi đặt ra là làm sao để biết được tấn công này đến từ đâu và hệ thống nào điều khiển cuộc tấn công này thì vẫn còn là một dấu hỏi lớn cần được giải đáp.

Mục tiêu chúng tôi đặt ra trong trường hợp này như sau:

  • Phát hiện được cách thức tấn công
  • Phát hiện hệ thống điều khiển tấn công
  • Phát hiện kẻ đứng sau thực hiện tấn công.

Điều tra cách thức tấn công

Sau khi phân tích các dữ liệu được cung cấp từ đội ngũ quản trị hệ thống, chúng tôi đã đưa ra kết luận đây là một cuộc tấn công SYN Flood nhằm vào hệ thống máy chủ ứng dụng. Đây là một hình thức tấn công từ chối dịch vụ thông qua việc gửi liên tục các gói tin khởi tạo kết nối SYN đến máy chủ dẫn đến vượt quá khả năng xử lý của máy chủ làm cho hệ thống không kịp phản hồi các kết nối hợp lệ từ người dùng thông thường.

Ngay sau khi phát hiện hình thức tấn công thì các biện pháp khắc phục, xử lý đã được thực hiện để đưa hệ thống trở lại trạng thái hoạt động bình thường.

Điều tra hệ thống điều khiển tấn công

Ghi nhận thông tin hệ thống bị tấn công đồng loạt từ nhiều ip khác nhau (tấn công từ nhiều máy trạm), để làm được điều này kẻ tấn công không thể đến trực tiếp từng máy trạm để thực hiện hành động này. Do đó chắc chắn phải có một hệ thống đứng sau điều khiển tất cả máy trạm thực hiện tấn công đồng loạt vào một thời điểm nhất định.

Chúng tôi thực hiện lọc trên hệ thống bảo vệ và có kết quả nhận về một số lượng lớn ip vẫn đang có các hành vi thực hiện tấn công vào hệ thống nhưng đã bị chặn. Để tìm được kẻ đứng sau thì chúng tôi quyết định tiến hành điều tra truy vết thông tin từ những địa chỉ ip này.

Danh sách ip bị chặn khi phát hiện tấn công SYN Flood

Qua kiểm tra một số ip thuộc danh sách trên chúng tôi đưa ra hai giả thuyết như sau:

  • Tấn công đến từ hệ thống máy tính bị nhiễm mã độc
  • Tấn công đến từ một hệ thống các thiết bị IoT bị kiểm soát

Sử dụng hệ thống tra cứu thông tin của NCSC Việt Nam, chúng tôi phát hiện số lượng lớn ip bị chặn thuộc các hệ thống botnet.

Các ip bị chặn nằm trong các hệ thống botnet

Như vậy có thể nhận định rằng đây là một cuộc tấn công đến từ một hệ thống botnet. Kiểm tra các ip này phần lớn đang mở các dịch vụ quản trị từ xa của các thiết bị IoT. Có thể nhận định các thiết bị IoT này tồn tại các lỗ hổng bảo mật dẫn đến bị khai thác chiếm quyền điều khiển và đưa vào hệ thống botnet. Tuy nhiên, làm sao để biết được hệ thống botnet này hoạt động như nào và được điều khiển từ đâu lại là một vấn đề phức tạp.

Để giải quyết vấn đề này tôi có đưa ra hai cách khả thi như sau:

  1. Liên hệ nhà mạng (bởi các ip này có nhiều ip thuộc các nhà mạng Việt Nam) để biết được ip này của khách hàng nào. Sau đó liên hệ khách hàng liên quan để lấy thiết bị, tiến hành phân tích thiết bị để tìm kiếm mã độc.
  2. Tìm cách truy cập vào thiết bị từ xa để phân tích, tìm kiếm mã độc.

Có thể dễ thấy cách đầu tiên nêu ra tốn rất nhiều thời gian và nguồn lực, do đó bằng kỹ năng nghiệp vụ và những hệ thống thông tin có sẵn của NCSC, chúng tôi đã quyết định tìm phương án sử dụng cách thứ 2.

Sau khi truy cập thành công vào thiết bị nghi ngờ nằm trong hệ thống botnet, chúng tôi đã phát hiện được một số tiến trình lạ đang chạy trong thiết bị.

Một số tiến trình lạ đang chạy trên thiết bị

Truy cập vào dịch vụ ftp của ip tìm thấy trong command khởi chạy của một tiến trình bất thường chúng tôi phát hiện nhiều mẫu mã độc IoT được lưu tại đó.

Mẫu mã độc IoT được lưu trên server nghi là c&c

Các mẫu tìm thấy trùng khớp với các tập tin đang được chạy trên thiết bị, từ đó khẳng định một cách chính xác được thiết bị đang bị điều khiển bởi máy chủ mạng botnet.

Thực hiện phân tích mẫu mã độc thu được chúng tôi đã thấy được đây là một mẫu mã độc được sử dụng cho mục đích tấn công DDoS với nhiều chức năng khác nhau được điều khiển thông qua các lệnh được gửi về từ máy chủ c&c. Tìm kiếm trên mạng internet chúng tôi thấy được một số mã nguồn tương tự với mẫu này đã được công bố trên internet:

Phân tích mẫu mã độc tìm thấy trên thiết bị

Mã độc nhận lệnh từ máy chủ c&c (dịch vụ chạy tại port 1111) và thực hiện hành động tấn công DDoS tương ứng.

Thông tin dịch vụ c&c được tìm thấy trong mẫu mã độc

Thực hiện kết nối đến c&c của botnet và nhận các lệnh từ trên c&c gửi về các máy trạm thông qua việc mô phỏng lại một thiết bị IoT nhiễm độc. Chúng tôi thấy rằng hệ thống này vẫn hoạt động bình thường, và các lệnh tấn công vẫn đang được gửi về từ c&c tới mạng botnet.

Các lệnh được gửi về từ c&c

Truy tìm kẻ đứng sau thực hiện tấn công

Ngoài ra chúng tôi còn phát hiện trên thiết bị chạy một mẫu mã độc thực hiện các hành động tấn công dò quét lỗ hổng trên các thiết bị IoT khác nhằm mục đích mở rộng hệ thống botnet.

Mẫu mã độc sử dụng để mở rộng hệ thống botnet
Một trong số các mã khai thác được sử dụng để tấn công các thiết bị khác (CVE-2017–17215)

Qua quá trình điều tra và phân tích các mẫu tìm được, chúng tôi đã phát hiện được 3 c&c:

  • 163[.]172[.]40[.]236 có địa chỉ IP tại Pháp
  • 51[.]77[.]220[.]127 có địa chỉ IP tại Pháp
  • 185[.]132[.]53[.]194 có địa chỉ IP tại Đức
Thông tin liên quan đến máy chủ c&c

Trong số 3 c&c ở trên, có một c&c có chứa nhiều thông tin hơn 2 c&c còn lại, kiểm tra thông tin máy chủ c&c này chúng tôi phát hiện một nhóm chuyên bán các dịch vụ DDoS nextstress[.]pw. Tuy nhiên tại thời điểm điều tra, trang web này không còn hoạt động. Có thể nhóm này đã chuyển sang sử dụng một hệ thống web khác tương tự.

Thông tin liên quan đến máy chủ c&c
Nhóm hacker quảng cáo dịch vụ DDoS trên twitter https://twitter.com/httpg0d1

Kết luận

Từ những kết quả trên chúng ta có thể kết luận rằng kẻ xấu đã thuê dịch vụ tấn công DDoS thuộc một trong các hệ thống tương tự nextstress[.]pw để thực hiện các hành vi tấn công vào hệ thống.

Tấn công DDoS là một dạng tấn công gây tác động lớn đến các hệ thống, và có thể thấy rằng việc thực hiện các hành vi xấu thông qua tấn công DDoS ngày càng dễ dàng thực hiện thông qua việc thuê các dịch vụ từ bên thứ ba. Các dịch vụ cung cấp các tấn công này thì có hệ thống botnet ngày càng phức tạp, và quy mô ngày càng lớn.

Có thể nói an toàn thông tin cho các thiết bị IoT là rất quan trọng, nó vừa đảm bảo an toàn cho hệ thống, vừa ngăn chặn được việc tận dụng thiết bị IoT cho các chiến dịch tấn công DDoS. Có thể nhiều người sẽ thắc mắc những vấn đề sau:

  • Tại sao các thiết bị IoT lại là đối tượng để kẻ xấu tận dụng để xây dựng các hệ thống mạng botnet phục vụ cho các hình thức tấn công DDoS?
  • Tại sao một thiết bị IoT lại có thể trở thành một máy trạm trong hệ thống mạng botnet?
  • Làm sao để đảm bảo an toàn cho các thiết bị IoT?

Có thể những câu hỏi trên sẽ được giải đáp trong những blog tiếp theo của chúng tôi.

Cuối cùng, xin cảm ơn các bạn đã đọc bài viết này và hẹn gặp lại trong blog tiếp theo!

P/s: Do tính chất đặc thù và một số nguyên tắc trong công việc, ngoài ra blog chỉ tập trung vào chia sẻ các kỹ thuật nên nhiều thông tin quan trọng khác chúng tôi xin phép không nêu trong bài viết này.

Khai thác lỗ hổng bảo mật trên các thiết bị mạng D-Link

Bài này viết về gì?

Chào mọi người, tôi là @chung96vn. Ở bài viết này tôi sẽ trình bày cách mà tôi đã tìm được hai lỗ hổng bảo mật CVE-2020-8863CVE-2020-8864 trên các dòng Router DIR-867, DIR-878, and DIR-882.
Cụ thể trong bài này tôi sẽ trình bày một cách chi tiết từ cách tiếp cận đến cách tôi phát hiện ra hai lỗ hổng bảo mật này. Có thể nói 2 lỗ hổng bảo mật này không khó để phát hiện, nhưng để hiểu và khai thác được chúng thì cũng cần phải tốn một chút thời gian và công sức. Nhưng thực sự mà nói thì dễ tìm v*i l**, tôi chỉ là may mắn hơn các bạn mà thôi =))

Tôi đã tiếp cận target này như thế nào?

Thực sự mà nói thì khi tôi gà và chẳng làm được gì còn anh em ngoài kia cứ bug này bug kia nên cũng chọn một cái target nào đó mà tôi nghĩ là nó easy nhất để thử thôi. Ban đầu tôi có thử và tìm được một số bug trên một dòng router khác của D-Link, tuy nhiên sau khi đem đi report thì tôi biết nó là End Of Life (EOL) product. Sau đó tôi lên trang chủ của D-Link và pick đại một con route bất kì để nghiên cứu và nó là DIR-882.

Tóm tắt về 2 CVE

2 CVE nêu ở trên đều là lỗ hổng bảo mật liên quan đến quá trình xác thực của hệ thống web quản trị của thiết bị. Cụ thể là lỗ hổng bảo mật cho phép một người dùng bất kỳ có thể truy cập và sử dụng các chức năng quản trị thiết bị trên web quản trị mà không cần sử dụng bất kì thông tin xác thực nào.

Thông tin chi tiết

Thông thường với các target kiểu này tôi thường tập trung vào tìm các lỗi không cần thông tin xác thực bởi với quan niệm của tôi thì nếu cần thông tin xác thực thì mức độ nguy hiểm của lỗi đối với các thiết bị này sẽ giảm đi khoảng 99%. Chính vì thế việc đầu tiên khi tìm bug trên các thiết bị này tôi tập trung vào tìm hiểu cách thức mà hệ thống này xác thực người dùng.

Việc đầu tiên tôi làm là đọc và vẽ lại mô hình thuật toán dùng để xác thực của thiết bị này. Có thể nói đây là thuật toán rất an toàn và được sử dụng bởi nhiều các thiết bị khác nữa. Tuy nhiên việc triển khai code các thuật toán đối với từng thiết bị còn tồn tại nhiều điểm yếu dẫn đến có thể tận dụng để bypass qua lớp xác thực này.

Dưới đây là mô hình đăng nhập được sử dụng trong thiết bị DIR-882 của D-Link.

Quy trình đăng nhập

Nhìn vào quy trình trên ta thấy việc xác thực có liên quan mật thiết đến password của tài khoản admin. Tuy nhiên việc lập trình để tích hợp thuật toán xác thực trên không phải lúc nào cũng hoàn hảo mà thông thường sẽ tồn tại một số điểm yếu do phải tích hợp thêm để phù hợp với từng thiết bị.


Nguyên nhân gây nên bug này là do việc tích hợp một chức năng PrivateLogin mà tôi vẫn không hiểu nó tạo ra với mục đích gì hay là một backdoor được thiết lập sẵn trong thiết bị.

Server thực hiện tính toán privatekey

Nhìn vào hình vẽ trên chúng ta có thể thấy, nếu giá trị PrivateLogin được gửi kèm trong gói tin request login và có giá trị là “Username” thì giá trị được sử dụng để tính toán privatekey là Username được gửi kèm theo thay vì là password của tài khoản admin. Như vậy chúng ta có thể hoàn toàn tính toán được giá trị privatekey qua đó sử dụng chúng cho các bước xác thực tiếp theo.

Như vậy việc đầu tiên là thực hiện gửi gói tin request login với giá trị PrivateLogin kèm theo để lấy về các giá trị cần thiết để tính toán privatekey.

Thực hiện login với tham số PrivateLogin

Sau khi thực hiện request trên chúng ta có được các giá trị cần thiết như cookie, challenge, publickey và từ đó tính toán được giá trị của privatekey.

Sau khi có được giá trị privatekey chúng ta hoàn toàn có thể sử dụng chúng để xác thực các chức năng yêu cầu người dùng phải đăng nhập.


Khác với CVE-2020-8863, lỗ hổng bảo mật này có vẻ sẽ quen thuộc hơn với các bạn có tìm hiểu về pwnable. Nguyên nhân gây nên CVE-2020-8864 là do việc sử dụng các hàm so sánh chuỗi ký tự không đúng cách. Cụ thể lập trình viên sử dụng các hàm so sánh như strncmp mà không kiểm tra kỹ giá trị độ dài cần so sánh dẫn đến có thể tận dụng để vượt qua bước xác thực mà không cần thông tin tài khoản.

Chức năng login để tạo một validate session

Nhìn vào hình trên chúng ta có thể thấy nếu giá trị LoginPassword có độ dài là 0 thì hàm strncmp sẽ luôn return về 0 tức là việc so sánh AuthenKey và LoginPassword là luôn trả về kết quả là giống nhau.

Tuy nhiên vượt qua được bước xác thực là chưa đủ bởi để sử dụng được các chức năng của quản trị viên chúng ta cần phải có được giá trị của privatekey thay vì chỉ cần giá trị của cookie, tuy nhiên trong trường hợp này chúng ta không tính toán được giá trị của privatekey.

Vậy làm thế nào để có được giá trị của privatekey, và nó có thực sự cần thiết hay không?

Để giải quyết được vấn đề này chúng ta cần phải tìm hiểu về cách thức kiểm tra xem người dùng đã đăng nhập thành công hay chưa. Dưới đây là mô hình kiểm tra xác thực người dùng

Mô hình xác thực người dùng

Nhìn vào mô hình trên chúng ta có thể thấy để xác thực thì giá trị Hnap_Auth_key cần phải được tính toán dựa vào privatekey. Tuy nhiên lập trình viên lại tiếp tục mắc phải một lỗi khi sử dụng hàm strncmp với kích thước kiểm tra phụ thuộc vào dữ liệu người dùng gửi lên server. Như vậy nếu Hnap_Auth_key có độ dài bằng 0 thì kết quả trả về luôn là Authenticated. Tuy nhiên trong trường hợp này chúng ta không thể tạo được Hnap_Auth_key với độ dài bằng 0 bởi giá trị này nằm ở đầu của HNAP_AUTH header.

Mã nguồn xử lý xác thực

Để giải quyết vấn đề này tôi đã có một ý tưởng là sử dụng Hnap_Auth_key có độ dài là 1 và brute force giá trị này trong khoảng tối đa 16 ký tự, điều này là hoàn toàn khả thi vì số lượng request cần tối đa là 16.

Kết luận

Có thể nói hai lỗ hổng bảo mật trên là không khó để có thể phát hiện và khai thác. Tuy nhiên để có thể đến được các bước mà tôi đã nói ở trên chúng ta cần phải có cả một quá trình nghiên cứu, tìm hiểu. Tôi cũng đưa ra một số lời khuyên cho các bạn trẻ muốn đi theo con đường này như sau:

  • Hãy tìm hiểu và nghiên cứu thật nhiều và thành quả sẽ đến với bạn trong một tương lai không xa.
  • Muốn đi nhanh thì đi một mình, muốn đi xa thì đi cùng nhau và vừa rồi tôi cũng đã hợp tác với một người anh (@phieulang) để nghiên cứu về lĩnh vực này và dưới đây là một trong những thành quả nghiên cứu chung đầu tiên của hai anh em.

What Next???

Ngoài những CVE được nhắc đến trong bài này tôi còn tương đối nhiều bug khác trên các thiết bị khác nhau của D-Link. Và tôi cũng dự kiến sẽ chia sẻ chi tiết và cụ thể hơn cách tôi tìm bug trên dòng thiết bị này tại hội thảo Hacker Mũ Cối sắp tới.

Chính vì thế bạn nào quan tâm và hứng thú thì cùng đón chờ thông tin chính thức của sự kiện Hacker Mũ Cối nhé.
Thanks for reading!

ATT&CK: Những ngày tháng gian khổ

MITRE’s ATT&CK là một framework về kỹ thuật-chiến thuật-chiến lược tấn công của adversary (kẻ tấn công) dựa vào những tình huống thực tế.

MITRE’s ATT&CK framework provide names, descriptions, and links to examples of the high-level tactics adversaries’ use during an operation, as well as the techniques the adversary uses to achieve them. For example, the ATT&CK framework has a tactic called ‘Launch’ that refers to an adversary attempting to penetrate a network. One technique associated with this tactic is called “Spear phishing messages with malicious attachments”, which describes how the adversary would launch an attack on the network. This provides common definitions and understandings of how a specific goal is accomplished by attackers.
Nhìn hình sẽ dể hiểu hơn

Trong quá trình Threat Hunting đầy gian khổ, chúng tôi nhận thấy ATT&CK này rất hiệu quả trong việc tổng hợp và đưa ra một cái nhìn có tính tổng quan về các surface có thể bị tấn công để áp dụng . Chúng ta sẽ bắt đầu kỹ thuật đầu tiên mà các adversary sử dụng cho mục đích Persistence, đó là lợi dụng các tính năng về Accessibility features trong Windows.

Accessibility Features

Nội dung chính:

  • Khái niệm
  • Các kỹ thuật hiện có
  • Các case study
  • Các cách phát hiện và phòng chống

Khái niệm

  • Adversary lợi dụng tính năng accessibility (trợ năng) có sẵn trên Windows để khởi tạo 1 tổ hợp phím trước khi người dùng đăng nhập (ví dụ khi người dùng ở màn hình đăng nhập và nhấn 5 lần phím SHIFT) để có thể thực hiện lệnhCMD hoặc bất kỳ file thực thi nào mà không cần phải đăng nhập.
  • Trên thực tế, kỹ thuật tấn công này thường được sử dụng trên các máy tính đang bật Remote Desktop Protocol (RDP). Các adversary sử dụng RDP như một kênh để thực hiện tấn công.
Các công cụ accessibility có thể bị lợi dụng (hay gặp nhất có lẽ là Sticky Keys)

Kỹ thuật thực hiện

Có 2 cách phổ biến để thực hiện kỹ thuật này:

  • Thay thế file thực thi của accessibility feature(ví dụ như C:\Windows\System32\sethc.exe) bằng file thực thi khác, thường là cmd.exe hoặc explorer.exe để phục vụ các bước tiếp theo của adversary.
  • Thay đổi Registry để chạy một debugger mỗi khi C:\Windows\System32\sethc.exe được thực thi. Đăng ký debugger đó là cmd.exe hoặc bất kỳ file thực thi nào. Ví dụ với cmd.exe được sử dụng như một debugger.

Các case study

AttackThông tin về nhómKỹ thuật
APT29Được cho là của chính phủ Nga, bắt đầu hoạt động từ khoảng 2008Thay thế Sticky Keys binary C:\Windows\System32\sethc.exe bằng cmd.exe
APT3Có trụ sở tại Trung Quốc. Trong bài viết được đề cập, nhóm này còn được gọi là UPSTham khảo thêm bài viết sau 
AxiomCó liên quan đến chính phủ Trung Quốc. Vận hành chiến dịch Operation SMN, sử dụng mã độc WinntiCơ bản kỹ thuật cũng giống các nhóm khác. Tham khảo thêm bài viết sau
Deep PandaNhóm TQ từng tấn công vào công ty AnthemSử dụng kỹ thuật sticky-keys để bypass RDP login

Các cách phát hiện và phòng chống

  • Do kỹ thuật này thường phải sử dụng kết hợp với RDP, ta phải đảm bảo tính năng Network Level Authentication đang enable để các phiên RDP đều phải được authen. Hiện tại tính năng này là mặc định trên các phiên bản từ Vista trở lên. Đối với các mạng nội bộ (của công ty hoặc gia đình, tổ chức,…), có thể sử dụng tính năng Remote Desktop Gateway để quản lý các kết nối RDP. Tham khảo thêm cách cấu hình Remote Desktop Gateway trên Windows Server 2008.
  • Sử dụng whitelist tool như AppLocker hoặc Software Restriction Policies để ngăn chặn việc load các malicious file.
  • Theo dõi Registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options

Đây là trường hợp một cuộc tấn công sử dụng Accessibility Features được phát hiện.

Tham khảo

Technique: Accessibility Features – MITRE ATT&CK™
bash_profile and .bashrc Accessibility Features Account Manipulation AppCert DLLs AppInit DLLs Application Shimming…attack.mitre.org

Lazarus, ngân hàng X và chuyện bên lề — Phần 1: Hai con chuồn chuồn con

Gần đây, Zepto có nhận được một số mẫu mã độc được cho rằng có liên quan tới các cuộc tấn công APT vào hệ thống ngân hàng của Việt Nam mà báo chí có đưa tin gần đây [1]. Trong đó có đề cập đến 2 mẫu mã độc được cho là sử dụng trong chiến dịch trên.

Liệu 2 mẫu trên thật sự làm gì và có gì liên quan đến nhau? Bức tranh toàn cảnh của chiến dịch này là gì? Câu trả lời sẽ dần được hé lộ trong series bài viết phân tích về cuộc tấn công APT này.

Quan hệ giữa 2 file trên sau khi phân tích

Phân tích mẫu 1— syschk.ps1

Để ngắn gọn, đây là 1 script Powershell với mục đích inject 1 đoạn code DLL vào process Explorer. Đoạn code DLL này tạo ra 3 thread trong DLLMain có tác vụ lần lượt như sau:

  • Keylog: gồm lưu lại phím và Clipboard
  • Screenshot: lưu lại ảnh màn hình
  • Hàm Sleep: Đưa 2 thread trên vào trạng thái ngủ
Hàm Main của mẫu Powershell
Decode, Replace 1 đoạn String để tạo ra 1 mẫu Powershell khác
Các biến thú vị được sử dụng ở hàm trên

Cụ thể khi mẫu mã độc tìm được process Explorer, nó sẽ tạo ra 1 mẫu Powershell khác ở thư mục %temp%tmp\XXXX.ps1 với XXXX là [0–9][A-F].

Sau đó mẫu XXXX.ps1 được thực thi bằng lệnh sau:

Start-Process powershell.exe -PassThru -WindowStyle Hidden -ArgumentList -ep bypass -file C:\Windows\Temp\tmp\XXXX.ps1

File được tạo ra bởi hàm DoProcess
Nội dung của file tmp9603.ps1

Nội dung của file tmp trên là sử dụng một kỹ thuật Invoke-ReflectivePEInjection để inject một file DLL từ bộ nhớ (RAM) vào 1 process đang chạy [2], dù hàm này bị thay đổi khá nhiều tuy nhiên chúng cùng chung 1 mục đích như đã nói.

FYI: Mẫu DLL chính là $PEBytes

Những câu lệnh chính của biến $NewBlock

Tiếp đó ta load file DLL vào IDA để phân tích kỹ hơn các tính năng theo dõi nạn nhân.

Phân tích mẫu DLL

Nhảy vào entry point, ta thấy có 3 thread riêng biệt

Câu lệnh thực thi chính của file DLL

Cần chú ý thư mục %temp%GoogleChrome, vì nơi đây sẽ chứa dữ liệu mà hàm Screenshot và Keylog ghi lại từ User.

Phân tích Thread 1 — Keylog

Ta tóm gọn T1 thực thi lần lượt như sau:

  • Lấy Title của “Cửa sổ” hiện tại mà User đang sử dụng
  • Hàm Keylog (trùng tên với thread)
  • Hàm lấy Clipboard
  • Lưu ra file
Nội dung lấy Title của “Cửa sổ” hiện tại
Nội dung hàm Keylog

FYI: Tại sao một mã độc APT tấn công vào ngân hàng VN lại không hỗ trợ log lại tiếng Việt hay Unicode. Dù log tiếng Việt nằm ở 1 phạm trù khác với các ngôn ngữ Unicode.

Ngoài ra project này [3] đề cập chi tiết cách log được kí tự Unicode.

Nội dung hàm lấy Clipboard

Sau đó 2 loại log phím trên lưu dữ liệu tại %temp%chromeupdater_pk.

Nội dung hàm lưu dữ liệu log User


Log sau khi chạy thread Keylog

Phân tích Thread 2 — Screenshot

Nội dung chính của thread Screenshot
Nội dung hàm takeScreenshot

FYI: Nội dung hàm takeScreenshot rất giống link này[4]

Phân tích Thread 3 — Hàm Sleep
Với Thread này, ta thấy nó đang cố gắng điều khiển 1 biến boolean shouldSleep dựa vào kiểm tra file C:\ProgramData\2.dat có tồn tại hay không.

Nội dung hàm điều khiển này

Biến shouldSleep cũngđược sử dụng ở 2 thread còn lại (hình dưới). Nói ngắn gọn, thread số 3 này đưa 2 thread còn lại vào trạng thái Sleep. Đây là 1 cách cơ bản để đưa mã độc vào trạng thái Inactive để bypass các AV và sandbox online đang scan các hành vi độc hại.

Biến shouldSleep được sử dụng trong 2 thread Keylog Screenshot

Kết thúc của thread này là hàm deleteAllInLogFolder và WINAPI RemoveDirectoryA.

Nhiệm vụ của 2 hàm này để xóa toàn bộ các thư mục lưu log của thread Keylog Screenshot, nói đơn giản là nó đang xóa các dấu vết của chính nó.

hàm deleteAllInLogFolder

Nhận xét

Mẫu Powershell và DLL đều đi vay mượn code, và không có gì đặc biệt về mặt kỹ thuật.

Ngoài ra ta chắc chắn mẫu này sẽ cần đi kèm với các mẫu mã độc khác để hoạt động được, ví dụ như gửi thông tin thu thập được đến C&C server hay ra lệnh Sleep (chỉnh sửa file 2.dat).

Phân tích mẫu 2 — hs.exe

Load mã độc vào IDA, mở tab Import ta có

Các hàm import nghi ngờ

Nhìn vào số lượng các hàm được sử dụng, ví dụ như hàm connect được gọi ở 4 nơi. Ta đoán chương trình này sử dụng Winsock (WS2_32.dll) để thiết lập kết nối (connect), gửi (send) và nhận (recv) lệnh và dữ liệu.

Bắt đầu với hàm WinMain. Ở đây ta tách được 2 tác vụ rõ ràng như:

  • Giải mã tham số đầu vào (ở đây là thông tin về C&C server)
  • Tạo 1 thread để nhận lệnh của C&C server

FYI: Tham số đầu vào của mã độc này được truyền vào bởi một mẫu khác (giải thích ở cuối bài) như sau

hs.exe [địa chỉ bị encrypt của victim]

Tổng thể nội dung của mã độc

Đầu tiên, ta để ý tham số đầu vào đi qua hàm decrypt. Sau đó, ta có địa chỉ C&C cần kết nối tới.

Nội dung hàm decrypt
Rút gọn hàm decrypt

Sau khi có địa chỉ C&C server, mẫu sẽ tạo 1 thread(main_thread) với mục đích nhận lệnh từ C&C server (xem hình tổng quan ở trên).

Mục đích chính của việc nhận lệnh này là forward các lệnh điều khiển từ C&C server đến máy đã bị lây nhiễm (địa chỉ của máy lây nhiễm lấy từ C&C server).

Sau đây ta chứng thực lại điều đó.

Nội dung main_thread

Trong main_thread này mã độc nhận một số lệnh tiếng Nga như dưới

Các câu lệnh mà mã độc chấp nhận từ C&C server

Vì ở đây có 1 trường hợp thú vị về việc người phát triển mã độc cố gắng đánh lừa người phân tích bằng cách tạo sự sai lệch giữa tên và mục đích thực sự của 1 đoạn nhận lệnh (poluchit), nên ta sẽ đi phân tích tên câu lệnh, tên dịch và lệnh thực thi thực sự của mã độc.

FYI: Tất cả các câu lệnh ở đây đều được mã hóa khi cả gửi và nhận. Tuy nhiên các câu lệnh dưới đây đều dưới dạng không mã hóa để trực quan hơn.

Bảng các lệnh thực thi của mã độc

Gửi lệnh “Nachalo”: Khởi tạo kết nối với C&C server. Cụ thể hình dưới là khởi tạo kết nối với C&C server 5 lần để nhận các lệnh tiếp theo (forwarder).

Khởi tạo kết nối với C&C server

Nhận lệnh “Ustanavlivat”: Nhận địa chỉ của máy cần forward lệnh tới

Hình dưới giải thích khá rõ cách hoạt động. Bắt đầu với nhận dữ liệu từ C&C server, tuy nhiên chỉ lấy ra 4 byte đầu tiên để decrypt ra được kích cỡ của dữ liệu còn lại (gọi là A). Sau đó so sánh kích cỡ lấy được với kích cỡ của A. Nếu sai thì ngừng Session hiện tại, nếu đúng thì tiếp tục .

Nhận địa chỉ của máy cần forward lệnh tới

Nhận lệnh “Poluchit”: Gửi địa chỉ của máy bị lây nhiễm mã độc lên C&C server.

Đây có thể coi là bước xác thực sau quá trình nhận được IP cần forward tới.

Điểm thú vị ở đây nghĩa của từ “Poluchit” là nhận, trong khi mục đích thực sự của nó lại là gửi địa chỉ máy bị lây nhiễm lên C&C server.

Đây là 1 trong những điểm nghi ngờ mấu chốt giúp chúng tôi tiếp tục phân tích và tìm thêm những mẫu khác có liên quan tới một nhóm chuyên tấn công APT vào các ngân hàng ĐNÁ, Lazarus.

FYI: Có 1 bài phân tích [5] đối với 1 mẫu khá tương tự mẫu này(sample #5), tuy nhiên đây có vẻ là 1 chiến dịch khác của nhóm Lazarus. Vì vậy, chúng tôi sẽ viết phần 2 về việc phân tích chiến dịch có sử dụng mẫu Forwarder này.

Gửi lại địa chỉ của máy bị lây nhiễm lên C&C server

Nhận lệnh “Pereslat”: Chuyển tiếp dữ liệu giữa C&C server và máy đã bị cài mã độc.

Tạo 1 thread forward_*
Nội dung của thread này
Cụ thể hàm redirect_traffic giữa C&C server và máy bị nhiễm mã độc

Khi nhận lệnh “derzhat” tiếp tục giữ kết nối. Còn lại, nếu nhận lệnh “vykhodit” thì sẽ thông báo cho C&C server và thực thi việc ngắt Session.

2 lệnh cuối “derzhat” và “vykhodit”

Dựa vào phân tích trên, ta thấy đây chỉ là 1 mẫu mã độc dùng để chuyển tiếp (forward) dữ liệu giữa C&C server và mã độc. Sự chuyển tiếp này rất có thể xảy ra trong mạng private của tổ chức bị tấn công, nghĩa là C&C server cũng nằm trong mạng của tổ chức, và cũng nhận lệnh thông qua mẫu Forwarder này.

Ngoài ra, mẫu thứ nhất (Powershell) đóng vai trò là 1 trong nhiều mẫu RAT được cài đặt vào Client.

Chưa dừng ở đó, dựa vào những điểm nghi ngờ nêu trong bài viết, chúng tôi cũng tìm được những thông tin, dẫn chứng về các chiến dịch tấn công vào ngân hàng Việt Nam có liên quan tới nhóm Lazarus (thông tin cụ thể ở phần 2).

Góc nhìn hiện tại

Hiện tại chúng tôi khá chắc chắn đây là mẫu mã độc được phân tán bởi nhóm Lazarus đến từ Triều Tiên. Với hồ sơ và các bài phân tích về nhóm này, đây là 1 nhóm được quản lý trực tiếp bởi Cục 121 của cơ quan tình báo Triều Tiên. Mục tiêu của nhóm này những năm gần đây là tấn công vào hệ thống tài chính của các nước ĐNÁ, đặc biệt là các ngân hàng. Đặc biệt là vụ suýt đánh cắp thành công 1 tỷ đô-la ở ngân hàng TW Bangladesh. Ngoài ra trong quá khứ nhóm này cũng đã từng thực hiện các cuộc tấn công APT vào ngân hàng Việt Nam.

Timeline các chiến dịch của nhóm Lazarus từ năm 2007 đến 2018 (tổng hợp bởi TrendMicro [6]), các ngân hàng Việt Nam cũng nằm trong danh sách đó.

FYI: Hiện tại C&C server vẫn đang hoạt động.

Tạm gác lại 2 con chuồn chuồn con, đáp án cho những câu hỏi chưa được giải đáp sẽ dần được hé lộ qua phần 2: Lộ diện.

Tham khảo

  1. http://ictnews.vn/cntt/bao-mat/canh-bao-khan-ma-doc-dang-tan-cong-co-chu-dich-vao-ngan-hang-va-ha-tang-quan-trong-quoc-gia-170123.ict
  2. https://clymb3r.wordpress.com/2013/04/06/reflective-dll-injection-with-powershell/
  3. https://github.com/SherifEldeeb/UniLogger/blob/master/README.md
  4. https://www.apriorit.com/dev-blog/193-multi-monitor-screenshot
  5. https://baesystemsai.blogspot.com/2017/02/lazarus-false-flag-malware.html
  6. https://www.trendmicro.com/vinfo/us/security/news/cybercrime-and-digital-threats/a-look-into-the-lazarus-groups-operations

@nl @floppydisk @bakhoang @tofu

Phân tích mã độc lừa đảo khách hàng Techcombank

Gần đây trong quá trình nghiệp vụ, chúng tôi nhận được 1 mẫu mã độc có đuôi SCR trong phần đính kèm ở mail của nạn nhân.

Nội dung email phishing
Mẫu gốc sau khi phân tích

Qua phân tích, chúng tôi phát hiện mục đích chính của mẫu gốc (Techcombank…) là unpack và thực thi một mã độc RAT khá nổi tên là NanoCore.

Mẫu RAT này có tính năng ghi lại phím bấm trên bàn phím (Keylog), thực thi lệnh (Remote command), sử dụng giao diện đồ họa của máy nạn nhân (Remote desktop), …

Nhìn hình trên, ta thấy mẫu gốc NanoCore được ẩn mình 2 lớp. Tiếp ta sẽ cùng bóc tách mẫu này để hiểu sâu và tìm cách phòng chống.

Phân tích mẫu Wrapper

Sử dụng bất kỳ phần mềm PE viewer nào, ta đều nhận được đây là 1 file .NET

Trong trường hợp này ta sử dụng Detect It Easy

Thông tin PE file của Wrapper 1

Với file .NET, ta sử dụng dnSpyđể view/debug code. Kết quả ta có là tên các namespace, class và method đều là tiếng ngoại quốc.

Tính năng “Go To EntryPoint” với mẫu trên

Chữ kiểu này làm giảm hiệu suất đọc hiểu của chúng ta. Ta sử dụng de4dot để deobfuscate (nếu có) mẫu này và có một kết quả dễ nhìn hơn.

Hàm Main sau khi kéo thả vào de4dot

Lướt qua nội dung code 1 lượt, ta thấy đây chính là 1 Wrapper với mục đích giải mã và thực thi một mẫu khác nằm trong Resource Directory.

Resource Directory của mẫu gốc

Hàm giải mã ở đây là thực hiện phép XOR giữa 1 đoạn Assembly và 1 array byte cùng được lưu trong Resource Directory.

Đoạn decrypt Assembly

Cách hoạt động của mẫu này có thể đơn giản hóa như sau, bạn quan sát hình 4 để có cái nhìn cụ thể.

  • Load 1 object từ Resource Directory
  • Decrypt object (smethod_0)
  • Tạo Assembly với object (smethod_3)
  • Load EntryPoint của Assembly (smethod_1)
  • Thực thi đoạn EntryPoint
Một quá trình hoạt động tương tự lấy từ trong sách

Hiểu được cách hoạt động, ta xử lý và có được 1 mẫu từ bộ nhớ. Tạm đặt tên là Stub.

Lưu mã độc trong Memory

Phân tích mẫu Wrapper số 2

Tương tự như trên, ta load mẫu Stub này dnSpy. Tuy nhiên kết quả nhận được là hàm Main không có nội dung, và các hàm khác còn bị lỗi không decompile được.

EntryPoint của Stub

Vì hàm Main không có nội dung, ta xem thử qua đoạn mã khởi tạo của class StubCode này. Một kĩ thuật thường thấy là giấu code trong static class constructor (.cctor) để giấu mã độc trước khi chạy EntryPoint thường thấy.

Thật vậy, có code ở đây. Dù tên của những hàm này đều bị obfuscate, dưới dạng Unicode không in được.

Hàm .cctor của Stub

Dựa trên watermark của một số công cụ obfuscate tự động, ta biết rằng mẫu này sử dụng ConfuserEx v1.0.0 [1]

Note: Bước deobfuscate quá dài và không liên quan tới chủ đề, nên ta sẽ bỏ qua và mặc định rằng mẫu này đã được deobfuscate.

Sau khi phân tích mẫu đã được deobfuscate, ta nhận định đây là 1 Wrapper cho mẫu RAT (mục đích chính của kẻ tấn công).

Mẫu Wrapper số 2 này có rất nhiều tính năng, điều thú vị nó có thể được điều chỉnh thông qua Config của Resource Directory (lần nữa). Vì quá nhiều tính năng, ta sẽ chỉ phân tích những tính năng ta cần quan tâm liên quan tới dấu vết của mã độc (IOC).

Vì là Config, nên có thể bật/ tắt. Mẫu Stub có những tính năng sau được sử dụng:

  • Decompress và thực thi mẫu RAT
  • Khởi động cùng hệ thống thông qua Registry hoặc TaskScheduler
  • Bypass AV (Avast)
  • Cố gắng tắt các chức năng liên quan tới Security của Windows như Cmd, Task Manager và UAC

Ngoài ra, những tính năng bị tắt:

  • Downloader
  • Anti-Dump
  • Anti-Sandbox
  • Ẩn file với attribute là Hidden và System
  • Và nhiều nữa
Resource Directory của Stub

Ta sẽ phân tích tính năng đầu tiên: giải nén và thực thi mẫu RAT.

Để ngắn gọn, mẫu này sử dụng MainFile từ Resource Directory.

Cụ thể, mẫu này cho ta 2 lựa chọn giải nén là sử dụng thuật toán LZMA hoặc thuật toán phần mềm GZIP sử dụng.

Tuy nhiên Config cho 2 tính năng này đều bị tắt, nên mẫu RAT chính là MainFile trong Resource.

Những lựa chọn để giải nén
Giải nén từ MainFile
MainFile trong Resource Directory

Tính năng thứ 2 là khả năng mã độc khởi chạy cùng hệ thống.

Đầu tiên, Stub tạo 1 bản sao có tên là <filename>. Sau đó, Stub dùng Reg để thực thi cmd với tham số là một file Update.txt, file này chứa nội dung thực thi mẫu mã độc <filename>.

Sử dụng Reg.exe thay vì Task Scheduler
Registry: Khởi chạy Update.txt mỗi lần User log on
Nội dung file Update.txt

Phân tích mẫu RAT

Sau khi chúng ta có được mẫu RAT, kéo thả vào de4dot phát hiện mẫu RAT bị obfuscate với Eazfuscator.NET v3.3

Mẫu RAT sau khi được deobfuscate

Dựa vào tên mẫu và chức năng các hàm, ta xác thực đây là mẫu NanoCore Client. Cách tốt nhất để thuyết trình về mã độc RAT chính là đứng trên góc nhìn của kẻ tấn công để xác thực lại các chức năng mà mã độc RAT cung cấp.

Điều này có nghĩa là chúng ta sẽ cài đặt NanoCore Server và kiểm tra những tính năng mà kẻ tấn công có thể thực hiện trên máy nạn nhân.

Có nhiều cách để thực hiện điều trên, cụ thể ở đây ta tạo 1 loopback adapter để lừa mã độc kết nối tới IP của ta. Sau đó đọc HDSD và “trải nghiệm” những tính năng của NanoCore Server.

FYI: NanoCore là sản phẩm được phát triển dưới công ty “Nimoru Software”. Trong NanoCore Server có mục feedback để bạn có thể nhận được sự trợ giúp từ nhà phát triển, và địa chỉ của feedback được gửi đi là “nimoru.com”. Và cha đẻ của mẫu mã độc này đã phải nhận án phạt 33 tháng, bạn có thể đọc thêm tại [2]

Tính năng “feedback”

Với 1 mẫu RAT khá đầy đủ chức năng như NanoCore, Remote Desktop là tính năng phổ thông.

Tính năng này giúp kẻ tấn công dễ dàng thực thi các hành vi xấu trên máy nạn nhân một cách dễ dàng hơn, nhanh hơn và không cần có chủ đích.

Tính năng Remote Desktop

Ngoài ra mẫu NanoCore còn có các tính năng sau :

  • Quản trị file từ xa
  • Thực thi lệnh từ xa (CMD)
  • Remote Desktop
  • Keylog
  • Ghi âm
  • Và nhiều nữa
Các tính năng của C&C server

Như nói ở trên, việc mã độc RAT này là phần mềm thương mại và UI của nó dễ dàng cho những kẻ tấn công phổ thông, nên những loại mã độc này thường được phát tán rất nhiều và không có chủ đích.

Điều xấu là chúng ta có khả năng cao sẽ trở thành nạn nhân, tuy nhiên điều tốt ở đây là những loại tấn công này thường sẽ đơn giản, việc sử dụng phần mềm diệt virus hay cẩn trọng với các email và đường link nguồn gốc không rõ ràng sẽ giúp bạn trên Internet hơn rất nhiều.

FYI: Ta có thể lấy được Config bao gồm địa chỉ C&C server của mã độc thông qua sử dụng script RatDecoders [3]

Kết quả sau khi chạy script RatDecoders

Ngoài ra hiện tại C&C server của mẫu RAT này vẫn còn hoạt động.

Liên lạc giữa NanoCore Client và Server

IP này đến từ Hàn Quốc. Ngoài ra, IP này cũng được cho rằng là NanoCore BotNet Server [4] và spam Email [5]. Cùng đó trên VirusTotal, ta thấy mẫu mã độc này đang trong giai đoạn phát tán.

Những upload liên quan tới IP này trên VirusTotal

Một lần nữa, các bạn nên cẩn trọng trong việc mở các email, các đường link có nguồn gốc không rõ ràng. Đồng thời, rà soát hệ thống với các dấu hiệu ở dưới (sẽ cập nhật thêm).




IP & Domain:


58B25347820B820F4FA46680CFF6BFC8 — TechcomBank_Dien_201883.scr

353F5EAACF70554CEB327D3578244177 — stub.exe

28C864D3F592B51AB646CEC8B1FF2CD7 — NanoCore Client.exe


  1. https://github.com/yck1509/ConfuserEx/blob/master/Confuser.Core/ConfuserEngine.cs#L303
  2. https://krebsonsecurity.com/wp-content/uploads/2017/04/W.D.Ark_._null_null_0.pdf
  3. https://github.com/kevthehermit/RATDecoders/blob/master/StandAlone/NanoCore.py
  4. https://www.spamhaus.org/sbl/query/SBL398403
  5. https://www.spamhaus.org/sbl/query/SBL320946

@nl @floppydisk @tofu @bakhoang

XSS inbox.google.com | Thanks to “XYX Check Mail” Chrome extension


02/01/2018 công ty bảo mật XYX ra mắt công cụkiểm tra email có bị rò rỉ thông tin. Tuy nhiên việc cài đặt Chrome Extension mở ra lỗ hổng cho phép attacker có thể tấn công XSS vào trang inbox.google.com. Từ đây attacker có thể chiếm đoạt tài khoản Gmail hay thực hiện các tình huống tấn công nguy hiểm khác.


Tình cờ ngày tối qua được một người bạn chia sẻ bài blog công cụ kiểm tra email trong danh sách rò rỉ thông tin của công ty bảo mật XYX, cũng tò mò nên có vọc vạch thử bên trong nó có cái gì hay ho không :D. Trong bài viết có 2 app là app Android và Chrome Extension. Trong bài viết này mình sẽ kể lại quá trình vọc vạch cái extension.

Chrome Extension

Cài đặt Extension vào dùng thử :D.

Xem qua demo thấy cũng khá thú vị đó chứ, view thử source xem sao.

… Nhận ra bất ngờ đầu tiên:

Extension này sử dụng API từ trang thứ 3 haveibeenpwned.com, trong khi trong bài viết không hề đề cập đến việc này.

Mình sẽ không comment gì về vấn đề này, tiếp tục xem code để tìm sạn nào 😀

Có thể nói nôm na cách hoạt động của extension này như sau:

  • Lấy danh sách toàn bộ Email trên trang inbox/gmail
  • Kiểm tra địa chỉ email có tồn tại trong localStorage của trình duyệt, nếu tồn tại, tạo 1 cái InfoDiv kèm ảnh như dưới, nếu di chuột vào ảnh, sẽ show infoDiv ra.
  • Nếu email chưa có trong localStorage, gửi request kèm địa chỉ email lên API https://haveibeenpwned.com/api/v2/breachedaccount/ và thực hiện như bước trên.

Có một vấn đề gặp phải ảnh hưởng đến độ tin cậy của kết quả cũng như ảnh hưởng việc tìm sạn đó là API Rate Limit của trang haveibeenpwned=))


Câu hỏi đặt ra: Liệu mình có thể kiểm soát cái $email trong innerHTML kia không để làm cái mà ai cũng biết là cái đấy không?

Rất thú vị là tham số email đó mình có thể kiểm soát được bằng alias address.

Email gửi đi dạng nforma <nforma***@gmail.com>

-> Mục tiêu: nforma <nforma***+[inject_here]@gmail.com>

Đây là kết quả sau nhiều lần thử nghiệm

<nforma***+<img src=x1 onerror=alert(document.domain)>[API][Email_X]@gmail.com>


<“nforma***+<img src=x1 onerror=alert(document.domain)>/../../../../../../../../api/v2/breachedaccount/[Email_X]”@gmail.com>

Final PoC

<nforma***+<img src=x1 onerror=alert(document.domain)>/../../../../../../../../api/v2/breachedaccount/phenslei”@gmail.com

Tại sao lại là phenslei?

Proof of Concept

#1. Thử nghiệm trên mail.google.com


Có thể thấy kết quả FAIL do Gmail đã cấu hình CSP (Content Security Policy).

#2. Thử nghiệm trên inbox.google.com


Chrome extension mang đến nhiều tiện lợi cho người dùng nhưng bên cạnh đó cũng mang đến nhiều rủi ro. Chrome extension có thể thực thi JavaScript, thay đổi DOM,… ở bất kỳ trang web nào bạn ghé thăm, hay tận dụng các Chrome API để làm nhiều việc theo trí tưởng tượng của developer. Tuy nhiên developer với mục đích tốt cần cẩn thận hơn khi “vô tình” mở ra lỗ hổng nghiêm trọng đến chính người dùng của mình.


Sáng 3/1: Phát hiện vulnerable

Trưa 3/1: Report XYX, XYX đã có biện pháp xử lý ngay

Chiều 3/1: Viết blog, chờ confirmed

Sáng 4/1: Publish

@bakhoang @floppydisk

USB bảo mật VS-KEY — Niềm tin về sự an toàn? Nói có vẻ đúng làm chưa đúng

Tuần trước tụi mình có cơ hội trên tay chiếc USB 2.0 8GB bảo mật có bằng sáng chế tại Việt Nam. Lúc đầu chỉ định xài thử, nhưng nghe quả giá hơn 800k thì vọc ngay xem nó có worth với cái giá trên hay không?

Golden USB 880k!

Giới thiệu

USB này được BQP cấp bằng sáng chế và vừa mới được thương mại hóa, trước đó đã sử dụng trong quân đội nhiều năm nên mình cũng không nghĩ kiếm chác được gì. Nhưng đời ai biết đâu chữ ngờ, một bạn trong nhóm mình (credit: floppydisk) nhanh chóng tìm ra được thiếu sót trầm trọng trong quá trình làm sản phẩm này…

Giờ mình xin chia sẻ với các bạn cách làm của tụi mình (zepto team). Title mặc dù là phân tích USB nhưng bài này sẽ đi sâu vào RE phần mềm, đặc biệt là .NET.

Tìm hiểu thêm về sản phẩm tại đây:

Vọc thử

Cắm USB vào lap, cảm nhận độ chất của cái giá trên.

Với tính năng AutoPlay enable, 1 phần mềm autorun yêu cầu quyền Administrator để hiện ra 1 Form Login sau.

Form Login của USB VS-KEY

Nhập password mặc định “admin”, ta có phần mềm quản lý USB. Phần mềm không có gì đặc biệt, ngoài trừ việc không cho user tạo file trực tiếp trên USB.

phần mềm quản lý USB VS-KEY

Sau khi sử dụng thử vài phút, cảm nhận đầu tiên là các thao tác copy/paste từ/sang USB chậm hơn bình thường. Nhưng lại không rõ cụ thể vì không có tốc độ copy/paste. Cái hay nhất của phần mềm là giao diện Tiếng Việt đem lại cảm giác thoải mái khi sử dụng 😅

Vọc thêm chút nữa

Quay về bước đầu cắm USB. Nhận thấy USB mount 1 CD-ROM drive, gồm các phần mềm

thư mục CD-ROM drive

Tụi mình đã thử dd toàn bộ physical disk ra, tuy nhiên ngoài CD-ROM drive thì không collect được partition nào khác.

File autorun.inf giúp user , vậy ta sẽ kiểm tra nội dung của file này


Vậy autorun.inf gọi tới file Run.exe. Mở CFF Explorer xác định file này dùng VB Compiler.

Kéo thả file Run.exe vào CFF Explorer

Ta sẽ dùng VB Decompiler để decompile file này.

case “win8” và “win10”

Kết quả Run.exe chạy các file .NET với OS tương ứng

  • OS 7 trở xuống sẽ sử dụng .NET 2 (Tool20.exe)
  • OS 8, 10 sẽ sử dụng .NET 4.5 (Tool45.exe)

Những file Tool*.exe tiếp tục gọi đến fileU_Tools.exe với quyền Administrator.

U_Tools process

Xác định đượcU_Tools.exe là phần mềm quản lý USB gốc, kéo thả nó vào CFF Explorer (cách làm như trên) thì xác định là .NET application.

Reverse Engineering .NET app

Có rất nhiều tool decompile hoặc debug .NET app, tuy nhiên ở đây mình sử dụng và recommend dnSpy. Vì nó open-source, rất nhiều tính năng và tác giả rất active trên Github.

Giao diện của dnSpy rất user-friendly. Sau khi kéo thả U_Tools.exe vào dnSpy, ở tab bên trái Assembly Explorer ta thấy 1 mục tên U_Tools. Tiếp theo Right-Click -> Go To Entry Point để nhảy vào hàm Main

Nhảy tới Entry Point, tuy nhiên bị obfuscate

Nhìn vào các namespace (màu vàng) ta đoán phần mềm này đã bị obfuscate. Tiếp đây mình cũng giới thiệu 1 công cụ deobfuscate và unpack (đồng tác giả với dnSpy) — de4dot. Cách làm đơn giản như sau:

> de4dot.exe -f <obfuscated> -o <deobfuscated>

Thêm argument -d ta xác định được U_Tools dùng Reactor Obfuscator.

Theo Entry Point của file được deobfuscate trong dnSpy một lần nữa (cách làm giống trên), ta tới được hàm Main(). Đọc code thì thấy tạo 1 authentication dialog tên frmLogin , nếu auth succeed thì sẽ chạy phần mềm quản lý USB LTOOLSnet .

hàm Main()

Dựa vào hàm constructor mặc định của Form/Window là InitializeCompnent, ta đặt được 2 breakpoint trong classfrmLoginfrmLogin_Load khi load form và 1 EventHandler tên cmdLogin_Click khi submit password.

Dừng việc debug tại đây 1 lát, giờ mình sẽ nói qua về phân tích tĩnh file này..

Có 3 class cần chú ý RAW.DISK, X.{frmLogin, LTOOLSnet}.

Đại khái chức năng chính của 3 class này:

  • RAW.DISK: tương tác với PHYSICALDRIVE(trường hợp này là USB), nhiệm vụ chính là read/write các sector trên USB.
  • frmLogin: class tạo ra Form Login (hình Form Login trên)
  • LTOOLSnet: phần mềm quản lý USB (hình Phần Mềm Quản Lý trên), cóp nhặt phần mềm từ các nơi..

Ngoài lề: rất nhiều hàm trong các class dưới đây không được sử dụng. Như class DISK.RAW là 1 file .DLL được share trên 1 forum, và rất nhiều tính năng “ẩn” vô hại nữa 🙂 Quan trọng điều này làm phần mềm bloat một cách không cần thiết…

các class trong 2 namespace này

Tiếp tục debug..

Đặt được 2 breakpoint này, ta nhập đúng pass và trace tới khi fLogin(object init từ frmLogin) Dispose (tạm hiểu là trace đến khi Form Login biến mất). Ta có thể tóm tắt cách hoạt động của Form Login như sau:

Giờ đi vào chi tiết xíu…

Hàm smethod2 ở bước 3: compute hash SHA512 với tham số là pass từ input— strPassword. Salt ở đây là MD5.CODE_STRING.

Compute hash

FYI: Salt ở đây là hardcoded string “Ivan Medvedev”. Không riêng mình mà cũng có người có câu hỏi :))

Đoạn xác thực password dựa vào compare hash SHA512 — @string với key xác thực — txtKey.text

Get key xác thực từ 1 đoạn trong sector 5
Compare hash và key xác thực

Quan trọng nhất, là USB không hề encrypt dữ liệu. Việc xác thực password này chỉ có tác dụng với cái form 😨

Đơn giản kiểm tra thiếu sót này bằng cách tạo 1 file trong USB

file trong USB

Sau đó copy sang USB (thậm chí đổi cả pass nữa), dùng hex editor với USB

content file trong USB không bị encrypt

Dễ dàng thấy file trong USB không hề được encrypt. Chứng tỏ USB không hề encrypt dữ liệu. Myth confirmed!

Mã hóa ngoại truyện

Mình có nói qua là phần mềm này được cóp nhặt từ rất nhiều nơi, vì vậy có 1 vài feature “ẩn” khá là hài hước.

USB mặc định không encrypt dữ liệu. Tuy nhiên việc mã hóa là một tính năng “ẩn” của 1 “USB an toàn bảo mật” :))

Tính năng này bị ẩn đi (Visible = False)

Sau khi patch lại ta có menu như sau

patch lại

Khi chế độ trên bật lên, phần mềm sẽ sử dụng Rijndael AES để encrypt file với biến bientoancuc.FORMAT_KEY và salt (vẫn là magic string khi hash SHA512).

hàm EncryptFile
hàm EncryptFile sử dụng Rijndael

Điều thú vị là FormatKey và mã hash SHA512 đều có thể dễ dàng lấy từ USB như nhau.

get FormatKey từ sector 12

Ngoài ra đoạn kiểm tra định dạng của USB có thể nói vô cùng nhảm, ở các hàm sau:

  • frmLogin.method_5(không resolve được tên) — compare magic string với sector 8
  • frmLogin.ReadCountPassFalse() — compare magic string với sector 16 , đồng thời lưu số lần nhập sai password vào trong sector 16 + 33 bytes
  • DISK.CreateStream() — compare 2 byte 450466sector 0 với magic value. Đặc biệt hàm này là cách duy nhất mà tác giả gọi tới hàm CreateFile()…
  • Một vài hàm nữa…


Tóm lại mình có 2 cách để bypass

Cách 3 là extract hash SHA512 từ USB rồi tìm pass tương ứng với mã hash, nhưng không khả thi với password phức tạp.

Clone USB

Trong quá trình làm, nhóm thường hay đùa về giá cả của chiếc USB này. Giờ mình để lại script clone chiếc USB này dựa vào hàm format của chính nó, đầu tiên là giúp các bạn có thể kiểm chứng lại bài viết này mà không cần mua USB (tất nhiên firmware hay cách tạo CD-ROM thì chắc để lần sau zz)


Script trên có gọi tới 3 file .bin, những file này đều nằm trong CD-ROM.

Kết luận và Gợi ý

Kiểm lại những gì tụi mình vọc:

  • Tìm và bypass phần xác thực USB
  • Clone USB

Tới đây, chiếc USB này có thể thực sự gọi là USB bảo mật hay không là tùy cách nghĩ của bạn!

Ngoài ra, mình có 1 vài personal recommendation cho những bạn nào muốn thử nghiệm làm USB an toàn hơn:

  • Có option FDE (Full Disk Encrytion) cho user, nên đặt làm mặc định. Bạn có thể sử dụng AES mode XTS vì Bitlocker Windows 10 sử dụng cái này làm mặc định 😳
  • Hardware Encryption thay vì Software Encryption.

Software Encryption đơn giản là dựa vào phần mềm để encrypt/decrypt dữ liệu. Tuy nhiên phần mềm chậm, yêu cầu cài đặt driver/update và dễ dàng bị crack/detect cho các cuộc tấn công trong tương lai.

  • Áp dụng KEK (Key Encryption Key) cho DEK (Data Encryption Key) nếu sử dụng FDE.

DEK là key dùng để encrypt dữ liệu.

KEK được tạo nên bởi nhiều yếu tố, dùng để encrypt DEK.

FDE software sẽ khởi tạo một giá trị random cho DEK. KEK cũng được khởi tạo bởi nhiều yếu tố và password của user cũng là 1 trong. Một lợi ích của việc sử dụng KEK/DEK là khi user đổi password thì sẽ chỉ re-encrypt lại KEK, thay vì toàn bộ volume.

USB protection profile

Cảm ơn các bạn đã đọc tới đây!

By nl+tofu

Về chất lượng bài viết hay bạn có thắc mắc, đừng ngại comment phía dưới. Mình rất sẵn lòng trả lời các bạn.