0

In Node.js, is there any value to validate if a text message is a linux shell command or a normal message with/without actually executing the text? Please give any suggestions.

  • 2
    are you running on linux or is it multiplatform? – Hagai Wild Mar 19 '19 at 14:44
  • On windows , in nodejs environment, i need to confirm if a text is a linux command or not...@HagaiWild – Simranjit Kaur Mar 19 '19 at 14:48
  • 1
    you'll need to save a list of linux commands https://ss64.com/bash/. then check if the first word is in that list, all that comes later is just arguments for the command (which may be valid and also may not). – Hagai Wild Mar 19 '19 at 14:52
  • This seems a long approach to create a list and save all the commands in a data structure. Is there any short approach to go about it ? – Simranjit Kaur Mar 19 '19 at 14:54
  • that's actually the easiest one. – Hagai Wild Mar 19 '19 at 14:57
  • What are you planning to do with this string? The most complete approach, I think, would be to extract the first word on the string and then ask the shell if it is a command (using the shell's builtin `type` command) – glenn jackman Mar 19 '19 at 17:03
  • Possible duplicate of [Linux command to list all available commands and aliases](https://stackoverflow.com/q/948008/608639), [How do I get a list of all available shell commands](https://stackoverflow.com/q/9960465/608639), [How to sanitize an input command in shell script by blacklisting/whitelisting?](https://stackoverflow.com/q/30624461/608639), etc. – jww Mar 20 '19 at 02:02
  • If "shell command" is something that can be executed by a posix shell, then testing the first word is not enough. – jhnc Mar 20 '19 at 03:50
  • @glennjackman I was to test the message is a shell command or not on node.js platform and i cant find any method in npm which can tell this. – Simranjit Kaur Mar 20 '19 at 12:52
  • You'll definitely have to ask the shell. You can't just hardcode a list of words. I can create a script called `~/bin/foobar` (~/bin is in my $PATH) and now `foobar` is a "shell command". You'll also need to check every time. I can start your application, and then create foobar, and then input "foobar some args" to your app -- If you just query the list once at startup, I've defeated you. – glenn jackman Mar 20 '19 at 13:09
  • Are these commands or text messages: `GET IT`; `who am i?` – jhnc Mar 20 '19 at 14:06
  • these are text messages received from a webpage and sent to a nodejs server for validation. – Simranjit Kaur Mar 20 '19 at 14:29

3 Answers3

1

The shell's type command will detect builtin commands, aliases, function, external commands, etc.

child_process = require('child_process')

['lua','foobar'].forEach((cmd) => {
  result = child_process.spawnSync('sh', ['-c', `type ${cmd}`])
  console.log(result.status + '\t' + result.stdout.toString())
})
0       lua is /usr/local/bin/lua

127     foobar: not found

Indeed, malicious input is still malicious.

Here's one workaround: quote the command in the type cmd string, but you'll have to handle any quotes in the command itself

// 1. shell-quote any single quotes in the cmd
cmd = "da$(echo 'hello world')te";      // 'da$(echo \'hello world\')te'
escaped = cmd.replace(/'/g, `'"'"'`);   // 'da$(echo \'"\'"\'hello world\'"\'"\')te'
// 2. in the command string, quote the escaped cmd argument
result = child_process.spawnSync('sh', ['-c', `type '${escaped}'`]);
// .................................................^..........^
console.log(result.status, result.stdout.toString());
127 'da$(echo \'hello world\')te: not found\n'

And, to incorporate @dee's answer, to find the command word, you'll first have to parse out any leading variable assignments and/or redirections (https://www.gnu.org/software/bash/manual/bashref.html#Simple-Command-Expansion) and/or leading open parentheses or braces and/or ... basically implement a sh parser.

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
1

This looks like simply the wrong design. In the general case a Linux command can be any binary in your PATH, a shell builtin or alias.

You could check if the first word points to a binary in your path, but that still does not solve shell aliases or built ins (you at least need a list of builtins).

And what if someone enters a "text message" that just happens to start with a common word that is also a Linux command (echo, cat, ...) ?

Short answer: don't do this, or suffer the consequences.

dee
  • 526
  • 4
  • 8
  • the command doesn't have to be the first word: redirections and variable assignments can precede it, for example – jhnc Mar 20 '19 at 13:56
0
var commnads = 'alias,apt-get,aptitude,aspell,awk,basename,bc,bg,bind,break,builtin,bzip2,cal,case,cat,cd,cfdisk,chattr,chgrp,chmod,chown,chroot,chkconfig,cksum,cmp,comm,command,continue,cp,cron,crontab,csplit,curl,cut,date,dc,dd,ddrescue,declare,df,diff,diff3,dig,dir,dircolors,dirname,dirs,dmesg,du,echo,egrep,eject,enable,env,eval,exec,exit,expect,expand,export,expr,false,fdformat,fdisk,fg,fgrep,file,find,fmt,fold,for,fsck,ftp,function,fuser,gawk,getopts,grep,groupadd,groupdel,groupmod,groups,gzip,hash,head,history,hostname,htop,iconv,id,if,ifconfig,ifdown,ifup,import,install,iostat,ip,jobs,join,kill,killall,less,let,link,ln,local,locate,logname,logout,look,lpc,lpr,lprm,lsattr,lsblk,ls,lsof,lspci,man,mkdir,mkfifo,mkfile,mknod,mktemp,more,most,mount,mtools,mtr,mv,mmv,nc,netstat,nft,nice,nl,nohup,notify-send,nslookup,open,op,passwd,paste,Perf,ping,pgrep,pkill,popd,pr,printenv,printf,ps,pushd,pv,pwd,quota,quotacheck,ram,rar,rcp,read,readonly,rename,return,rev,rm,rmdir,rsync,screen,scp,sdiff,sed,select,seq,set,shift,shopt,shutdown,sleep,slocate,sort,source,split,ss,ssh,stat,strace,su,sudo,sum,suspend,sync,tail,tar,tee,test,time,timeout,times,touch,top,tput,traceroute,trap,tr,true,tsort,tty,type,ulimit,umask,unalias,uname,unexpand,uniq,units,unrar,unset,unshar,until,useradd,userdel,usermod,users,uuencode,uudecode,vi,vmstat,w,wait,watch,wc,whereis,which,while,who,whoami,write,xargs,xdg-open,xz,yes,zip,.,!!,###'.split(',');

if (commands.some(command => text_to_check.startsWith(command + ' ')))
{
    //code goes here
}
Hagai Wild
  • 1,904
  • 11
  • 19
  • 1
  • 1
    `/bin/echo does not start with echo`; `${E:+}e${C:+}h${H:+}h${O:+}o hello` – jhnc Mar 20 '19 at 03:36
  • @jhnc if running from windows. there's no assurance what the folders in the supposedly linux environment would look like. perhaps folders located directly at the root folder such as /bin can be assumed, but folders other than that cannot. – Hagai Wild Mar 20 '19 at 07:35
  • That's true. But the question was to test whether a string was a valid shell command, not to check that a particular shell command would executre on some specific machine. – jhnc Mar 20 '19 at 13:36