---
tags: re, ctf
---
# LINE CTF 2022 - Reversing
## Rolling
At the first time, we spent a lot of time to try run blow script (using `dlopen`, `aarch64` simulation) but it's segfaulted all times 😢
```cpp
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <unistd.h>
int main()
{
printf("Hello World!\n");
/*
char cwd[255];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
printf("[+] Current working dir: %s\n", cwd);
} else {
perror("[-] getcwd() error");
return 1;
}*/
// declare a function pointer for the function to import
typedef long (*h_meatbox)(char*);
// open the shared object
void *dlh = dlopen("libnative-lib.so", RTLD_LAZY);
// void *dlh=NULL;
if (dlh == NULL) {
printf("[-] open library fail\n");
exit(1);
}
// resolve the function symbol
h_meatbox meatbox = dlsym(dlh, "_Z7meatboxPc");
printf("[+] meatbox: 0x%lx\n", meatbox);
for (int i=0; i<4; i++) printf("%x ", (char*)(meatbox+i));
if (meatbox==NULL){
printf("[-] resolve function fail\n");
exit(1);
}
/*
// call function
char arr[]="abc\0";
printf("[+] Result meatbox: %ld\n", (*meatbox)(arr));*/
printf("[+] here\n");
return 0;
}
// aarch64-linux-gnu-gcc test.c -o test -ldl
// sudo qemu-aarch64 -L /usr/aarch64-linux-gnu ./test
```
Finally, we decided to use `frida` hooking `libnative` in the android mobiles. Here's my script that extracts the required output for the decryption flag.
**Script hooking**
```jsx
Interceptor.attach(Module.getExportByName('libnative-lib.so', '_Z7meatboxPc'), {
onEnter: function(args) {
console.log("attach meatbox...")
},
onLeave: function(retval) {
// simply replace the value to be returned with 0
var buf = Memory.readByteArray(ptr(retval), 1)
// console.log(retval);
// console.log(buf);
var b = new Uint8Array(buf);
var str = "";
for(var i = 0; i < b.length; i++) {
str += (b[i].toString(16) + " ");
}
console.log(str);
}
});
Interceptor.attach(Module.getExportByName('libnative-lib.so', '_Z7soulboxPc'), {
onEnter: function(args) {
console.log("attach soulbox...")
},
onLeave: function(retval) {
// simply replace the value to be returned with 0
var buf = Memory.readByteArray(ptr(retval), 1)
// console.log(retval);
// console.log(buf);
var b = new Uint8Array(buf);
var str = "";
for(var i = 0; i < b.length; i++) {
str += (b[i].toString(16) + " ");
}
console.log(str);
}
});
Interceptor.attach(Module.getExportByName('libnative-lib.so', '_Z6godboxPc'), {
onEnter: function(args) {
console.log("attach godbox...")
},
onLeave: function(retval) {
// simply replace the value to be returned with 0
var buf = Memory.readByteArray(ptr(retval), 1)
// console.log(retval);
// console.log(buf);
var b = new Uint8Array(buf);
var str = "";
for(var i = 0; i < b.length; i++) {
str += (b[i].toString(16) + " ");
}
console.log(str);
}
});
```
## RES
The challenge’s webpage displays an input box that we can supply the plaintext and get the ciphertext. Our goal is to decrypt the password and get flag.
The challenge is written in WebAssembly. Like other Wasm challenges, our team had encountered before, our approach was just debug the crap out of the program and try to understand the workflow. After a while we figured out that the RES will generate 5 random numbers form 0 to 4 and each number will be correspond to a different encryption algorithm. Our plaintext will get passed into each algorithms followed the order of the random numbers. Based on the strings and the constants in the binary, we uncovered all 5 encryption algorithms as followed:
- func10 → Camellia
- func11 → AES
- func12 → 3DES
- func13 → SEED
- func14 → RC4
For the key for each algorithms, we continue to debug the program and also took some leap of faith to figured out the correct keys. This is the most consumed part of the challenge for our team and it was 3A.M so we were exhausted . Luckily, we managed to recovered all the keys. Finally we wrote a Python script to iterate through all the permutations and try to decrypt the password
```python
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from Crypto.Cipher import ARC4, DES3, AES
import itertools
import base64
def solveCamellia(ciphertext):
key = bytes.fromhex('112233445566778899aabbccddeeff00')
cipher = Cipher(algorithms.Camellia(key), modes.ECB(), default_backend())
decryptor = cipher.decryptor()
return decryptor.update(ciphertext) + decryptor.finalize()
def solveSEED(ciphertext):
key = bytes.fromhex('ff04286121ea1be86d71ccb1fda74382')
cipher = Cipher(algorithms.SEED(key), modes.ECB(), default_backend())
decryptor = cipher.decryptor()
return decryptor.update(ciphertext) + decryptor.finalize()
def solveRC4(ciphertext):
key = bytes.fromhex('4706480851e61be85d74bfb3fd956185')
cipher = ARC4.new(key)
return cipher.decrypt(ciphertext)
def solveDES3(ciphertext):
key = bytes.fromhex('48454c504d4521005448414e4b5321001020304050607080')
return DES3.new(key=key, mode=DES3.MODE_ECB).decrypt(ciphertext)
def solveAES(ciphertext):
key = bytes.fromhex('a741be1431dd82496357baf131aecfd5')
iv = bytes.fromhex('c91928c84fc61be85d79cf83fd95c185')
return AES.new(key=key, mode=AES.MODE_CBC, IV=iv).decrypt(ciphertext)
ciphertext = "N9Nb2sPYFl6sEbVORzuK1kUXMvs+/LbyrTpJaxQj3fdDhXyKN8mBELPRTX5904o9"
ciphertext = base64.b64decode(ciphertext)
for funcs in itertools.permutations([solveCamellia, solveSEED, solveRC4, solveDES3, solveAES]):
func1, func2, func3, func4, func5 = funcs
result = func1(func2(func3(func4(func5(ciphertext)))))
if b'LINECTF' in result:
print(result)
```
Flag: **LINECTF{RE7ard3d_3ncryp710n_53rv1c3_x0x}**