Flare-on9 2022
Nguồn ở đây nhá các bạn: 💀👆👆👆💀
Xin chào các bạn đến với writeupp lần này. Lần đầu gà con vào đảo của các lãnh làng sẽ như thế nào nhỉ? Hốt hoảng thật sự hí hí… Sau quá trình nghiên cứu và tìm hiểu tôi sẽ viết hoàn thành tất của các chall của mùa giải năm nay cho mn được tham khảo nhé. (Link)
Ok bắt đầu thôi… gét gô…
1: Flaredle (Solved)
Description:
Welcome to Flare-On 9!
You probably won't win. Maybe you're like us and spent the year playing Wordle. We made our own version that is too hard to beat without cheating.
Play it live at: http://flare-on.com/flaredle/
Chúng ta được nhận 4 file. Đầu tiên sẽ mở file đuôi
.html
để xem nội dung hiện thị là gì? Ta thấy nó sử dụng js
được cung cấp sẵn. Thế nên là tôi mở file js
check xem họ viết gì và dấu gì ở đó.
Xem qua ta thấy có hàm if
kiểm tra chuỗi từ người dùng và chuỗi flag nằm trong file script.js
:
Ta tìm kiếm
rightGuessString
xem nó là gì??
Ok nhận thấy biến này được lấy từ thứ
57
trong file words.js
. Từ đó ta nhận được: flareonisallaboutcats
. Kiểm tra lại trên web thỏa mãn.
2: PixelPocker (Solved)
Description
I said you wouldn't win that last one. I lied. The last challenge was basically a captcha. Now the real work begins. Shall we play another game?
Công cụ được sử dụng:
- CFF Explorer
- IDA Pro
- Python
- PIL: pip install pillow (1 fork từ thư viện PIL của python được sử dụng để xử lý hình ảnh)
Nội dung của readme.txt
Welcome to PixelPoker ^_^, the pixel game that's sweeping the nation!
Your goal is simple: find the correct pixel and click it
Good luck!
Đầu tiên ta mở bằng CFF Explorer
quan sát metadata của file exe. Và ta có chú ý về resourse là dạng Bitmaps (ảnh) gồm 2 bức ảnh với tên 129 và 133.
Chương trình hướng đến việc cần phải lưạ chọn 1 điểm ảnh với tọa độ hiện thị trên cửa sổ và có đối ta 10 lần thử.
và tôi thử xem ra kết quả là gì:
Ta nhận được thông báo
Womp womp...:(
. Rồi chúng ta sẽ mở chúng bằng IDA Pro kiếm strings này nằm ở hàm nào?.
Ta sửa đổi lại tên của một số biến nhận diện rồi.
Như đã thấy thì ta thấy có hàm kiểm tra 2 vị trí
x,y
với một giá trị có sẵn lấy dư với uX
và uY
.
Ta cần tìm hiểu xem biến
dword_413280
là gì? thì nó nằm trong hàm BitBlt
- 1 hàm thực hiện truyền khối bit dữ liệu tương ứng với một hình chữ nhật pixel từ ngữ cảnh thiết bị nguồn đã chỉ định sang ngữ cảnh thiết bị đích.
BOOL BitBlt(
[in] HDC hdc,
[in] int x,
[in] int y,
[in] int cx,
[in] int cy,
[in] HDC hdcSrc,
[in] int x1,
[in] int y1,
[in] DWORD rop
);
Do đó dword_413280
là cx
- là chiều rộng của nguồn (ở trường hợp này là hình ảnh); còn cy
- là chiều cao của hình ảnh.
[in] cx
The width, in logical units, of the source and destination rectangles.
[in] cy
The height, in logical units, of the source and the destination rectangles.
Bước so sánh ở dòng 43 và 46 kiểm tra giá trị của tọa độ click chuột theo trục
(x,y)
thỏa mãn điều kiện sau:
x = 0x52414c46 % độ rộng ảnh = 0x52414c46 % 741 = 95
y = 0x6e4f2d45 % độ cao ảnh = 0x6e4f2d45 % 641 = 313
Như vậy ta click đúng tọa độ trên thì sẽ chuyển sang luồng khác và có kết quả:
3: Magic_8_Ball (Solved)
Description:
You got a question? Ask the 8 ball!
Đầu tiên ta giải nén thì ta nhận được nhiều file không biết file nào sẽ là quan trọng nên chúng ta trước mắt ta cứ quan tâm chính vào file chương trình .exe
nha.
Mở file thực thi nên thấy nhập 1 gì đó rồi Enter thì ta nhập được các thông điệp và nhấn các mũi tên thì ta thấy quả bóng lắc:
Ta mở nó bằng
IDA Pro
xem sao nhá. Thì thấy được các string hiện thị lúc nãy đều nằm cùng 1 hàm sub_4012B0
:
Tiếp tục theo dấu xem hàm nào sẽ call đến hàm này (chúng ta sẽ rename là
predict_string_func
) thì thấy nó được gọi từ sub_4027A0
, có lẽ đây là hàm main của chương trình. Để ý phía dưới có một vòng lặp do while, rất giống với vòng lặp xử lý các sự kiện (event) rất hay gặp trong các ứng dụng GUI.
Đi dạo quanh các hàm trong vòng lặp do while thì ta nhận ra đoạn này giống như đoạn điều hướng của quả bóng:
và kéo xuống dưới thì là các câu lệnh điều kiện kiểm tra lồng nhau. Trường hợp này ta convert các số
76,85,82,68
sang kiểu dữ liệu char
:
Ta nhận được: LLURULDUL
. Sau khi kiểm tra chuỗi này xong thì sẽ so sánh chuỗi có độ dài 15 ký tự:
result = strncmp(v21, (const char *)(this + 92), 15u);
Ta debug tại IDA luôn điều hướng quả bóng như trên mình phân tích rồi ta nhập 1 string nào đó rồi đặt breakpoint
(F2) tại hàm so sánh này thì ta nhận được như sau:
Như vậy ta nhận thấy có 2 câu lệnh 3 câu lệnh
push
trước khi gọi hàm strncmp
có nghĩa là truyền tham số vào hàm đó tương ứng: push
từ phải qua trái -> ta thấy thanh ghi ecx
sẽ là string mình nhập và thanh ghi eax
chính là nguồn sẽ so sánh.
và mọi thứ coi như đã xong kiếm được string so sánh là:
gimme flag pls?
Chạy lại chương trình, nhập đúng chuỗi phím định hướng quả bóng và nhập câu hỏi vừa tìm được sẽ in ra flag:
U_cRackeD_th1$_maG1cBaLL_!!_@flare-on.com
4: darn_mice
Description:
"If it crashes its user error." - Flare Team
Đề bài cho 1 file darn_mice.exe
. Đầu tiên tôi sẽ kiểm tra các thông tin của file bằng phần mềm Detect It Easy
(viết tắt của chương trình sẽ là die
màu vàng) chúng ta biết được đây là 1 ứng dụng console viết bằng C++.
Tôi vào console chạy thử không cho tham số thì không thấy ra gì và thêm tham số thì có ra kết quả -> bài yêu cầu truyền tham số như password nếu đúng sẽ in ra flag gì đó.
Để kiểm tra và làm tôi mở IDA thì ta thấy
Như vậy hàm này chính xác là yêu cầu ta truyền vào là 2
argc
.
Nếu đủ sẽ vào chương trình kiểm tra password
:
Ở đây ta phân tích như sau: (sửa tên lại ta có như sau)
- Chuỗi ta nhập thì sẽ gọi là
pbPassword
. - Sau đó sẽ in ra màn hình -> tiếp đến là kiểm tra kích thước của
pbPassword
:if (!v3 || v3 > 0x23)
phần này check strlen phải thỏa mãn tồn tại và không được lớn hơn0x23
nó là 35 -> kích thước củapbPassword
là35
:
Tiếp đến ta để ý đến vòng lặp for:
- Đầu tiên, thực hiện allocation một vùng nhớ, kích thước 0x1000 lưu vào
v2
- Sau đó là lấy từng ký tự của
pbPassword
đem cộng tương ứng với vị trí của biếnmagic
đã được khai báo và gán giá trị ở đầu func. - Gán giá trị này cho byte đầu tiên của vùng nhớ vừa được khởi tạo
- Nhảy đến vào chạy code tại vùng nhớ đó (tương ứng với lệnh gọi
v2(v2)
) - in ra chuỗi
Nibble...
- Tiếp tục vòng lặp
Qua đoạn for này nếu nhập đúng, chương trình sẽ dùng password này để decrypt ra flag
Vậy là bài toán đặt ra là xây dựng code làm sao để thực hiện đúng 1 lệnh assembly (opcode) để chương trình không bị crash và sau đó lại quay lại thực hiện theo flow cũ của chương trình (tiếp tục in ra dòng Nubble...
).
Tôi thử với pass là 123456789
. Ta thấy dòng code vị trí .text:01011155
là nó cộng rồi lưu vào thanh ghi ecx
; tiếp theo mov địa chỉ ô nhớ sẽ gọi cho thanh ghi edx
. Khi gọi vào vùng nhớ, gặp opcode
nào đó để ngay lập tức quay lại để tiếp tục flow cũ chạy như bình thường.
Như vậy hex(ord('1') + ord('P')) = '0x81'
nó là câu lệnh add ))). Thử kết quả là NOP
thì code lại chạy tiếp tục trong vùng nhớ đó và báo lỗi, và thử opcode RET = 'C3'
câu lệnh cuối của mỗi hàm thì nó trở về và xong.
Giờ viết mà code để tìm pass nhá:
str_magic = [0x50, 0x5E, 0x5E, 0xA3, 0x4F, 0x5B, 0x51, 0x5E, 0x5E, 0x97, 0xA3, 0x80, 0x90, 0xA3, 0x80, 0x90, 0xA3, 0x80, 0x90, 0xA3, 0x80, 0x90, 0xA3, 0x80, 0x90, 0xA3, 0x80, 0x90, 0xA3, 0x80, 0x90, 0xA2, 0xA3, 0x6B, 0x7F]
password = "".join([chr(0xC3 - m) for m in str_magic])
print(password)
#see three, C3 C3 C3 C3 C3 C3 C3! XD
Và chạy password vừa tìm được thì ta nhận được:
Xong flag sẽ là: i_w0uld_l1k3_to_RETurn_this_joke@flare-on.com
5: t8
FLARE FACT #823: Studies show that C++ Reversers have fewer friends on average than normal people do. That's why you're here, reversing this, instead of with them, because they don't exist.
We’ve found an unknown executable on one of our hosts. The file has been there for a while, but our networking logs only show suspicious traffic on one day. Can you tell us what happened?
7-zip password: flare
Ta nhận được 2 file t8.exe
và trafic.pcapng
- file chứa các thông tin networking log của file nghi ngờ. Sử dụng Wireshark
để quan sát tập tin chứa dữ liệu mạng.
Đối với TCP Stream là loại HTTP thì Wireshark cho phép thao tác để lấy dữ liệu trong trường data của method POST một cách dễ dàng.
Quay trở lại với file t8.exe
, để bước vào phân tích thì cần kiểm tra một số thông tin cần thiết liên quan. Đọc metadata sử dụng CFF Explorer
cho thấy tập tin là PE32 và có khả năng là sử dụng chương trình biên dịch là VS C++. Do đó cần sử dụng công cụ như x64dbg, IDA Pro hoặc Ghidra để phân tích tĩnh và động.
Trong hàm main có kiểm tra điều kiện:
while ( sub_404570(xmmword_45088C, DWORD1(xmmword_45088C), DWORD2(xmmword_45088C), HIDWORD(xmmword_45088C)) != 15 )
Sleep(0x2932E00u);
Ta kiểm tra xem xmmword_45088C
biến này là gì? Kiểm tra xem xref các các địa chỉ xmmword_45088C
, thì kiếm được hàm sub_401020()
khởi tạo giá trị này. Biến này được gná bằng thời gian hiện tại của chương trình lúc thực thi.
int sub_401020()
{
struct _SYSTEMTIME SystemTime; // [esp+4h] [ebp-20h] BYREF
int v2; // [esp+20h] [ebp-4h]
v2 = 0;
sub_405930(&dword_450874, L"FO9", 3);
GetLocalTime(&SystemTime);
srand(SystemTime.wMilliseconds + 1000 * (SystemTime.wSecond + 60 * SystemTime.wMinute));
dword_450870 = rand();
xmmword_45088C = (__int128)SystemTime;
return atexit(sub_43DC50);
}
Tiếp đến là đi sâu vào hàm sub_404570
thì được:
int __cdecl sub_404570(unsigned int a1, unsigned int a2)
{
unsigned int v2; // ecx
int v3; // esi
unsigned int v4; // eax
float v5; // xmm0_4
float v9; // [esp+2Ch] [ebp+14h]
v2 = HIWORD(a1);
v3 = (unsigned __int16)a1 - 1;
if ( HIWORD(a1) > 2u )
v3 = (unsigned __int16)a1;
v4 = v2 + 12;
if ( v2 > 2 )
v4 = HIWORD(a1);
v9 = (float)((float)((double)(int)(v3 / 100 / 4
+ HIWORD(a2)
+ (int)((double)(v3 + 4716) * 365.25)
- (int)((double)(int)(v4 + 1) * -30.6001)
- v3 / 100
+ 2)
- 1524.5)
- 2451549.5)
/ 29.53;
v5 = floor(v9);
return (int)roundf((float)(v9 - v5) * 29.53);
}
Có các con số lạ thì ta tra google xem nó là gì thì nhận thấy đây là hàm tính toán có liên quan tới xác định chu kì mặt trăng (Moon phase). Với kết quả sub_404570() ==15
thì có thể xác định là thời điểm hiện tại là ngày rằm (trăng tròn).
Để vượt qua kiểm tra thì đơn giản là ta chỉnh lại thời gian ngày là ngày rằm (full moon).
Chạy chương trình và bắt dữ liệu mạng bằng Wireshark ta biết t8.exe sẽ phân giải tên miền flare-on.com và kết nối bằng giao thức HTTP.
(tiếp sẽ có sau)