010Editor is a hex-editor that includes a sophisticated template and scripting engine. One of the major advantages of 010Editor is that it contains a large repository of templates that can be downloaded and used to parse new file formats. These templates are used to present an elaborate definition of a file and its structure in an easily digestable form (colors and windows).
Just as have many other people, I’ve been using 010Editor for a while. This software is a leader in its specific market, and it’s hard to find a good alternative. I was curious on how the 010Editor scripting engine was implemented, and whether the implementation was secure, so I (naturally) decided to audit the security of the scripting engine.
The scripting engine can be used for running scripts or templates. Both of which run the same C-like code, but templates have additional restrictions (some functions require explicit user permission to execute). The code is compiled and executed by the scripting engine, and is manifested as a template file (.bt) or as a script file (.1sc). New templates can be uploaded to a central repository, from which other users can download and make use of new templates. At the time of writing, this repository contains a large number of templates that can be used to parse many different types of file formats. When a new file is opened, 010 checks if a template that can parse the file is found in the repository, if a template is found, 010Editor prompts the user with an option to download the template. Templates execute when a file associated with the template is loaded by the editor or when explicitly ran by the user.
I started out by reviewing the documentation in order to gain an understanding of what kind of functionality the scripting engine provides the developer, and what kind of security guarantees the engine was supposed to provide. After looking at the list of functions provided by the engine, it was clear that the developers have implemented a large number of C-like functions. These functions are separated into 5 classes: Interface Functions, I/O functions, String functions, Math functions and Tool functions.
010Editor also allows the use of external(DLL) functions, but the documentation clearly states that using these functions in templates requires explicit permission by the user. The usage of these functions in scripts is permitted. This situation made it clear that exploitation of a script file (.1sc) is not interesting, as scripts allow for the execution of arbitrary DLLs - and are expected to run at the discretion of the user (should be considered insecure).
Out of the five different classes of functions, one stood out - String functions. These functions deal with string and memory operations (strcpy, memcpy, memmove, printf etc…) - this kind of logic is known to be very bug-prone and difficult to implement securely. At that point, I figured that there’s a fairly good chance that bugs would exist in the implementation of some of these functions, as they deal with the copying and moving of binary data (of which a string is made). As I am more interested in exploitable bugs (bugs that could result in code execution), the kind of memory corruptions that could occur from faulty implementation of these functions seemed like a good target (likely to overwrite memory).
After reviewing a bunch of different functions, and finding some bugs that I deemed unexploitable, I came across the following (truncated and commented) code.
/*
* Internal implementation of function Memcpy in the template engine
*/
Memcpy(arg1, arg2, n, dest_offset, src_offset)
...
mov edi, [rdx+8] // dest_offset
mov rdx, [rax+20h]
mov rax, [rax+10h]
mov ecx, [r9+4]
mov esi, [rdx+8] // src_offset
mov edx, [r8+4]
mov eax, [rax+8]
sub ecx, edi // dest_len -= dest_offset 1) no check on dest_offset for negative value
sub edx, esi // src_len -= src_offset 2) no check on src_offset for negative value
cmp ecx, edx // if (dest_len < src_len)
cmovle edx, ecx // copy_length = dest_len
cmp edx, eax
cmovg edx, eax
test edx, edx
jle short loc_XXX
movsxd rdi, edi
movsxd rsi, esi
add rdi, [r9+8] // dest += dest_offset 3) passing dest += dest_offset could lead to underflow
add rsi, [r8+8] // src += src_offset 4) passing src += src_offset could lead to underflow
movsxd rdx, edx // n
call _memcpy ; Call Procedure
...
As the comments specify, this is the internal implementation of the Memcpy function. This function has the following signature: void Memcpy( uchar dest[], const uchar src[], int n, int destOffset=0, int srcOffset=0 )
The bug here is that the code does not validate destOffset and srcOffset properly. These variables can be assigned a negative value, which can result in an underflow and corruption of the heap.
At this point I had a memory corruption vulnerability, but I still needed something to overwrite. Surprisingly, the binary was not compiled with aslr (linux version) - which meant that if I could get a primitive to write an absolute address, I could easily overwrite the GOT and redirect execution.
As I already reversed the code, I knew that the string variable was pointed to by a structure that represented the scripting engine’s “string object”. I realized that I could set the heap in such a way that this structure will be placed at a known location behind the array that I can underflow - this way I could overwrite this pointer to an absolute address of my choosing. After that pointer is overwritten, the “string object” would point to wherever I want, and I could use it to read/write arbitrary memory.
To summarize, the exploitation follows these steps:
As 010Editor is a fairly popular product, these kinds of bugs can be used to attack a large number of people. If a malicious template is uploaded to the central repository it could be used as an attack vector against anyone who downloads the template. It’s also possible to exploit a non-malicious template that uses a vulnerable function by sending a malicious file to a victim machine and inducing the victim to open that file with 010Editor (a less promising attack vector).
During the audit of 010 Editor version 9.0.1, numerous exploitable (and non exploitable) bugs were found. After gathering up the findings and completing the POC, I contacted Sweetscape and presented them with the findings. They quickly responded and cooperatively worked on fixing all the issues found. The bugs were fixed in version 9.0.2.
the following CVE IDs were assigned for the vulnerabilities:
https://github.com/ereisr00/bagofbugz/tree/master/010Editor/memcpy_rce.bt: CVE-2019-12551
https://github.com/ereisr00/bagofbugz/tree/master/010Editor/null_deref.bt: CVE-2019-12552
https://github.com/ereisr00/bagofbugz/tree/master/010Editor/strcat_heap_overflow.bt: CVE-2019-12553
https://github.com/ereisr00/bagofbugz/tree/master/010Editor/SubStr.bt: CVE-2019-12555
https://github.com/ereisr00/bagofbugz/tree/master/010Editor/WSubStr.bt: CVE-2019-12554