
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:
- $ ZF (-1) - calls the program or command of the operating system. The call is made in the new process, the parent process is waiting for the completion of the called process. After executing, $ ZF (-1) returns the status of the process execution: 0 if successful, 1 if an error occurred, and -1 if it failed to create a process.
')
It looks like this: set status = $ ZF (-1, "mkdir" "test folder" "" )
- $ ZF (-2) - is similar, with the difference that the main process does not wait for the results of the created process. As a result, 0 is returned if the creation of the process was successful and -1 if the creation of the process failed.
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:
- RunCommandViaCPIPE - executes the command via the Command Pipe . Returns the created device and process output string. Directly execution of commands on the server using Command Pipe is described on Habré in this article .
- RunCommandViaZF - executes the command in $ ZF (-1). Writes the output of the process to a file, and also returns it as a string.
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:
- Opening and modifying stored objects;
- Execution of class and object methods;
- Execution of requests.
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:
- Connect to the Caché server;
- Opening an instance of the class Sample.Person with Id 1;
- Getting property value;
- Change property value;
- Setting arguments to a method;
- Call instance method;
- Run the Sample.Person: ByName query .
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:
- Running scripts on remote servers from Caché;
- No need to configure a remote server (hereinafter - the client);
- Minimum configuration of the local server (hereinafter - the server);
- Transparent to the user switching between the commands of the operating system and COS;
- Support for Windows and Linux as a client.
The class hierarchy of the project is as follows:
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 - InstanceSet 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 repositoryRCE project class archive