wannaShare | Writeup Google Capture The Flag 2021 | WEATHER – Reversing

PHAPHA_JIàN
14:36 21/07/2021

Nhóm Wanna.One chia sẻ một số Challenges giải được và việc chia sẻ writeup nhằm mục đích giao lưu học thuật. Mọi đóng-góp ý-kiến bọn mình luôn-luôn tiếp nhận qua mail: wannaone.uit@gmail.com

Mochi Nishi - PwN3v3rY7h1nG

Challenge

Entry point

File: weather

Disclaimer:

Bài này lúc thi mình không giải ra, vì lúc đầu mình đã có một vài nhận xét sai nên nghĩ rằng không làm được. Nhưng trước khi kết thúc kì thi khoảng 6 tiếng thì mình có xem lại bài và phát hiện là những nhận xét của mình có phần sai sót. Sau khi đánh giải lại thì mình thấy mình có thể làm được bài này, nhưng không còn thời gian để giải trong lúc thi nữa. Bài này mình giải được sau khi thi 2 ngày, nhưng mình khá tự hào vì đã tự giải quyết nó mà không có sự trợ giúp từ bên ngoài.

Solve:

Bài này đòi hỏi một vài kiến thức khá mới lạ so với những WriteUp trước đó mình viết, nên mình sẽ nói về những kiến thức đó trong bài này:

Hàm init

Nếu như chúng ta để ý hàm __libc_start_main() thì ngoài trừ tham số là hàm main, còn có một hàm đáng được quan tâm là hàm init.
Hàm init là một constructor trước khi vô hàm main. Hay nói nôm na dễ hiểu là hàm init sẽ được chạy đầu tiên rồi sau đó mới đến hàm main.
Như vậy chuyện tác giả có thể giấu code trong hàm init là một điều hoàn toàn khả thi. Và trong bài này tác giả đã làm như thế. Ta thử xem sơ qua hàm init:

Entry point

Đây là một câu trúc chung của hàm init trong các chương trình ELF. Trong hình ta thấy có biến funcs_2701. Đó là biến con trỏ, sẽ trỏ tới các chương trình con nó sẽ gọi để khởi tạo chương trình. Ta vô xem thử thì thấy có 2 chương trình con:

Entry point

Thường thì chương trình đầu tiên là của hệ thống nên ta không quan tâm. Nhưng chương trình con thứ 2 (nếu xuất hiện) thường sẽ là của tác giả, nên ta vô xem hàm này:

Entry point

Và ... có một đống hàm register_printf_function...

Custom printf

Hàm printf được dùng để xuất kết quả ra chương trình, tuy nhiên hàm đòi hỏi một tham số khá quan trọng, đó là tham số format, mính sẽ không nói chi tiết printf hoạt động như thế nào, các bạn có thể lên google tra thử.
Thì như tiêu đề, tham số format hoàn toàn có thể custom được, hay nói cách khác, ta có thể tạo ra một (format) mới theo ý của riêng ta.
Để giúp đỡ chúng ta trong việc tạo format mới, hàm register_printf_function được ra đời. Lên mạng đọc về hàm này thì mình sẽ tóm tắt lại một số điều quan trọng của hàm như sau:

Entry point

Ở hàm này, nếu như mình thực hiện lệnh printf('%W'); thì hàm func sẽ được gọi để xử lí chương trình. Chi tiết các bạn có thể tham khảo ở https://www.gnu.org/software/libc/manual/html_node/Registering-New-Conversions.html

Ok, giờ là chương trình chính:

Entry point

Entry point

Mình để ý ngay đến dòng cuối, nó sẽ in ra flag tuỳ vào input ta nhập. Mình xem thử hàm xử lí foramt %F

Entry point

Nó sẽ gọi cho %C, ta xem tiếp %C nó làm gì:

Entry point

Hmmmmmm, nhìn khá phức tạp. Nếu như tham khảo tài liệu kĩ hơn thì ta sẽ hiểu ngoài format ra ta còn có những tham số truyền vào format, ví dụ như %+12.45llF. Ở đây có 4 phần: Dấu +, số 12, số 45 và kí hiệu ll
Những phần này sẽ quyết định các tham số và 'opcode' của chương trình. Đúng vậy, đây là một bài Virtual Machine. Lúc này mình debug để hiểu thêm và phát hiện có 3 phase chính:

Bài này mình có viết script để dịch opcode cho dễ hiểu, nhưng script mình viết chỉ có một mình bản thân mình hiểu nên mình không dám đưa script lên :p, tuy nhiên script không quá khó, các bạn có thể debug để hiểu thêm và viết script cho bản thân.
Mình đã nhảy sang Phase 3 để mình tìm các tham số và viết một chương trình để decrypt lại tìm input phù hợp:

script.py

li = [161, 51, 163, 51, 173, 51, 185, 51, 193, 51, 203, 51, 211, 51, 235, 51, 241, 51, 253, 51, 1, 52, 15, 52, 19, 52, 25, 52, 27, 52, 55, 52, 69, 52, 85, 52, 87, 52, 99, 52, 105, 52, 109, 52, 129, 52, 139, 52, 145, 52, 151, 52, 157, 52, 165, 52, 175, 52, 187, 52, 201, 52, 211, 52, 225, 52, 241, 52, 255, 52, 9, 53, 23, 53, 29, 53]
char = [0xf5, 0xcc, 0xcf, 0xf9, 0xa9, 0xc4, 0xa5, 0x8a, 0xa3, 0xa0, 0x57, 0x6f, 0x88, 0x86, 0x79, 0x79, 0x48, 0x15, 0x53, 0xd, 0x31, 0x28, 0xf6, 0xe6, 0x15, 0x2, 0x68, 0xe8]
import string
for i in range(len(char)):
    e = li[i * 2]
    cou = 0
    if (i != 0):
        num = i + 1
        cou = 0
        while (num != 1):
            cou += 1
            if (num % 2 == 0): num //= 2
            else: num = (num * 3) + 1
    val = (char[i] - cou) & 255
    val ^= e
    print(chr(val), end = "")
print()

Entry point

Đưa kết quả vào chương trình:

Entry point

TIN LIÊN QUAN
CLB ATTTT Wanna.One chia sẻ một số Challenges giải được và việc chia sẻ writeup nhằm mục đích giao lưu học thuật. Mọi đóng-góp ý-kiến bọn mình luôn-luôn tiếp nhận qua mail: wannaone.uit@gmail.com PWN pivik simultaneity Reversing the binary int main() { size_t size; char *chunk; setvbuf(stdout, 0, 2, 0);...
Nhóm Wanna.One chia sẻ một số Challenges giải được và việc chia sẻ writeup nhằm mục đích giao lưu học thuật. Mọi đóng-góp ý-kiến bọn mình luôn-luôn tiếp nhận qua mail: wannaone.uit@gmail.com Category: WEB Author: th13ntc My First Website Bài này điêu toa cực, cần-trôn U lên để Ctr+F được...
Nhóm Wanna.One chia sẻ một số Challenges giải được và việc chia sẻ writeup nhằm mục đích giao lưu học thuật. Mọi đóng-góp ý-kiến bọn mình luôn-luôn tiếp nhận qua mail: wannaone.uit@gmail.com Mochi Nishi - PwN3v3rY7h1nG Challenge File: cpp.c Solve: Mở file cpp.c thì thấy một đóng code loằng ngoằng...