2 - garbage
One of our team members developed a Flare-On challenge but accidentally deleted it. We recovered it using extreme digital forensic techniques but it seems to be corrupted. We would fix it but we are too busy solving today's most important information security threats affecting our global economy. You should be able to get it working again, reverse engineer it, and acquire the flag.
Ta giải nén và chạy thử file exe:
File đã bị corrupt đúng như đề bài nói. Tiếp theo ta dùng “Detect it easy” để lấy thêm thông tin về file.
“Detect it easy” là một tool dùng để xác định xem 1 file PE được biên dịch bằng compiler nào, được pack bằng packer nào, từ đó ta có thể có sử dụng các tool thích hợp để phân tích file đó.
Như hình trên thì file được nén bằng UPX, ta sẽ dùng đúng tool UPX để unpack file này.
UPX là một tool dùng để nén file executable, open source, bạn đọc có thể xem ở đây.
UPX không thể unpack file này, có thể là vì nó đã bị lỗi. Giờ ta mở file lên bằng “PE-bear” để xem phần nào trong file này bị lỗi.
PE-bear là một tool dùng để xem PE header của 1 file PE, bạn đọc có thể tải ở đây.
Ta thấy ngay phần section “.rsrc” bị lỗi (màu đỏ).
Ta phân tích tiếp: mục .rsrc có “Raw size” là 0x124, tức là khi map file lên bộ nhớ tại Virtual address 0x19000, phần data thật sự sẽ kết thúc ở 0x19123, trong khi ở hình trên thì phần “Import Directory” bắt đầu ở Virtual address 0x191DC, tức là nằm ngoài vùng data thật sự (3 vùng màu đỏ ở hình trên đều nằm ngoài vùng data).
Như vậy ta chỉ cần pad thêm vào file các byte null để nó có thể bao hết các Virtual address trên. Ta cần thêm vào 0x1929C+0x10-(0x19000+0x124) = 0x188 byte.
Nhưng chưa đủ, nếu ta thêm chỉ chừng đó byte thì chưa chắc file đã “hoạt động” được, vì dung lượng của file phải chia hết cho “File alignment” (tham khảo về PE struct tại đây).
Như hình trên, File alignment là 0x200. Vậy là sau khi thêm, ta phải đảm bảo là size của file này chia cho 0x200 dư 0, đoạn code dưới đây mình đã pad thêm cho tới bội của 0x200 là 0x400.
# python3
if __name__ == '__main__':
with open('garbage.exe', 'rb') as f:
with open('fix.exe', 'wb') as f2:
data = f.read()
n = 0x9E00+0x400-0x9F23
data = data + b'\x00' * n
f2.write(data)
print ('[+] Done')
Sau khi chạy code trên, ta có file “fix.exe” và có thể được unpack bởi UPX.
Ta mở file mới lên trong IDA và bấm F5
int __cdecl main(int argc, const char **argv, const char **envp)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
v12 = 741548835;
v13 = 1231306510;
strcpy(&v10, "nPTnaGLkIqdcQwvieFQKGcTGOTbfMjDNmvibfBDdFBhoPaBbtfQuuGWYomtqTFqvBSKdUMmciqKSGZaosWCSoZlcIlyQpOwkcAgw ");
v14 = 67771914;
v15 = 436344355;
v16 = 604530244;
strcpy(&v11, "KglPFOsQDxBPXmclOpmsdLDEPMRWbMDzwhDGOyqAkVMRvnBeIkpZIhFznwVylfjrkqprBPAdPuaiVoVugQAlyOQQtxBNsTdPZgDH ");
v17 = 745804082;
v18 = 255995178;
// truncated ...
sub_401000(&v28, 20, &v11, 0);
v3 = MEMORY[0x12418](v9, 0x40000000, 2, 0, 2, 128, 0);
sub_401045(&v9);
if ( v3 != -1 )
{
v8 = 0;
sub_401000(&v12, 61, &v10, v4);
MEMORY[0x123F8](v3, v9, 61, &v8, 0);
sub_401045(&v9);
MEMORY[0x12426](v3);
sub_401000(&v28, 20, &v11, v5);
MEMORY[0x12442](0, 0, v9, 0, 0, 0);
sub_401045(&v9);
}
v6 = MEMORY[0x123E4](-1);
MEMORY[0x12404](v6);
return 0;
}
Ta thấy có một số chỗ MEMORY[0x?????]
, đó là vì khi pack file bằng UPX, phần “Import data” nằm ở đó (và bị phá huỷ), nên khi ta thêm null byte vào, nó sẽ không chính xác, tuy nhiên điều này cũng không quá quan trọng.
Hai hàm sub_401000
và sub_401045
lần lượt là hai hàm set key và decrypt data bằng phép xor cơ bản, ta dùng script sau để giải mã.
# python3
from struct import pack
def p32(n: int) -> bytes:
return pack('<I', n)
def dec(data: bytes, key: bytes) -> bytes:
key_len = len(key)
r = b''
for i in range(len(data)):
r = r + (data[i] ^ key[i % key_len]).to_bytes(1, 'little')
return r
if __name__ == '__main__':
d1, d2 = [], []
d1.append(741548835)
d1.append(0x49643F0E)
d1.append(67771914)
d1.append(436344355)
d1.append(604530244)
d1.append(745804082)
d1.append(255995178)
d1.append(224677950)
d1.append(387646557)
d1.append(84096534)
d1.append(134815796)
d1.append(237248867)
d1.append(1479808021)
d1.append(981018906)
d1.append(1482031104)
d1.append(84)
d2.append(989990456)
d2.append(874199833)
d2.append(1042484251)
d2.append(1108412467)
d2.append(1931350585)
d1 = b''.join([p32(i) for i in d1])
d2 = b''.join([p32(i) for i in d2])
k1 = b'nPTnaGLkIqdcQwvieFQKGcTGOTbfMjDNmvibfBDdFBhoPaBbtfQuuGWYomtqTFqvBSKdUMmciqKSGZaosWCSoZlcIlyQpOwkcAgw '
k2 = b'KglPFOsQDxBPXmclOpmsdLDEPMRWbMDzwhDGOyqAkVMRvnBeIkpZIhFznwVylfjrkqprBPAdPuaiVoVugQAlyOQQtxBNsTdPZgDH '
print (dec(d1,k1))
print (dec(d2,k2))
Run:
b'MsgBox("Congrats! Your key is: C0rruptGarbag3@flare-on.com")\x00Fqv'
b'sink_the_tanker.vbs\x00'