# WRECKCTF 2022

Chào mọi người lại quay trở lại với một giải đấu được gọi là vừa sức đối với những người mới và trung bình kinh nghiệm còn thấp của tôi. Sau đây không lòng vòng tôi đi vào mục tiêu chính với 4/6 thử thách RE - Dịch ngược tôi hoàn thành.

Sau chuỗi bài đầu tiên tôi sẽ tinh gọn những bước đơn giản và các bước đầu tiên và sẽ tập trung phân tích và tiếp nạp các kiến thức trong quá trình giải và tìm hiểu kiến thức mới từ các challenges nhá.

## 1: flag-checker (Solved)

![title](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2022/Wreckctf/flag-checker/img/00_title.png)

Tôi sẽ mở nó bằng `IDA pro` và nhận được kết quả của hàm main:

```c
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[3]; // [rsp+0h] [rbp-40h] BYREF
  char v5[3]; // [rsp+3h] [rbp-3Dh] BYREF
  char v6[3]; // [rsp+6h] [rbp-3Ah] BYREF
  char v7[3]; // [rsp+9h] [rbp-37h] BYREF
  char v8[3]; // [rsp+Ch] [rbp-34h] BYREF
  char v9[3]; // [rsp+Fh] [rbp-31h] BYREF
  char v10[3]; // [rsp+12h] [rbp-2Eh] BYREF
  char v11[3]; // [rsp+15h] [rbp-2Bh] BYREF
  char v12[3]; // [rsp+18h] [rbp-28h] BYREF
  char v13[3]; // [rsp+1Bh] [rbp-25h] BYREF
  char v14[3]; // [rsp+1Eh] [rbp-22h] BYREF
  char v15[3]; // [rsp+21h] [rbp-1Fh] BYREF
  char v16[20]; // [rsp+24h] [rbp-1Ch] BYREF
  unsigned __int64 v17; // [rsp+38h] [rbp-8h]

  v17 = __readfsqword(0x28u);
  fgets(s, 41, _bss_start);
  v16[4] = 0;
  if ( strlen(s) != 40 )  //flag có length = 40
    bad();
  if ( strncmp(v14, "d94", 3uLL) )
    bad();
  if ( strncmp(v6, "db_", 3uLL) )
    bad();
  if ( strncmp(v10, "35t", 3uLL) )
    bad();
  if ( strncmp(v8, "y0u", 3uLL) )
    bad();
  if ( strncmp(v7, "1s_", 3uLL) )
    bad();
  if ( strncmp(v13, "d_6", 3uLL) )
    bad();
  if ( strncmp(v5, "g{g", 3uLL) )
    bad();
  if ( strncmp(v11, "_fr", 3uLL) )
    bad();
  if ( v16[3] != 125 )
    bad();
  if ( strncmp(v12, "13n", 3uLL) )
    bad();
  if ( strncmp(v16, "fa6", 3uLL) )
    bad();
  if ( strncmp(v9, "r_b", 3uLL) )
    bad();
  if ( strncmp(v15, "620", 3uLL) )
    bad();
  if ( strncmp(s, "fla", 3uLL) )
    bad();
  puts("Nice job! Submit your answer as the flag.");
  return 0;
}
```

Bài check `length` của flag và các `subflag` với các `string`, nếu không thỏa mãn 1 câu lệnh if nào sẽ gọi hàm `bad()`

Flag: `flag{gdb_1s_y0ur_b35t_fr13nd_6d94620fa6}` -> Done với thử thách đầu nhé🥸

## 2: advanced-flag-checker (Solved)

![title 2](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2022/Wreckctf/advanced-flag-checker/img/00_title.png)

Tiếp tục với IDA:

![open ida pro](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2022/Wreckctf/advanced-flag-checker/img/01_open_ida.png)

Ta nhận ra hàm main có gọi function `sys_write` để in ra thông báo cần nhập `flag` và đọc flag nhập vào. Tiếp theo chương trình sử dụng toán tử `XOR` cho lần lượt `4 byte` của `input` với giá trị tương ứng của đề bài và so sánh giá trị yêu cầu.

Vậy cũng khá dễ để giải quyết bài này🫡. Nhắc lại kiến thức `XOR` 1 chút là nếu: `A xor Value đã biết = value nào đó đã biết` thì ta chỉ vần `xor với 2 value đã biết` đó với nhau thì ta sẽ tìm được `A`

Dưới đây là code của tôi về bài này:

```python
# Tôi tạo 1 hàm reverse lại kết quả nhận được sau khi xor 2 giá trị đã biết
def rever(a1,a2):
    a = hex(a1 ^ a2)[2:]
    lst = [chr(int(a[6:8],16)),chr(int(a[4:6],16)),chr(int(a[2:4],16)),chr(int(a[:2],16))] 
    # tạo list được chuyển ngược vì nó ngắn nên tôi làm thế nào vì code xấu ae ta thông cảm nhé, mấy giải mới sẽ ngon hơn 🫡
    return ''.join(lst) # trả về chuỗi

print(rever(0x558C4DC,0x6239A8BA),end='')
print(rever(0x71100C9B,0x17F64E0),end='')
print(rever(0xCE3D1DDE,0xA14442BB),end='')
print(rever(0x322958FC,0x415C0789),end='')
print(rever(0x8CBE8F4E,0xF6E1EB2B),end='')
print(rever(0xB14A374B,0xDE2C6878),end='')
print(rever(0xEE9707A,0x669D2F08),end='')
print(rever(0xF98DDD38,0xC8D2AE51),end='')
print(rever(0x5D715F4D,0x6C12677F),end='')
print(rever(0x410B9F90,0x3C3CFBA3),end='')
```

Có 1 lưu ý là kết quả nhận được 4 bytes liên tiếp nhau thì ta cần tách nó ra thành. Nhưng kiết quả nhận được bố trí theo kiểu **Little-endian** - 1 dạng sắp xếp các giá trị ít quan trọng nhất được lưu trữ trước. Ví dụ này cho dễ hiểu nhé.😁

Nếu số ta có là `0xFFAA0322` thì sẽ được sắp xếp là `22 03 AA FF` vì nếu lấy 1 bytes thì quan trọng nhất là `22` còn lại về sau sẽ không quan trọng phải không, còn nếu lấy nhiều hơn thì tiếp tục (những cũng chắc chắn số đó sẽ to rồi😜 mà ta thường sử dụng các số bé thì sẽ thuận tiện hơn thì phải). Đây là ảnh minh họa và cũng là kết thúc của thử thách 2 nhé:

![little endian](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2022/Wreckctf/advanced-flag-checker/img/02_little_endian.webp)

À mà quên flag đây nhá: `flag{hope_you_used_z3_for_this_128c13d7}`.

## 3: reverser (Solved)

![title 3](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2022/Wreckctf/reverser/img/00_title.png)

Với thử thách này code bằng python:

```python

#!/usr/local/bin/python

import os

def check_license(license):         #check license của mình với target đã được thay đổi qua 1 2 3 ...
    characters = set('0123456789abcdef')
    s = [9]
    for c in license:
        if c not in characters:
            return False
        s.append((s[-1] + int(c, 16)) % 16)  # đại lại là lấy số dư của (cái trước + cái sau) với 16
    target = '51c49a1a00647b037f5f3d5c878eb656'
    return ''.join(f'{c:x}' for c in s[1:]) == target #kết quả list vừa nhận được sẽ tạo thành chuỗi đem so sánh với target nếu thỏa mãn trả về true

print('welcome to reverser as a service!')
license = input('please enter your license key: ') #nhận input license của mình

if not check_license(license):
    print('sorry, incorrect key!')
    exit()

string = input('what should i reverse? ')
print(f'output: {string[::-1]}') # cho vào cho vui))))
print(os.environ.get('FLAG', 'no flag given')) # nếu không exit() ở trên thì chắc chắn có flag rồi

```

Và ý tưởng như đã phân tích đó tôi đã viết `keygen` cho chương trình này nhé: (với input đầu vào như trên là target đó và output đương nhiên là `license` chính hiệu cần tìm rồi)

```python
license_enc = input("\nInput lincense encode: ")
# license_enc = "51c49a1a00647b037f5f3d5c878eb656"

lst_lin_enc = [9]
for i in license_enc:
    lst_lin_enc.append(int(i,16))

# [9, 5, 1, 12, 4, 9, 10, 1, 10, 0, 0, 6, 4, 7, 11, 0, 3, 7, 15, 5, 15, 3, 13, 5, 12, 8, 7, 8, 14, 11, 6, 5, 6]

lst = []
for i in range(len(lst_lin_enc)-1,0,-1):  # reverse lại các hàm chương trình chính làm thôi)))
    temp = lst_lin_enc[i]-lst_lin_enc[i-1]
    if temp <0:
        temp += 16
    lst.append(temp)

print("License: ", end='')
print(''.join(hex(i)[2:] for i in lst)[::-1]) 
```

Và kết quả nó sẽ thế này:

![result license](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2022/Wreckctf/reverser/img/01_result_license.png)

Và ném cái `license` nhận được lên và nhận kết quả thôi:

![flag](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2022/Wreckctf/reverser/img/02_flag.png)

Vẫn như thường lệ Flag: `flag{clock_math_too_hard}`

## 4: my-frob (Solved)

![title](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2022/Wreckctf/my-frob/img/00_title.png)

Mở *IDA* và kiếm hàm `main` thôi các pro:

![open](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2022/Wreckctf/my-frob/img/01_func_main.png)

Có một số hàm đáng chú ý như lload\_flag():

![show func load flag](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2022/Wreckctf/my-frob/img/02_func_open_flag.png)

Giải thích 1 chút về hàm này:

* mở file `flag.txt` với quyền read;
* The C library function `int fseek(FILE *stream, long int offset, int whence)` sets the file position of the stream to the given offset. (Đặt vị trí file stream thành phần bù đã cho) - tôi hiểu nó là đọc bao nhiêu ký tự từ vị trí nào😁;
* The C library function `long int ftell(FILE *stream)` - dùng để lấy tổng kích thước của tệp sau khi di chuyển con trỏ tệp ở cuối tệp. Như trong bài là lấy kích thước của `flag` trong file `flag.txt`.

Tiếp tục ta đi vào hàm `my_memfrob`:

![func my\_mem](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2022/Wreckctf/my-frob/img/03_func_my_mem.png)

Dễ nhận thấy hàm này sẽ XOR lần lượt các phân tử của `flag` với giá trị truyền vào là `a3`.

Quay lại hàm `main` thì ta thấy hàm này sẽ gọi lại hàm `my_memfrob` 1 vài lần nếu `v7` vẫn khác 233.

![main](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2022/Wreckctf/my-frob/img/01_func_main.png)

Ta thấy giá trị ban đầu của `v7 = 1` sau khi gọi hàm nó sẽ được lưu tạm vào `v5` và sẽ cộng thêm với giá trị `v8`, rồi ta thấy `v8 = v5` gán lại giá trị v7 chứng tỏ `v7` sau bằng tổng của 2 số v7 trước cộng lại.

Cộng với kết quả đã được encode nhận được:

![encode](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2022/Wreckctf/my-frob/img/04_show_flag_encode.png)

Giờ tôi code decode thôi:

```python
#nhận kết quả từ trên nc ....
flag_encode = "af a5 a8 ae b2 a5 a0 a7 bc b1 96 ba a1 a6 bc a5 ad 96 a8 ad ad 96 a4 b0 96 a4 ac a4 af bb a6 ab b4"

lst_from_flag = flag_encode.split(" ") # tách và chuyển thành list

lst_int_fe = []
for i in lst_from_flag:
    lst_int_fe.append(int(i,16))

# [175, 165, 168, 174, 178, 165, 160, 167, 188, 177, 150, 186, 161, 166, 188, 165, 173, 150, 168, 173, 173, 150, 164, 176, 150, 164, 172, 164, 175, 187, 166, 171, 180]

v7 = [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144][::-1] # list các số xor nên ngược lại là ...

for i in lst_int_fe:
    for j in v7:
        i = i ^ j
    print( chr(i) ,end='')
```

Và kết quả nhận được là flag: `flag{linux_should_add_my_memfrob}`. Vậy là kết thúc 4 challenges đã giải được qua mùa giải này nhé.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://viettaliii.gitbook.io/home/ctf/write-up/wreckctf-2022.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
