---
# System prepended metadata

title: ARA CTF 6.0 QUALIFICATION WRITEUP

---

<style>
img[alt=chall-sc] {
  display: block;
  margin: 0 auto;
  width: 100em; 
}

p {
  text-align: justify;
}

p::first-line {
  text-indent: 0;
}

</style>


# ARA CTF 6.0 QUALIFICATION WRITEUP
## Sanity Check
![chall-sc](https://hackmd.io/_uploads/BkcI3gIFyg.png)
Free flag
`Flag: ARA6{apakah_kalian_akan_memasak_atau_dimasak?????}`

## Simple Math
![chall-sc](https://hackmd.io/_uploads/BJ2aTxLYJe.png)
Given a disassembled Python bytecode and the output
```python
  0           0 RESUME                   0

  2           2 LOAD_CONST               9 ((5,))
              4 LOAD_CONST               1 (<code object conv at 0x000001D2B5453870, file "<string>", line 2>)
              6 MAKE_FUNCTION            1 (defaults)
              8 STORE_NAME               0 (conv)

  6          10 PUSH_NULL
             12 LOAD_NAME                1 (open)
             14 LOAD_CONST               2 ('flag.txt')
             16 CALL                     1
             24 LOAD_ATTR                5 (NULL|self + read)
             44 CALL                     0
             52 STORE_NAME               3 (flag)

  7          54 BUILD_LIST               0
             56 STORE_NAME               4 (flags)

  8          58 BUILD_LIST               0
             60 LOAD_CONST               3 ((412881107802, 397653008560, 378475773842, 412107467700, 410815948500, 424198405792, 379554633200, 404975010927, 419449858501, 383875726561))
             62 LIST_EXTEND              1
             64 STORE_NAME               5 (N)

  9          66 PUSH_NULL
             68 LOAD_NAME                6 (reversed)
             70 LOAD_NAME                5 (N)
             72 CALL                     1
             80 STORE_NAME               7 (NR)

 11          82 PUSH_NULL
             84 LOAD_NAME                8 (len)
             86 LOAD_NAME                3 (flag)
             88 CALL                     1
             96 LOAD_CONST               0 (5)
             98 BINARY_OP                6 (%)
            102 LOAD_CONST               4 (0)
            104 COMPARE_OP              40 (==)
            108 POP_JUMP_IF_TRUE         2 (to 114)
            110 LOAD_ASSERTION_ERROR
            112 RAISE_VARARGS            1

 13     >>  114 PUSH_NULL
            116 LOAD_NAME                9 (zip)
            118 PUSH_NULL
            120 LOAD_NAME                0 (conv)
            122 LOAD_NAME                3 (flag)
            124 CALL                     1
            132 LOAD_NAME                5 (N)
            134 LOAD_NAME                7 (NR)
            136 CALL                     3
            144 GET_ITER
        >>  146 FOR_ITER                71 (to 292)
            150 UNPACK_SEQUENCE          3
            154 STORE_NAME              10 (i)
            156 STORE_NAME              11 (j)
            158 STORE_NAME              12 (k)

 14         160 LOAD_NAME               13 (int)
            162 LOAD_ATTR               29 (NULL|self + from_bytes)
            182 LOAD_NAME               10 (i)
            184 LOAD_ATTR               31 (NULL|self + encode)
            204 CALL                     0
            212 LOAD_CONST               5 ('big')
            214 CALL                     2
            222 STORE_NAME              16 (x)

 15         224 LOAD_NAME               16 (x)
            226 LOAD_NAME               11 (j)
            228 BINARY_OP                0 (+)
            232 LOAD_CONST               6 (1337)
            234 BINARY_OP                5 (*)
            238 LOAD_NAME               12 (k)
            240 BINARY_OP               12 (^)
            244 STORE_NAME              17 (y)

 16         246 LOAD_NAME               17 (y)
            248 LOAD_CONST               7 (871366131)
            250 BINARY_OP               23 (-=)
            254 STORE_NAME              17 (y)

 17         256 LOAD_NAME                4 (flags)
            258 LOAD_ATTR               37 (NULL|self + append)
            278 LOAD_NAME               17 (y)
            280 CALL                     1
            288 POP_TOP
            290 JUMP_BACKWARD           73 (to 146)

 13     >>  292 END_FOR

 19         294 PUSH_NULL
            296 LOAD_NAME               19 (print)
            298 LOAD_NAME                4 (flags)
            300 CALL                     1
            308 POP_TOP
            310 RETURN_CONST             8 (None)

Disassembly of <code object conv at 0x000001D2B5453870, file "<string>", line 2>:
  2           0 RETURN_GENERATOR
              2 POP_TOP
              4 RESUME                   0

  3           6 LOAD_GLOBAL              1 (NULL + range)
             16 LOAD_CONST               1 (0)
             18 LOAD_GLOBAL              3 (NULL + len)
             28 LOAD_FAST                0 (str)
             30 CALL                     1
             38 LOAD_FAST                1 (l)
             40 CALL                     3
             48 GET_ITER
        >>   50 FOR_ITER                12 (to 78)
             54 STORE_FAST               2 (i)

  4          56 LOAD_FAST                0 (str)
             58 LOAD_FAST                2 (i)
             60 LOAD_FAST                2 (i)
             62 LOAD_FAST                1 (l)
             64 BINARY_OP                0 (+)
             68 BINARY_SLICE
             70 YIELD_VALUE              1
             72 RESUME                   1
             74 POP_TOP
             76 JUMP_BACKWARD           14 (to 50)

  3     >>   78 END_FOR
             80 RETURN_CONST             0 (None)
        >>   82 CALL_INTRINSIC_1         3 (INTRINSIC_STOPITERATION_ERROR)
             84 RERAISE                  1
```
### Disassembled Bytecode Analysis

The provided disassembled bytecode indicates the following operations:

1. **Reading `flag.txt`**: The script opens and reads the contents of `flag.txt` into a variable named `flag`.

2. **Initialization of Lists**:
   - `N`: A list containing ten large integers.
   - `NR`: A reversed version of the list `N`.

3. **Assertion**: The script checks that the length of `flag` is a multiple of 5.

4. **Processing Loop**: The script iterates over the zipped result of a function `conv(flag)`, `N`, and `NR`. For each tuple `(i, j, k)`:
   - Converts the string `i` to an integer `x` using `int.from_bytes(i.encode(), 'big')`.
   - Applies the following transformation to compute `y`:
     $$
     y = ((x + j) \times 1337) \oplus k - 871366131
     $$
   - Appends `y` to a list named `flags`.

5. **Output**: Finally, the script prints the `flags` list.

### Reversing the Transformation

To reconstruct the original content of `flag.txt`, we need to reverse the transformation applied to each character. Given the transformation:
$$
y = ((x + j) \times 1337) \oplus k - 871366131
$$
We can solve for `x` as follows:
$$
x = \left( \frac{(y + 871366131) \oplus k}{1337} \right) - j
$$

### Solving It

This is the script that that I made to reverse the transformation:

```python
#!/usr/bin/env python3

N = [412881107802, 397653008560, 378475773842, 412107467700, 410815948500, 424198405792, 379554633200, 404975010927, 419449858501, 383875726561]
NR = list(reversed(N))

ct = [927365724618649, 855544946535839, 1075456339888851, 1051300489856216, 854566738228717, 862564607600557, 1107196607637040, 835104762026329, 1108826984434051, 843310935687105]

pt = b""
for y, j, k in zip(ct, N, NR):
    x = ((y + 871366131) ^ k) // 1337 - j
    pt += x.to_bytes((x.bit_length() + 7) // 8, 'big')

print(pt)
```
![chall-sc](https://hackmd.io/_uploads/HyCHWZ8KJe.png)
`Flag: ARA6{8yT3_c0d3_W1Th_51MPl3_m4th_15_345Y____R19ht?}`

## memory
![chall-sc](https://hackmd.io/_uploads/Sk-dZb8Yyx.png)
Given two ELF (Executable and Linkable Format) 64-bit files: `memory` and `memory-v2`.  
I used `diff` to compare the symbol tables of two ELF binaries (`memory` and `memory-v2`) and show their differences
![chall-sc](https://hackmd.io/_uploads/rJ0wGZIYkl.png)
`memory-v2` includes a reference to String::len() from Rust's alloc crate, whereas `memory` does not. I decompiled the `memory-v2` using IDA. This is the result:
### main
```c
int __fastcall main(int argc, const char **argv, const char **envp)
{
  return std::rt::lang_start(memory::main, argc, (u8 **)argv, 0);
}
```
### memory::main
```c
void __cdecl memory::main()
{
  __int64 v0; // rax
  void *v1; // rax
  __int64 v2; // rax
  __int64 v3; // rax
  __int64 v4; // rdx
  _str v5; // rdi
  _str v6; // rdx
  _str v7; // rdi
  core::str::iter::Chars v8; // rax
  unsigned __int16 v9; // ax
  __int16 v10; // ax
  _str v11; // rdi
  core::str::iter::Chars v12; // rax
  usize v13; // [rsp+10h] [rbp-218h]
  unsigned __int8 v14; // [rsp+59h] [rbp-1CFh]
  unsigned __int8 v15; // [rsp+5Ah] [rbp-1CEh]
  core::fmt::Arguments v16; // [rsp+E8h] [rbp-140h] BYREF
  core::fmt::Arguments v17; // [rsp+118h] [rbp-110h] BYREF
  alloc::string::String self; // [rsp+148h] [rbp-E0h] BYREF
  core::fmt::Arguments v19; // [rsp+160h] [rbp-C8h] BYREF
  __int64 v20; // [rsp+190h] [rbp-98h]
  core::result::Result<usize,std::io::error::Error> v21; // [rsp+198h] [rbp-90h] BYREF
  __int64 v22; // [rsp+1A8h] [rbp-80h]
  core::option::Option<char> v23; // [rsp+1B4h] [rbp-74h] BYREF
  core::option::Option<char> v24[2]; // [rsp+1B8h] [rbp-70h] BYREF
  u8 *end_or_len; // [rsp+1C0h] [rbp-68h]
  unsigned int v26; // [rsp+1CCh] [rbp-5Ch]
  char v27; // [rsp+1D2h] [rbp-56h]
  char v28; // [rsp+1D3h] [rbp-55h]
  core::option::Option<char> v29; // [rsp+1D4h] [rbp-54h] BYREF
  core::option::Option<char> v30[2]; // [rsp+1D8h] [rbp-50h] BYREF
  u8 *v31; // [rsp+1E0h] [rbp-48h]
  alloc::string::String other; // [rsp+1E8h] [rbp-40h] BYREF
  char v33; // [rsp+203h] [rbp-25h]
  int v34; // [rsp+204h] [rbp-24h]
  void *v35; // [rsp+208h] [rbp-20h]
  std::io::error::Error v36; // [rsp+210h] [rbp-18h]

  core::fmt::Arguments::new_const(&v16, (_str (*)[1])off_5A2A8);
  std::io::stdio::_print();
  core::fmt::Arguments::new_const(&v17, (_str (*)[1])off_5A2B8);
  ((void (__fastcall *)(core::fmt::Arguments *))std::io::stdio::_print)(&v17);
  alloc::string::String::new(&self);
  core::fmt::Arguments::new_const(&v19, (_str (*)[1])off_5A2C8);
  std::io::stdio::_print();
  std::io::stdio::stdout();
  v20 = v0;
  <std::io::stdio::Stdout as std::io::Write>::flush();
  v35 = v1;
  if ( v1 )
  {
    v36.repr.__0.pointer = v35;
    core::result::unwrap_failed();
  }
  std::io::stdio::stdin();
  v22 = v2;
  std::io::stdio::Stdin::read_line();
  *(_QWORD *)v21.gap0 = v3;
  *(_QWORD *)&v21.gap0[8] = v4;
  core::ptr::drop_in_place<core::result::Result<usize,std::io::error::Error>>(&v21);
  alloc::string::String::pop((core::option::Option<char> *)&self, &self);
  v5 = <alloc::string::String as core::ops::deref::Deref>::deref(&self);
  v6.data_ptr = (u8 *)"ARA6{";
  v6.length = 4LL;
  if ( core::str::<impl str>::starts_with(v5, v6) )
  {
    v7 = <alloc::string::String as core::ops::deref::Deref>::deref(&self);
    v8 = core::str::<impl str>::chars(v7);
    *(_QWORD *)v24[0].gap0 = v8.iter.ptr.pointer;
    end_or_len = v8.iter.end_or_len;
    v23 = (core::option::Option<char>)core::iter::traits::iterator::Iterator::nth(
                                        v24,
                                        (core::str::iter::Chars *)&::self,
                                        (usize)v8.iter.end_or_len);
    if ( <core::option::Option<T> as core::cmp::PartialEq>::eq(&v23, (core::option::Option<char> *)"{") )
    {
      v26 = 5;
      v27 = 0;
LABEL_9:
      v28 = 0;
      while ( 1 )
      {
        v15 = v28 + v27;
        if ( __CFADD__(v28, v27) )
          core::panicking::panic_const::panic_const_add_overflow();
        LOBYTE(v9) = v15 / 0x1Au;
        HIBYTE(v9) = v15 % 0x1Au;
        v10 = HIBYTE(v9);
        v14 = v10 + 64;
        if ( __CFADD__((_BYTE)v10, 64) )
          core::panicking::panic_const::panic_const_add_overflow();
        v33 = v10 + 64;
        v34 = v14;
        v11 = <alloc::string::String as core::ops::deref::Deref>::deref(&self);
        v12 = core::str::<impl str>::chars(v11);
        *(_QWORD *)v30[0].gap0 = v12.iter.ptr.pointer;
        v31 = v12.iter.end_or_len;
        v29 = (core::option::Option<char>)core::iter::traits::iterator::Iterator::nth(
                                            v30,
                                            (core::str::iter::Chars *)v26,
                                            (usize)v12.iter.end_or_len);
        LODWORD(other.vec.buf.inner.cap.__0) = v14;
        if ( core::cmp::PartialEq::ne(&v29, (core::option::Option<char> *)&other) )
          break;
        if ( v28 == -1 )
          core::panicking::panic_const::panic_const_add_overflow();
        ++v28;
        if ( v26 == -1 )
          core::panicking::panic_const::panic_const_add_overflow();
        ++v26;
        if ( v28 == 15 )
        {
          if ( v27 == -1 )
            core::panicking::panic_const::panic_const_add_overflow();
          ++v27;
          goto LABEL_9;
        }
        if ( v27 == 4 )
        {
          HIDWORD(other.vec.buf.inner.cap.__0) = (unsigned int)alloc::string::String::pop(
                                                                 (core::option::Option<char> *)&self,
                                                                 &other);
          if ( <core::option::Option<T> as core::cmp::PartialEq>::eq(
                 (core::option::Option<char> *)&other.vec.buf.inner.cap.__0 + 1,
                 (core::option::Option<char> *)&::other) )
          {
            v13 = alloc::string::String::len(&self);
            if ( v13 == -1LL )
              core::panicking::panic_const::panic_const_add_overflow();
            if ( v13 == 66 )
            {
              memory::yes();
              core::ptr::drop_in_place<alloc::string::String>(&self);
              return;
            }
          }
          break;
        }
      }
    }
  }
  memory::no();
  core::ptr::drop_in_place<alloc::string::String>(&self);
}
```
### memory::yes
```c
void __cdecl memory::yes()
{
  core::fmt::Arguments v0; // [rsp+8h] [rbp-30h] BYREF

  core::fmt::Arguments::new_const(&v0, (_str (*)[1])off_5A298);
  std::io::stdio::_print();
}
```
### memory::no
```c
void __cdecl memory::no()
{
  core::fmt::Arguments v0; // [rsp+8h] [rbp-30h] BYREF

  core::fmt::Arguments::new_const(&v0, (_str (*)[1])pieces);
  std::io::stdio::_print();
}
```
This is a flag checker challenge. If we input the correct flag, the result is `Yes! This one you got it right!`, and if we input the incorrect flag, the result is `That is... wrong`.

### Observing the Flag Pattern

The flag follows this structure:

- **Prefix**: `"ARA6{"` 
- **Grid-based character sequence**: (60 characters)
  - Generated using an indexed ASCII transformation.
- **Suffix**: `"}"` 

### Solving It
The flag is compared character by character at elf_base + 0x94be against our input using `<core::option::Option<T> as core::cmp::PartialEq>::eq(&v23, (core::option::Option<char> *)"{")`.
![chall-sc](https://hackmd.io/_uploads/ryTXJX8Y1g.png)
I manually checked each of the compared character to retrieve the full flag.
![chall-sc](https://hackmd.io/_uploads/SJKmgm8Fye.png)
`Flag: ARA6{@ABCDEFGHIJKLMNABCDEFGHIJKLMNOBCDEFGHIJKLMNOPCDEFGHIJKLMNOPQD}`