From: Edward P. <es...@pg...> - 2004-08-30 20:04:41
|
hey all, I'm writing an application whose intent is to take a gnuplot file, turn it into a PNG graph, and then display that graph online. Anyway, I would like to therefore disable anything that gnuplot can do outside of drawing graphs, for example: !rm -rf / considering that I don't want someone to upload something to wipe out my system (or even try).. Also - I was wondering - is there a good format that people would suggest to make any and all plots self-contained? I'd like something like: - one plot per graph file - forcing of png format - data and plot statement in the same file yet the plot statemnts (at least for data) tend to be of the form plot [x1:x2] [y1:y2] "filename" How can you make it so that the plot statement refers to itself, ie a dataset in the file itself? Ed |
From: Hans-Bernhard B. <br...@ph...> - 2004-08-31 08:10:01
|
Edward Peschko wrote: > Anyway, I would like to therefore disable anything that gnuplot can do outside of > drawing graphs, for example: > > !rm -rf / No way of doing that is foreseen inside gnuplot --- you'll have to use external means, e.g. run it in a chroot or jail environment. > How can you make it so that the plot statement refers to itself, ie a dataset in the > file itself? See 'help plot datafile special' |
From: Edward P. <es...@pg...> - 2004-08-31 18:58:27
|
On Tue, Aug 31, 2004 at 10:09:03AM +0200, Hans-Bernhard Broeker wrote: > Edward Peschko wrote: > > >Anyway, I would like to therefore disable anything that gnuplot can do > >outside of drawing graphs, for example: > > > >!rm -rf / > > No way of doing that is foreseen inside gnuplot --- you'll have to use external means, e.g. run it in a chroot or jail environment. well, the main idea was to integrate it into wiki (to be used for preparing graphs). Hence a chroot/jail environment might not be possible since the server would be running the software in producing the graph. Just making a chroot environment for the sake of gnuplot is not going to happen. Would a 'taint' gnuplot be possible? (ie: compile it such that dangerous behaviors are not allowed? Or perhaps a switch to gnuplot that doesn't allow them? And is the above the only dangerous behaviour that is possible from gnuplot? > look up help plot datafile special thanks, that worked.. Ed |
From: Arun P. <ape...@lb...> - 2004-08-31 19:54:54
|
Edward Peschko wrote: > Would a 'taint' gnuplot be possible? (ie: compile it such that dangerous > behaviors are not allowed? Or perhaps a switch to gnuplot that doesn't allow them? > > And is the above the only dangerous behaviour that is possible from gnuplot? How about disabling the "!" command completely and checking that the output file is in the right directory... deleting the "< ..." option for input files might also be a good thing... I also would just including one terminal e.g. for png shouldn't be too much work to delete the right lines in the source code... if you don't want to mess with the gnuplot source code just write a php-file that checks the gnuplot input file before you call gnuplot and disallow the use of "^\s*!" ".*plot.*< ", etc... I'm not sure though in what other ways you could trick gnuplot to do dangerous things... HTH ARUN |
From: Hans-Bernhard B. <br...@ph...> - 2004-08-31 20:55:47
|
Arun Persaud wrote: > How about disabling the "!" command completely and checking that the > output file is in the right directory... deleting the "< ..." option > for input files might also be a good thing... As Ethan already pointed out, that would run into serious usability problems. > shouldn't be too much work to delete the right lines in the source code... Deleting them: no, that wouldn't be hard. But *finding* them would be, esp. if you want to be sure you found not just some of the relevant lines, but strictly *all* of them. Miss just one, and you've turned a known-insecure program into a presumably secure one with a hole. That would be rather the opposite of an improvement. > I'm not sure though in what other ways you could trick gnuplot to do > dangerous things... Neither are we. That's why I wrote that there are no way of doing that is foreseen in the source. This would require a full-blown audit of the entire code, and IMHO neither the team nor the code is in the condition that would warrant trying that. |
From: Ethan M. <merritt@u.washington.edu> - 2004-08-31 19:30:47
|
On Tuesday 31 August 2004 11:50 am, Edward Peschko wrote: > And is the above the only dangerous behaviour that is possible from gnuplot? No. Not by a long shot. Consider: set output "~/.login" # trash the user's login file print `dd if=/bin/zero of=/somewhere/bad` # abuse the back-tic syntax plot '< rm -rf .' #abuse the pipe mechanism sh "bad command" # abuse the shell escape mechanism You'd have to disable all of these, and probably a few more that I'm not thinking of at the moment. Disabling shell escapes and back-tics would not harm most applications. But disabling pipes, in particular, would drastically cripple gnuplot's flexibility and ability to work with other programs. That's probably a deal-breaker right there; you could disable pipes, but the program you were left with wouldn't be very useful. And what could you possibly do to limit "set output <foo>"? I think the only possible mechanism would be to create a wrapper script that set the UID/EID to a non-privileged user with no permission to write outside of a captive directory tree. -- Ethan A Merritt merritt@u.washington.edu Biomolecular Structure Center Mailstop 357742 University of Washington, Seattle, WA 98195 |
From: Edward P. <es...@pg...> - 2004-08-31 19:54:43
|
On Tue, Aug 31, 2004 at 12:30:38PM -0700, Ethan Merritt wrote: > On Tuesday 31 August 2004 11:50 am, Edward Peschko wrote: > > And is the above the only dangerous behaviour that is possible from gnuplot? > > No. Not by a long shot. > > Consider: > > set output "~/.login" # trash the user's login file > print `dd if=/bin/zero of=/somewhere/bad` # abuse the back-tic syntax > plot '< rm -rf .' #abuse the pipe mechanism > sh "bad command" # abuse the shell escape mechanism > > You'd have to disable all of these, and probably a few more > that I'm not thinking of at the moment. > Disabling shell escapes and back-tics would not harm most > applications. But disabling pipes, in particular, > would drastically cripple gnuplot's flexibility and ability to work with > other programs. That's probably a deal-breaker right there; well, of course I wouldn't expect a safe version of gnuplot to come standard - I could live with compiling gnuplot with a separate flag that gets rid of these things. > you could disable pipes, but the program you were left with wouldn't > be very useful. not really true, IMO. In mediawiki we'd probably want to limit plotting to inline, which I asked about the other time. IE: it would be up to the user to use programs to create data, etc. which would then be uploaded to mediawiki. > And what could you possibly do to limit "set output <foo>"? disallow it... let output only go to STDOUT.. > I think the only possible mechanism would be to create a > wrapper script that set the UID/EID to a non-privileged user > with no permission to write outside of a captive directory tree. Its barely possible, but its still pretty ugly... You'd need a separate user/etc for each graph. Suppose we had a chroot jail and someone did 'rm -rf /'? The fact that it only eliminated all of the mediawiki graphs is pretty small consolation.. Ed |
From: Ethan M. <merritt@u.washington.edu> - 2004-08-31 21:41:40
|
On Tuesday 31 August 2004 12:47 pm, Edward Peschko wrote: > > > you could disable pipes, but the program you were left with wouldn't > > be very useful. > > not really true, IMO. In mediawiki we'd probably want to limit plotting to inline, > which I asked about the other time. IE: it would be up to the user to use programs > to create data, etc. which would then be uploaded to mediawiki. ??? What do you mean by "in line"? I normally interpret that to mean "via pipe", but that's exactly what you would be disabling. > > I think the only possible mechanism would be to create a > > wrapper script that set the UID/EID to a non-privileged user > > with no permission to write outside of a captive directory tree. > > Its barely possible, but its still pretty ugly... You'd need a separate > user/etc for each graph. I don't think you would. The wrapper script itself could save the output graph back to the user's own area. Its flow would look like: stdin = open input stdout = open output drop privileges mkdir /tmp_<process_id> chroot /tmp_<process_id> gnuplot -- Ethan A Merritt merritt@u.washington.edu Biomolecular Structure Center Mailstop 357742 University of Washington, Seattle, WA 98195 |
From: Arun P. <ape...@lb...> - 2004-08-31 22:48:43
|
Ethan Merritt wrote: > On Tuesday 31 August 2004 12:47 pm, Edward Peschko wrote: >>>[disabled pipes] >>not really true, IMO. In mediawiki we'd probably want to limit plotting to inline, >>which I asked about the other time. IE: it would be up to the user to use programs >>to create data, etc. which would then be uploaded to mediawiki. > > ??? > What do you mean by "in line"? I guess something like plot "-" followed by the data... >>>[wrapper script issues] > I don't think you would. The wrapper script itself could save the > output graph back to the user's own area. Its flow would look like: > stdin = open input > stdout = open output > drop privileges > mkdir /tmp_<process_id> > chroot /tmp_<process_id> gnuplot this and a having the wiki (per php or similar) check the gnuplot input file for "!" "set output","print" and other commands which could be harmfull and not needed for just simple ploting etc. might be a good way to do it then... perhaps you even want to be very restrictive anyway to get the same look for most of the graphs in the wiki and so the user would only need to supply the data and the plotstyle and then you would give gnuplot most of the input (e.g. use of grid yes/no, set terminal, etc) and your plot command would always look like: plot "-" $userplotstyle $data in that case you just have to scan those two variables for dangerous items or just allow for example numbers in $data and certain words in $userplotstyle just my two cents ARUN |
From: Edward P. <es...@pg...> - 2004-08-31 23:36:50
|
On Tue, Aug 31, 2004 at 02:41:28PM -0700, Ethan Merritt wrote: > On Tuesday 31 August 2004 12:47 pm, Edward Peschko wrote: > > > > > you could disable pipes, but the program you were left with wouldn't > > > be very useful. > > > > not really true, IMO. In mediawiki we'd probably want to limit plotting to inline, > > which I asked about the other time. IE: it would be up to the user to use programs > > to create data, etc. which would then be uploaded to mediawiki. > > ??? > What do you mean by "in line"? > I normally interpret that to mean "via pipe", but that's exactly what > you would be disabling. plot '-' index 0, '-' index1 .. .. .. .. e via help plot special I'm assuming this isn't implemented via pipes, but I to be fair I don't know. > > > I think the only possible mechanism would be to create a > > > wrapper script that set the UID/EID to a non-privileged user > > > with no permission to write outside of a captive directory tree. > > > > Its barely possible, but its still pretty ugly... You'd need a separate > > user/etc for each graph. > > I don't think you would. The wrapper script itself could save the > output graph back to the user's own area. Its flow would look like: > stdin = open input > stdout = open output > drop privileges > mkdir /tmp_<process_id> > chroot /tmp_<process_id> gnuplot yes, I could do this (I guess). It sort of sucks that I need to bend the tool in order to get something done though. And chroot itself is a pain in the #!% to get working correctly. You need to get the entire library structure, all associated files with the command put underneath /tmp/_<process_id> in order to run it (remember - the OS doesn't have access to them as soon as you run chroot). And you'd have to do this with *every call to chroot*. Plus, portability would go out the window because different systems would require different files to be copied for chroot, and some systems chroot doesn't work under anything but 'root' - so you'd need root perms to run it. And trying to sell the idea of making it standard functionality to include with mediawiki would be well-nigh impossible. I think you should take the effort to make it compilably secure, but that's just me... I would think that you would *want* the ability to run gnuplot using users' input. It would make the tool that much more powerful. Ed |
From: Ethan A M. <merritt@u.washington.edu> - 2004-09-01 01:13:32
|
On Tuesday 31 August 2004 04:28 pm, Edward Peschko wrote: > > plot '-' index 0, '-' index1 In my experience, that mode is not very useful. It's better to create a file with the data in it and plot the data from there. If nothing else, it allows 'replot' on demand, which the inline version doesn't. For instance, mousing with inline data does not allow zoom, because it requires an implicit replot. I don't think you want to go in this direction. > I think you should take the effort to make it compilably secure, but > that's just me... I would think that you would *want* the ability to > run gnuplot using users' input. It would make the tool that much more > powerful. We have that now. What you want is something a little different: you want the ability for users to safely run *each other's* input. It seems to me that the difficulties you are running into are not really a problem with gnuplot, but rather a limitation of a wiki's failure to distinguish one user from another. I think you're making this harder than it needs to be. Here's a variant of my previous suggestion for a wrapper; this one doesn't need chroot, just a captive account. open stdin from gnuplot script file open stdout to eventual plot image su nobody mkdir /tmp/gnuplot/<process_id> chdir /tmp/gnuplot/<process_id> gnuplot rm -rf /tmp/gnuplot/<process_id> The user "nobody" would have write access to /tmp/gnuplot but nowhere else on the system. Yes, an abusive input stream could be to corrupt another plot being made at the same time, but I would live with since the time window is small. -- Ethan A Merritt Department of Biochemistry & Biomolecular Structure Center University of Washington, Seattle |
From: Edward P. <es...@pg...> - 2004-09-01 01:34:29
|
> > I think you should take the effort to make it compilably secure, but > > that's just me... I would think that you would *want* the ability to > > run gnuplot using users' input. It would make the tool that much more > > powerful. > > We have that now. What you want is something a little different: > you want the ability for users to safely run *each other's* input. > It seems to me that the difficulties you are running into are not > really a problem with gnuplot, but rather a limitation of a wiki's failure > to distinguish one user from another. I think its more fundamental than that - its that gnuplot cannot accept untrusted input. > I think you're making this harder than it needs to be. > Here's a variant of my previous suggestion for a wrapper; > this one doesn't need chroot, just a captive account. > > open stdin from gnuplot script file > open stdout to eventual plot image > su nobody > mkdir /tmp/gnuplot/<process_id> > chdir /tmp/gnuplot/<process_id> > gnuplot > rm -rf /tmp/gnuplot/<process_id> ok.. so how do you make this generic and cross platform? Right now, you can self-configure mediawiki by simply dropping it into a apache directory. Do you require people to create an extra user in order to use gnuplot? And how do you make it so that the 'su' doesn't require dynamic input? And how about DOS attacks, ie: !mkfile 10000000000 IMO unless you've got some sort of taint mode or preprocessor, you are just asking for trouble here.. Ed |
From: Ethan A M. <merritt@u.washington.edu> - 2004-09-01 02:46:01
|
On Tuesday 31 August 2004 06:26 pm, Edward Peschko wrote: \> > > > open stdin from gnuplot script file > > open stdout to eventual plot image > > su nobody > > mkdir /tmp/gnuplot/<process_id> > > chdir /tmp/gnuplot/<process_id> > > gnuplot > > rm -rf /tmp/gnuplot/<process_id> > > ok.. so how do you make this generic and cross platform? By "cross platform" do you mean non-unix, non-cygwin? If so, the answer is that I have no interest in doing so. > Right now, you can > self-configure mediawiki by simply dropping it into a apache directory. > Do you require people to create an extra user in order to use gnuplot? Yes. Or rather, I don't know. mediawiki may provide such a non-privileged user name anyhow. Other wikis do. > And how do you make it so that the 'su' doesn't require dynamic input? Bog standard. Make the "nobody" account have no password, so no input required. Anyone who does "su nobody" is forfeiting all their privileges anyhow, so let them go ahead and do so. > IMO unless you've got some sort of taint mode or preprocessor, > you are just asking for trouble here.. You were doing that as soon as you decided to run a wiki. After thinking about it, I'm not sure that you really introduce any new security problems by running gnuplot that are not there already if you run a general access wiki. Vandals can already trash all the wiki files anyhow, and the rest of the system is invisible because the wiki area is chroot (or if it isn't then you really need to switch to another wiki). So other than maybe ease-of-trashing, what's different about running gnuplot? I use gnuplot as a web site back-end, and have done so for years. It has not been a problem in practice. True, I have not been running up-loaded scripts. I provide access via forms, and have the form generate a gnuplot script. In my case any given form always produces the same style of plot, although the user can force other parameters like xrange or xtics by filling in the form. It would not be that hard to extend this to having a set of radio-buttons for plot style and check-boxes for many of the common gnuplot options. The form would always generate a trusted script, but configurable by the user. Then, as I already do, I would offer the choice of running gnuplot server-side and returning the image, or returning the script itself as a mime-tagged object to be run client-side. Writing such a form+cgi interface would be less work by far than securing gnuplot, and would be a welcome contribution to the gnuplot project if you want to volunteer. EAM -- Ethan A Merritt Department of Biochemistry & Biomolecular Structure Center University of Washington, Seattle |
From: Ethan M. <merritt@u.washington.edu> - 2004-08-31 23:29:16
|
On Monday 30 August 2004 12:56 pm, Edward Peschko wrote: > > I'm writing an application whose intent is to take a gnuplot file, turn it into a > PNG graph, and then display that graph online. > IE: it would be up to the user to use programs > to create data, etc. which would then be uploaded to mediawiki. I took a step back to think about what you said you want to do, and now I am puzzled. If the external user is writing the gnuplot script, then I presume they know how to use gnuplot. You also say that the external user will be generating the data. So why can't they just run the script themselves and upload the resulting png file to the wiki, rather than uploading the script and having the wiki's host machine run it there? -- Ethan A Merritt merritt@u.washington.edu Biomolecular Structure Center Mailstop 357742 University of Washington, Seattle, WA 98195 |
From: Edward P. <es...@pg...> - 2004-08-31 23:38:37
|
On Tue, Aug 31, 2004 at 04:29:04PM -0700, Ethan Merritt wrote: > On Monday 30 August 2004 12:56 pm, Edward Peschko wrote: > > > > I'm writing an application whose intent is to take a gnuplot file, turn it into a > > PNG graph, and then display that graph online. > > > IE: it would be up to the user to use programs > > to create data, etc. which would then be uploaded to mediawiki. > > I took a step back to think about what you said you want to do, > and now I am puzzled. If the external user is writing the gnuplot script, > then I presume they know how to use gnuplot. You also say that the > external user will be generating the data. So why can't they just run > the script themselves and upload the resulting png file to the wiki, > rather than uploading the script and having the wiki's host machine > run it there? Because the whole idea was to make it so: a) other people can reproduce the graph b) other people can see the data used to generate the graph c) other people can modify the data used to generate the graph, or modify the layout. You lose lots in the translation to the PNG - just like you lose lots when you edit an illustrator or PSP file and don't save it in their native format. Ed |
From: Ethan M. <merritt@u.washington.edu> - 2004-08-31 23:49:41
|
On Tuesday 31 August 2004 04:31 pm, Edward Peschko wrote: > > Because the whole idea was to make it so: > > a) other people can reproduce the graph > b) other people can see the data used to generate the graph > c) other people can modify the data used to generate the graph, or modify > the layout. > > You lose lots in the translation to the PNG - just like you lose lots when you > edit an illustrator or PSP file and don't save it in their native format. True. There is another option that I have found useful in the past. It would achieve exactly what you describe above, but it does assume that the script is trusted. What you can do is to associate the mime type "application/gnuplot" with a gnuplot wrapper script, and have the web site return the script itself via a browser click. This is the ultimate in not losing anything to translation. For details, see http://www.bmsc.washington.edu/people/merritt/gnuplot_test.html In my case the script on the server side is trusted, so the issues you are worried about are not of primary concern. The data being plotted can either be local to the user's machine, or can be pulled from the web site via http protocols. If the data were on a wiki site, my procedure would allow your (a), (b) and (c) above. -- Ethan A Merritt merritt@u.washington.edu Biomolecular Structure Center Mailstop 357742 University of Washington, Seattle, WA 98195 |
From: Edward P. <es...@pg...> - 2004-09-01 00:54:37
|
> > There is another option that I have found useful in the past. > It would achieve exactly what you describe above, but it > does assume that the script is trusted. What you can do > is to associate the mime type "application/gnuplot" with > a gnuplot wrapper script, and have the web site return the > script itself via a browser click. This is the ultimate in not > losing anything to translation. For details, see well, yes, but I also want to display the graph itself, not just the data. Seeing the graph would be the default - there would be a data function to see the data associated with it - associated with Perhaps the way around this is to start from the ground up - namely extract the parts of gnuplot functionality that I'd need and build a 'mini-gnuplot'. Just thinking out loud here, I don't know how hard this would be to do. > issues you are worried about are not of primary concern. > The data being plotted can either be local to the user's machine, > or can be pulled from the web site via http protocols. > If the data were on a wiki site, my procedure would allow > your (a), (b) and (c) above. right, but wiki allows an 'upload file' feature, which means you can't assume trust. And even if you *did* show just the graph, you really can't take the chance that someone won't cut and copy it into their machine, run it, and cause themselves grief.. Come to think of it, maybe a preprocessor is the way to go - but instead of running the gnuplot graph, it shields against malicious constructs before the fact, so that they never even get to the server. Or perhaps just allows a small subset of functionality, and junks the rest. I think that a wrapper like this would be a worthwhile thing to include with the gnuplot distribution.. Ed |
From: Petr M. <mi...@ph...> - 2004-09-01 15:08:25
|
Few notes: A first attempt to more secure way is to compile gnuplot without PIPES being defined. Then, system() and ! commands need to be disabled. And then, overload/redefine fopen() function by such a one which only plot or splot can use for reading a file, and fail for other. -- PM |
From: Ethan M. <merritt@u.washington.edu> - 2004-09-01 15:29:40
|
On Wednesday 01 September 2004 08:08 am, Petr Mikulik wrote: > Few notes: > > A first attempt to more secure way is to compile gnuplot without PIPES > being defined. > > Then, system() and ! commands need to be disabled. It's harder than you might think. If you are bound and determined to abuse a program, many paths are open. For example, x11.trm fires up gnuplot_x11 internally by executing execvp(X11_full_command_path, optvec); But a vandal could corrupt the path, or the environmental variables, such that $(GNUPLOT_DRIVER_DIR)/gnuplot_x11 is a malicious program or shell script. To make the X terminal secure, I think you would have to replace this whole mechanism with something else. |
From: Edward P. <es...@pg...> - 2004-09-02 05:09:52
|
Ok all, here's my first attempt at a 'safe' gnuplot. It simply looks for certain characters in a file ('<', '!', etc) and operations (set terminal, set output) and disallows them if it finds the character strings anywhere in the file. If you want, you can run the command through a certain user via 'su': examples - gplot_safe.p data.dat > data.png gplot_safe.p data.dat nobody > data.png gplot_safe.p data.dat myself fig > data.fig The special user myself is used as a placeholder if you want another type of file (fig, illustrator, etc) without going through su. It was a little more difficult than I anticipated because of the abbreviation feature of gnuplot - and I don't know if I got all the 'unsafe' features so feedback is appreciated. It errs on the side of safety, so there may be a couple of false positives - for example, if there is a '!' anywhere in the file, it tags it as unsafe. Anyways, script follows.. Ed ---- #!/bin/env perl use strict; my $errorclasses = { '!' => 'shell escape not allowed!', '`' => 'backtick not allowed!', '<' => '< input not allowed!', '>' => '> output not allowed!', 'output' => 'output to another file is not allowed (use stdin)', 'outpu' => 'output to another file is not allowed (use stdin)', 'outp' => 'output to another file is not allowed (use stdin)', 'out' => 'output to another file is not allowed (use stdin)', 'ou' => 'output to another file is not allowed (use stdin)', 'terminal' => 'setting terminal is not allowed', 'termina' => 'setting terminal is not allowed', 'termin' => 'setting terminal is not allowed', 'termi' => 'setting terminal is not allowed', 'term' => 'setting terminal is not allowed', 'ter' => 'setting terminal is not allowed', 'te' => 'setting terminal is not allowed', 'shell' => 'external shell is not allowed', 'shel' => 'external shell is not allowed', 'she' => 'external shell is not allowed', 'system' => 'system call is not allowed', 'syste' => 'system call is not allowed', 'syst' => 'system call is not allowed', 'sys' => 'system call is not allowed', 'sy' => 'external shell is not allowed', }; my $script = $ARGV[0]; my $user = ($ARGV[1] eq 'myself')? undef : $ARGV[1]; my $terminal = $ARGV[2] || "png"; my $text = _gettext($script); my $errors = _safety(\$text); if (@$errors) { print STDERR map("Unsafe - $_\n", @$errors) if (@$errors); } else { if ($user) { system("su $user -c '( echo \"set terminal $terminal\";cat $script )| gnuplot'"); } else { system("(echo \"set terminal $terminal\"; cat $script ) | gnuplot"); } } sub _safety { my ($text) = @_; my @errors; my $total = 1; $$text =~ s"#[^\n]*""sg; # no comments. $DB::single = 1; while ( $$text =~ m/ (.*?) ( \!| # no shells `| # no backticks <| # no pipes >| # no pipes (?:(?:\n|\A)\s* se (?:t?) [\\\s]+ ou \S*)| # no output (?:(?:\n|\A)\s* se (?:t?) [\\\s]+ te \S*)| # no terminal (?:(?:\n|\A)\s* she (l*))| # no shell (?:(?:\n|\A)\s* sy [stem\s\\]* [\"']) # no system ) /sgx ) { my $before = $1; my $class = $2; my $text = $2; $class = _modify($class); my $lines = ($before =~ tr"\n"\n"); if ($errorclasses->{$class}) { $lines += ($text =~ tr"\n"\n"); my $tot = $lines + $total; $text =~ s"\n""sg; $text =~ s"^\s*""sg; push(@errors, "line $tot - '$text': $errorclasses->{$class}"); $total += $lines; } else { $total += $lines; next; } } return(\@errors); } sub _modify { my ($class) = @_; $class =~ s"se\S*\s+""sg; $class =~ s"[\\\"\']""sg; $class =~ s"\s+""sg; return($class); } sub _gettext { my ($script) = @_; open(FD, $script); local($/) = undef; my $line = <FD>; close(FD); return($line); } |
From: Ethan A M. <merritt@u.washington.edu> - 2004-09-02 06:08:21
|
On Wednesday 01 September 2004 10:01 pm, Edward Peschko wrote: > here's my first attempt at a 'safe' gnuplot. It simply looks for certain > characters in a file ('<', '!', etc) So no math in gnuplot any more? No commands like plot 'data' using ($1<$2 ? $1 : $2) No logical operations like if (!defined(VAR)) ... I think you are embarking on an impossible project. What about commands like load "malicious.script" call "timebomb" "new shell" "arg1" "arg2" And that's without even touching the problems that will be introduced by new syntax in version 4.1 I rather suspect that in 4.1 it will be possible to bypass your test sequence using new string-handling syntax: PART1 = "set " PART2 = "te" PART3 = "rm x11" NEW_TERM = PART1.PART2.PART3 set print "temp" print NEW_TERM load "temp" or maybe even in-line set $(PART2.PART3) If you really want to pursue this, I think you would be better off wrapping all source code that implements the "dangerous" features with an #ifndef SECURE <suspect code> #endif Then people who were willing to accept a substantially less flexible, but purportedly secure, gnuplot could do ./configure --enable-secure Hans-Berhard has already pointed out that a purportedly secure version is in a way worse than an known insecure version. If you use it in some critical place with no additional protection, then you're toast as soon as some hacker proves cleverer than you were in finding exploitable code sections. > and operations (set terminal, set > output) and disallows them if it finds the character strings anywhere in > the file. If you want, you can run the command through a certain user via > 'su': > > examples - > > gplot_safe.p data.dat > data.png > gplot_safe.p data.dat nobody > data.png > gplot_safe.p data.dat myself fig > data.fig > > > The special user myself is used as a placeholder if you want another type > of file (fig, illustrator, etc) without going through su. > > It was a little more difficult than I anticipated because of the > abbreviation feature of gnuplot - and I don't know if I got all the > 'unsafe' features so feedback is appreciated. It errs on the side of > safety, so there may be a couple of false positives - for example, > if there is a '!' anywhere in the file, it tags it as unsafe. > > Anyways, script follows.. > > Ed > > ---- > > #!/bin/env perl > > use strict; > > my $errorclasses = > { > '!' => 'shell escape not allowed!', > '`' => 'backtick not allowed!', > '<' => '< input not allowed!', > '>' => '> output not allowed!', > 'output' => 'output to another file is not allowed (use stdin)', > 'outpu' => 'output to another file is not allowed (use stdin)', > 'outp' => 'output to another file is not allowed (use stdin)', > 'out' => 'output to another file is not allowed (use stdin)', > 'ou' => 'output to another file is not allowed (use stdin)', > > 'terminal' => 'setting terminal is not allowed', > 'termina' => 'setting terminal is not allowed', > 'termin' => 'setting terminal is not allowed', > 'termi' => 'setting terminal is not allowed', > 'term' => 'setting terminal is not allowed', > 'ter' => 'setting terminal is not allowed', > 'te' => 'setting terminal is not allowed', > > 'shell' => 'external shell is not allowed', > 'shel' => 'external shell is not allowed', > 'she' => 'external shell is not allowed', > > 'system' => 'system call is not allowed', > 'syste' => 'system call is not allowed', > 'syst' => 'system call is not allowed', > 'sys' => 'system call is not allowed', > 'sy' => 'external shell is not allowed', > }; > > my $script = $ARGV[0]; > my $user = ($ARGV[1] eq 'myself')? undef : $ARGV[1]; > my $terminal = $ARGV[2] || "png"; > > my $text = _gettext($script); > my $errors = _safety(\$text); > > if (@$errors) > { > print STDERR map("Unsafe - $_\n", @$errors) if (@$errors); > } > else > { > if ($user) > { > system("su $user -c '( echo \"set terminal $terminal\";cat $script )| > gnuplot'"); } > else > { > system("(echo \"set terminal $terminal\"; cat $script ) | gnuplot"); > } > } > > sub _safety > { > my ($text) = @_; > > my @errors; > my $total = 1; > > > $$text =~ s"#[^\n]*""sg; # no comments. > > $DB::single = 1; > > while > ( > $$text =~ m/ > (.*?) > ( > \!| # no shells > `| # no > backticks <| # no pipes > > >| # no pipes > > (?:(?:\n|\A)\s* se (?:t?) [\\\s]+ ou \S*)| # no output > (?:(?:\n|\A)\s* se (?:t?) [\\\s]+ te \S*)| # no > terminal (?:(?:\n|\A)\s* she (l*))| # no shell > (?:(?:\n|\A)\s* sy [stem\s\\]* [\"']) # no system ) > /sgx > ) > { > my $before = $1; > my $class = $2; > > my $text = $2; > > $class = _modify($class); > > my $lines = ($before =~ tr"\n"\n"); > > if ($errorclasses->{$class}) > { > $lines += ($text =~ tr"\n"\n"); > my $tot = $lines + $total; > $text =~ s"\n""sg; > $text =~ s"^\s*""sg; > > push(@errors, "line $tot - '$text': $errorclasses->{$class}"); > $total += $lines; > } > else > { > $total += $lines; > next; > } > } > return(\@errors); > } > > sub _modify > { > my ($class) = @_; > > $class =~ s"se\S*\s+""sg; > $class =~ s"[\\\"\']""sg; > $class =~ s"\s+""sg; > return($class); > } > > > > sub _gettext > { > my ($script) = @_; > > open(FD, $script); > local($/) = undef; > my $line = <FD>; > > close(FD); > > return($line); > } -- Ethan A Merritt Department of Biochemistry & Biomolecular Structure Center University of Washington, Seattle |
From: Daniel J S. <dan...@ie...> - 2004-09-02 06:42:35
|
Ethan A Merritt wrote: >If you really want to pursue this, I think you would be better off >wrapping all source code that implements the "dangerous" features >with an #ifndef SECURE <suspect code> #endif > >Then people who were willing to accept a substantially less >flexible, but purportedly secure, gnuplot could do > ./configure --enable-secure > >Hans-Berhard has already pointed out that a purportedly secure >version is in a way worse than an known insecure version. >If you use it in some critical place with no additional protection, >then you're toast as soon as some hacker proves cleverer >than you were in finding exploitable code sections. > Just following along, I tend to agree with this philosophy. I understand the motivation for a SECURE version of a the program, but much of that security should fall upon the environment that it runs in. Unix has evolved with that in mind. A certain large software company keeps issuing patches to make their operating environment secure. It seems to me a SECURE version should require only a few restrictions here and there if the program is launched from a non-su account. The instructions where an output file or pipe are opened should probably be investigated. Also, that thing Ethan pointed out with gnuplot_x11 being launched separately. You'd probably have to force gnuplot_x11 to originate from a specific location. You couldn't ensure security in gnuplot_x11 via some magic cookie, parity check, hand-shake, etc. because the code would be easily available for deciphering. Dan |
From: Edward P. <es...@pg...> - 2004-09-02 07:07:47
|
On Wed, Sep 01, 2004 at 11:08:17PM -0700, Ethan A Merritt wrote: > On Wednesday 01 September 2004 10:01 pm, Edward Peschko wrote: > > here's my first attempt at a 'safe' gnuplot. It simply looks for certain > > characters in a file ('<', '!', etc) > > So no math in gnuplot any more? > > No commands like > plot 'data' using ($1<$2 ? $1 : $2) good point.. although I think I could get rid of this, assuming that "<" has to come inside a backtick or shell command in order to be used. Backtick is already covered... > No logical operations like > if (!defined(VAR)) ... likewise, '!' may only be used in unsafe context if it came at the beginning of a string, so I could qualify this... although I'm not sure if this is totally true. > I think you are embarking on an impossible project. > What about commands like > load "malicious.script" > call "timebomb" "new shell" "arg1" "arg2" call and load will need to be disabled too.. > PART3 = "rm x11" > NEW_TERM = PART1.PART2.PART3 > set print "temp" > print NEW_TERM > load "temp" this is fixed if load is disabled... set print needs to be disabled, too > or maybe even in-line > set $(PART2.PART3) ok - then 'set \$' needs to be disabled as well. > If you really want to pursue this, I think you would be better off > wrapping all source code that implements the "dangerous" features > with an #ifndef SECURE <suspect code> #endif > > Then people who were willing to accept a substantially less > flexible, but purportedly secure, gnuplot could do > ./configure --enable-secure of course, that might be the ultimate goal of this. However, for the purposes of both rapid prototyping and getting something useful (quickly), its hard to beat perl. And - as I wrapped it under nobody, perhaps an option could be given to accept *all* of gnuplot syntax if a wrapper user is used. So, it might be useful as-is as an end product. As for hackers, yes, that is a possibility, but I think that there will be plenty of examples of what they try to do when they connect to my wiki (if it gets popular). The script has two modes: a) safe safe mode (running under nobody) b) safe mode All I have to do is run it for a six months or so under safe-safe mode - and log the things that people try to do. I'm sure I'll get a lot of creative attempts to try to break into it in that time (especially if gnuplot gets incorporated into wikipedia itself.) And anyhow, the fact that safe mode was hard didn't stop perl (for example) from having taint mode.. I don't see why its not worth a shot to do the same for gnuplot. Ed ----- ps - updated script ----- #!/bin/env perl use strict; my $errorclasses = { '!' => 'shell escape not allowed!', '`' => 'backtick not allowed!', '<' => '< input not allowed!', '>' => '> output not allowed!', 'output' => 'output to another file is not allowed (use stdin)', 'outpu' => 'output to another file is not allowed (use stdin)', 'outp' => 'output to another file is not allowed (use stdin)', 'out' => 'output to another file is not allowed (use stdin)', 'ou' => 'output to another file is not allowed (use stdin)', '' => 'setting to a variable is not allowed', 'print' => 'printing to external files is not allowed', 'prin' => 'printing to external files is not allowed', 'pri' => 'printing to external files is not allowed', 'pr' => 'printing to external files is not allowed', 'load' => 'loading external files is not allowed', 'loa' => 'loading external files is not allowed', 'lo' => 'loading external files is not allowed', 'l' => 'loading external files is not allowed', 'call' => 'loading external files is not allowed', 'cal' => 'loading external files is not allowed', 'ca' => 'loading external files is not allowed', 'terminal' => 'setting terminal is not allowed', 'termina' => 'setting terminal is not allowed', 'termin' => 'setting terminal is not allowed', 'termi' => 'setting terminal is not allowed', 'term' => 'setting terminal is not allowed', 'ter' => 'setting terminal is not allowed', 'te' => 'setting terminal is not allowed', 'shell' => 'external shell is not allowed', 'shel' => 'external shell is not allowed', 'she' => 'external shell is not allowed', 'system' => 'system call is not allowed', 'syste' => 'system call is not allowed', 'syst' => 'system call is not allowed', 'sys' => 'system call is not allowed', 'sy' => 'external shell is not allowed', }; my $script = $ARGV[0]; my $user = ($ARGV[1] eq 'myself')? undef : $ARGV[1]; my $terminal = $ARGV[2] || "png"; my $text = _gettext($script); my $errors = _safety(\$text); if (@$errors) { print STDERR map("Unsafe - $_\n", @$errors) if (@$errors); } else { if ($user) { system("su $user -c '( echo \"set terminal $terminal\";cat $script )| gnuplot'"); } else { system("(echo \"set terminal $terminal\"; cat $script ) | gnuplot"); } } sub _safety { my ($text) = @_; my @errors; my $total = 1; $$text =~ s"#[^\n]*""sg; # no comments. $DB::single = 1; while ( $$text =~ m/ (.*?) ( (?:(?:\n|\A)\s*\!)| # no shells `| # no backticks (?:(?:\n|\A)\s* se (?:t?) [\\\s]+ \$ \S*)| # no variable (?:(?:\n|\A)\s* se (?:t?) [\\\s]+ pr \S*)| # no print (?:(?:\n|\A)\s* se (?:t?) [\\\s]+ ou \S*)| # no output (?:(?:\n|\A)\s* se (?:t?) [\\\s]+ te \S*)| # no terminal (?:(?:\n|\A)\s* she (?:l*))| # no shell (?:(?:\n|\A)\s* sy [stem\s\\]* [\$\"'])| # no system (?:(?:\n|\A)\s* l [oad\s\\]* [\$\"'])| # no load (?:(?:\n|\A)\s* ca (?:[l\\\s]*) [\$\"']) # no call ) /sgx ) { my $before = $1; my $class = $2; my $text = $2; $class = _modify($class); my $lines = ($before =~ tr"\n"\n"); if ($errorclasses->{$class}) { $lines += ($text =~ tr"\n"\n"); my $tot = $lines + $total; $text =~ s"\n""sg; $text =~ s"^\s*""sg; push(@errors, "line $tot - '$text': $errorclasses->{$class}"); $total += $lines; } else { $total += $lines; next; } } return(\@errors); } sub _modify { my ($class) = @_; $class =~ s"se\S*\s+""sg; $class =~ s"[\$\\\"\']""sg; $class =~ s"\s+""sg; return($class); } sub _gettext { my ($script) = @_; open(FD, $script); local($/) = undef; my $line = <FD>; close(FD); return($line); } |