
DefCamp 2022
Nguồn ở đây nhá các bạn: 💀👆👆👆💀
Chào mừng bạn đã quay trở lại với 1 vài bài RE thú vị và khá đơn giản của giải mà phải nói là tôi tham gia ngẫu hứng thui 😁. Không dài dòng nữa vào việc thôi.
1: cryogenics (Solved)
Cái đề bài cũng không có gì (nhưng lúc trong quá trình giải khiến tôi phải tốn thời gian về nó quá)
Bắt đầu với việc tải file (Link nguồn tôi có để trên đầu bài rồi nhá) và kiểm tra xem thông tin file nhỉ: Nay tôi sài phần mềm HxD
- phần mềm chỉnh sửa hex:
Đó như ta quan sát thấy có dòng .ELF
- Executable and Linkable Format - định dạng phổ biến dành cho các mã thực thi, code đối tượng, thư viện được chia sẻ và kết xuất lõi, được xuất bản cho giao diện nhị phân ứng dụng (ABI) của phiên bản hệ điều hành Unix. Đại lại nó phù hợp để chạy trên Ubuntu, linux,…(nó được phát triển từ các OS Unix.
Chú thích:
0x7F
theo sauELF
(45 4C 46
) và bytes tiếp theo số 5 nếu là01
thì 32 bit or02
thì 64 bit nhá.
Tôi mở máy ảo linux
và chạy thử:
Thử thách yêu cầu đầu vào là Password
và output cho ta flag💀. Tôi sẽ chạy IDA để phân tích
Bắt đầu đọc code nào🫡: (Tôi thấy bài code bị dối và có thể đã có tác động khiến IDA không hiện thi đúng logic của chương trình, bởi đó mình thường sẽ đi kiếm strings
của chương trình):
Đó ta nhận thấy có đoạn strings (shortcut key: Shift + F12) output mà ta đã bắt gặp khi chạy. Too cold outside
-> cứ tiếp tục theo đó nào. Nhấn đúp chuột:
nhấn X để hiện thị xem câu lệnh nào gọi hay sử dụng đến strings đó
và nhận và ta thấy có câu lệnh test eax, eax
kiểm tra để chuyển hướng chương trình:
trước câu lệnh test
có câu lệnh call
đến function để kiểm tra gì đó rồi trả về giá trị eax
đem so sánh, và ở dưới đó có lệnh jnz
jump if not zeoro - nhảy nếu không bằng hay là output Too...
và kết thúc chương trình không thỏa mãn điều kiện.
Đi vào strcmp
và sử dụng F5
huyền thoại nhé))
// positive sp value has been detected, the output may be wrong!
__int64 __fastcall strcmp(__int64 a1)
{
__int64 v1; // rax
__int64 i; // rax
char v4[15]; // [rsp+2h] [rbp-26h] BYREF
char v5[23]; // [rsp+11h] [rbp-17h] BYREF
qmemcpy(v4, "000000000000000", sizeof(v4)); // đại khái như tôi hiểu là nếu input cho mk mà bé hơn kích thước của biến v4 sẽ chèn 0000000 vào sau input
v1 = 0LL;
qmemcpy(v5, &unk_400328, 0xFuLL); // khả năng lấy dữ liệu đã lưu
do
{
v4[v1] = __ROL1__(*(_BYTE *)(a1 + v1), 3); // __ROL1__: circular rotation to the lelf (xoay vòng tròn sang trái) (unit8)
++v1;
}
while ( v1 != 15 );
for ( i = 0LL; i != 15; ++i )
v4[i] = __ROR1__(v4[i], 2); // __ROR1__: circular rotation to the right (xoay vòng tròn sang phải) (unit8)
return ((__int64 (__fastcall *)(char *, char *, __int64))strncmp)(v4, v5, 15LL); //gọi hàm tiếp
}
Kiểm tra biến &unk_400328
không xác định có địa chỉ:
đó là 1 mảng ta định dạng 1 chút nó sẽ trông như này:
Như định dạng có nó theo dạng byte (vì đang là unit8), tạo mảng với phím tắt A và kết quả nhận được như hình trên với mảng gồm 15 phần tử.
__ROR1__ và __ROL1__
đại lại là nhân và chia với 2 các cơ số lần. Tôi tham khảo được code python của nó ở 1 trang web này: Link đây nhé
và thứ chúng ta cần nè code python:
def __ROL__(num, count, bits=8):
return ((num << count) | (num >> (bits - count))) & ((0b1<<bits) - 1)
def __ROR__(num, count, bits=8):
return ((num >> count) | (num << (bits - count))) & ((0b1<<bits) - 1)
Tiếp đến ta đi vào hàm strncmp
xem thế nào: (với 3 tham số đầu vào: v4
là input của mình đã được ROR và ROL
, v5
là mảng được lấy từ nguồn lưu trữ, 15LL
là kích thước của input và cũng là kích thước của mảng)
// positive sp value has been detected, the output may be wrong!
__int64 __fastcall strncmp(__int64 a1, __int64 a2, __int64 a3)
{
__int64 v3; // r8
unsigned __int8 *v4; // r9
unsigned __int8 v5; // al
char v6; // cl
v3 = 0LL;
do
{
v4 = (unsigned __int8 *)(a2 + v3);
if ( a3 == v3 ) // so sánh với kích thước
return 0LL; // kết quả return mong muốn mà ta muốn đây rồi
v5 = *(_BYTE *)(a1 + v3); //lấy giá trị phần tử thứ v3 (input) trong mảng
if ( !v5 ) //if not tồn tại giá trị v5 dừng vòng lặp do while
break;
v6 = *(_BYTE *)(a2 + v3++); // lấy value phần tử thứ v3 của a2 (nguồn) trong mảng rồi tăng giá trị của v3 lên 1
}
while ( (char)v5 == (v6 ^ 0xC) + 6 ); //kiểm tra v5 với v6 xor với 0xC + 6
return v5 - (unsigned int)*v4;
}
Thế là ý tưởng của bài đã được hé lộ rồi, giờ tôi sẽ sử dụng python để viết ra đoạn mã cần -> flag🏴 Dưới là code python solve của tôi nhé:
def __ROL__(num, count, bits=8):
return ((num << count) | (num >> (bits - count))) & ((0b1<<bits) - 1)
def __ROR__(num, count, bits=8):
return ((num >> count) | (num << (bits - count))) & ((0b1<<bits) - 1)
lst = [166, 166, 108, 226, 226, 222, 132, 188, 124, 236, 226, 120, 152, 166, 166]
for i in lst:
for x in range(256):
if (i ^ 12) + 6 == __ROR__(__ROL__(x,3),2):
print(chr(x), end="")
Kết quả nhận được đúng theo yêu cầu đề bài là được đóng băng, kết thúc bằng XX: XX3zzlG[;sz=MXX
và mã hóa sha256
là xong -> Kết quả nhận được CTF{a41f954f18646f115d653d28213175a6d9ef0d383c80c99ac0ee060c217b99c6}
-> Done 1 bài thú vị.
Lúc đầu tôi chơi nhìn qua thì họ đánh lừa tôi tới 2 lần (lần 1 là đoạn strings công khai kiến tôi tưởng là so sánh với nó và –> game easy, but not; lần 2 là hàm strncmp
làm tôi lần tưởng chỉ so sánh và trả về 0 hoặc âm dương không thôi ai dè có cũng còn xor and add six
🥶 mới ra).
2: new-buldozer (Solved)
Đến với thử thách này ta được làm quen với chương trình trên điện thoại di động, cụ thể là Android
.
Tôi sử dụng tool apktool
để giải mã và đọc nó xem sao nhá:
Nó sẽ trả về cho chúng ta 1 thư mục mà công cụ có thể giải mã được. Tiếp đến tôi mở ra và kiếm kiểm tra các file và mở chúng bằng tool jadx-gui
(Thường là các file có đuôi .smail
):
Tôi kiểm tra qua hết tất cả thì không thấy có gì đó cả toàn các hàm của chương trình thực thi bằng java
. Tiếp đến tôi thấy nghi ngờ file private.taz
được nén vào mà tôi chưa đọc:
Ồ có hẳn 3 file trong đó và giờ tôi vào đọc nó, format file .pyc
- là file thông dịch Python khi nó chuyển đổi code thành mã bytecode được biên dịch.
Tôi thử kiếm strings trong file trước xem sao:
strings main.pyc
X3c
m Z
1.0.9)
Builder)
GridLayout)
NumericProperty)
Appz
<HelloWorldScreen>:
cols: 1
Label:
text: 'Welcome to the Hello world'
Button:
text: 'Click me! %d' % root.counter
on_release: root.my_callback()
HelloWorldScreenr
The button has been pushed
V1ROU2JXVjZaRzFPVkZKc1RWUldhVmt5V1hsYVZFNXFUVmRaTVU1NlVUVlplbWhvVG5wU2JVMVVRVEJOYW1jeFdXcGplRnBYV1RKWk1sVjZUVlJCZUZsNmJHMU9SMVY2VFZkU2ExbHRVbXhOVkZVMFRsUlZlazlFU2prPQ==)
print
counter
self
H/home/lucian/Desktop/ctf/new-buldozer/dev/.buildozer/android/app/main.py
my_callback
HelloWorldScreen.my_callbackN)
__name__
__module__
__qualname__r
HelloWorldAppc
build
HelloWorldApp.buildN)
__main__)
kivyZ
requireZ kivy.langr
kivy.uix.gridlayoutr
kivy.propertiesr
kivy.appr
load_stringr
runr
<module>
Ồ có 1 đoạn mã base64
kìa decode xem sao nhá và kết quả khi ném nó lên CyberChef
thì thật bất ngờ:
Thật là Magic luôn khi tôi chỉ giải mã base64 1 lần còn lại do web gợi í và đúng như ý muốn.😜
Và tất nhiên rồi flag: ctf{7f54e15bcf2e3c1f5749c8a74f104285b71ef6ce3101c9f4e31ddbde15855382}
.
3: xrypto (Unsolved)
__int8, __int16, __int32, __int64
- Tương ứng với biến khai biến có kích thước 8, 16, 32, 64 bit.
__readfsbyte, __readfsdword, __readfsqword, __readfsword
đọc bộ nhớ từ một vị trí được chỉ định bởi một phần bù so với đầu của offset FS:[Offsett]