**TL;DR:** Obfuscated Python code using lambda-calculus.

**Description:** Mary had a flagchecker, its fleece was white as snow.

## Introduction

We are given a Python script, consisting in a single line of ~26k characters,
with lots of lambda-functions. The full script is available
[here](https://github.com/ret2school/ctf/blob/master/2023/imaginaryctf/reverse/sheepish/src/sheepish.py)  
, see the beginning and the end of the file below.

```python  
print((((lambda _____________:((lambda ___:_____________(lambda
_______:___(___)(_______)))(lambda ___:_____________(lambda
_______:___(___)(_______)))))(lambda _____________:lambda ___________:lambda
______:(lambda ____:(lambda _:_(lambda __________:lambda
_____:__________))(____))(___________)(lambda _:(lambda __________:lambda
_____:__________))(lambda _:(lambda __________:lambda
_____:__________(_____)(lambda __________:lambda _____:_____))((lambda
__________:lambda _____:(lambda __________:lambda
_____:__________(_____)(lambda __________:lambda _____:_____))((lambda
__________:lambda _____:(lambda __________:__________(lambda _:(lambda
__________:lambda _____:_____))(lambda __________:lambda _____:__________))  
[...]  
(lambda _____________:(lambda ________:(((lambda ____:lambda ___:(lambda
__________:lambda _____:lambda
______________:______________(__________)(_____))(lambda __________:lambda
_____:_____)((lambda __________:lambda _____:lambda
______________:______________(__________)(_____))(___)(____)))(_____________(________[1:]))(((lambda
_____________:((lambda ___:_____________(lambda
_______:___(___)(_______)))(lambda ___:_____________(lambda
_______:___(___)(_______)))))(lambda _____________:(lambda __:(((lambda
__:lambda __________:lambda
_____:__________(__(__________)(_____)))(_____________(__-1))) if __ else
(lambda __________:lambda _____:_____)))))(________[0]))) if len(________)
else ((lambda __________:lambda _____:lambda
______________:______________(__________)(_____))(lambda __________:lambda
_____:__________)(lambda __________:lambda _____:__________))))))(input(">>>
").encode())))("Well done!")("Try again..."))  
```

In order to make the code more "readable", we can replace the variable names
(`_`, `__`, `___`, ...) with more readable names (`x1`, `x2`, `x3`, ...)

## A bit of culture

In theoretical computer science, it is known that [lambda-
calculus](https://en.wikipedia.org/wiki/Lambda_calculus) is Turing-complete.
In other words, any program can be simulated with "lambda-terms", namely,
terms similar to `lambda` functions in Python.

For instance, the constant "true" can be simulated with the lambda-term
λx.λy.x, and "false" with λx.λy.y. Integers can be represented as [Church
numerals](https://en.wikipedia.org/wiki/Church_encoding).

The website <https://lambdacalc.io/> provides a good summary of "common
lambda-terms" used to simulate common operations in programming.

## Deobfuscation, and solve

When looking closer at the code, we can observe such terms.

For instance, the constants true and false:  
```python  
tru = (lambda x10:lambda x5:x10)  
fls = (lambda x10:lambda x5:x5)  
```

as well as the Church numerals and their arithmetic operations:  
```python  
power = (lambda x10:lambda x5:x5(x10))  
is0 = (lambda x10:x10(lambda x01:(fls))(tru))  
succ = (lambda x2:lambda x10:lambda x5:x10(x2(x10)(x5)))  
pred = (lambda x2:lambda x13:lambda x3:x2(lambda x12:lambda
x9:x9(x12(x13)))(lambda x01:x3)(lambda x10:x10))  
plus = (lambda x10:lambda x5:x10(succ)(x5))  
minus = (lambda x10:lambda x5:x5(pred)(x10))  
le = (lambda x10:lambda x5:is0(minus(x10)(x5)))  
ge = (lambda x10:lambda x5:is0(minus(x5)(x10)))  
mult = (lambda x10:lambda x5:lambda x14:x10(x5(x14)))  
two = (lambda x10:lambda x5:x10(x10(x5)))  
three = (lambda x10:lambda x5:x10(x10(x10(x5))))  
four = (succ)(three)  
```

The script is now way shorter, and a bit understandable (see
[here](https://github.com/ret2school/ctf/blob/master/2023/imaginaryctf/reverse/sheepish/src/sheepish_deobf2.py)).
We can recognize a sequence of arithmetic expressions, such as:

```  
((plus)(mult((power)(two)(four))(succ(mult(two)(three))))((plus)(mult(two)(three))(succ(mult(two)(three)))))  
```

The characters of the flag, maybe?

To solve the chall, I took the expressions, and I reimplemented the operators
(full script
[here](https://github.com/ret2school/ctf/blob/master/2023/imaginaryctf/reverse/sheepish/src/sheepish_arith.py)):

```python  
def plus(x):  
   return lambda y: x + y

def mult(x):  
   return lambda y: x * y

def power(x):  
   return lambda y: x ** y

def succ(x):  
   return x+1

zero = 0  
two = 2  
three = 3  
four = 4

flag = ""

flag +=
chr(((plus)(mult((power)(two)(four))(succ(mult(two)(three))))((plus)(mult(two)(three))(succ(mult(two)(three))))))  
flag +=
chr(((plus)(mult((power)(two)(four))(three))(mult((plus)(two)(three))(three))))  
[...]  
flag += chr(((plus)(mult((power)(two)(four))(mult(two)(three)))(three)))  
flag +=
chr(((plus)(mult((power)(two)(four))(mult(two)(three)))((power)(three)(two))))

print(flag[::-1])  
```

**FLAG:** ictf{d0_sh33p_b@@@?}

## Upsolve

Even if identifying the arithmetic expressions was enough to solve the
challenge, I was curious to understand the rest of the script.

In particular, the first lambda-term is very strange:  
```python  
(lambda x13:((lambda x3:x13(lambda x7:x3(x3)(x7)))(lambda x3:x13(lambda
x7:x3(x3)(x7)))))  
```

`x3` is applied to itself!

This term is a fixed-point combinator, more precisely a Z combinator: see
theoretical details [here](https://en.wikipedia.org/wiki/Fixed-
point_combinator). Roughly, it's a term that can be used to simulate
recursion.

Moreover, a long sequence of "chained" pairs appears at the beginning:  
```python  
((lambda x4:lambda x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda x3:pair(fls)(pair(x3)(x4)))
((lambda x4:lambda x3:pair(fls)(pair(x3)(x4))) ((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda x3:pair(fls)(pair(x3)(x4)))
((lambda x4:lambda x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda x3:pair(fls)(pair(x3)(x4)))
((lambda x4:lambda x3:pair(fls)(pair(x3)(x4))) (pair(tru)(tru)) [...]) [...])
[...])  
```

This term actually represents a linked list, whose elements are the
susmentionned arithmetic expressions.

After further deobfuscation/understanding, we can conclude that the script
performs successive comparisons on the chars of the input, in reverse order,
with the chars in the linked list.

## Conclusion

As a functional programming lover, I enjoyed a lot solving this chall. A big
thanks to the author!  
I know it was possible to side-channel it, but it was funnier with lambda-
calculus :)  

Original writeup (https://ret2school.github.io/post/sheepish/).**TL;DR:** Obfuscated Python code using lambda-calculus.

**Description:** Mary had a flagchecker, its fleece was white as snow.

## Introduction

We are given a Python script, consisting in a single line of ~26k characters,
with lots of lambda-functions. The full script is available
[here](https://github.com/ret2school/ctf/blob/master/2023/imaginaryctf/reverse/sheepish/src/sheepish.py)  
, see the beginning and the end of the file below.

```python  
print((((lambda _____________:((lambda ___:_____________(lambda
_______:___(___)(_______)))(lambda ___:_____________(lambda
_______:___(___)(_______)))))(lambda _____________:lambda ___________:lambda
______:(lambda ____:(lambda _:_(lambda __________:lambda
_____:__________))(____))(___________)(lambda _:(lambda __________:lambda
_____:__________))(lambda _:(lambda __________:lambda
_____:__________(_____)(lambda __________:lambda _____:_____))((lambda
__________:lambda _____:(lambda __________:lambda
_____:__________(_____)(lambda __________:lambda _____:_____))((lambda
__________:lambda _____:(lambda __________:__________(lambda _:(lambda
__________:lambda _____:_____))(lambda __________:lambda _____:__________))  
[...]  
(lambda _____________:(lambda ________:(((lambda ____:lambda ___:(lambda
__________:lambda _____:lambda
______________:______________(__________)(_____))(lambda __________:lambda
_____:_____)((lambda __________:lambda _____:lambda
______________:______________(__________)(_____))(___)(____)))(_____________(________[1:]))(((lambda
_____________:((lambda ___:_____________(lambda
_______:___(___)(_______)))(lambda ___:_____________(lambda
_______:___(___)(_______)))))(lambda _____________:(lambda __:(((lambda
__:lambda __________:lambda
_____:__________(__(__________)(_____)))(_____________(__-1))) if __ else
(lambda __________:lambda _____:_____)))))(________[0]))) if len(________)
else ((lambda __________:lambda _____:lambda
______________:______________(__________)(_____))(lambda __________:lambda
_____:__________)(lambda __________:lambda _____:__________))))))(input(">>>
").encode())))("Well done!")("Try again..."))  
```

In order to make the code more "readable", we can replace the variable names
(`_`, `__`, `___`, ...) with more readable names (`x1`, `x2`, `x3`, ...)

## A bit of culture

In theoretical computer science, it is known that [lambda-
calculus](https://en.wikipedia.org/wiki/Lambda_calculus) is Turing-complete.
In other words, any program can be simulated with "lambda-terms", namely,
terms similar to `lambda` functions in Python.

For instance, the constant "true" can be simulated with the lambda-term
λx.λy.x, and "false" with λx.λy.y. Integers can be represented as [Church
numerals](https://en.wikipedia.org/wiki/Church_encoding).

The website <https://lambdacalc.io/> provides a good summary of "common
lambda-terms" used to simulate common operations in programming.

## Deobfuscation, and solve

When looking closer at the code, we can observe such terms.

For instance, the constants true and false:  
```python  
tru = (lambda x10:lambda x5:x10)  
fls = (lambda x10:lambda x5:x5)  
```

as well as the Church numerals and their arithmetic operations:  
```python  
power = (lambda x10:lambda x5:x5(x10))  
is0 = (lambda x10:x10(lambda x01:(fls))(tru))  
succ = (lambda x2:lambda x10:lambda x5:x10(x2(x10)(x5)))  
pred = (lambda x2:lambda x13:lambda x3:x2(lambda x12:lambda
x9:x9(x12(x13)))(lambda x01:x3)(lambda x10:x10))  
plus = (lambda x10:lambda x5:x10(succ)(x5))  
minus = (lambda x10:lambda x5:x5(pred)(x10))  
le = (lambda x10:lambda x5:is0(minus(x10)(x5)))  
ge = (lambda x10:lambda x5:is0(minus(x5)(x10)))  
mult = (lambda x10:lambda x5:lambda x14:x10(x5(x14)))  
two = (lambda x10:lambda x5:x10(x10(x5)))  
three = (lambda x10:lambda x5:x10(x10(x10(x5))))  
four = (succ)(three)  
```

The script is now way shorter, and a bit understandable (see
[here](https://github.com/ret2school/ctf/blob/master/2023/imaginaryctf/reverse/sheepish/src/sheepish_deobf2.py)).
We can recognize a sequence of arithmetic expressions, such as:

```  
((plus)(mult((power)(two)(four))(succ(mult(two)(three))))((plus)(mult(two)(three))(succ(mult(two)(three)))))  
```

The characters of the flag, maybe?

To solve the chall, I took the expressions, and I reimplemented the operators
(full script
[here](https://github.com/ret2school/ctf/blob/master/2023/imaginaryctf/reverse/sheepish/src/sheepish_arith.py)):

```python  
def plus(x):  
return lambda y: x + y

def mult(x):  
return lambda y: x * y

def power(x):  
return lambda y: x ** y

def succ(x):  
return x+1

zero = 0  
two = 2  
three = 3  
four = 4

flag = ""

flag +=
chr(((plus)(mult((power)(two)(four))(succ(mult(two)(three))))((plus)(mult(two)(three))(succ(mult(two)(three))))))  
flag +=
chr(((plus)(mult((power)(two)(four))(three))(mult((plus)(two)(three))(three))))  
[...]  
flag += chr(((plus)(mult((power)(two)(four))(mult(two)(three)))(three)))  
flag +=
chr(((plus)(mult((power)(two)(four))(mult(two)(three)))((power)(three)(two))))

print(flag[::-1])  
```

**FLAG:** ictf{d0_sh33p_b@@@?}

## Upsolve

Even if identifying the arithmetic expressions was enough to solve the
challenge, I was curious to understand the rest of the script.

In particular, the first lambda-term is very strange:  
```python  
(lambda x13:((lambda x3:x13(lambda x7:x3(x3)(x7)))(lambda x3:x13(lambda
x7:x3(x3)(x7)))))  
```

`x3` is applied to itself!

This term is a fixed-point combinator, more precisely a Z combinator: see
theoretical details [here](https://en.wikipedia.org/wiki/Fixed-
point_combinator). Roughly, it's a term that can be used to simulate
recursion.

Moreover, a long sequence of "chained" pairs appears at the beginning:  
```python  
((lambda x4:lambda x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda x3:pair(fls)(pair(x3)(x4)))
((lambda x4:lambda x3:pair(fls)(pair(x3)(x4))) ((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda x3:pair(fls)(pair(x3)(x4)))
((lambda x4:lambda x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda
x3:pair(fls)(pair(x3)(x4)))((lambda x4:lambda x3:pair(fls)(pair(x3)(x4)))
((lambda x4:lambda x3:pair(fls)(pair(x3)(x4))) (pair(tru)(tru)) [...]) [...])
[...])  
```

This term actually represents a linked list, whose elements are the
susmentionned arithmetic expressions.

After further deobfuscation/understanding, we can conclude that the script
performs successive comparisons on the chars of the input, in reverse order,
with the chars in the linked list.

## Conclusion

As a functional programming lover, I enjoyed a lot solving this chall. A big
thanks to the author!  
I know it was possible to side-channel it, but it was funnier with lambda-
calculus :)  

Original writeup (https://ret2school.github.io/post/sheepish/).