63
\$\begingroup\$

Inspired by this comment...

Thanks to users Step Hen, Wheat-Wizard, and Dennis for helping my solidify the specification of this challenge before posting it!

This is the Cops' thread. For the Robbers' thread, go here


In this challenge, you are tasked with running some code that makes it so that your language no longer satisfies our criteria of being a programming language. In that challenge, that means making it so that the language can no longer...

  • Take numerical input and output

  • Add two numbers together

  • Test if a certain number is a prime or not.

This is a challenge, where there are two different challenges with two different objectives: the Cops will try to write some code that makes the language mostly unusable, and the robbers will try to find the hidden workaround that allows the cops to recover their language.

As a cop, you must write two snippets of code:

  1. One that makes your language mostly unusable, e.g. by removing built-in functions for taking input/output and numerical operations. The more features you remove, the better. This code is not allowed to crash or exit. It should be possible to add code to the end of this snippet, and that code will get evaluated. And...

  2. ...a snippet of code that takes two non-negative integers as input, adds them together, and outputs their sum. This snippet must still correctly function even after running the first snippet. When the two snippets are combined together, they must form a full program that adds two numbers, or define a function that adds two numbers. Ideally, this snippet should rely upon very obscure behavior, so as to be more difficult to find.

You may choose any standard method of input and output. However, you must reveal exactly which format (input and output) you are using. A robber cannot crack your answer unless they use the same format as you.

After writing both of these snippets, you must post the first one as an answer, without revealing the second one. Your answer should contain all of the following information:

  • The first snippet (obviously not the second).

  • Language (including minor version, since most submissions will probably rely on strange edge-cases)

  • IO format, including whether it's a function or full program. Robbers must use the same format for their crack to be valid.

  • Any strange edge cases required for your answer to work. For example, only runs on linux, or requires an Internet connection. Obviously, this is slightly subjective, but if a cop has some extreme edge case that prevents it from being cracked, and then only reveals this after being safe, I consider this poor sportsmanship. A potential robber should have all information necessary to crack your answer before it is cracked.

You do not need to reveal your byte count until your answer is safe.

Here's an example. For the first snippet, you could submit the following Python 3 program:

Python 3

print=None

Takes input from STDIN and output to STDOUT

And then as your second snippet, you could write:

import sys
a,b=int(input()),int(input())
sys.stdout.write(a+b)

This is valid because it will take two numbers as input, and output their sum even if you join the two snippets together, e.g.

print=None
import sys
a,b=int(input()),int(input())
sys.stdout.write(a+b)

However, this will be extremely easy for a robber to find a solution to. Since this would be very easy to crack, you could attempt to patch this particular approach like so:

import sys
sys.stdout=None
print=None

However, even this has a very easy workaround:

del print
a,b=int(input()),int(input())
print(a+b)

As a cop, your goal is to make the hidden workaround as obscure as possible, to prevent the robbers from finding it.

The robbers will look at one of your answers, and attempt to crack it. They may crack it by writing any valid snippet that could work as snippet 2 (adding two numbers together after the language is made mostly unusable). This does not have to be the same snippet as you originally intended. If a robber cracks your answer, they will leave a comment on your answer, and then you should edit it to indicate that it has been cracked. If your post is cracked, you should edit your answer to show the solution (snippet 2) that you originally intended. This isn't a rule per se, just a friendly suggestion to keep the game fun. You do not have to.

If an answer remains uncracked for one whole week, you can edit in your second snippet, and indicate that your answer is now safe. If you do not edit it after the week is up, other users can still crack it until you do. If you do not reveal your second snippet, you cannot claim points for your answer, or call it safe.

The winner of the cops' thread is the shortest safe answer including both snippets, counted in bytes, and this answer will be accepted after sufficient time has passed. You do not need to reveal your byte count until your answer is safe, since byte count is irrelevant to your score until your answer is safe. In the event that sufficient time has passed and no answers remain uncracked, the winner will be the answer that remained uncracked for the longest period of time.

Have fun!

Rule clarifications

  • The first snippet must run correctly without taking any input. It may output whatever you like, and this output will be ignored - as long as after the snippet is done, the second snippet runs correctly.

  • The second snippet must actually be executed for your answer to be valid. This means an answer like

    import sys
    sys.exit()
    

    is not valid because it doesn't break the language. It simply quits. Similarly, entering an infinite loop is not valid, since the second snippet will never be executed.

  • After being safe, your score is the byte count of both snippets.

  • This goes back to Please reveal any strange edge cases required for your answer to work... Your submission must contain enough information before being revealed to be reproducible after being revealed. This means that if your answer becomes safe, and then you edit in: Here's my answer. Oh ya, BTW this only works if you run it on Solaris, joke's on you! your answer is invalid and will be deleted and not considered eligible for winning.

  • The second snippet is allowed to crash after outputting the sum - as long as the output is still correct (for example, if you choose to output to STDERR, and then you get a bunch of crash information, this is invalid).

  • You may not edit your code after submitting an answer.

  • You may not rely on cryptographic functions like encryption, hash functions, CSPRNGs etc.

Snippet to find uncracked submissions:

<script>site='meta.codegolf';postID=5686;isAnswer=false;QUESTION_ID=133174;</script><script src='//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'></script><script>jQuery(function(){var u='//api.stackexchange.com/2.2/';if(isAnswer)u+='answers/'+postID+'?order=asc&sort=creation&site='+site+'&filter=!GeEyUcJFJeRCD';else u+='questions/'+postID+'?order=asc&sort=creation&site='+site+'&filter=!GeEyUcJFJO6t)';jQuery.get(u,function(b){function d(s){return jQuery('<textarea>').html(s).text()};function r(l){return new RegExp('<pre class="snippet-code-'+l+'\\b[^>]*><code>([\\s\\S]*?)</code></pre>')};b=b.items[0].body;var j=r('js').exec(b),c=r('css').exec(b),h=r('html').exec(b);if(c!==null)jQuery('head').append(jQuery('<style>').text(d(c[1])));if (h!==null)jQuery('body').append(d(h[1]));if(j!==null)jQuery('body').append(jQuery('<script>').text(d(j[1])))})})</script>

\$\endgroup\$
11
  • 3
    \$\begingroup\$ What should be done for languages like C? Concatenation only allows for one "main snippet", and any logic is going to have to go there. E.g., if I have int main(){ do_evil_stuff(); } where should the users code go? In a function? After all the statements in main? \$\endgroup\$ Jul 19, 2017 at 0:34
  • 1
    \$\begingroup\$ Can the second snippet be placed anywhere in the first snippet? \$\endgroup\$ Jul 19, 2017 at 2:51
  • 1
    \$\begingroup\$ I know nothing about coding, but this challenge looks amazing, \$\endgroup\$ Jul 19, 2017 at 14:04
  • 2
    \$\begingroup\$ I edited in jimmy23013's awesome snippet. Feel free to revert, but I was using it myself anyway to find submissions and thought it might help others. \$\endgroup\$ Jul 20, 2017 at 18:13
  • 2
    \$\begingroup\$ @DomHastings That's extremely helpful! Thank you very much :) \$\endgroup\$
    – DJMcMayhem
    Jul 20, 2017 at 18:14

46 Answers 46

21
\$\begingroup\$

Haskell, cracked by Christian Sievers

import Prelude(getLine,print)
a=a

Full program, reading two integers (including negative ones) from stdin and writing to stdout.

I've just disabled the Prelude so almost nothing is in scope, and then added a definition; further imports are syntactically invalid. I gave you getLine and print though.


Edited to add my original solution. Christian's crack was different, but exploits the same basic features (you can get a surprising amount of computation done by accessing functions that have syntactic sugar, even when you can't call anything builtin directly or even name the types involved).

import Prelude(getLine,print)
a=a
(x:l)!0=x
(x:l)!n=l!d[0..n]
d[x,y]=x
d(x:l)=d l
x^y=[x..]!y
x+y=f[0..y](x^y)(-((-x)^(-y)))
f[]x y=y
f _ x y=x
f.g= \x->f(g x)
f&0= \x->x
f&n=f.(f&d[0..n])
x*y=((+x)&y)0
x%[]=x
x%('-':s)= -(x%s)
x%(c:s)=x*10+i c%s
i c=l['1'..c]
l[]=0
l(x:s)=1+l s
main=do
 x<-getLine
 y<-getLine
 print((0%x)+(0%y))

Which probably isn't super-golfed anyway, but here it is more readibly:

import Prelude(getLine,print)
a=a

-- List indexing
(x : _) !! 0 = x
(_ : xs) !! n = xs !! (sndLast [0..n])

-- sndLast [0..n] lets us decrement a positive integer
sndLast [x, _] = x
sndLast (_ : xs) = sndLast xs

-- Pseudo-addition: right-operator must be non-negative
x +~ y = [x..] !! y

-- Generalised addition by sign-flipping if y is negative
x + y = switch [0..y] (x +~ y) (-((-x) +~ (-y)))
  where switch [] _ empty = empty   -- [0..y] is null if y is negative
        switch _ nonempty _ = nonempty

f . g = \x -> f (g x)

-- compose a function with itself N times
composeN f 0 = \x -> x
composeN f n = f . (composeN f (sndLast [0..n]))

-- multiplication is chained addition
x * y = composeN (+x) y 0

strToNat acc [] = acc
strToNat acc ('-' : cs) = -(strToNat acc cs)
strToNat acc (c : cs) = strToNat (acc * 10 + charToDigit c) cs

charToDigit c = length ['1'..c]

length [] = 0
length (_ : xs) = 1 + length xs

main = do
  x <- getLine
  y <- getLine
  print (strToNat 0 x + strToNat 0 y)
\$\endgroup\$
1
18
\$\begingroup\$

Python 2, Cracked

Implements addition as a named function

import sys
c="".join(open(__file__).read().split('\n')[4:])
if set(c)-set(' &)(,.:[]a`cdfijmonrt~')or"import"in c:sys.setrecursionlimit(1)
f=lambda\

Try it online!

What does this do?

For the purposes of helping you out a bit I'll explain what this does. This code opens the source file and checks if the remainder of the code fits the following criteria:

  • Does not contain the string import
  • Is made solely of the characters &)(,.:[]a`cdfijmonrt~

If it fails either criterion the recursion limit is set to 1 meaning that any code you write will hit the recursion limit.

There are no tricks here, I have written a solution that uses only these characters and no imports, I'm not doing anything subversive, but I will say that I think this will be pretty hard to crack.

To save you some time here is a short list of useful things you cannot do with this restriction

  • + well duh,

  • eval/exec Wasn't going to let you get away with that

  • Numbers, They might be more useful than you think

  • String literals

  • len

  • =, No assigning variables

  • >,<,==. . . I have left you with no comparisons

  • *,-,/,%,^,|,>>,<< The only operators available are ~ and &

  • __foo__, None of those fancy double underscore methods are allowed.

\$\endgroup\$
9
  • 1
    \$\begingroup\$ Wow this is quite evil. Nice! \$\endgroup\$
    – hyper-neutrino
    Jul 19, 2017 at 1:24
  • \$\begingroup\$ Fantastic answer to kick things off :) \$\endgroup\$
    – DJMcMayhem
    Jul 19, 2017 at 1:33
  • \$\begingroup\$ Hehe, this just might have been inspired by that dumb king-of-the-hill challenge I tried to spec out in chat that one time \$\endgroup\$
    – Stephen
    Jul 19, 2017 at 1:37
  • 4
    \$\begingroup\$ I think this is a valid crack: codegolf.stackexchange.com/a/133209/68942 \$\endgroup\$
    – hyper-neutrino
    Jul 19, 2017 at 2:03
  • \$\begingroup\$ RE the first snippet: This code is not allowed to crash or exit. (see chat for discussion on it) \$\endgroup\$
    – Stephen
    Jul 19, 2017 at 2:18
13
\$\begingroup\$

Python 2, Cracked

This is the fourth iteration of this answer. Each of the last answers has was cracked via reseting the recursion depth.

Implements addition as a named function

import sys
if set("".join(open(__file__).read().split('\n')[4:]))-set(' &)(,.:[]a`cdfijmonrt~'):sys.setrecursionlimit(1)
for m in sys.modules:sys.modules[m]=None
del sys;f=lambda\

Try it online!

What does this do?

For the purposes of helping you out a bit I'll explain what this does. This code opens the source file and checks if the remainder of the code is made solely of the characters &)(,.:[]a`cdfijmonrt~

If it fails the recursion limit is set to 1 meaning that any code you write will hit the recursion limit.

I've also disabled all of the modules, so you can't import anything.

There are no tricks here, I have written a solution that uses only these characters and no imports, I'm not doing anything subversive, but I will say that I think this will be pretty hard to crack.

To save you some time here is a short list of useful things you cannot do with this restriction

  • + well duh,

  • eval/exec Wasn't going to let you get away with that

  • Numbers, They might be more useful than you think

  • String literals

  • len

  • =, No assigning variables

  • >,<,==. . . I have left you with no comparisons

  • *,-,/,%,^,|,>>,<< The only operators available are ~ and &

  • __foo__, None of those fancy double underscore methods are allowed.

My solution

So now that xnor has cracked it in a way I am sufficiently satisfied with I am going to reveal my solution

r,o:(o and f(~(~r&~o)&~(r&o),int(`r`[:r&~r].join([`dict()`[r&~r],`r&~r`,`dict([(r&~r,r&~r)])`[int(`~([]in[[]])`[[]in[[]]:])],`min`[[]in[[]]],`dict()`[~(r&~r)],`r&~r`]).format(r&o),int(`~([]in[[]])`[[]in[[]]:]))))or r

Surprise, surprise its a hulking pile of gibberish. Rather than break this down I'm going to go through the process of how I made this.

I started with a pretty standard addition algorithm

r,o:(o and f(r^o,r&o<<1))or r

Then I used a bitwise trick for representing ^ with |,&,~.

r,o:(o and f((r|o)&~(r&o),r&o<<1))or r

I used another bitwise trick to get rid of the |

r,o:(o and f(~(~r&~o)&~(r&o),r&o<<1))or r

Now all thats left is the <<, shouldn't be too hard, right? Well get ready for a bumpy ride. To replace the bitshift I used strings to append a zero to the end of its binary representation

r,o:(o and f(~(~r&~o)&~(r&o),int(bin(r&o)[2:]+"0",2)))or r

This has a few problems but the primary one is using addition, so I worked around this by using a format instead

r,o:(o and f(~(~r&~o)&~(r&o),int("{}0".format(bin(r&o)[2:]),2)))or r

We are not allowed to use bin, so I used string formatting to convert to binary.

r,o:(o and f(~(~r&~o)&~(r&o),int("{0:b}0".format(r&o),2)))or r

Since string literals are forbidden I have to build the string {0:b}0 out of parts made with back ticks and join them together.

r,o:(o and f(~(~r&~o)&~(r&o),int("".join(["{","0",":","b","}","0"]).format(r&o),2)))or r

The empty string is pretty easy, you can just do

`r`[:0]

The zeros were

`0`

and the {:} were all grabbed from dictionaries.

r,o:(o and f(~(~r&~o)&~(r&o),int("".join([`dict()`[0],`0`,`dict([(0,0)])`[2],"b",`dict()`[-1],`0`]).format(r&o),2)))or r

b seems pretty hard to get, its not in our character set, so how are we supposed to get an object that has a b in its repr? Well here's how: When you use repr on a builtin function you get something that looks like

<built-in function name>

And thats from where we'll get our b.

r,o:(o and f(~(~r&~o)&~(r&o),int("".join([`dict()`[0],`0`,`dict([(0,0)])`[2],`min`[1],`dict()`[-1],`0`]).format(r&o),2)))or r

Now all thats left are numbers, I only need -1, 0, 1, and 2 so here's how I represented them:

-1 = ~(r&~r)
 0 = r&~r
 1 = []in[[]]
 2 = `~([]in[[]])`[[]in[[]]:]

2 could actually be a byte shorter as

```r&~r```.find(`r&~r`)

based on @Blender's suggestions in the comments, but I didn't think of this until after the fact.

So we substitute these numbers in

r,o:(o and f(~(~r&~o)&~(r&o),int(`r`[:r&~r].join([`dict()`[r&~r],`r&~r`,`dict([(r&~r,r&~r)])`[int(`~([]in[[]])`[[]in[[]]:])],`min`[[]in[[]]],`dict()`[~(r&~r)],`r&~r`]).format(r&o),int(`~([]in[[]])`[[]in[[]]:]))))or r

And thats the crack.

\$\endgroup\$
17
  • \$\begingroup\$ This snippet seems to error on its own. \$\endgroup\$
    – ATaco
    Jul 19, 2017 at 5:22
  • \$\begingroup\$ @ATaco I believe this was discussed in chat and it was decided that this was ok. \$\endgroup\$
    – Wheat Wizard
    Jul 19, 2017 at 5:23
  • \$\begingroup\$ Rules explicitly state otherwise. "This code is not allowed to crash or exit." \$\endgroup\$
    – ATaco
    Jul 19, 2017 at 5:24
  • \$\begingroup\$ @ATaco Here's the message he said he would update it when he got the chance. \$\endgroup\$
    – Wheat Wizard
    Jul 19, 2017 at 5:26
  • 5
    \$\begingroup\$ Cracked? \$\endgroup\$
    – xnor
    Jul 19, 2017 at 10:03
11
\$\begingroup\$

Haskell, cracked by Ben

main=main--

Try it online! This should be a full program reading two numbers from stdin and outputting the sum to stdout.

Each full program starts by running the main function, but here main calls itself and causes an infinite loop. To make matters worse, a line comment is started with -- directly behind the recursive call to prevent changing it to e.g. main2 and then defining that to do the summation.


Intended solution:

main=main--$()
_ --$ _ = do
     x <- readLn
     y <- readLn
     print $ x+y

Try it online!

-- starts a line comment unless it can also be parsed as part of an operator. (The syntax highlighting seems to be unaware of this fact.) --$ is a valid infix operator which takes main as first argument and some dummy second argument (). It is then defined to ignore both arguments and to perform the required task instead.

\$\endgroup\$
3
  • 2
    \$\begingroup\$ Cracked it: codegolf.stackexchange.com/a/133244/17061 \$\endgroup\$
    – Ben
    Jul 19, 2017 at 6:42
  • 5
    \$\begingroup\$ you can just add "where main = ..." \$\endgroup\$
    – michi7x7
    Jul 19, 2017 at 7:20
  • \$\begingroup\$ +1 for a Haskell solution that only works because of Haskell's lazy evaluation. \$\endgroup\$
    – Jules
    Jul 20, 2017 at 17:38
10
\$\begingroup\$

C (gcc) Cracked!

#define D(f)void f(void);
D(printf)D(fprintf)D(putc)D(puts)D(getchar)D(putc)D(fputc)D(ferror)D(feof)D(read)D(fclose)D(fread)D(wr1te)D(fgets)D(fgetc)D(popem)D(gets)D(read)D(scanf)D(setbuf)D(execl)D(execlp)D(putchar)D(execle)D(execv)D(malloc)D(execvp)D(execvpe)D(exec)D(system)D(close)D(fwrite)D(open)D(free)
int stdin;
int main(){
//your code goes here...hehe
}

Try it online!

Input from STDIN and output to STDOUT.

This runs without error. Hahaha this is quite evil. I've only tested it on TIO's gcc. Per usual, you must append your code after this snippet in order for it to work :) The comment is a mean one, don't listen to it.

Tested on gcc (GCC) 6.3.1 20161221 (Red Hat 6.3.1-1). Should work on any linux system.

Original solution

#define D(f)void f(void);
D(printf)D(fprintf)D(putc)D(puts)D(getchar)D(putc)D(fputc)D(ferror)D(feof)D(read)D(fclose)D(fread)D(wr1te)D(fgets)D(fgetc)D(popem)D(gets)D(read)D(scanf)D(setbuf)D(execl)D(execlp)D(putchar)D(execle)D(execv)D(malloc)D(execvp)D(execvpe)D(exec)D(system)D(close)D(fwrite)D(open)D(free)
int stdin;
int main(){
//your code goes here...hehe
}
void __attribute__ ((destructor)) dtor() {
    int a,b,c,d;a=b=c=0;
    struct FILE* z = popen("cat", "r");
#define q(x)for(;(c=getc(z))^32&&c^-1;)x=10*x+c-48;
q(a);q(b);
    char*y=calloc(c=a+b,1);
    for(a=0;c;){y[a++]=(48+(c%10));c=c/10;}
    for(b=0;b<a/2;b++){d=y[b];y[b]=y[a-b-1];y[a-b-1]=d;}
    write(1,y,a);
}
\$\endgroup\$
8
  • \$\begingroup\$ @LegionMammal978 Ah yes \$\endgroup\$ Jul 19, 2017 at 2:38
  • 2
    \$\begingroup\$ Specify your platform! \$\endgroup\$
    – Joshua
    Jul 19, 2017 at 2:48
  • \$\begingroup\$ @Joshua I have added some information \$\endgroup\$ Jul 19, 2017 at 3:02
  • 4
    \$\begingroup\$ cracked \$\endgroup\$
    – Dennis
    Jul 19, 2017 at 3:23
  • \$\begingroup\$ Well, __asm__ and you have plenty of functions to choose from :) don't think C and C++ are good enemies here. \$\endgroup\$
    – edmz
    Jul 19, 2017 at 13:07
10
\$\begingroup\$

C (GCC on Linux) (cracked)

Instead of using silly file-reading sandboxing techniques, we do it the proper way - with SECCOMP whitelisting!

Your task: implement addition with input from STDIN and output to STDOUT.

#include <stdlib.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <linux/seccomp.h>
#include <syscall.h>
#include <stdio.h>
void sandbox();
__attribute__ ((constructor(0))) int s() {
    close(0);
    close(1);
    close(2);
    prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
}
int main() {
    sandbox();
    syscall(SYS_exit, EXIT_SUCCESS);
}
void sandbox() {
    // Your code here!
}

Try it online!

WTF is this!?

To help you in your insurmountable task I'll explain what this code does.

__attribute__ ((constructor(0))) ensures the s function is run first. The function closes all open file descriptors for STDIN, STDOUT and STDERR. Then the program restricts itself with a strict SECCOMP whitelist, which limits your system calls to the following:

read(2)
write(2)
_exit(2)
sigreturn(2)

Therefore you cannot open any new files (or basically do anything). We then come to main and call your code, nicely wrapped in the sandbox function.

The syscall(SYS_exit, EXIT_SUCCESS); at the end is just to ensure the program exits cleanly - by default GCC will exit with exit_group(2) which is not allowed by the SECCOMP whitelist. This exiting function is called after your code is run.

So you have no open file descriptors, and you can't open anything new. Impossible, right? ;)

\$\endgroup\$
1
8
\$\begingroup\$

x86 16 bit real mode Assembly (Cracked)

_main:
    call l
    cli
    hlt
l:  pop si
    xor ax, ax
    mov bp, cs
    mov es, ax
    mov di, 12
    mov [di], si
    mov [di + 2], bp
    pushf
    mov bp, sp
    or word [bp], 256
    popf

Easy if you know the trick.

\$\endgroup\$
11
  • 1
    \$\begingroup\$ How are you taking the input? On the stack, or in registers? (Also, it looks like this is supposed to be 16-bit assembly, but if so, or [bp], 256 is invalid. Is that supposed to be or WORD PTR [bp], 256?) \$\endgroup\$ Jul 19, 2017 at 8:10
  • 1
    \$\begingroup\$ Also, you should specify which processor you're using; there's lots of x86 versions and clones out there, and lots of undefined instructions. If I wrote code for an "obscure 80186 clone" that just so happened to have an undefined instruction that took a few arguments and blah blah blah... We also might need environment. 16 bit Windows gave an SS==DS guarantee that other systems might not, for example. \$\endgroup\$
    – Orion
    Jul 19, 2017 at 9:06
  • 1
    \$\begingroup\$ You only need to specify which processor if you actually are using some trick that works only on one particular model (or one particular generation). This code isn't like that, so I think "x86-16" is sufficient. In my opinion, the more general the better. Agreed that real or protected mode should be specified, although the presence of the hlt instruction (ring 0) strongly implies that this is not protected mode. \$\endgroup\$ Jul 19, 2017 at 12:30
  • 3
    \$\begingroup\$ @Joshua if it doesn't work on every platform, you have to at least specify a platform it will work on, I believe. Your submission must contain enough information before being revealed to be reproducible after being revealed \$\endgroup\$
    – Stephen
    Jul 19, 2017 at 21:08
  • 1
    \$\begingroup\$ @StepHen: The solution to unbreak the language is platform agnostic once specified x86-16 real mode, but I/O is not platform agnostic. He who breaks out it may specify the OS for which he broke out. I added the _main label late so that someone could in theory make a nearly agnostic break by linking against libc. \$\endgroup\$
    – Joshua
    Jul 19, 2017 at 21:11
4
\$\begingroup\$

cQuents, cracked by Mayube

#|1,1:A

This should be fairly easy, but you never know.

The "problem" was that without C in your code, you got an error.

Mayube's solution:

#|1,1:A+BC

Each item in the sequence is the first input plus the second times the third (aka 1)

My solutions:

#1,1:A+B,C

The sequence cycles between the first input plus the second input, and the third input (1). The first item in the second is A+B.

#1,1:A+B+C-C

Similar to Mayube's solution - instead of multiplying B*C, just adds C and then subtracts it.

Try it online!

Explanation

#|1,1      Append 1 and 1 to the end of the user's input
     :     Set mode to : (sequence 1: if given n, output nth term in sequence; if given no n, output whole sequence)
      A    Each item in the sequence equals the first input

Currently, this program outputs 1, since with no user input, the first input is the first 1 in the default input (#).

\$\endgroup\$
8
  • \$\begingroup\$ The docs seem really awkwardly worded, I can't for the life of me figure out what it means when it says Default input is combined with user input to form the total input, which must align with the expected input (which is based on the highest input requested by the Sequence Definition) \$\endgroup\$
    – Mayube
    Jul 19, 2017 at 14:49
  • \$\begingroup\$ @Mayube it's weird, I need to find a way to say it correctly. Basically, your input to the program can be equal to the highest input queried by variables A,B,C,D,E in the code. For example, if at any point you have the variable D in your program, the parser expects there to be 4 inputs, but if there is also an E, the parser expects there to be 5 inputs. There cannot be less than the expected amount. However, there is always an optional last input, n, which is used in different ways by different modes. \$\endgroup\$
    – Stephen
    Jul 19, 2017 at 14:55
  • \$\begingroup\$ @Mayube the snippet I posted above contains an A, so it looks for one input. Since there are two, both coming from # which specifies default input, it uses the first one as A's value and the second one as n. \$\endgroup\$
    – Stephen
    Jul 19, 2017 at 14:56
  • \$\begingroup\$ So if I were to give 2 inputs, and append BC, A would be the first input, B would be the second, C would be 1, and n would be the second 1? \$\endgroup\$
    – Mayube
    Jul 19, 2017 at 15:12
  • \$\begingroup\$ @Mayube exactly, sorry for my crappy docs. TMI: if the beginning looked like #1,1 (no bar), it would be: A as the first 1, B as the second 1, C as the first input, and n as the second input. You can also do #1|1, where A is the first 1, B is is the first input, C is the second input, and n is the second 1. \$\endgroup\$
    – Stephen
    Jul 19, 2017 at 15:15
4
\$\begingroup\$

Javascript, Cracked

This challenge builds off of Grant Davis's, but fixes the solution he had in mind (which creates an iframe and uses the iframe's window). The solution runs in the javascript console on chrome's about:blank page, and takes two input()s, adds them together, and console.logs the result. Put your code after:

d=prompt=console=document;new MutationObserver(s=>s.forEach(e=>{t=e.target;t.parentNode.removeChild(t)})).observe(d,{"childList":d, "subtree":d})

First, we clobber prompt and console and set the shortcut d. Then, we create a mutation observer with a callback which removes every target mutated. We set that mutation observer to observe the document, and notify on childList and subtree modifications. Instead of the literal true, we use our shortcut to the truthy value document (the spec doesn't allow this, but chrome does).

After I posted this, I realized a much more elegant clobber. My intended solution still works, but the crack posted does not:

 h=document.querySelector("html");h.parentNode.removeChild(h);
\$\endgroup\$
2
4
\$\begingroup\$

Perl 5, cracked by Ilmari Karonen

$_=<DATA>;
s/[+'{dPz|K.UD!_ iJ;o}e6tjWb7253k@%&Iq4l0AN:?\$8B`Yywn9^pfmZQTF"M#-]//g;
eval;
print@_,$!,pop,shift,<>,eval"@>",$\,@ARGV,eval"@$",$@,eval"@@",$,,eval"@,",$/
__DATA__

Input is received on separate lines of STDIN and output is printed to STDOUT.

All code goes after the __DATA__ marker. This uses a similar method to @WheatWizard's solution in that the code is parsed and unusable chars are removed.

This has been tested on versions 5.8, 5.10 and 5.16, and requires no command-line flags.

Try it online!

\$\endgroup\$
3
  • 2
    \$\begingroup\$ Could you please specify the input/output method and format? \$\endgroup\$ Jul 19, 2017 at 21:44
  • \$\begingroup\$ @IlmariKaronen Apologies, it's STDIN with chars on separate lines and STDOUT. I'll add this to the main body. \$\endgroup\$ Jul 20, 2017 at 4:37
  • \$\begingroup\$ Cracked, I think. \$\endgroup\$ Jul 20, 2017 at 23:22
4
\$\begingroup\$

Python 3, cracked by zbw

import sys
for mod in sys.modules.values():mod.__dict__.clear()
1+1

All modlues have been deleted, which means there are no builtins available and not much else can be done. Output to STDOUT, input from STDIN. This is the second iteration of this answer after the previous one was broken by a trivial crack by adding a break statement.

\$\endgroup\$
4
  • \$\begingroup\$ I'm really curious to see the snippet that works after this \$\endgroup\$
    – user52452
    Jul 21, 2017 at 1:50
  • \$\begingroup\$ Well, you have to wait seven days or for a non-trivial crack, whichever comes first ... \$\endgroup\$ Jul 21, 2017 at 2:19
  • \$\begingroup\$ Cracked! \$\endgroup\$
    – zbw
    Jul 21, 2017 at 17:55
  • \$\begingroup\$ Well, well, challenges like these are very difficult to do well \$\endgroup\$ Jul 21, 2017 at 19:23
4
\$\begingroup\$

APL (ngn-apl), cracked by ngn

Made in cooperation with my colleague Marshall.

Input through left and right arguments to +. I.e. your goal is to insert code after the the following, so that your last line reads ⎕←3+2 and outputs 5 to STDOUT.

+←-←−←⍴←≢←≡←⊥←⊤←⍟←○←⍳←⌹←~←∈←∊←⍷←<←≤←=←≥←>←≠←,←⍪←⌷←⌽←⍉←⊖←{}⋄⍣←∘

Try it online!

Works by setting all useful functions to {} which takes one or two arguments and returns an empty numeric list. Also sets to just compose functions.


Crack

+←{⌈/⍋⍺⍵1/0}

⍺⍵1/0 replicate 0 by the left argument and the right argument and 1

 get the indices that would sort that (since all elements are zero, it gives 0 1 2…(a+b)

⌈/ the maximum value (a+b)

\$\endgroup\$
1
  • \$\begingroup\$ ngn/apl includes the ability to execute arbitrary JavaScript. I do not consider such a solution valid, as it would then be about disabling JavaScript rather than APL. There is indeed a valid (albeit obscure) way to reset + using only pure APL and no dirty tricks. \$\endgroup\$
    – Adám
    Jul 19, 2017 at 20:51
3
\$\begingroup\$

Python 2, Cracked

This is the second iteration of an answer that has been cracked once by @HyperNuetrino using a method I had not expected. I've now patched it so hopefully the only solutions left will have to abide by the restrictions I intended.

Implements addition as a named function

import sys
c="".join(open(__file__).read().split('\n')[4:])
if set(c)-set(' &)(,.:[]a`cdfijmonrt~')or"import"in c:sys.setrecursionlimit(1)
sys.modules['sys'],sys.modules['os']=None,None;del sys;f=lambda\

Try it online!

\$\endgroup\$
8
  • \$\begingroup\$ I think I could do this if I had a u, but I'm stuck without it. \$\endgroup\$
    – isaacg
    Jul 19, 2017 at 3:21
  • \$\begingroup\$ @isaacg Just out of curiosity, what would you to with u? \$\endgroup\$
    – Wheat Wizard
    Jul 19, 2017 at 3:21
  • \$\begingroup\$ .count. I can get a string as long as the desired output, but I have no way to take its length. \$\endgroup\$
    – isaacg
    Jul 19, 2017 at 3:22
  • \$\begingroup\$ __import__('sys').setrecursionlimit(100)... and nothing actually got patched. I don't really feel like posting it in the robber's thread though, feels like cheating. Try it online \$\endgroup\$
    – Value Ink
    Jul 19, 2017 at 3:27
  • 2
    \$\begingroup\$ Cracked, I think? \$\endgroup\$
    – Sisyphus
    Jul 19, 2017 at 4:13
3
\$\begingroup\$

Java 8, Cracked by @OlivierGrégoire

Here's my attempt. Pretty much, the idea is to just overload all the namespaces you can use to output (and reflect, I hope). Output is intended to sdout (System.out).

class java {
    public static void main(String[]s){
       //there is no executable code in snippet one.
       //your code here.
    }
    class Class{}
    class Method{}
    class System{}
    class FileDescriptor{}
    class Logger{}
    class Runtime{}
    class Scanner{}
}

Blacklisting is typically a worse approach than whitelisting, so I'm sure it's just a matter of time before someone comes up with an approach I didn't consider.

\$\endgroup\$
12
  • 1
    \$\begingroup\$ This is not an executable class... \$\endgroup\$ Jul 19, 2017 at 14:26
  • 1
    \$\begingroup\$ @OlivierGrégoire Sorry about that, I added class String{} after testing without realizing it would knock out main(String[] ...). It should work now \$\endgroup\$ Jul 19, 2017 at 14:30
  • 1
    \$\begingroup\$ Yep, that'll do it, thank you! :) It doesn't change the crack I'm about to do, though :p \$\endgroup\$ Jul 19, 2017 at 14:33
  • 1
    \$\begingroup\$ Cracked! I really enjoyed this one :) \$\endgroup\$ Jul 19, 2017 at 14:57
  • 1
    \$\begingroup\$ I was looking at something like this (sorry it's hard to format code in comments), but I think your solution is much cleaner: int sum = 0; new Exception("" + sum) { public void printStackTrace() { ClassLoader cl = ClassLoader.getSystemClassLoader(); try { printStackTrace(new PrintStream((PrintStream)cl.loadClass("java.lang.System").getDeclaredField("out").get(null))); } catch (Exception e){} } }.printStackTrace(); \$\endgroup\$ Jul 19, 2017 at 15:24
3
\$\begingroup\$

Node.JS version 7.3.0 (Cracked by Dom Hastings)

var p=process,f;(_=>{var w=p.stdout.write,n='f'+(Math.random()*1e7|0),l=1
f=p.stdout.write=a=>eval(`(function ${n}(a){while(l&&((typeof a)[0]!='s'||'f'+a!=n));a=l?l="":a;w.apply(p.stdout,arguments);})`)(a)})();

Place the second code block after the first.

Disclaimer: the second code block will not function on its own (without being placed after the first). If this is not allowed however I can modify the second snippet.

This is a full program. Output is process.stdout (STDOUT), input is process.argv (command line arguments)

This is my first cops and robbers, hopefully this is a good challenge :)

Try it online!


The challenge explained

Generates a random variable n from 0 to 1e7. If you call write with the correct n, doesn't print anything but sets l to 0 which "unlocks" the write function, allowing you to print anything. If you try to call write with a non-string, sends you into an infinite loop. If you try to call write with anything other than the correct n while write is "locked", sends you into an infinite loop to prevent guessing.

The intended solution

Sneaks past the typeof that seemingly checks for strings only by using a Symbol, which also starts with s. This throws an error in the function resulting from the eval call because you can't add the string "f" to a Symbol. We catch the error and use regex to recover n from the stack trace, where it is in the function's name. Then we try to write n which doesn't print anything, but sets the "lock" variable l to 0 to "unlock" the write function. Now that the write function is unlocked we just print the sum.

try{f(Symbol())}catch(e){f(e.stack.match(/f(\d+)/)[1])
f(+p.argv[2]+ +p.argv[3]+"")}
\$\endgroup\$
2
  • \$\begingroup\$ Cracked! \$\endgroup\$ Jul 20, 2017 at 17:00
  • \$\begingroup\$ That's genius... I was on the right track originally then! Thanks for the brain training! \$\endgroup\$ Jul 20, 2017 at 18:06
3
\$\begingroup\$

RProgN2, Cracked by Arnold Palmer

"+-/*÷^"{²[[\=};

Writes over all the math operators, with no way to restore them. In particular, it replaces them with a function that removes the top two items on the stack.

Try it online!

Original Solution

{S]‘[L}`d={0RL}`i=«x=y=x{xd`x=yi`y=x}:y»`+=

{S]‘[L}`d={0RL}`i=«x=y=x{xd`x=yi`y=x}:y»`+=
{     }`d=                                  #Define a function, "d", which returns n-1
 S                                          #Convert the input to a stack, which, as a number, makes a stack of 1 - n.
  ]‘                                        #Duplicate the stack, and pop the top value off it.
    [                                       #Discard the popped'd value.
     L                                      #Get the length of the stack, which now is n-1.
          {   }`i=                          #Define a function, "i", which returns n+1
           0R                               #Get the range of numbers between 0 and n.
             L                              #Get the length of that stack, which is n+1
                  «                    »`+= #Define a function, "+", which takes two numbers, and outputs their sum. We use «» here, because it localises references, instead of globalising them.
                   x=                       #Set the first input to the value of "x", which by default, is x.
                     y=                     #Ditto for y.
                       x{          x}:      #While x is truthy, which in this case, is non-zero.
                         xd                 #Get x - 1
                           `x=              #Set x to it.
                              yi`y=         #And set y to y + 1
                                      y     #Push y to the output. And we're done.

Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ I'm going through your documentation and I can't seem to find what the ² symbol does. Care to enlighten me? \$\endgroup\$ Jul 19, 2017 at 17:31
  • \$\begingroup\$ That documentation is not incredibly relevant for RProgN2, and that symbol takes the next two concepts [[ in this case, and wraps them in a function @ArnoldPalmer \$\endgroup\$
    – ATaco
    Jul 19, 2017 at 21:25
  • \$\begingroup\$ Cracked \$\endgroup\$ Jul 20, 2017 at 13:03
  • \$\begingroup\$ Dang, that's much better. I didn't know about the stack operators, which sure would've been handy. Also, knowing «» creates local variables as opposed to messing up global ones would've been super helpful. \$\endgroup\$ Jul 21, 2017 at 10:32
3
\$\begingroup\$

Haskell, 161 144 bytes, Cracked by BlackCap

{-#OPTIONS_GHC -fth -w#-}
module M where

Input to STDIN, output to STDERR. Add to the end of the program.

Edit: Intended to be compiled with no extra GHC arguments, just the normal ghc --make prog.hs.

Edited again to lower the byte count.

Have fun!

\$\endgroup\$
6
  • \$\begingroup\$ So I cannot do this, because the main function won't be called? main = do x <- readLn :: IO Integer; y <- readLn; print $ x + y \$\endgroup\$
    – BlackCap
    Jul 22, 2017 at 0:11
  • \$\begingroup\$ @BlackCap No, because GHC expects the main function to be in the module Main when no -main-is flag is provided. \$\endgroup\$
    – zbw
    Jul 22, 2017 at 17:18
  • \$\begingroup\$ This does not work, but I want to share the idea anyways \$\endgroup\$
    – BlackCap
    Jul 23, 2017 at 23:49
  • \$\begingroup\$ I'll call that cracked. Here was my intended solution, golfed down. It doesn't work on TIO, because the wrapper doesn't send the input to the compiler. \$\endgroup\$
    – zbw
    Jul 24, 2017 at 1:54
  • \$\begingroup\$ If you post your solution, I'll mark it cracked. \$\endgroup\$
    – zbw
    Jul 24, 2017 at 1:55
3
\$\begingroup\$

Mascarpone, cracked by Ilmari Karonen

[ Make 'i' and 'z' print 'q' ]$
v ['q.]v* 'i<^
v ['q.]v* 'z<^

[ Disable some standard commands ]$
v[]v*   '1<^
v[]v*   '$<^
v[]v*   '@<^
v[]v*   '{<^
v[]v*   '}<^
v[<:]v* '<<^
v[]v*   'v<^$

Input is church numerals on stdio, using i for increment and z for zero. For instance, 2+3 would be:

iiziiiz

With a trailing newline

Output should be a number on stdout, in the same format as on stdio. For example, if the answer is five you should output:

iiiiiz

(mascarpone has no concept of numbers)


Intended solution:

: '[/''/'i/'./' /':/',/'>/'!/']/* 'i<^
: '[/':/',/'>/'!/']/* 'z<^
: ,>!
'z.

It is not immediately apparent from the documentation, but as @IlmariKaronen stated in his crack, string literals in Mascarpone are actually syntactic sugar for pushing a sequence of characters.

I deliberately wrote comments like [this]$ to make it look like I am pushing a string and popping it immediately afterwards. A naive cracker might have tried something like [:,>!]/* to push a string, swap it with the interpreter, and interpret it.

I also pretend to pop the interpreter I left on the stack with $, but $ has already been redefined to a NOP. You are left with this interpreter on the stack, and you have to carry it with you trough the entire program; trough each character of every string.

\$\endgroup\$
2
  • \$\begingroup\$ Cracked. And no, I'd never heard of Mascarpone before this challenge. \$\endgroup\$ Jul 25, 2017 at 22:14
  • \$\begingroup\$ @IlmariKaronen New favorite language? Good job! \$\endgroup\$
    – BlackCap
    Jul 25, 2017 at 23:16
2
\$\begingroup\$

Gforth 0.7.3 (TIO), 231 bytes [SAFE]

This code redefines as useless some necessary output methods, as well as addition and something crucial for declaring functions. Good luck!

: . ;
: dec. ;
: u. ;
: .r ;
: u.r ;
: d. ;
: ud. ;
: d.r ;
: ud.r ;
: emit ;
: type ;
: + postpone 2drop ;
: ; + + + postpone exit reveal postpone [ ;

Input will be two signed integers taken from the top of the stack as function parameters. Output to STDOUT.

So you should fix the damage done, and define a function that takes the top two values from the stack and prints the result as an integer (not a float) to STDOUT without additional output (no trailing space).

Here's a template, if your goal function is named f.

Solution:

79 bytes

I actually removed the immediate keyword from the end of the redefinition of ;, so it was necessary for an answer to include it at the start. The function I defined is mostly equivalent to the internal definition of ., but it doesn't print the space at the end, and the addition is performed first, by moving the numbers to the floating point stack and back.

immediate : f s>f s>f f+ f>d swap over dabs <<# #s rot sign #> (type) #>> 0 0 ;

Try it online

\$\endgroup\$
2
  • 1
    \$\begingroup\$ This is a very nice answer. At this rate, it looks like it might end up being the only uncracked answer! \$\endgroup\$
    – DJMcMayhem
    Jul 25, 2017 at 16:24
  • \$\begingroup\$ :) I combined a couple of different obstacles. At this point, I'm wondering if I could've done just a single one to make my score better. But it's possible that having more than one is why it's uncracked yet. \$\endgroup\$
    – mbomb007
    Jul 25, 2017 at 18:08
2
\$\begingroup\$

C# (.NET Core) Cracked by Ilmari Karonen

Also cracked by Joshua.

namespace System
{
    class Console
    {
        static void Main()
        {
            //Your code goes here
        }
    }
}

Reads the two values from stdin and writes the result to stdout. Tested on Windows with Framework Version 3, 4.6 and on TIO.

Here is the full program I had intended.

namespace System
{
    class Console
    {
        static void Main()
        {
            var t = Reflection.Assembly.Load("mscorlib").GetType("System.Console");
            var r = t.GetMethod("ReadLine");
            int a = int.Parse((string)r.Invoke(null, null));
            int b = int.Parse((string)r.Invoke(null, null));
            var w = t.GetMethod("WriteLine", new[] { typeof(int) });
            w.Invoke(null, new object[] { a + b });
        }
    }
}

Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ Cracked. \$\endgroup\$ Jul 19, 2017 at 17:44
  • \$\begingroup\$ codegolf.stackexchange.com/a/133412/14306 I assume this wasn't the intended solution. \$\endgroup\$
    – Joshua
    Jul 19, 2017 at 17:54
  • \$\begingroup\$ @IlmariKaronen: +1. This was the intended solution. \$\endgroup\$
    – raznagul
    Jul 20, 2017 at 7:35
  • \$\begingroup\$ @Joshua: +1 for finding a different solution than I had intended. \$\endgroup\$
    – raznagul
    Jul 20, 2017 at 7:38
2
\$\begingroup\$

GolfScript, cracked by Dennis

{}' !$%&()*+,-./<=>?@[\]^`|~'':'*~;

Try it online!

This is a challenge, after all, so why not try GolfScript?

A valid solution should be a snippet that reads two integers off the stack, adds them together and returns the result on the stack. The catch is that it should still work even after the code above has redefined almost all of the built-in GolfScript operators to do abolutely nothing. At least I left ; untouched, so you can still pop values off the stack. ;-) Your code should work on the standard GolfScript interpreter, as implemented e.g. on TIO (see link above).


Dennis' solution, like my own, relies on the rarely used feature of GolfScript that allows interpolated Ruby code in double quoted strings. We use this feature to define a new addition operator that works exactly like the built-in + operator, and then call it.

(One reason why the Ruby interpolation feature in GolfScript is so rarely used is that, awkwardly, the interpolated Ruby code is executed during parsing, and its output is cached by the GolfScript interpreter. Thus, if you e.g. have a string with interpolated Ruby code in a loop, the code will run only once before the actual program starts and thereafter always return the same value on every iteration of the loop. You can work around that using string eval to defer parsing, but that makes the already awkward syntax even more ugly and verbose, and in any case, for this challenge I disabled the eval operator ~, too. However, it turns out that defining new built-in GolfScript operators is one thing this feature actually does quite nicely and cleanly.)

\$\endgroup\$
3
  • \$\begingroup\$ Hint \$\endgroup\$ Jul 19, 2017 at 17:32
  • \$\begingroup\$ Cracked. Finally figured out what I was doing wrong. \$\endgroup\$
    – Dennis
    Jul 20, 2017 at 3:14
  • \$\begingroup\$ @Dennis: Yeah, you nailed it this time. FWIW, my intended solution was "#{var'_','gpush a+b'.cc2}";_, which works exactly like yours except for being a few bytes shorter. \$\endgroup\$ Jul 20, 2017 at 10:37
2
\$\begingroup\$

Node.js v8.2.0, Cracked by Dom Hastings

let mess = ctx => f => new Proxy (f, {
  has: (t, p) => p in t || p in ctx
, get: (t, p) => {
    let k = p in t? t[p]: ctx[p];

    if (k instanceof Function) return (
      function fetch (_k) {
        return mess (ctx) ( x => ( q => q instanceof Function
                                      ? fetch (q)
                                      : t (q)
                                  ) ( _k(x) )
                          )
      })(k);

    return k;
  }
});

with (mess (global) (x => x)) {
  dot   = f => a => b => f(a(b))
  ap    = f => g => x => f (x) (g (x))
  flip  = f => x => y => f (y) (x)
  Const = a => b => a
  id    = x => x
  num   = n => n (x => x + 1) (0)
  log   = console.log

  let x = flip (Const . id . id)
    , y = flip (Const . id . id . id)
  for (let i = 0; i < process.argv[2]; i++) x = ap (dot) (x)
  for (let i = 0; i < process.argv[3]; i++) y = ap (dot) (y)
  process.argv = [];

  logic = x => y => /* Your code here */;

  log . id . num ( logic (ap (dot) (x))
                         (f => z => (( y(flip (id) . id . flip (dot (id)) (f)) ) (Const (z))) (id) )
                 );
}

You are to implement the logic function. Input is the arguments provided (from stdin), output is whatever your function returns (is printed to stdout).


My code church encodes the numbers from the input. The rest of the code is just there to intimidate you.
The mess function does some trickery to implement point-free notation (a . b == dot (a) (b)), which I primarely use to add . id . to random places, which doesn't do anything, but will confuse anyone unfamiliar with functional programming.
The transformation applied to the numbers before I pass them to the logic function is x+1 and y-1, which adds up to 0, so it's another NOP to add to the obscurity.

The intended solution was:

logic = x => y => f => z => x (f) (y (f) (z))
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Cracked! \$\endgroup\$ Jul 20, 2017 at 17:36
  • \$\begingroup\$ @DomHastings That's not the intended solution, but I'm gonna say that you can, as long as the program halts without an exception, and doesn't print additional characters to the output \$\endgroup\$
    – BlackCap
    Jul 20, 2017 at 17:37
  • \$\begingroup\$ I've just posted an alternative! (You can see my previous solution in the history of that answer though!) \$\endgroup\$ Jul 20, 2017 at 17:37
  • \$\begingroup\$ Oh wow, I was a way off... Still that's better than my first very cheaty attempt! Thanks for the puzzle! \$\endgroup\$ Jul 20, 2017 at 17:43
2
\$\begingroup\$

Inform 7, cracked by ppperry

For reading a command: rule fails.

[Your code here.]

The input should be typed by the player as an interactive command, e.g. add 17 to 25 or sum 17 25. You're free to choose the exact form of the command that should be entered, as long as it includes two numbers. The sum of the numbers (e.g. 42) should be printed in response to the command.

The challenge, of course, is doing that while the entire "reading a command" activity is replaced by a no-op. There are probably several ways to solve this problem, but at least it should require some familiarity with the language. The one I came up with is actually quite simple, if a bit unexpected.

I've tested my solution in the GNOME Inform 7 IDE, version 6L38, on Ubuntu Linux. The intended solution works on both the Glulx and the Z-machine back-ends, and should work on other recent versions of Inform 7, too. Note that (without a suitable work-around) the code above will cause the interpreter to busy-loop when it tries to read a command; the Z-machine interpreter seems to become completely unresponsive when this happens, and can't be stopped from within the IDE, so I recommend using Glulx for testing.

\$\endgroup\$
1
  • \$\begingroup\$ cracked, and in case you were wondering, I had never heard of inform before this challenge \$\endgroup\$ Jul 21, 2017 at 22:30
2
\$\begingroup\$

CPython 3 (again), cracked by Sisyphus

import sys,os,functools
def p(f,e,a,_=os._exit):
 if e == "c_call":_(1)
sys.setprofile(p)

You can do anything you want -- as long as it isn't implemented in C. This means no print, no input -- all of those will hit the _(1) line and terminate. Input from STDIN with the numbers on two seperate lines, output to STDOUT. I wonder how long this is going to last ... Took me quite a while to find the second working snippet after coming up with this disabling trick. Explicitly specifying Cpython to avoid being cracked based non some alternative implementation of sys.setprofile.

\$\endgroup\$
4
  • \$\begingroup\$ Cracked. I have very little idea why this works. \$\endgroup\$
    – Sisyphus
    Jul 22, 2017 at 6:24
  • \$\begingroup\$ I guess I can ask now: why functools? \$\endgroup\$
    – Dennis
    Jul 22, 2017 at 6:29
  • \$\begingroup\$ @Dennis Because sispyphus discovered a loophole, not the intended solution \$\endgroup\$ Jul 22, 2017 at 12:14
  • \$\begingroup\$ @Sisyphus Your crack has been reported as a bug in python \$\endgroup\$ Jul 22, 2017 at 12:52
2
\$\begingroup\$

Java 8 (Cracked)

Second attempt. This time I invested two minutes of testing.

static {
    
    try {
        
        System.setIn(null);
        System.setOut(null);
        System.setErr(null);
        
        for (Method m : System.class.getMethods()) {
            
            m.setAccessible(false);
            
        }
        
        System.class.getMethod("getSecurityManager", new Class[0]).setAccessible(false);
        
        for (Method m : Class.class.getMethods()) {
            
            m.setAccessible(false);
            
        }
        
        SecurityManager mngr = new SecurityManager() {
            
            @Override
            public void checkPermission(Permission p) {
                
                if (p.getName().equals("createSecurityManager")) throw new SecurityException();
                if (p.getActions().startsWith("read")) throw new SecurityException();
                
            }
            
        };
        
        System.setSecurityManager(mngr);
        
        // Your code goes here.
        
    } catch (Throwable t) {
        
    }
    
}

Most things shouuuld be covered.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Would you please enclose this in a class with appropriate imports? It's the kind of challenge where this small changes can make or break an entry. I got several solutions for this one as is, but that reduces drastically if you simply enclose this in a class / interface. Also, format to remove all those while lines would be pretty nice for us, readers. \$\endgroup\$ Jul 19, 2017 at 13:47
  • \$\begingroup\$ There, a cracked answer using exactly your code. And a +1 because it seems I forgot it. Sorry. \$\endgroup\$ Jul 19, 2017 at 15:23
  • \$\begingroup\$ The #setAccessible(false) calls do nothing. \$\endgroup\$
    – Nevay
    Jul 19, 2017 at 21:48
1
\$\begingroup\$

Python 2 cracked

import sys,hashlib
c=open(__file__).read().split()[-1]
if c!='#'and hashlib.sha256(c).hexdigest()!='e6400dd63733d10ec042e3c28033cfa85e1d25fbef80020810c354d7c942e843':sys.exit() #

Try it online!

I'll preface this by saying this answer is a jerk move, intended as a lower-bound answer.


Inspired by Wheat Wizard's and HyperNeutrino's answers.

The snippet reads the source file and refuses to continue if the last whitespace-separated chunk of code does not sha256 into e6400dd63733d10ec042e3c28033cfa85e1d25fbef80020810c354d7c942e843.

EDIT: Edited slightly in response to this comment. The core problem does not change, any crack attempt is not invalidated.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ RE the first snippet: This code is not allowed to crash or exit. \$\endgroup\$
    – Stephen
    Jul 19, 2017 at 2:19
  • \$\begingroup\$ This is invalid because it exits, which is not allowed for the first snippet. \$\endgroup\$
    – DJMcMayhem
    Jul 19, 2017 at 2:40
  • 1
    \$\begingroup\$ cracked \$\endgroup\$
    – Dennis
    Jul 19, 2017 at 2:48
1
\$\begingroup\$

Java 8 Cracked by @OlivierGrégoire

I tried to make it as hard as possible! :) And, unlike the other Java answer so far, you'll have to follow the exact rules of the challenge, by placing it after this entire snippet (so no, you don't put your code in the public static void main(String[] args) method, you put it after the entire class. :) Good luck!

I've added comments to show what is being restricted.
(Inspired by this post, which is less restrictive and beatiable with the same approach I could use for my answer.)

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.FilePermission;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class Main {

  // Put everything in a static block so it is run before the static main method 
  // and any trailing (static) initializer-blocks:
  static {
    try {
      initializing();
    } catch (final Exception e) {
    }
  }

  static void initializing() throws Exception {
    // Overwrite System.out, System.err and System.in:
    System.setOut(new PrintStream(new ByteArrayOutputStream()));
    System.setErr(new PrintStream(new ByteArrayOutputStream()));
    System.setIn(new ByteArrayInputStream(new byte[0]));

    // Enable reflection for System.out, System.err and System.in:
    final Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    final Class<?> fdClass = java.io.FileDescriptor.class;
    final Field outField = fdClass.getDeclaredField("out");
    outField.setAccessible(true);
    modifiersField.setInt(outField, outField.getModifiers() & ~Modifier.FINAL);
    final Field errField = fdClass.getDeclaredField("err");
    errField.setAccessible(true);
    modifiersField.setInt(errField, errField.getModifiers() & ~Modifier.FINAL);
    final Field inField = fdClass.getDeclaredField("in");
    inField.setAccessible(true);
    modifiersField.setInt(inField, inField.getModifiers() & ~Modifier.FINAL);

    // Replace existing System.out FileDescriptor with a new (useless) one:
    outField.set(null, new FileDescriptor());
    // Replace existing System.err FileDescriptor with a new (useless) one:
    errField.set(null, new FileDescriptor());
    // Replace existing System.in FileDescriptor with a new (useless) one:
    inField.set(null, new FileDescriptor());

    // Disable reflection for System.out, System.err, System.in again:
    modifiersField.setInt(outField, outField.getModifiers() & ~Modifier.FINAL);
    modifiersField.setInt(errField, errField.getModifiers() & ~Modifier.FINAL);
    modifiersField.setInt(inField, inField.getModifiers() & ~Modifier.FINAL);
    inField.setAccessible(false);
    errField.setAccessible(false);
    outField.setAccessible(false);
    modifiersField.setAccessible(false);

    // Overwrite the SecurityManager:
    System.setSecurityManager(new SecurityManager() {

      private boolean exitAllowed = false;

      @Override
      public void checkExec(final String cmd) {
        throw new SecurityException();
      }

      @Override
      public void checkPermission(final java.security.Permission perm) {
        final String name = perm.getName();
        // You're not allowed to read/write files:
        if (name.equals("setIO") || name.equals("writeFileDescriptor")
            || name.equals("readFileDescriptor")
            || ((perm instanceof FilePermission) && name.startsWith("/proc/self/fd/"))) {
          throw new SecurityException();
        }
        // You're not allowed to overwrite the Security settings:
        if (name.equals("setSecurityManager") || name.equals("suppressAccessChecks")) {
          throw new SecurityException();
        }
        // You're not allowed to use reflection anymore:
        if (name.equals("getModifiers") || name.equals("get") || name.equals("set")
            || name.equals("setBoolean") || name.equals("setByte")
            || name.equals("setChar") || name.equals("setShort") || name.equals("setInt")
            || name.equals("setLong") || name.equals("setFloat") || name.equals("setDouble")
            || name.equals("setFieldAccessor") || name.equals("setFieldAccessor")) {
          throw new SecurityException();
        }
        // When you try to leave the current VM it will stop the program:
        if (name.startsWith("exitVM") && !this.exitAllowed) {
          this.exitAllowed = true;
          System.exit(0);
        }

        // You know what, nothing is allowed!
        throw new SecurityException("Mhuahahahaha!");
      }
    });
  }

  public static void main(String[] args) {
    // Overwritting all given arguments:
    args = new String[0];

    // Exit the program before you can do anything!
    System.exit(0);
  }
}

// Your code goes below:

Try it here. (ideone.com instead of TIO, since it doesn't seem to work there.. Testing has been done in the Eclipse IDE, but my intended solution does work if you use ideone.com)

\$\endgroup\$
1
1
\$\begingroup\$

Jelly: CRACKED

This will be insanely easy compared to Wheat Wizard's awesome Python answer, but here we go :P

“for c in code_page:
 if c in atoms:atoms[c].call=None”ŒVø<insert code snippet here>

The sha256 hexdigest of my workaround solution, including the first snippet, is cfeb1e193ad77f66f039c0d6a792a3e4c311490f6412698e019ca1fae10c0e0a.

Note

You may not have any newlines in the code except for strings otherwise this code will not even be run, which defeats the purpose of this challenge.

Cracked by DJMcMayhem

To be fair, this uses a newline, so I'd like to see a solution that doesn't use a newline.

Also a solution by Jonathan Allan

This doesn't use a newline, so it's been cracked. :P

My solution is this:

“for c in code_page:
 if c in atoms:atoms[c].call=None”ŒVø“print(int(input())+int(input()))”ŒV

The first snippet only deletes single character atoms which means that Python eval still works :)))

\$\endgroup\$
7
  • \$\begingroup\$ The second snippet is always appended to the end of the first snippet. \$\endgroup\$
    – Stephen
    Jul 19, 2017 at 1:38
  • \$\begingroup\$ @StepHen Just specifying :P But I forgot to add the note; that's really important. \$\endgroup\$
    – hyper-neutrino
    Jul 19, 2017 at 1:42
  • 3
    \$\begingroup\$ I don't think you can restrict the robbers like that. If you can crack it with Newlines, that's a valid crack. Is there anyway to prevent Newlines from being added, or forcing the first line to be executed? \$\endgroup\$
    – DJMcMayhem
    Jul 19, 2017 at 1:49
  • 2
    \$\begingroup\$ codegolf.stackexchange.com/a/133213/31716 \$\endgroup\$
    – DJMcMayhem
    Jul 19, 2017 at 2:49
  • 1
    \$\begingroup\$ I like your intended crack. Very sneaky. \$\endgroup\$
    – Dennis
    Jul 20, 2017 at 3:21
1
\$\begingroup\$

JavaScript, Cracked

Input: prompt() twice

Output: console.log()

My solution does not work in jsfiddle. Works on the about:blank page with Google chrome's JS console.

prompt=console=0

My solution:

x=document.createElement("iframe")
x.src="data:text/html,<script>console.log(prompt()-0+(prompt()-0))</script>"
document.body.appendChild(x)

Explanation:

I removed prompt and console by setting them equal to 0.

In my solution I create an iframe, which creates a sandbox, and a new instance of window where prompt and console work properly.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Cracked? \$\endgroup\$ Jul 19, 2017 at 15:49
  • \$\begingroup\$ @CRDrost I don't believe there is primality testing in the spec, and you don't show both snippets. \$\endgroup\$
    – Stephen
    Jul 19, 2017 at 21:21
  • \$\begingroup\$ Sorry, you're right, I misread. \$\endgroup\$
    – CR Drost
    Jul 19, 2017 at 21:45
1
\$\begingroup\$

Java, Cracked

import java.lang.reflect.*;
public class Main{
  public static void main(String... args){
    System.setOut(null);
    System.setErr(null);
    /*Your code here*/
  }
}

This should be was very easy to crack.

Intended solution

import java.lang.reflect.*;
public class Main{
public static void main(String... args){
  System.setOut(null);
  System.setErr(null);
  try{
    Class<?> cistream = Class.forName("java.io.InputStream");
    Class<?> cfostream = Class.forName("java.io.FileOutputStream");
    Class<?> costream = Class.forName("java.io.OutputStream");
    Class<?> cfdescriptor = Class.forName("java.io.FileDescriptor");
    Object sout = cfostream.getConstructor(cfdescriptor).newInstance(cfdescriptor.getField("out").get(null));
    Class<?> csys = Class.forName("java.lang.System");
    Field mod = Field.class.getDeclaredField("modifiers");
    mod.setAccessible(true);
    Field stdout = csys.getField("out");
    mod.set(stdout,Integer.class.cast(mod.get(stdout) )&~ Modifier.FINAL);
    stdout.set(null,Class.forName("java.io.PrintStream").getConstructor(costream).newInstance(sout));
    Class<?> cscanner = Class.forName("java.util.Scanner");
    Object scanner = cscanner.getConstructor(cistream).newInstance(System.in);
    Method nextInt = cscanner.getMethod("nextInt");
    int f = Integer.class.cast(nextInt.invoke(scanner));
    int s = Integer.class.cast(nextInt.invoke(scanner));
    int sum = s + f;
    System.out.println(sum);
  }catch(Throwable t){t.printStackTrace();}
  }
}

Try it online

\$\endgroup\$
4
  • \$\begingroup\$ I think this is valid \$\endgroup\$
    – Salem
    Jul 19, 2017 at 9:17
  • \$\begingroup\$ I totally forgot about java.io.. But you got the intended solution anyways.. \$\endgroup\$ Jul 19, 2017 at 9:35
  • \$\begingroup\$ I don't see any problem here. I actually wrote the second snipet just forgot to edit it on. According to TIO the first snipppet compiles without any warning. \$\endgroup\$ Jul 19, 2017 at 13:12
  • \$\begingroup\$ @OlivierGrégoire Done. I think any IDE will yell at me for this but I at least the compiler accepts it... \$\endgroup\$ Jul 19, 2017 at 16:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.