## HXP CTF 2022 - Required (RE 385)### 10-12/03/2023 (48hr)___
## Description **Difficulty estimate:** easy - easy
**Points:** round(1000 · min(1, 10 / (9 + [17 solves]))) = 385 points
**Description:**
*I have written a super safe flag encryptor. I’m sure nobody can figure out what my original flag was:*
```0xd19ee193b461fd8d1452e7659acb1f47dc3ed445c8eb4ff191b1abfa7969```
*Dockerfile for your convenience / to ensure correct environment.*
**Download:**```required-27edfc0c02c5f748.tar.xz (11.4 KiB)```___
## Solution
Let's start with the `Dockerfile`:```bash# see docker-compose.yml
FROM node:19
RUN useradd --create-home --shell /bin/bash ctfWORKDIR /home/ctf
COPY flag files/* /home/ctf/
USER ctf
CMD sh run.sh```
This challenge contains **250** JavaScript files under `files/` directory:```ispo@ispo-glaptop2:~/ctf/hxp_2022/required$ ls files/*.js | wc    250     250    3226```
Everything starts from `files/run.sh`:```bash#!/bin/bash
if [ "$(node required.js)" = "0xd19ee193b461fd8d1452e7659acb1f47dc3ed445c8eb4ff191b1abfa7969" ]; then    echo ":)"else    echo ":("fi```
`files/required.js` contains a long sequence of `require` calls:```javascriptf=[...require('fs').readFileSync('./flag')]  // load flagrequire('./28')(753,434,790)require('./157')(227,950,740)/* ... ~1228 more `require` calls ... */require('./725')(9,30,288)require('./37')(f)  // print encrypted flag````
Let's start looking into some of these files:```ispo@ispo-glaptop2:~/ctf/hxp_2022/required$ cat files/103.jsmodule.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[i]*=f[25],f[i]&=0xff)
ispo@ispo-glaptop2:~/ctf/hxp_2022/required$ cat files/118.jsmodule.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[i]*=f[8],f[i]&=0xff)
ispo@ispo-glaptop2:~/ctf/hxp_2022/required$ cat files/1.jsmodule.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[i]*=-1,f[i]&=0xff)```
These files look very similar and they are probably automatically generated. We quickly dumpall these files to see how they differ from each other:```bashfor i in files/*.js; do echo -e "\n-------------------------- $i"; cat $i; done | less```
All files have the same format (with very few exceptions that we will see in a moment):```javascriptmodule.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],/*f operation */)```
Each time, only one of the `i`, `j` and `t` variables is used to access a single character from`f` -which contains the flag- and do some transformations to it. Some operations (such as addition)have an extra statement `f[i]&=0xff` to ensure that the result is only **1** byte. Let's now lookat some examples of all different operations:```js// add, sub, mul, divmodule.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[j]+=f[i],f[j]&=0xff)module.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[j]-=f[t],f[j]&=0xff)module.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[i]*=f[25],f[i]&=0xff)module.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[i]/=f[9],f[i]&=0xff)
// xormodule.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[t]^=f[i])
// notmodule.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[i]=~f[i]&0xff)
// rol (operates on the same f element)module.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[j]=f[j]<<1&0xff|f[j]>>7)
// neg (operates on the same f element)module.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[i]*=-1,f[i]&=0xff)
// left and right shift (operates on the same f element)module.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[i]<<=f[j],f[i]&=0xff)module.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[i]>>=f[j],f[i]&=0xff)
// xor with shifted by 1 (operates on the same f element)module.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[j]=f[j]^(f[j]>>1))
// weirdo calculation (operates on the same f element)module.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],                         f[i]=(((f[i]*0x0802&0x22110)|(f[i]*0x8020&0x88440))*0x10101>>>16)&0xff)```
There are also some files which are different:```js// 37.js    ~> print flagmodule.exports=(i,j,t)=>(i+=[],j+"",t=(t+{}).split("[")[0],console.log(require('./314')(i)))
// 314.js  ~> flag to hexmodule.exports=(i,j,t)=>(i+=[],j+"",t=(t+{}).split("[")[0],s='0x',                         i.split(',').forEach(b=>(s+=('0'+(b-0).toString(16)).slice(-2))),s)
// 556.js   ~> dtormodule.exports=(i,j,t)=>(i+=[],j+"",t=(t+{}).split("[")[0],                         Object.keys(require.cache).forEach(i=>{delete require.cache[i]}))
// 289.js  ~> build json obj//      > i = 123; j = 998//          ['__proto__']: { data: { name: './123', exports: [Object] }, path: './' }//      > json['__proto__']['data']['exports']//          { '.': './998.js' }module.exports=(i,j,t)=>(    i+=[],  // if this none, add the empty array to give it a type    j+"",   // same for this    t=(t+{}).split("[")[0], // same for this    JSON.parse(`{"__proto__":{"data":{"name":"./${i}","exports":{".": "./${j}.js"}},"path": "./"}}`))
/* all these are the same but different combination of i,j,t is used. */
// 28.jsmodule.exports=(i,j,t)=>(i+=[],j+"",t=(t+{}).split("[")[0],o={},    Object.entries(require('./289')(i,j)).forEach(        ([K,V])=>Object.entries(V).forEach(([k,v])=>(o[K]=o[K]||{},o[K][k]=v))),require(`./${i}`))
// 157.jsmodule.exports=(i,j,t)=>(i+=[],j+"",t=(t+{}).split("[")[0],o={},    Object.entries(require('./289')(i,t)).forEach(        ([K,V])=>Object.entries(V).forEach(([k,v])=>(o[K]=o[K]||{},o[K][k]=v))),require(`./${i}`))
// 299.jsmodule.exports=(i,j,t)=>(i+=[],j+"",t=(t+{}).split("[")[0],o={},    Object.entries(require('./289')(t,j)).forEach(        ([K,V])=>Object.entries(V).forEach(([k,v])=>(o[K]=o[K]||{},o[K][k]=v))),require(`./${t}`))
// 394.jsmodule.exports=(i,j,t)=>(i+=[],j+"",t=(t+{}).split("[")[0],o={},    Object.entries(require('./289')(t,i)).forEach(        ([K,V])=>Object.entries(V).forEach(([k,v])=>(o[K]=o[K]||{},o[K][k]=v))),require(`./${t}`))
// 555.jsmodule.exports=(i,j,t)=>(i+=[],j+"",t=(t+{}).split("[")[0],o={},    Object.entries(require('./289')(j,t)).forEach(        ([K,V])=>Object.entries(V).forEach(([k,v])=>(o[K]=o[K]||{},o[K][k]=v))),require(`./${j}`))
// 736.jsmodule.exports=(i,j,t)=>(i+=[],j+"",t=(t+{}).split("[")[0],o={},    Object.entries(require('./289')(j,i)).forEach(        ([K,V])=>Object.entries(V).forEach(([k,v])=>(o[K]=o[K]||{},o[K][k]=v))),require(`./${j}`))```
To understand what the last **6** files do, we run them in `node`:```js> i=1111,j=2222,t=33333333
>  i+=[],j+"",t=(t+{}).split("[")[0],o={},...     Object.entries(require('./289')(i,j)).forEach(...         ([K,V])=>Object.entries(V).forEach(([k,v])=>(o[K]=o[K]||{},o[K][k]=v))),...         require(`./${i}`)Uncaught Error: Cannot find module '/home/ispo/ctf/hxp_2022/required/files/2222.js'
???```
Even though we require `i`, program actually tries to load `required/files/2222.js` (whichcorresponds to `j`) and fails. This has to do with the modification of `__proto__` (for moredetails about it, please take a look[here](https://levelup.gitconnected.com/the-mysterious-javascript-objects-proto-property-67b7c6b3140c)).First, we invoke `require('./289')(i,j)`, so `exports` takes the value of the **2nd** parameter (`j`).If we replace it with `require('./289')(i,tj)`, we will get a different error:```js> i+=[],j+"",t=(t+{}).split("[")[0],o={},...     Object.entries(require('./289')(i,t)).forEach(...         ([K,V])=>Object.entries(V).forEach(([k,v])=>(o[K]=o[K]||{},o[K][k]=v))),...         require(`./${i}`)Uncaught Error: Cannot find module '/home/ispo/ctf/hxp_2022/required/files/3333.js'    at createEsmNotFoundErr (node:internal/modules/cjs/loader:1016:15)    at finalizeEsmResolution (node:internal/modules/cjs/loader:1009:15)    at trySelf (node:internal/modules/cjs/loader:505:12)    at Module._resolveFilename (node:internal/modules/cjs/loader:972:24)    at Module._load (node:internal/modules/cjs/loader:841:27)    at Module.require (node:internal/modules/cjs/loader:1061:19)    at require (node:internal/modules/cjs/helpers:103:18) {  code: 'MODULE_NOT_FOUND',  path: '/home/ispo/ctf/hxp_2022/required/files/package.json'}```
## Extracting Actual Computations
Program takes a flag as input, it invokes many many `require` functions to make various operationsin `f` and then prints the result. Our goal is to crack the flag from the encrypted version:```    0xd19ee193b461fd8d1452e7659acb1f47dc3ed445c8eb4ff191b1abfa7969```
The first task is to find out exactly which computations take place. I first tried to parse the`required.js` file and get the order of the JavaScript files. But it didn't work as they weremany files that seem to be missing, so I tried another approach:**I appended a console.log() statement to every .js files and I run it through the flag.**.This approach works because there are no if-conditions; no matter the flag input, the exact samecomputations are being applied. Function `patch_js_files` does the patching:```pythondef patch_js_files(root_dir):    """Patches all js files to append a console.log() statement."""    for root, dirs, files in os.walk(root_dir):        for file in files:            if not file.endswith(".js"):                continue
            # Blacklisted files.            if file in ['289.js', '37.js', '314.js', '556.js', '28.js', '157.js',                        '299.js', '394.js', '555.js', '736.js', 'required.js']:                continue
            # Read file            with open(os.path.join(root_dir, file)) as fp:                content = fp.read().strip()
            # Verify that all files start the same.                    prolog = 'module.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],'            if not content.startswith(prolog):                raise Exception(f'Invalid file content: {content}')
            line = content[len(prolog):]        # Drop the prolog                        line = line[:-1]                    # Drop the last ')'            stmt = line.split(',')[0]           # Get the 1st operation on f                                                # (we can have an extra f[i]&=0xff too)            stmt = stmt.replace('i', '${i}')    # Substitute parameters with formatted strings            stmt = stmt.replace('j', '${j}')            stmt = stmt.replace('t', '${t}')
            # Put operation into a console.log() statement with i,j,t being substituted            line = prolog + line + f",console.log(`{stmt}`))"             print(f'[+] Patching {file}: {line}')
            # Write patched file back.            with open(os.path.join(root_dir, file), 'w') as fp:                fp.write(line)```
This is how the new files look like:```javascript// 1.jsmodule.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[i]*=-1,f[i]&=0xff,    console.log(`f[${i}]*=-1`))
// 506.jsmodule.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[t]=f[t]^(f[t]>>1),    console.log(`f[${t}]=f[${t}]^(f[${t}]>>1)`))
// 743.jsmodule.exports=(i,j,t)=>(i%=30,j%=30,t%=30,i+=[],j+"",t=(t+{}).split("[")[0],f[i]*=f[2],f[i]&=0xff,    console.log(`f[${i}]*=f[2]`))```
Then we simply run `node required.js` and we dump all the equations:```f[17]+=f[5]f[29]=~f[29]&0xfff[3]^=f[11]f[6]=f[6]<<7&0xff|f[6]>>1f[2]=~f[2]&0xfff[20]=f[20]<<7&0xff|f[20]>>1f[23]=f[23]^(f[23]>>1)f[15]=f[15]^(f[15]>>1)f[9]^=f[1]f[9]^=f[4]f[16]=f[16]^(f[16]>>1)f[11]=f[11]<<1&0xff|f[11]>>7f[28]=~f[28]&0xfff[0]=~f[0]&0xfff[16]+=f[13]f[14]+=f[29]f[13]=~f[13]&0xfff[26]-=f[7]f[26]-=f[0]f[18]-=f[29]f[8]=f[8]<<1&0xff|f[8]>>7f[4]=f[4]^(f[4]>>1)f[5]-=f[7]f[10]^=f[29]f[15]^=f[20]f[22]=f[22]<<7&0xff|f[22]>>1f[4]^=f[15]f[13]-=f[3]f[5]=f[5]<<1&0xff|f[5]>>7f[26]=f[26]<<7&0xff|f[26]>>1f[14]^=f[21]f[29]=f[29]<<7&0xff|f[29]>>1f[1]-=f[4]f[4]=~f[4]&0xfff[13]-=f[18]f[16]=f[16]<<1&0xff|f[16]>>7f[11]=f[11]<<7&0xff|f[11]>>1f[7]-=f[6]f[11]-=f[20]f[23]=~f[23]&0xfff[4]+=f[3]f[26]+=f[22]f[16]=f[16]<<1&0xff|f[16]>>7f[11]+=f[8]f[8]^=f[9]f[24]+=f[14]f[29]-=f[24]f[4]-=f[18]f[1]=f[1]<<7&0xff|f[1]>>1f[20]=f[20]<<7&0xff|f[20]>>1f[20]=f[20]<<7&0xff|f[20]>>1f[20]=~f[20]&0xfff[11]^=f[2]f[20]-=f[24]f[2]+=f[6]f[10]+=f[24]f[25]=f[25]^(f[25]>>1)f[12]^=f[14]f[25]=f[25]<<7&0xff|f[25]>>1f[15]=f[15]<<1&0xff|f[15]>>7f[25]+=f[12]f[2]+=f[5]f[0]-=f[11]f[6]-=f[1]f[6]+=f[17]f[29]-=f[9]f[7]=~f[7]&0xfff[2]+=f[5]f[22]-=f[2]f[24]=f[24]<<1&0xff|f[24]>>7f[20]=f[20]^(f[20]>>1)f[28]=f[28]^(f[28]>>1)f[15]^=f[20]f[3]=f[3]<<1&0xff|f[3]>>7f[17]=f[17]<<7&0xff|f[17]>>1f[11]=f[11]<<7&0xff|f[11]>>1f[18]=~f[18]&0xfff[13]=f[13]^(f[13]>>1)f[15]-=f[2]f[9]+=f[20]f[6]^=f[1]f[1]-=f[13]f[0]-=f[4]f[14]=~f[14]&0xfff[17]=f[17]<<1&0xff|f[17]>>7f[17]=f[17]<<7&0xff|f[17]>>1f[14]=f[14]^(f[14]>>1)f[24]-=f[7]f[16]^=f[6]f[13]+=f[9]f[1]-=f[10]f[28]=f[28]<<1&0xff|f[28]>>7f[25]-=f[22]f[14]=f[14]^(f[14]>>1)f[2]=f[2]<<7&0xff|f[2]>>1f[2]^=f[15]f[17]=f[17]<<7&0xff|f[17]>>1f[3]-=f[22]f[23]=f[23]<<7&0xff|f[23]>>1f[11]=f[11]<<7&0xff|f[11]>>1f[9]+=f[16]f[7]=f[7]<<7&0xff|f[7]>>1f[6]=~f[6]&0xfff[5]+=f[15]f[6]-=f[17]f[7]-=f[6]f[3]+=f[28]f[1]^=f[18]f[22]-=f[5]f[14]-=f[2]f[21]^=f[22]f[4]-=f[29]f[26]=(((f[26]*0x0802&0x22110)|(f[26]*0x8020&0x88440))*0x10101>>>16)&0xfff[17]-=f[18]f[17]=f[17]<<1&0xff|f[17]>>7f[16]-=f[3]f[25]^=f[21]f[14]+=f[9]f[1]+=f[13]f[0]^=f[1]f[1]^=f[28]f[14]=~f[14]&0xfff[27]=(((f[27]*0x0802&0x22110)|(f[27]*0x8020&0x88440))*0x10101>>>16)&0xfff[9]^=f[2]f[17]=f[17]<<7&0xff|f[17]>>1f[13]^=f[1]f[5]^=f[13]f[10]^=f[0]f[12]^=f[1]f[2]=~f[2]&0xfff[1]=f[1]<<7&0xff|f[1]>>1f[11]=f[11]<<1&0xff|f[11]>>7f[9]^=f[28]f[3]=(((f[3]*0x0802&0x22110)|(f[3]*0x8020&0x88440))*0x10101>>>16)&0xfff[19]=f[19]<<1&0xff|f[19]>>7f[16]-=f[9]f[8]=f[8]<<1&0xff|f[8]>>7f[28]=f[28]<<1&0xff|f[28]>>7f[12]-=f[3]f[25]=(((f[25]*0x0802&0x22110)|(f[25]*0x8020&0x88440))*0x10101>>>16)&0xfff[14]=(((f[14]*0x0802&0x22110)|(f[14]*0x8020&0x88440))*0x10101>>>16)&0xfff[11]=f[11]<<7&0xff|f[11]>>1f[6]+=f[28]f[6]^=f[5]f[28]^=f[0]f[10]-=f[22]f[8]=f[8]^(f[8]>>1)f[19]=f[19]<<7&0xff|f[19]>>1f[26]-=f[14]f[25]^=f[28]f[15]-=f[17]f[12]^=f[4]f[25]+=f[4]f[11]=~f[11]&0xfff[1]=f[1]<<7&0xff|f[1]>>1f[9]+=f[28]f[4]^=f[18]f[15]=~f[15]&0xfff[12]=f[12]<<1&0xff|f[12]>>7f[12]=f[12]<<7&0xff|f[12]>>1f[2]=f[2]^(f[2]>>1)f[6]=~f[6]&0xfff[10]=f[10]<<7&0xff|f[10]>>1f[20]=f[20]^(f[20]>>1)f[20]+=f[24]f[4]=f[4]<<1&0xff|f[4]>>7f[16]^=f[11]f[8]=~f[8]&0xfff[1]=(((f[1]*0x0802&0x22110)|(f[1]*0x8020&0x88440))*0x10101>>>16)&0xfff[4]+=f[18]f[5]=f[5]^(f[5]>>1)f[25]-=f[4]f[9]^=f[26]f[5]^=f[3]f[4]^=f[2]f[29]-=f[21]f[20]=f[20]<<1&0xff|f[20]>>7f[24]^=f[27]f[8]+=f[16]f[22]=f[22]<<7&0xff|f[22]>>1f[3]=f[3]<<7&0xff|f[3]>>1f[10]-=f[9]f[9]=f[9]^(f[9]>>1)f[24]^=f[25]f[9]=~f[9]&0xfff[1]=f[1]^(f[1]>>1)f[19]=f[19]<<1&0xff|f[19]>>7f[7]=f[7]<<7&0xff|f[7]>>1f[21]+=f[25]f[28]-=f[0]f[18]=f[18]<<7&0xff|f[18]>>1f[20]^=f[5]f[17]^=f[12]f[22]-=f[23]f[18]+=f[25]f[4]=f[4]<<1&0xff|f[4]>>7f[0]=f[0]<<1&0xff|f[0]>>7f[29]=f[29]<<1&0xff|f[29]>>7f[17]=f[17]<<1&0xff|f[17]>>7f[7]^=f[21]f[8]-=f[17]f[10]+=f[22]f[8]-=f[18]f[21]+=f[0]f[15]^=f[20]f[1]=f[1]<<1&0xff|f[1]>>7f[14]=f[14]<<7&0xff|f[14]>>1f[13]^=f[2]f[9]^=f[6]f[15]-=f[8]f[8]^=f[1]f[6]=f[6]^(f[6]>>1)f[21]^=f[5]f[17]^=f[13]f[12]-=f[8]f[19]^=f[12]f[2]^=f[1]f[25]=f[25]<<1&0xff|f[25]>>7f[19]=f[19]^(f[19]>>1)f[0]=f[0]^(f[0]>>1)f[17]+=f[27]f[20]=f[20]<<7&0xff|f[20]>>1f[28]-=f[13]f[22]=~f[22]&0xfff[26]^=f[17]f[10]=f[10]<<1&0xff|f[10]>>7f[24]=~f[24]&0xfff[4]-=f[22]f[4]-=f[20]f[24]+=f[12]f[13]=f[13]<<1&0xff|f[13]>>7f[2]=f[2]<<7&0xff|f[2]>>1f[1]-=f[24]f[11]^=f[27]f[14]=f[14]^(f[14]>>1)f[17]=f[17]^(f[17]>>1)f[21]=f[21]^(f[21]>>1)f[24]=(((f[24]*0x0802&0x22110)|(f[24]*0x8020&0x88440))*0x10101>>>16)&0xfff[12]=f[12]^(f[12]>>1)f[3]=f[3]<<1&0xff|f[3]>>7f[8]+=f[1]f[21]+=f[18]f[0]+=f[22]f[4]=f[4]<<7&0xff|f[4]>>1f[25]=f[25]<<1&0xff|f[25]>>7f[10]=f[10]<<7&0xff|f[10]>>1f[13]=f[13]^(f[13]>>1)f[1]-=f[27]f[13]=(((f[13]*0x0802&0x22110)|(f[13]*0x8020&0x88440))*0x10101>>>16)&0xfff[11]=(((f[11]*0x0802&0x22110)|(f[11]*0x8020&0x88440))*0x10101>>>16)&0xfff[2]+=f[17]f[6]=f[6]<<7&0xff|f[6]>>1f[10]=f[10]^(f[10]>>1)f[4]-=f[8]f[1]-=f[2]f[0]-=f[14]f[11]=f[11]^(f[11]>>1)f[7]-=f[17]f[18]=~f[18]&0xfff[0]^=f[16]f[12]+=f[13]f[23]=~f[23]&0xfff[10]-=f[7]f[29]=f[29]^(f[29]>>1)f[3]=f[3]<<7&0xff|f[3]>>1f[20]^=f[3]f[8]=f[8]<<1&0xff|f[8]>>7f[25]-=f[24]f[26]=f[26]<<1&0xff|f[26]>>7f[10]=f[10]^(f[10]>>1)f[26]=f[26]^(f[26]>>1)f[16]-=f[7]f[8]=~f[8]&0xfff[14]^=f[13]f[3]+=f[24]f[15]=(((f[15]*0x0802&0x22110)|(f[15]*0x8020&0x88440))*0x10101>>>16)&0xfff[15]-=f[28]f[10]=f[10]^(f[10]>>1)f[17]+=f[15]f[22]-=f[2]f[27]=~f[27]&0xfff[5]=f[5]^(f[5]>>1)f[20]=~f[20]&0xfff[13]^=f[24]f[23]^=f[21]f[2]-=f[23]f[5]+=f[20]f[24]^=f[12]f[9]-=f[8]f[11]=f[11]^(f[11]>>1)f[27]-=f[14]f[18]+=f[25]f[6]+=f[26]f[7]=f[7]^(f[7]>>1)f[28]=f[28]^(f[28]>>1)f[10]-=f[1]f[18]-=f[14]f[20]+=f[14]f[15]-=f[17]f[0]=~f[0]&0xff0x2a8c594b90bc4be941624cac7493f521772b475b27209734942302ded9f30a```
We can verify that the computations are correct by initializing a `f` and checking the finalresult (we also need to replace `>>>` with `>>`).
## Reversing the Computations
Now that we have the computations, the next step is to find the initial value of `f` that givesthe desired flag `d19ee193b461fd8d1452e7659acb1f47dc3ed445c8eb4ff191b1abfa7969`. Once approachwould be to use `z3` but it's going to be a mess because the same variables are being updated(e.g., `f[1] += f[2]`, so we need to have multiple instances for each symbolic variable:`s.add(f1_1 = f1_0 + f2_0`). However, we can do better: **all operations are invertible**, sowe can execute them in the reverse order and get the flag. That is, we need to write a scriptthat generates a python script with the inverted operations. We do this and we run the generatedscript to get the flag.
For more details, please take a look at the [required_crack.py](./required_crack.py) file.
So the flag is: `hxp{Cann0t_f1nd_m0dule_'fl4g'}`
We verify that the flag is correct:```ispo@ispo-glaptop2:~/ctf/hxp_2022/required/files$ cat flag hxp{1234567890123456789012345}
ispo@ispo-glaptop2:~/ctf/hxp_2022/required/files$ ./run.sh :(
ispo@ispo-glaptop2:~/ctf/hxp_2022/required/files$ echo -n "hxp{Cann0t_f1nd_m0dule_'fl4g'}" > flag
ispo@ispo-glaptop2:~/ctf/hxp_2022/required/files$ ./run.sh :)```___