35
\$\begingroup\$

Inspired by this challenge, which got closed. This is meant to be an easier, but no less interesting version of that.

This is the cops thread of a challenge. For the robbers thread, see here.

Cops will provide a program/function and a flag. Robbers will try to guess a password such that, when the password is given to the cop's program, the flag is outputted.

Basic rules

  • The language used should be provided.
  • The flag, which can be an integer, string, or value of any other type, should be provided.
  • The flag may be printed to STDOUT, returned from a function, or outputted using any of the other standard output methods, as long as you specify how it will be outputted.
  • The program/function can take the password through STDIN, as a function argument, or using any of the other standard input methods, as long as you specify how the it will be inputted.
  • A free online compiler/interpreter should also be linked, preferably with the cop's code already pasted in and ready to run.

Some more rules

  • There must be at least one valid password that causes your program to return the flag, and you should know at least one of those passwords when posting your answer.
  • In case of a function submission, the cop should also include a full runnable program including the function either in the answer or in the linked online compiler/interpreter.
  • If it is at all ambiguous what the type of the flag is, it must be specified.
  • If a cop's description of the output is ambiguous (e.g. "HashSet(2, 1) should be printed"), robbers are allowed take advantage of that (e.g. print the string "HashSet(2, 1)" instead of an actual hashset)
  • Forcing robbers to simply brute force the password is not allowed.
  • The program must take input, and must output the flag when given the correct password. When not given the correct password, you are free to error, output something else, or immediately terminate. If your program never halts if given the wrong password, you must tell robbers of this behavior so no one waits around for the program to output something.

Cops's score will be the number of bytes their code takes up.

Cop answers will be safe if they haven't been cracked for two weeks.

Example

Cop:

Scala, 4 bytes

x=>x

Flag: Yay, you cracked it! (an object of type String is returned from the lambda above) Try it online!

Robber:

Password: the string "Yay, you cracked it!" Try it online!

Find Uncracked Cops

<script>site='meta.codegolf';postID=5686;isAnswer=false;QUESTION_ID=213962;</script><script src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'></script><script>jQuery(function(){var u='https://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\$
19
  • 6
    \$\begingroup\$ This is already explicitly mentioned in the challenge, but here is the meta post from Loopholes that are forbidden by default about using cryptographic functions in CnR challenges. \$\endgroup\$
    – Arnauld
    Oct 22 '20 at 17:56
  • 1
    \$\begingroup\$ May we specify multiple output formats at once; that is, specify that STDOUT must be a and STDERR must be b? \$\endgroup\$
    – hyper-neutrino
    Oct 22 '20 at 18:23
  • 4
    \$\begingroup\$ @SunnyMoon Sure, you can tell robbers that the password is a multiple of 34. Whether it's wise to leave robbers that clue, I don't know :) \$\endgroup\$
    – user
    Oct 22 '20 at 20:36
  • 4
    \$\begingroup\$ What is your definition of cryptographic functions? \$\endgroup\$ Oct 24 '20 at 12:08
  • 2
    \$\begingroup\$ This challenge seems to amount to just do cryptography without using cryptography. \$\endgroup\$
    – Grain Ghost
    Oct 25 '20 at 12:09

54 Answers 54

1
2
2
\$\begingroup\$

Python 3, 42 bytes, cracked by pppery

Just a single line of Python.

eval(input(),{'__builtins__':{}})(**{0:0})

Try it online!

The password is inputted via STDIN, the flag is (nothing) and should be printed to STDERR. That means no output to STDERR.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Cracked \$\endgroup\$ Oct 24 '20 at 16:38
  • \$\begingroup\$ @pppery Thats not how I intended it ;) \$\endgroup\$
    – ovs
    Oct 24 '20 at 16:44
2
\$\begingroup\$

Python 3, 73 bytes, cracked by pxeger

Hopefully this time there are no loopholes.

s=input()
assert not{*s}&{*'()[]{}'}
eval(s,{'__builtins__':{}})(**{0:0})

Try it online!

Just as before, the password is inputted via STDIN, the flag is (nothing) and should be printed to STDERR. That means no output to STDERR.

\$\endgroup\$
2
2
\$\begingroup\$

R, 143 bytes, cracked by Giuseppe

function(x, y, z){
  if(length(ls(1)) > 1 | length(ls()) != 3) return("S")
  LETTERS[lengths(lapply(y, intToUtf8(x), z)) * lengths(lapply(y, intToUtf8(x+32), z))]
}

Try it online!

Once again, the value to output is the string "R". The line with length(ls()) is there to try to close some loopholes; in any case, you need to find objects x, y and z such that f(x, y, z) == "R" is TRUE.


Giuseppe found a nice solution using the functions ^ and ~. The solution I had in mind was f(67, list(as.factor(1:3)), 4:6): Try it online! (any vectors of length 3 would work). The trick is that the functions c and C both exist (with the second being much less known). Calling c(1:3, 4:6) returns the length 6 integer vector 1 2 3 4 5 6; calling C(as.factor(1:3), 4:6) returns a length 3 factor 1 2 3 (with contrasts 4 5 6). The product of the lengths is thus 18, which is the position of R in the alphabet.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ cracked! I went down a real rabbit hole with C and D, but figured it out in the end! \$\endgroup\$
    – Giuseppe
    Oct 27 '20 at 14:59
  • 1
    \$\begingroup\$ @Giuseppe Well done! I actually had a different solution in mind, with c and C. \$\endgroup\$ Oct 27 '20 at 15:52
2
\$\begingroup\$

BrainF***, 22 bytes, Cracked by Cinaski

+++++[>,[--->+<]>.<<-]

Try it online!

The flag is wEe0H with nothing else. This shouldn't be too hard.

\$\endgroup\$
6
  • \$\begingroup\$ I made sure the flag would allow for a valid password \$\endgroup\$
    – SuperPizz
    Feb 12 at 1:08
  • \$\begingroup\$ Wait i'm unsure did you forget to remove the password from the try it online link? \$\endgroup\$
    – RezNesX
    Feb 12 at 7:50
  • \$\begingroup\$ Maybe? I didn't look into that. \$\endgroup\$
    – SuperPizz
    Feb 12 at 15:03
  • \$\begingroup\$ cracked \$\endgroup\$
    – Cinaski
    Feb 12 at 16:09
  • \$\begingroup\$ @SuperPizz You did leave the password in, but I edited in a link without it and anyway, Cinaski has cracked your answer. Btw, you should add "Cracked" to the header of your answer, with a link to the robber answer, so people know it's cracked. \$\endgroup\$
    – user
    Feb 12 at 16:44
2
\$\begingroup\$

Racket, 202 bytes, Safe

#lang racket

(define (h z)
  (when (procedure? z) (error "you lose"))
  (define a (λ (x) (not x)))
  ((λ (f) (call/cc (λ (k) (k (or (a z) (set! a ((eval f) k))))))) z)
  (and z (print (a "hello"))))

The flag is hello. The password (in the form of a quote-string) is passed as the argument to the h function.

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Python 3.8, 322 bytes, safe

from ast import*
a=input()
b=walk(parse(a,"","eval"))
c=Constant
n=Name
if not {z.__class__ for z in b}-{Load,Call,Expression,c,n}:
 for x in b:
  if (i:=instanceof)(x,c):
   if not i(x.value, str):
    break
  if i(x,n):
   if x.id=="getattr":
    break
 else:
  print(eval(a,{"__builtins__":{},"getattr":getattr})==eval)

Could probably be golfed more, but I'm trying to avoid accidentally leaking anything :P

Output is True followed by a newline

Solution:

The program only runs programs that load names or constants and call functions. It also runs the input with only the global function getattr (which is essentially a function implementation of the ., so a.b == getattr(a,"b"), so our goal is to get to eval with only these pieces. The solution that I came up with was by building up from an expression that I came up with that could become eval using the classes that Python loads at runtime, and then slowly using pythons magic dunder methods to try to "simplify" down language features that I can't use to get to getattr(getattr(getattr(getattr(getattr(getattr(getattr(getattr(getattr(getattr,"__class__"),"mro")(),"__getitem__")(1),"__subclasses__")(),"__getitem__")(getattr(getattr(getattr(getattr(getattr(getattr(getattr(getattr,"__class__"),"mro")(),"__getitem__")(1),"__subclasses__")(),"__repr__")(),"split")(","),"index")(" <class 'codecs.Codec'>")),"decode"),"__globals__"),"__getitem__")("__builtins__"),"__getitem__")("eval")

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ instanceof isn't a thing in Python. Did you mean isinstance? \$\endgroup\$
    – pxeger
    May 29 at 9:38
  • \$\begingroup\$ @pxeger I had actually meant to use isinstance, but I didn't realize until way too late to change it, and it would've changed the restrictions which would be unfair. \$\endgroup\$
    – Citty
    Jun 1 at 8:15
2
\$\begingroup\$

JavaScript (V8), 113 bytes, cracked by tsh

f=n=>n!=42?`${n} is a number`:`${n} is the answer to the ultimate question of life, the universe, and everything`

Try it online!

f needs to return 42 is a number.

Probably an easy one, but it's worth a shot.

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

Python 3, 958 bytes, safe

x=[(9,23),(10,24),(10,25),(11,23),(11,24)]
def f(g):
    h=g.copy()
    for move in range(30):
        n=[]
        for i in range(12):
            n.append([])
            for j in range(36):
                c=0
                for (a,b)in[(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]:
                    if i+a>=0 and i+a<12 and j+b>=0 and j+b<36:
                        c+=h[i+a][j+b]
                if h[i][j]==0 and c==3:
                    n[i].append(1)
                elif h[i][j]==0:
                    n[i].append(0)
                elif h[i][j]==1 and c!=2 and c!=3:
                    n[i].append(0)
                elif h[i][j]==1:
                    n[i].append(1)
        h=n.copy()
    for i in range(12):
        for j in range(36):
            if g[i][j]!=h[i][j]:
                if not((i,j)in x):
                    print('N')
    for (i,j)in x:
        if g[i][j]==h[i][j]:
            print('N')
    print('Y')

Try it online! Flag: Y. The password is taken through input to f, so to run the code just edit the last line f([]).

Solution:

The code simply runs Conway's game of life on a finite grid, and tests whether the result after 30 ticks is the original grid with a particular set of 5 cells toggled. The solution is:

Gosper's glider gun. [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ There's no need to post the solution right now, you can do that after your answer is cracked or it's safe \$\endgroup\$
    – user
    Feb 19 at 18:37
  • 1
    \$\begingroup\$ Welcome to Code Golf! Nice first answer. \$\endgroup\$ Feb 19 at 19:01
2
\$\begingroup\$

Python 3, 57 bytes, cracked by @the default.

class D(dict):__getitem__=0
exec("".join(open(0)),D())

Attempt This Online!

Works under CPython 3.9.6. Takes input from STDIN and should output uslcgtutmuexbwb with a trailing newline to STDOUT.

Hint: that string is completely random - it has no hidden meaning.


The crack was not my intended one; here's an answer with it fixed!

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

Python 3, 70 bytes, cracked by @the default.

class D(dict):__getitem__=0
s=open(0).read()
if"."not in s:exec(s,D())

Attempt This Online!

Works under CPython 3.9.6. Takes input from STDIN and should output ryjtufbohqszxgg with a trailing newline to STDOUT.

Hint: that string is pseudo-random with no hidden meaning.


@thedefault's crack was the same basic idea as mine, but it can be reduced to:

class c:
 from builtins import print
 print("ryjtufbohqszxgg")

As @thedefault says:

Our code is being executed in an environment where trying to access any global variable (including built-in functions) throws an error.

The way around this is to use local variables, using an immediately invoked function, or more simply here, an empty class.

However, import still functions correctly

This is because, when importing modules using the magic function __import__, the interpreter (bizarrely) doesn't dispatch to an overridden __getitem__ method on the __builtins__ namespace, but just uses normal built-in dict lookup semantics on the object. This is apparently not a bug, but an entirely implementation-defined quirk.

In fact, if you were a particularly good internet sleuth, you might have found this issue which I posted to the Python bug tracker yesterday about this very behaviour.

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

Pxem (lazypxem.posixism.tio.sh (8e9ac7ceb2)), filename only: 109 bytes, safe safe.

Sorry for misreading the rules; I misread I would safe if nobody cracked mine for one week; I had to wait for two weeks to be safe.

Some are escaped:

\002.r.w.i._._.-.-\240.z.d.aY.o.d.a\002.r.w.i.i.i.i.s.s.s.s._.i.!Q##.!.-.+.w.d.aY.o.d.a.w.+.i.c\001.+.a.+\377\377].+.+.z.d.aY.o
  • Flag: Y, without trailing LF.
  • Input from stdin, as a string consists of ASCII printables except space: 33 (!) to 126 (~).
  • Output to stdout.
  • This program works randomly; your password must always work.

Try it online!

Hint (posted after 5 days and 2 hours later, I think)

  • This program uses a bug of my interpreter.

Intended password

z317-35bP

\$\endgroup\$
2
\$\begingroup\$

Python 3.8 (pre-release), 163 bytes, safe.

My output is KDIITIWDRIKIDITI

import random
f=open(1,'w')
random.seed(0)
r=[random.randint(0,255) for l in range(255)]
a=input().encode()
for b in a:
 while b >26:
  b=r[b]
 f.write(chr(b+64))

Try it online!


My original password is passthevoidsalts

Since this basically follows a random directed graph (not a-cyclic, I just got lucky my password doesn't crash it) until it lands within a subset of nodes, it's straight forward to create a lookup table for each letter. Originally I tried to create a reversing crack, which works, but the .encode() on the input threw me off so I ran the process forwards to build a lookup table instead.

For each line output by this crack is the list of options to generate the corresponding character in the desired output.

import random 
out = 'KDIITIWDRIKIDITI'
a = [c for c in range(127) if chr(c).isalpha()]
random.seed(0)
r=[random.randint(0,255) for l in range(255)]
od={}
odd={}
for b in a:
 ob = b
 while b >26:
  b=r[b]
 ch = chr(b+64)
 od[ch] = ob
 if ch in odd:
  odd[ch].append(ob)
 else:
  odd[ch] = [ob]
for c in out:
 print(''.join(chr(x) for x in odd[c]))

Try it online!

dpw
JKMPVWXacjqrvx
ABCDEFHLNRSTZbfhilmnsyz
ABCDEFHLNRSTZbfhilmnsyz
t
ABCDEFHLNRSTZbfhilmnsyz
e
JKMPVWXacjqrvx
o
ABCDEFHLNRSTZbfhilmnsyz
dpw
ABCDEFHLNRSTZbfhilmnsyz
JKMPVWXacjqrvx
ABCDEFHLNRSTZbfhilmnsyz
t
ABCDEFHLNRSTZbfhilmnsyz

\$\endgroup\$
2
\$\begingroup\$

Python, 141 bytes, cracked by okie

from keyword import*
x=input()
if~-iskeyword(x)and x.isidentifier():
 exec(x,d:={"__builtins__":{}})
 try:exec(f"del {x}",d)
 except:print(1)

Attempt This Online!

This is quite a long setup for what is perhaps a simple trick. Works in CPython 3.9.7. Given the correct input, it should print 1 (with a newline, to STDOUT).

\$\endgroup\$
1
  • \$\begingroup\$ cracked \$\endgroup\$
    – okie
    Sep 13 at 5:18
2
\$\begingroup\$

Stable Rust 1.52.1, 171 bytes

fn u<T:'static>(_:T){use std::any::*;let _=unsafe{(1 as*mut T).read_volatile()};let a=type_name::<T>();print!("{}",&a[41..]=="(((), ()), ((), ()))>"&&a.contains("&dyn"))}

Playground

Entering the right password will print true and won't segfault (or print anything to stderr). This relies on implementation-defined behavior, so this will only probably work on different versions of Rust.

Password: u::<fn(&dyn std::any::Any)->(((),()),((),()))>.

Explanation:

There are probably other valid passwords but this is the intended one. The function is generic over all 'static types so you can put in almost anything into the function. However, most types will immediately segfault- unsafe{(1 as*mut T).read_volatile()} is a volatile read of address 1. However, not everything will segfault- in Rust, types with a size of zero can be read from any well-aligned non-null pointer, and most zero-sized types have an alignment of one.

This brings me to the second safeguard: parsing the type name. This is the implementation-defined part- the type_name function is only guaranteed to be a best-effort description of the type. The type name was chosen to be particularly difficult to find a zero-sized type to match. The solution I have uses a particular monomorphization of the function I submitted to pass the criteria. It is likely possible to define another type that meets the criteria. Ungolfed code with solution entered.

\$\endgroup\$
2
  • \$\begingroup\$ You are already safe but we still have no ideas what the password is. \$\endgroup\$ Sep 17 at 2:10
  • \$\begingroup\$ @nrgmsbki4spot1 oops I forgot about this. Solution and explanation added. \$\endgroup\$
    – Aiden4
    Sep 17 at 4:18
1
\$\begingroup\$

JavaScript (SpiderMonkey), 52 bytes, Cracked by r3mainer

i=>(a=+i,a<a/a?a/a<-a?1/a<a:a*a>1:1<a*a?a*a<a:1/a<a)

Try it online!

Expect output is true.

Input via parameter, output via return value. Global values should not be configured before the function execute. (For example, Object.defineProperty(globalThis, 'a', { get() { return ...; }, set() { return true; } }) is not valid.)

This one could be quite easy. I expected it will be cracked in 30 min...

\$\endgroup\$
2
  • \$\begingroup\$ Yes, it was quite simple in the end :-) Cracked \$\endgroup\$
    – r3mainer
    Oct 26 '20 at 8:21
  • \$\begingroup\$ Yeah, pretty much :-D \$\endgroup\$
    – r3mainer
    Oct 26 '20 at 8:39
1
\$\begingroup\$

C (x86-64), 100 bytes, cracked by @the-default.

This will survive until someone figures out how to run Xorshift in reverse. (So probably not very long!). Requires a key of 8 characters as a command line argument. The flag is CodeGolf followed by a line break (and nothing else before or after). Liable to crash if the key is missing or less than 8 characters in length.

main(int a,char**b){for(unsigned long *x=*++b,i=59295;i--;*x^=*x<<13,*x^=*x>>7,*x^=*x<<5);puts(*b);}

Try it online!

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

Ruby, 39 bytes, cracked by @EricDuminil

p eval($<.read.tr'Scfpvy.:?\'"%<`(',$/)

Try it online!

Here's hoping I've managed to close the backdoor that @Sisyphus exposed in the previous version. As before, input is via STDIN and the flag is """\n (with \n representing a trailing newline) printed to STDOUT. Nothing is printed to STDERR.


My password: Try it online! Same idea as the crack but somewhat different implementation.

\$\endgroup\$
2
  • \$\begingroup\$ cracked. Not sure if it was the intended solution. \$\endgroup\$ Oct 26 '20 at 21:52
  • 1
    \$\begingroup\$ Very interesting. I spent about 2h in order to find a solution which was very close to yours. I didn't like the fact that the methods' ID were hardcoded, and would only work on TIO and not on my computer. So I spent another 2h, trying to find a reliable way to access the methods. Congrats for the interesting challenge BTW: it was, to me at least, just the right balance between frustrating and fun. \$\endgroup\$ Oct 27 '20 at 10:46
1
\$\begingroup\$

R, 67 bytes, cracked by pppery

function(x) with(x, is.finite(a) && !is.finite(b) && is.nan(a + b))

Try it online!

The flag is TRUE. That is, find x such that f(x) is TRUE.

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

R, 66 bytes, Cracked by Dominic van Essen

function(x) with(x, is.finite(a) && is.finite(b) && is.nan(a + b))

Try it online!

This is a slight (but significant) modification of my previous post. The flag is TRUE. That is, find x such that f(x) is TRUE.

Intended solution

Try it online! There are no two finite finite numbers that add to NaN. So we have to exploit the use of with. with uses the the contents of x to evaluate the expression. So simply redefine the function && to be unconditionally TRUE.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I assume that this is not the intended solution... although I can't immediately find a way to rule it out... \$\endgroup\$ Oct 28 '20 at 22:35
  • \$\begingroup\$ Nice! Not exactly my solution, but still a valid solution. \$\endgroup\$
    – Paul
    Oct 29 '20 at 0:03
1
\$\begingroup\$

Japt, 6 bytes, safe

OvUc^H

The flag is the array [-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]. I recommend setting the language flag -Q to see the output correctly, this is included in the below link as well.

Beware that the above snippet may result in an endless loop for certain specific inputs, but this is not the case for most inputs.

Try it out here.

Solution:

The program takes the input, XORs its charcodes with 32 and then evaluates the result as Japt. More or less any valid program that outputs the range will work once the program string is XORed beforehand. One such answer might be "gçé", but interestingly also "fOOBAR".

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

Zsh + coreutils, 213 bytes, safe

n=$(shuf -n1 -i0-9999999);out=$( (eval "$(tr -dc '\t\n -/:-@[-`{-~')") );s=$((n**.5));i=1;p=Yes;while [[ "$i" -le "$s" ]];do;i=$((i+1));if [[ $((n%i)) -eq 0 ]];then;p=No;break;fi;done;[[ "$p" = "$out" ]]&&echo Win

Must be run as root on a typical modern Linux system. (so no TIO link). Telling you why would spoil the challenge.

Flag is Win with a trailing newline, printed to stdout.

I no longer have my exact intended solution, but you can use this technique or similar to achieve arbitrary code execution without alphanumerics.

\$\endgroup\$
3
  • \$\begingroup\$ Does the password have to work consistently? \$\endgroup\$ Nov 8 '20 at 16:12
  • 1
    \$\begingroup\$ @thedefault. yes \$\endgroup\$
    – pxeger
    Nov 8 '20 at 16:15
  • \$\begingroup\$ Cracked but too late \$\endgroup\$ Jun 12 at 9:34
1
\$\begingroup\$

Python 3, 53 bytes, cracked by EasyasPi

I=input
X=vars(vars()[I()])
X[I()]=X[I()]
class I:1/0

Try it online!

The password is 3 lines of input on STDIN. The flag is the following text, to be printed to STDERR:

Traceback (most recent call last):
  File ".code.tio", line 4, in <module>
    class I:1/0
IndexError: tuple index out of range

(replace .code.tio with whatever the filename of the program is)

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

Python 3, 157 bytes, cracked by Unrelated String and StackOverflow

import sys
B,V,I=__builtins__,eval,input()
class E(Exception):0
B.exec=B.eval=B.__import__=sys.stdout=0
try:V(I,{"E":E})
except E:sys.__stdout__.write("win")

Try it online!

Takes password via STDIN. Flag is win, printed to STDOUT with no newline.


@UnrelatedString found an unintended crack, which I had no idea existed:

(_ for _ in ()).throw(E)

Turns out generators have a .throw method which inserts an exception into their call stack.

It is, however, sad that my intended solution was also more or less right there on StackOverflow:

a python3 strong stomach solution:

type(lambda: 0)(type((lambda: 0).__code__)(1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b''),{})(Exception())

Even if it was slightly more complicated than it necessarily needed to be (here's mine:)

type(lambda:0)(compile("raise E","","exec"),{"E":E})()

We can construct the code object using compile instead of using quite so much dark arts, which is a bit less fragile. The type(lambda:0) obtains the class for user functions, which can be used to construct new functions using code objects.

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

Python, 54 bytes, cracked by m90

lambda x,y:x.isidentifier()and exec(f"{x}(1),1/0;{y}")

Attempt This Online!

Works in CPython 3.9.7. Accepts two strings as passwords. The flag is None, which should be returned from the function.


m90 got my intended solution. y was just a red herring

\$\endgroup\$
1
  • \$\begingroup\$ Cracked. \$\endgroup\$
    – m90
    Oct 3 at 15:23
1
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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