In Node, I'm using a module (GM) and noticed that it uses spawn from the child_process module to pass arguments to GraphicMagick's convert executable.
I'm passing user-submitted information to GM. Is there a security concern that the user could do some sort of injection attack using a pipe (or other command line trickery)? Or does spawn protect against that? If not, is there a best practice for escaping user submitted values in this case?
We recently published a blog post on avoiding command injection vulnerabilities in node.js. It explains a bit about how spawn prevents this.
If gm was using child_process.exec there would be a greater chance of injection. This is because child_process.exec executes the commands under a subshell and not directly, letting shell meta characters like backticks, $(), ;, &&, || etc to be used nefariously.
The resulting system call looks like this with .exec() for a simple ls -l that might take user input.
[pid 25170] execve("/bin/sh", ["/bin/sh", "-c", "ls -l user input"],
[/* 16 vars */]
Since gm uses spawn the resulting system call would look something like this.
[pid 25565] execve("/bin/ls", ["/bin/ls", "-l", "."], [/* 16 vars */]
As gm would be the first argument to execve. This means that a user cannot run subcommands in the shell using pipes and other command line trickery, because in our example /bin/ls has no idea what to do with backticks or pipes or ;. It’s /bin/bash that is going to be interpreting those commands. It’s similar to using parametrized vs string-based SQL queries, if you are familiar with that.
This does however come with a caveat: using spawn is not always a safe thing. User provided arguments could still potentially have a bad outcome, maybe not command injection but something else. Check with the behavior of gm and the arguments that you are pass in user provided input into and think about how the user might be able to abuse that argument.
So, here’s the generic collective guidance for running system commands from node.js:
Avoid using child_process.exec, and never use it if the command contains any input that changes based on user input.
Try to avoid letting users pass in options to commands if possible. Typically values are okay when using spawn or execfile, but selecting options via a user controlled string is a bad idea.
If you must allow for user controlled options, look at the options for the command extensively, determine which options are safe, and whitelist only those options.
Related
Does anyone know how to call a *CMD program in free RPG using a prototype?
In my case the command has 10 parameters and I want to call it with just 4.
Calling it with 10/10 parameter works. But how do I do it with fewer parameters?
Commands (*CMD) are executed by the command language processor, not called.
Assuming a user written command, thus you have the source for the program envoked by the command...I'd recommend creating a prototype and calling the program that processes the command directly...
DSPCMD will tell you what that program is...
If an IBM or third party command, you'll need to call the command language processor and pass it the command you want to execute.
IBM provides a few APIs for the command language processor..
Execute Command (QCMDEXC)
Process Commands (QCAPCMD)
Also, you can use the C-runtime API
system() — Execute a Command
Here's a nice article about using the most powerful (and complex) option, QCAPCMD...with links to articles about QCMDEXC and system().
QCAPCMD another alternative to QCMDEXC
Declare this in your D Specific:
DCL-PR GoCmd INT(10) EXTPROC('system');
CmdString POINTER VALUE OPTIONS(*STRING);
END-PR;
then you can call AS400 command... example:
CmdString = 'CLRPFM FILE(WORKFILE)' ;
ReturnCode = Gocmd(CmdString) ;
If you can use sqlrpgle then its very easy, you can do as if you are on command line, just use the params which you need only:
exec sql call qsys2.qcmdexc('DSPJOBLOG OUTPUT(*PRINT)');
see also here - obviously this works for a long time:
http://www.midrangenews.com/view?id=2395
I need to run a service program, written in FO for abas-ERP continuous.
I heard about some already existing scripts for calling service programs from the shell. If that is possible I could simply use a cronjob for starting this script.
But I don't know exactly where to find a template for these shell scripts, which conditions have to be complied and if there are any restrictions.
For Example: Is it possible to call several FO-programs successively (this might be important relating to blocking licences)?
You can use edpinfosys.sh and execute infosystem TEXTZEIGEN per cronjob.
You could also use batchlg.sh
batchlg.sh 'FOP-Name' [ -PASSARGS ] [Parameter ...]
Not sure if this is the right place to ask.
Say I write a shell that takes stdin input, filters this input so let's say only certain commands like
ls (list contents of binary directory and subdirectory)
update (git clone)
build (go build)
test (go test)
start (systemctl start this.service only)
stop (systemctl stop this.service only)
running (is the binary being executed and with how many GOMAXPROCS?)
usage (memory, cpu usage)
gensvc (generate .service file)
exit (leave shell/logout)
work, you guessed it, I'm trying to give a user only very limited maintenance access over ssh.
Say I'm careful with \0 (I'd write it in Go anyway using bufio.Scanner)
Is there any way to stop the running shell and execute /bin/sh or similar or any way to get around this shell?
The idea is a user should push their stuff via git to a bare repo, this repo is cloned to the filesystem to a certain directory, then go build is called and the binary is ran with a systemd .service file that is generated previously.
Thinking logically, if the user is only able to write certain strings that are accepted, no there is no way. But maybe you know of one, some ctrl+z witchcraft ;) or whatever.
The only attack surface is the input string or rather bytes. Of course the user could git push a program that builds its own shell or runs certain commands, but that's out of scope (I would remove capabilities with systemd and restrict device access and forbid anything but the connection to the database server, private tmp and all, namespace and subnamespace it TODO)
The only problem I see is git pushing but I'm sure I could work around that in a git only mode argv and adding it to ~/.ssh/authorized_keys. something like lish gitmode and execute stdin commands if they start with git or something like it.
Example:
https://gist.github.com/dalu/ce2ef43a2ef5c390a819
If you're only allowed certain commands, your "shell" will read the command, parse it and then execute it then you should be fine, unless I misunderstood it.
Go "memory" can't be executed, not without you doing some nasty hacks with assembly anyway, so you don't have to worry about shell injection.
Something along these lines should be safe:
func getAction() (name string, args []string) {
// read stdin to get the command of the user
}
func doAction() {
for {
action, args := getAction()
switch action {
case "update": //let's assume the full command is: update https://repo/path.git
if len(args) != 1 {
//error
}
out, err := exec.Command("/usr/bin/git", "clone", "--recursive", args[0]).CombinedOutput()
// do stuff with out and err
}
}
}
If you are implementing the shell yourself and directly executing the commands via exec() or implementing them internally, then it is certainly possible to produce a secure restricted shell. If you are just superficially checking a command line before passing it on to a real shell then there will probably be edge cases you might not expect.
With that said, I'd be a bit concerned about the test command you've listed. Is it intended to run the test suite of a Go package the user uploads? If so, I wouldn't even try to exploit the restricted shell if I was an attacker: I'd simply upload a package with tests that perform the actions I want. The same could be said for build/start.
Have it reviewed by a pentesting team.
People can be very creative when breaking out a sandbox of any type. Only if you never accept the user's input you can consider yourself rather safe on premises (but here any command is an input) - paper security assumptions are considered a weak to assess the software. They are similar to 'no-bug' assumptions for an algorithm on paper: as soon as you implement it, 99% of time a bug raises
I'm trying to add users to the server running my node application. Right now I am using:
exec("useradd -mp {password-hash}")
with a hash that gets created by
exec("mkpasswd -m des {password}")
This leaves the password visible in the process list, and that should be avoided at all costs.
That's why I am wondering if there is a module on npm or an easier way to add a linux user to the system programmatically (this is necessary because the app I am building creates a user account on the system when a user registers on the web). Can this be done without evoking system commands like I am currently doing? I have found neither npm module nor any information of using node to interact with ubuntu/unix user management.
Solution
Using Mustafa's hints from the top answer, I implemented a version of the mkpasswd command using spawn. In CoffeeScript, it would look like this:
{spawn} = require 'child_process'
child = spawn 'mkpasswd', ['-m','des','--stdin']
child.stdout.on 'data', (data)->
console.log 'password hash arrived: ', data.toString()
child.stdin.write 'password'
Make sure you add the proper error handling event handlers to child.stderr and child.stdout while debugging your code.
You either use those commands or manually add your user to /etc/passwd and its password to /etc/shadow.
Format of a /etc/passwd entry: username:passwd:UID:GID:full_name:directory:shell
Passwd should be x if you want it o make it secure, so it will read from shadow.
Format of a /etc/shadow entry: username:passwd:last:may:must:warn:expire:disable:reserved
If you add them correctly, there will be no problem.
But why would you bother with it manually while you have the required tool? If you are concerned about the privacy, you can issue mkpasswd -m des --stdin which will read the password from standart input. Instead of exec, when you use spawn, you can also control the stdin and stdout of the processes. stdin is just a writable stream, you can write to it and read the output from stdout. Or you can find a npm module that generates the hash with given algorithms, DES, AES etc.
I'm trying to execute a child_process synchronously in node.js (Yes, I know this is bad, I have a good reason) and retrieve any output on stdout, but I can't quite figure out how...
I found this SO post: node.js execute system command synchronously that describes how to use a library (node-ffi) to execute the command, and this works great, but the only thing I'm able to get is the process exit code. Any data the command executes is sent directly to stdout -- how do I capture this?
> run('whoami')
username
0
in otherwords, username is echo'd to stdout, the result of run is 0.
I'd much rather figure out how to read stdout
So I have a solution working, but don't exactly like it... Just posting here for reference:
I'm using the node-ffi library referenced in the other SO post. I have a function that:
takes in a given command
appends >> run-sync-output
executes it
reads run-sync-output synchronously and stores the result
deletes this tmp file
returns result
There's an obvious issue where if the user doesn't have write access to the current directory, it will fail. Plus, it's just wasted effort. :-/
I have built a node.js module that solves this exact problem. Check it out :)
exec-plan
Update
The above module solves your original problem, because it allows for the synchronous chaining of child processes. Each link in the chain gets the stdout from the previous process in the chain.
I had a similar problem and I ended up writing a node extension for this. You can check out the git repository. It's open source and free and all that good stuff !
https://github.com/aponxi/npm-execxi
ExecXI is a node extension written in C++ to execute shell commands
one by one, outputting the command's output to the console in
real-time. Optional chained, and unchained ways are present; meaning
that you can choose to stop the script after a command fails
(chained), or you can continue as if nothing has happened !
Usage instructions are in the ReadMe file. Feel free to make pull requests or submit issues!
However it doesn't return the stdout yet... Well, I just released it today. Maybe we can build on it.
Anyway, I thought it was worth to mention it. I also posted this to a similar question: node.js execute system command synchronously
Since Node version v0.11.12, there is a child_process.execSync function for this.
Other than writing code a little diferent, there's actually no reason to do anything synched.
What don't you like about this? (docs)
var exec = require('child_process').exec;
exec('whoami', function (error, username) {
console.log('stdout: %s', username);
continueWithYourCode();
});