📜 ⬆️ ⬇️

Remote code execution in InterSystems Caché (RCE)

Van Gogh Fishing Boats on the Beach

Introduction


In the event that you manage more than one Caché server, you may have the task of executing arbitrary code from one Caché server to another. In addition, you may need to execute arbitrary code on a remote Caché server, for example, for the needs of a sysadmin ... To solve these problems, the RCE utility was developed.

What in general there are variants of the decision of similar tasks, and that offers RCE (Remote Code Execution) - under a cat.

What is already there?


»Local OS commands


Let's start with a simple one — executing local commands from the Caché operating system. The functions of $ zf are used for this:


You can also use the methods of the class % Net.Remote.Utility , which provide convenient wrappers for standard functions, their advantage is to get the output of the called processes in a more convenient form:


An alternative option is to use a terminal command! (or $, they are identical), which opens the operating system shell inside the Caché terminal. There are two modes of operation:


»Remote COS code execution


It is possible using the class % Net.RemoteConnection , where the following functionality is available:


Sample code to demonstrate these features.
Set rc = ## class ( % Net.RemoteConnection ). % New ()
Set Status = rc . Connect ( "127.0.0.1" , "SAMPLES" , 1972, "_system" , "SYS" ) break : ' Status
Set Status = rc . OpenObjectId ( "Sample.Person" , 1 ,. per ) break : ' Status
Set Status = rc . GetProperty ( per , "Name" ,. Value ) break : ' Status
Write value
Set Status = rc . ResetArguments () break : ' Status
Set Status = rc . SetProperty ( per , "Name" , "Jones, Tom" _ $ r (100), 4) break : ' Status
Set Status = rc . ResetArguments () break : ' Status
Set Status = rc . GetProperty ( per , "Name" ,. Value ) break : ' Status
Write value
Set Status = rc . ResetArguments () break : ' Status
Set Status = rc . AddArgument (150,0) break : ' Status // Addition 150 + 10
Set Status = rc . AddArgument (10,0) break : ' Status // Addition 150 + 10
Set Status = rc . InvokeInstanceMethod ( per , "Addition" ,. AdditionValue , 1) break : ' Status
Write AdditionValue
Set Status = rc . ResetArguments () break : ' Status
Set Status = rc . InstantiateQuery (. Rs , "Sample.Person" , "ByName" )

In this code happens:


To run% Net.RemoteConnection on the server side, sending requests, you need to configure C ++ binding .

Separately, mention should be made of the ECP technology, which was written on Habré, and which allows you to call remote JOB processes from the application server on the database server.

As a result, combining the two approaches proposed above, in principle, it is possible to achieve the goal set at the beginning of this article, however, I wanted to achieve a simple process of creating a new executable script by the user, which is difficult when using existing approaches.

Rce


Thus, the following objectives were set for the project:


The class hierarchy of the project is as follows:

RCE

Hierarchy Machine - OS - Instance is used to store information needed to access remote servers.
To store the commands, use the RCE.Script class, which contains a sequential list of objects of the RCE.Command class, which can be either OS commands or COS code.

Example commands:
Set ommand1 = ## class ( RCE.Command ). % New ( "cd 1" , 0)
Set ommand2 = ## class ( RCE.Command ). % New ( "zn" "% SYS" "" , 1)

The first argument is the command text, the second is the execution level: 0 — OS, 1 — Cache.

An example of creating a new script:
Set Script = ## class ( RCE.Script ). % New ()
Do Script . Insert ( ## class ( RCE.Command ). % New ( "touch 123" , 0))
Do Script . Insert ( ## class ( RCE.Command ). % New ( "set ^ test = 1" , 1))
Do Script . Insert ( ## class ( RCE.Command ). % New ( "set ^ test (1) = 2" , 1))
Do Script . Insert ( ## class ( RCE.Command ). % New ( "touch 1234" , 0))
Do Script . % Save ()

Here, at the OS level, the 1st and 4th commands will be executed, and the 2nd and 3rd will be executed in Caché, and the process of switching the execution level is completely transparent to the user.

»Execution Mechanisms


The following execution paths are currently supported:
Server
Customer
Linux
Linux, Windows (requires installing an SSH server on the client)
Windows
Linux, Windows (requires installing an SSH server on the client or psexec on the server)
In the event that there is ssh support on the client, the server generates an ssh command and executes it on the client using the standard class % Net.SSH.Session .

In the case, if both the server and the client are running the Windows OS, a bat file is generated, which is then sent to the client and executed using the psexec utility.

»Add server


Download classes from the repository to any area. In case you have a Windows server and you want to manage other Windows servers, set the global ^ settings ("exec") to the path to the psexec utility. At this setting is complete!

»Adding a customer


It consists in saving all data required for authentication.

Sample code creating a new hierarchy Machine - OS - Instance
Set Machine = ## class ( RCE.Machine ). % New ()
Set Machine . IP = "IP or Host"

Set OS = ## class ( RCE.OS ). % New ( "OS" ) // Linux or Windows
Set OS . Username = "OS Username"
Set OS . Password = "User Password"
Set Instance = ## class ( RCE.Instance ). % New ()
Set Instance . Name = "Caché Instance Name"
Set Instance . User = "Caché username" // Not necessary if minimum security settings are set
Set Instance . Pass = "Caché user password" // Not necessary if minimum security settings are set
Set Instance . Dir = "Path to cterm instance" // Only necessary if cterm is not in PATH (for windows clients)

Set Instance . OS = OS
Set OS . Machine = Machine
Write $ System .Status . GetErrorText ( Machine . % Save ())

»Script execution


Continuing with the previous examples, the script execution is very simple - using the ExecuteScript method of the RCE.Instance class, to which the script object and the execution area are passed (by default -% SYS):
Set Status = Instance . ExecuteScript ( Script , "USER" )

findings


RCE provides a convenient mechanism for remote code execution from InterSystems Caché. Since the scripts are stored, you need to write the script only once, then it can be executed anytime and on any number of clients.

Links


GitHub RCE repository
RCE project class archive

Source: https://habr.com/ru/post/268573/


All Articles