# Polyglot (re/misc, 50p, 171 solved)
The challenge is sort-off matrioshka.
## Stage 1
We start off with some [C code](https://raw.githubusercontent.com/TFNS/writeups/master/2020-07-25-CybricsCTF/polyglot/code.c), which we can simply compile and run.It expects:
```cchar *key = getenv("XKEY");if((!key) ||strncmp("mod3r0d!",key,8 )){    puts(";[");    return 1;}```
So we can for simplicity just set `char *key  = "mod3r0d!";` and run it.This spits out [some C++ code](https://raw.githubusercontent.com/TFNS/writeups/master/2020-07-25-CybricsCTF/polyglot/code2.cpp)
## Stage 2
This stage is very similar - we have code, which should drop another stage.The issue here is that the code is unrolling some recursive templates at compile time and we need to optimize this.We have:
```cpptemplate <unsigned int a, unsigned int b>struct t1 {	enum { value = b + t1<a-1, b>::value };};template <unsigned int b>struct t1<0, b> {	enum { value = 0 };};template <unsigned int a, unsigned int b>struct t2 {	enum { value = 1 + t2<a-1, b>::value };};template <unsigned int b>struct t2<0, b> {	enum { value = 1 + t2<0, b-1>::value };};template<>struct t2<0, 0>{    enum { value = 0};};```
And we need the value of:
```cppt2<0xcaca0000, t2<444, t1<t2<100, t1<4,3>::value>::value, t2<44, t1<11,3>::value>::value>::value>::value>::value```
### t1 optimization
If we write down `t1` in simple recursive notation we have:
```pythondef t1(a,b):    if a == 0:        return 0    else:        return b + t1(a-1,b)```
So it simply adds `b` to the result `a` times, hence `a*b`
### t2 optimization
We do similar exercise for `t2`:
```pythondef t2(a,b):    if a == 0 and b == 0:        return 0    elif a == 0:        return 1 + t2(0, b-1)    else:        return 1 + t2(a-1,b)```
So it basically adds `1` to the result `a` times, and once `a == 0` it adds `1` to the sum `b` times, hence `a+b`
### Wrap up
Now we can simply calculate the constant to be `3402244972` and compile and run the code to drop last stage.
## Stage 3
Last stage generates some [python functions](https://raw.githubusercontent.com/TFNS/writeups/master/2020-07-25-CybricsCTF/polyglot/code3.py) from pure bytecode and runs them.We can either just do `dis.dis(f1)` on them, try with uncompyle or just blackbox to figure out that the functions are:
- f1 compares 2 arguments for equality- f2 calls `ord(argument)`- f3 calls `input()`- f4 is actual flag checker- f5 is just main which uses f4 and prints if we got the right flag or not
The only really important part is `f4` where the real logic is located:
Load lots of int constants.```  0 LOAD_CONST               1 (99)  2 LOAD_CONST               2 (121)  4 LOAD_CONST               3 (98)  6 LOAD_CONST               4 (114)  8 LOAD_CONST               5 (105) 10 LOAD_CONST               1 (99) 12 LOAD_CONST               6 (115) 14 LOAD_CONST               7 (123) 16 LOAD_CONST               8 (52) 18 LOAD_CONST               9 (97) 20 LOAD_CONST               3 (98) 22 LOAD_CONST              10 (100) 24 LOAD_CONST              11 (51) 26 LOAD_CONST              12 (101) 28 LOAD_CONST              13 (55) 30 LOAD_CONST               8 (52) 32 LOAD_CONST              12 (101) 34 LOAD_CONST              14 (57) 36 LOAD_CONST              12 (101) 38 LOAD_CONST              15 (53) 40 LOAD_CONST              14 (57) 42 LOAD_CONST              16 (54) 44 LOAD_CONST              17 (48) 46 LOAD_CONST               9 (97) 48 LOAD_CONST              18 (49) 50 LOAD_CONST               3 (98) 52 LOAD_CONST              16 (54) 54 LOAD_CONST               3 (98) 56 LOAD_CONST              14 (57) 58 LOAD_CONST              19 (50) 60 LOAD_CONST              11 (51) 62 LOAD_CONST              10 (100) 64 LOAD_CONST              20 (56) 66 LOAD_CONST               8 (52) 68 LOAD_CONST              19 (50) 70 LOAD_CONST               1 (99) 72 LOAD_CONST               1 (99) 74 LOAD_CONST              10 (100) 76 LOAD_CONST               9 (97) 78 LOAD_CONST               1 (99) 80 LOAD_CONST              18 (49) 82 LOAD_CONST              11 (51) 84 LOAD_CONST              16 (54) 86 LOAD_CONST              15 (53) 88 LOAD_CONST              20 (56) 90 LOAD_CONST               3 (98) 92 LOAD_CONST              11 (51) 94 LOAD_CONST              21 (102) 96 LOAD_CONST              22 (125) 98 BUILD_LIST              49100 STORE_FAST               1 (v1) ```
Get length of the created constant list, and compare it with user input length.If lengths don't match, return print error and return false.
```102 LOAD_GLOBAL              0 (len)104 LOAD_FAST                0 (v0)106 CALL_FUNCTION            1108 LOAD_GLOBAL              0 (len)110 LOAD_FAST                1 (v1)112 CALL_FUNCTION            1114 COMPARE_OP               3 (!=)116 POP_JUMP_IF_FALSE      130118 LOAD_GLOBAL              1 (print)120 LOAD_CONST              23 ('Length mismatch!')122 CALL_FUNCTION            1124 POP_TOP126 LOAD_CONST              24 (False)128 RETURN_VALUE```
If lengths are matching, use zip to combine user input with constants list.Use `f2` (ord) to get a number from each character of user input and then use `f1` (comparison) to check if the integer matches constant.```>>  130 LOAD_GLOBAL              2 (zip)132 LOAD_FAST                0 (v0)134 LOAD_FAST                1 (v1)136 CALL_FUNCTION            2138 GET_ITER>>  140 FOR_ITER                36 (to 178)142 STORE_FAST               2 (v2)144 LOAD_GLOBAL              3 (f1)146 LOAD_FAST                2 (v2)148 LOAD_CONST              25 (1)150 BINARY_SUBSCR152 LOAD_GLOBAL              4 (f2)154 LOAD_FAST                2 (v2)156 LOAD_CONST              26 (0)158 BINARY_SUBSCR160 CALL_FUNCTION            1162 CALL_FUNCTION            2164 LOAD_CONST              24 (False)166 COMPARE_OP               2 (==)168 POP_JUMP_IF_FALSE      140170 POP_TOP172 LOAD_CONST              24 (False)174 RETURN_VALUE176 JUMP_ABSOLUTE          140>>  178 LOAD_CONST              27 (True)180 RETURN_VALUE```
If everything matches, we got the right flag.
So we simply need to grab those constants and do `chr` on them:
```python    data = """0 LOAD_CONST               1 (99)  2 LOAD_CONST               2 (121)  4 LOAD_CONST               3 (98)  6 LOAD_CONST               4 (114)  8 LOAD_CONST               5 (105) 10 LOAD_CONST               1 (99) 12 LOAD_CONST               6 (115) 14 LOAD_CONST               7 (123) 16 LOAD_CONST               8 (52) 18 LOAD_CONST               9 (97) 20 LOAD_CONST               3 (98) 22 LOAD_CONST              10 (100) 24 LOAD_CONST              11 (51) 26 LOAD_CONST              12 (101) 28 LOAD_CONST              13 (55) 30 LOAD_CONST               8 (52) 32 LOAD_CONST              12 (101) 34 LOAD_CONST              14 (57) 36 LOAD_CONST              12 (101) 38 LOAD_CONST              15 (53) 40 LOAD_CONST              14 (57) 42 LOAD_CONST              16 (54) 44 LOAD_CONST              17 (48) 46 LOAD_CONST               9 (97) 48 LOAD_CONST              18 (49) 50 LOAD_CONST               3 (98) 52 LOAD_CONST              16 (54) 54 LOAD_CONST               3 (98) 56 LOAD_CONST              14 (57) 58 LOAD_CONST              19 (50) 60 LOAD_CONST              11 (51) 62 LOAD_CONST              10 (100) 64 LOAD_CONST              20 (56) 66 LOAD_CONST               8 (52) 68 LOAD_CONST              19 (50) 70 LOAD_CONST               1 (99) 72 LOAD_CONST               1 (99) 74 LOAD_CONST              10 (100) 76 LOAD_CONST               9 (97) 78 LOAD_CONST               1 (99) 80 LOAD_CONST              18 (49) 82 LOAD_CONST              11 (51) 84 LOAD_CONST              16 (54) 86 LOAD_CONST              15 (53) 88 LOAD_CONST              20 (56) 90 LOAD_CONST               3 (98) 92 LOAD_CONST              11 (51) 94 LOAD_CONST              21 (102) 96 LOAD_CONST              22 (125)"""    res = re.findall("(\d+) \((\d+)\)", data)    result = []    for x, y in res:        result.append(int(y))    print(result)    print("".join(map(chr, result)))```
And we get `cybrics{4abd3e74e9e5960a1b6b923d842ccdac13658b3f}`