Try   HackMD

Hack The Box - Reversing (Medium 2)

image

Ghi chú:

Difficulty: Medium

Challenge 7: Breakin

The group regularly changes cryptographic keys, and we believe this server is being used to coordinate them. If you can discover how the keys are being derived, then we'll be able to decrypt all their past communication!

Download Challenge Here

Solution

/proc trong Linux là một hệ thống tệp ảo đặc biệt cung cấp một giao diện giống như tệp để truy cập thông tin về hệ thống và các tiến trình đang chạy. Nói cách khác, nó không phải là một hệ thống tệp thông thường lưu trữ dữ liệu mà là một cửa sổ thể hiện trạng thái đang chạy của hệ thống.

Ta sẽ kết nối với Instance, chúng ta có thể truy cập vào danh sách thư mục từ một Linux root. Vì chúng ta để có thể duyệt đến bất kỳ tệp nào chúng ta muốn, chúng tôi có thể sử dụng hệ thống tệp /proc. Khi duyệt đến

  • /proc/self/maps hoặc /proc/self/cmdline chúng ta có thể khám phá đường dẫn sẽ có sự thay đổi.
  • /proc/self/exe cũng tải xuống tệp thực thi. Mình đã để tệp đó để mọi người có thể tải.

Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

image

Mở file trong IDA64, ta thấy có xuất hiện của các regex strings kèm theo method + function

Method Regex strings Function
GET ^/exec$ pingGet
POST ^/exec/([a-zA-Z0-9]+) execPost
GET ^/secret$ execGet
GET secretGet
GET defaultGet
  1. Hàm pingGet, hàm GET REQUEST với đường dẫn "/ping", thực hiện triển khai giao thức giao tiếp ping/pong bằng cách sử dụng SimpleWeb Framework để xử lý các HTTP request và response.
  2. Hàm execPost, hàm đọc dữ liệu từ một request và phân tích nó dưới dạng JSON, kiểm tra xem một số trường dữ liệu có tồn tại trong yêu cầu không. Nếu các trường dữ liệu cần thiết được tìm thấy, hàm tiếp tục giải mã một số dữ liệu hexa từ yêu cầu, tạo một đối tượng payload và liên kết nó với một tên trong một bản đồ.
  3. Hàm execGet, hàm sẽ tìm kiếm tệp trong danh sách chương trình. Nếu tìm thấy chương trình , server sẽ thực thi chương trình đó và gửi kết quả như là phản hồi.
  4. Hàm secretGet, khi ta truy cập đến /secret endpoint, password sẽ được truyền vào bằng tham số được điền. Kiểm tra password của ta có giống của chương trình không. Từ đó, ta biết ta cần truy cập với đường dẫn /secret?password=<password>
  5. Hàm defaultGet xử lý GET REQUEST mặc định trong ứng dụng server. Hàm khởi tạo và trích xuất đường dẫn tệp và thư mục từ GET REQUEST. Nếu đường dẫn trích xuất là một thư mục, hàm sẽ tạo một danh sách các tệp trong thư mục đó và gửi nó như là một phản hồi.

image

Ta truy cập với đường dẫn /secret?password=!IEN*113hRt^9@Z8Rz9hmy!E. Ta có thể upload python bytecode, thêm nó vào trong danh sách các tệp và thực thi nó.

Ta cần tạo một POST REQUEST đến /exec endpoint ở dạng json và tạo một GET REQUEST đến /exec/<program> để thực thi tệp đó.

image

Trong hàm secretGet, chương trình tạo chuỗi mới v24 bằng cách ghép các phần tử HTML cố định với nhau. Đoạn mã xây dựng phần HTML liên quan đến chương trình vào biến toàn cục Program, phần HTML của form tải lên cùng với một đoạn mã JavaScript để xử lý tải lên tệp và gửi dữ liệu lên máy chủ. Đoạn python bytecode của ta cũng sẽ được lưu vào biến Program.

image

Trang web cung cấp cho ta creds, key, stats.

image

Hàm executePython() thực hiện đúng như tên gọi của nó - load python object từ bytecode. Thực thi mã Python bằng cách nhập nó như một module bằng PyImport_ExecCodeModule. Gọi hàm main từ module bằng cách sử dụng PyObject_CallMethod. Kiểm tra nếu là chuỗi Unicode, xử lý cả chuỗi bằng thành chuỗi UTF8 và chuỗi byte.

Chúng ta cần tạo ra một đoạn mã Python và biên dịch nó thành mã bytecode. Đoạn mã Python này sẽ ghi ra tất cả các module được load trong chương trình.

import sys
import marshal

code_to_compile = """
def call_tracer(frame, event, arg):
    import marshal
    with open('./dump','wb') as f:
        o = marshal.dumps(frame.f_code)
        f.write(o)
    return None

def main():
    import sys
    sys.settrace(call_tracer)
    return dir(sys.modules['payload'].main)
"""

compiled_code = compile(code_to_compile, 'test', 'exec')
marshalled_code = marshal.dumps(compiled_code)

with open('dump.dmp', 'wb') as dump_file:
    dump_file.write(marshalled_code)

Ta thử thực thi các chương trình creds, key, stats đồng thời quan sát dump file được tạo, ta phát hiện chỉ khi thực tệp key thì hệ thống mới load các module mới, trong đó có: binascii, unhexlify, hexdigest, hashlib, hasher Ta có thứ tự thực thi sau:

  1. Chạy đoạn mã ở trên để tạo tệp dump.dmp
  2. Upload tệp dump.dmp lên web server.
  3. Thực thi chương trình vừa được ta tải lên để tiến hành ghi lại load module
  4. Thực thi chương trình key, load các module mới
  5. Tải tệp dump đã ghi lại thông tin load module của hệ thống.

Tiến hành trích nội dung từ tệp dump

import dis
import marshal

with open('dump', 'rb') as dump_file:
    bytecode = dump_file.read()

dis.dis(marshal.loads(bytecode))

image

Dùng https://kt.gy/tools.html để xem nội dung chuỗi hexa.

image

Flag: HTB{1_h0p3_y0u_w4lk3d_th3_tr33_f0r_m3?}

Challenge 8: Mr. Abilgate

Mr. Abilgate, the CFO of a Fortune 500 company, has reportedly been the victim of a recent spree of ransomware attacks. The behavior of the malware seems consistent with our current APT target's tactics, but the ransom note makes us think it's a targeted attack. We suspect bad faith from corporate espionage gone wrong. Could you investigate?

Download Challenge Here

Solution

Tôi làm bài này theo hướng giải của HTB. Sau khi đọc bài này, mình đã học được rất nhiều, cũng như các viết script mình cũng sẽ có sự thay đổi. Các bạn nên đọc tại đây.

Flag: HTB{b1g_br41ns_b1gg3r_p0ck3ts_sm4ll3r_p4y0uts}

Challenge 9: Curse Breaker

A dark wizard placed a curse on you - if you open your mouth to say anything, it'll strike! Only by perfectly reciting the counter-spell can you escape

Download Challenge Here

Solution

Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

image

Mở file trong IDA64, ta thay đổi kiểu dữ liệu từ char s[8] thành char s[56].

image

Ta sẽ cần phân tích hàm install_filter() và lệnh syscall ở dưới cùng.

image

Seccomp (viết tắt của "short for secure computing") là một cơ sở bảo mật máy tính trong nhân Linux, cho phép một quá trình thực hiện quá trình chuyển đổi một chiều sang trạng thái "an toàn" trong đó nó không thể thực hiện bất kỳ lệnh gọi hệ thống nào ngoại trừ exit(), sigreturn(), read(), write(). Nếu nó thử bất kỳ lệnh gọi hệ thống nào khác, kernel sẽ chỉ ghi nhật ký sự kiện hoặc chấm dứt quá trình bằng SIGKILL hoặc SIGSYS.
Tóm lại: rule seccomp chỉ cho phép thực thi các syscall: open, read, write, mprotect, alarm, exit và exit_group.

Tiến hành sử dụng seccomp tools để dump rule seccomp:

image

Luồng chương trình thực thi như sau:

  1. Kiểm tra arch == ARCH_X86_64sys_number ==0x258
  2. Kiểm tra args[0] != 0
    • Nếu đúng -> đến dòng 41 -> đến dòng 75 -> đến dòng 109 -> dòng 143 = Exit
    • Nếu sai, cứ thực hiện 5 phép toán thì gán A = 0 (dòng 8, 42, 76, 110). Mỗi lần thực hiện phép toán, kí tự kế tiếp = kí tự trước đó - kí tự hiện tại

Ta thực hiện trích dữ liệu để tính toán.

seccomp-tools dump ./breaker | grep -oP '(?<=if \(A ==)[^)]*' | tail -n +3 | while read -r n; do echo $((n > 2147483647 ? n - 4294967296 : n)); done | tr '\n' ' ' | sed 's/ $/\n/' | sed 's/ /, /g'

# Result: 72, 12, 54, 69, 46, 101, -2, 101, -53, 162, 112, -67, 164, -64, 116, 98, 16, 36, -3, 128

Từ đó, ta viết chương trình giải mã:

data = [72, 12, 54, 69, 46, 101, -2, 101, -53, 162, 112, -67, 164, -64, 116, 98, 16, 36, -3, 128]
flag = ''
for i in range(0,len(data)):
    if i%5 == 0:
        flag += (chr(data[i]))
    else:
        flag += (chr(data[i-1]+data[i]))
print(flag)
Flag: HTB{secc0mp-ad4br4!}

Challenge 10: RetoRetro

Welcome back to the eighties! Some mediocre game programmer from the 80s has hidden an old ROM inside a modern executable. Can you find it and beat the game to gain the flag?

Download Challenge Here

Solution

Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

image

Mở chương trình trong IDA, chương trình yêu cầu ta nhập dữ liệu từ bàn phím. Với dữ liệu được nhập, chương trình tiếp tục mã băm MD5 của nó. Giá trị băm sẽ được lưu vào byte_5150

image

Tại hàm sub_1205, với giá trị băm MD5 đó, chương trình thực hiện so sánh. Nếu trả về đúng thì mã băm của ta chính xác, nếu sai thì sử dụng giá trị băm theo dữ liệu từ bàn phím.

Ta có thể tính toán cơ bản, giá trị băm MD5 đúng là E7D52842CBE43040630B6B1E01093BC4.

image

Tại hàm sub_1397 nhận tham số gồm: mã băm MD5, bytecode, buffer và n = 1010.

image

Chương trình sử dụng mã băm MD5 là key trong thuật toán mã hóa AES để giải mã dữ liệu từ biến bytecode.

Ta có thể dùng CyberChef để tìm ra giá trị được giải mã

image

Tiếp đó, chương trình cho ta nhập cheatcode gồm 4 kí tự, với cheatcode này ta sẽ mã hóa giá trị tại byte_50E0 và thực hiện so sánh giá trị như sau:

image

Ta dễ dàng tìm được giá trị cheatcode = 6507

data = [  0x34, 0x37, 0x32, 0x35, 0x34, 0x3F, 0x36, 0x35, 0x48, 0x77, 
  0x72, 0x49, 0x48, 0x77, 0x72, 0x49, 0x2C, 0x13, 0x12, 0x25, 
  0x38, 0x37, 0x12, 0x2B, 0x48, 0x77, 0x52, 0x65, 0x7C, 0x73, 
  0x72, 0x49, 0x08, 0x75, 0xB0, 0x8B, 0xF4, 0xB7, 0x74, 0x0F, 
  0x08, 0x75, 0xB0, 0x8B, 0xF4, 0xB7, 0x74, 0x0F, 0x46, 0x7D, 
  0x78, 0x7F, 0x46, 0x75, 0x70, 0x77, 0x0A, 0x77, 0x8D, 0xD0, 
  0xC9, 0xEE, 0x4E, 0x0B]

print (chr(data[1]^ 2))    # 1 
print (chr(data[8]^ 126))  # 0   
print (chr(data[58]^ 189)) # 2 
print (chr(data[63]^ 60))  # 3 

image

Một công cụ chỉnh sửa sprite 8-bit nhỏ gọn dành cho máy Atari VCS (Atari 2600) là một công cụ thú vị cho cả các đam mê và nhà phát triển, cho phép họ tạo ra đồ họa tùy chỉnh để sử dụng trong các trò chơi Atari 2600. Atari 2600, nổi tiếng với đồ họa 8-bit đặc trưng của mình, đã thu hút các game thủ suốt nhiều thập kỷ.

image

Thật ra bạn có thể tìm ra flag từ đoạn giải mã AES rồi. Ta biểu diễn các số hex theo hệ máy Atari

hex_string = "004242427e7e4242420018181818181818ff00e0909090e09090e000304040c0c040403000fe828282fe8080fe003e4080bcc2824438000101017f4141417f00fc848484fc8080fc003f2121213f010101007e42427e7e42427e003e4080bcc2824438007e4262524a46427e000404047c44444440000404047c44444440007e4262524a46427e000404047c44444440001a2622120e02221c00fc848484fc8080fc007048484870404040003c0404043c20203c0002020202020a060200404040e040505020007e4262524a46427e000018202020180000003f2121213f010101000018202020180000003e4080bcc28244380002020202020a060200101010080402021e0002020202020a0602007e42427e7e42427e001a2622120e02221c007e4262524a46427e003e4080bcc2824438003e4080bcc2824438007048484870404040000c0202030302020c00"

flag = ""
for i in range(0, len(hex_string), 2):
        hex_pair = hex_string[i:i+2]
        binary_char = bin(int(hex_pair, 16))[2:].zfill(8)
        flag = binary_char.replace("1", "X").replace("0", " ") + "\n" + flag
print(flag)
Flag: HTB{6e96d8e04404a6b51f0cdce1718a0eeb}

Challenge 11: Alien Saboteur

You finally manage to make it into the main computer of the vessel, it's time to get this over with. You try to shutdown the vessel, however a couple of access codes unknown to you are needed. You try to figure them out, but the computer start speaking some weird language, it seems like gibberish

Download Challenge Here

Solution

Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

image

Mở chương trình trong IDA.

image

Ta có thể dự đoán chương trình sẽ tạo một máy ảo (VM) và chạy chương trình trên đó. Ta mở hàm vm_create để quan sát thêm.

image

Hàm vm_create được sử dụng để tạo ra một đối tượng máy ảo (VM) và cấp phát bộ nhớ cho ba mảnh bộ nhớ khác nhau trên heap.

  • Đối tượng VM có kích thước 0xA8 byte.
  • Hai mảnh bộ nhớ khác có kích thước 0x10000 byte và 0x200 * 4 byte (tương đương với 0x800 byte).

Tiếp theo làm hàm vm_run

image

Hàm vm_run gọi hàm vm_step

image

Khi giá trị của v1 > 0x19 thì điều kiện không hợp lệ trong quá trình thực thi của VM và thoát chương trình. Hàm sử dụng con trỏ hàm original_ops thể hiện máy ảo này có một tập hợp các lệnh được quản lý thông qua một mảng các con trỏ hàm.

1. vm_add 6. vm_muli 11. vm_push 16. vm_print 21. vm_jge
2. vm_addi 7. vm_div 12. vm_pop 17. vm_putc 22. vm_xor
3. vm_sub 8. vm_cmp 13. vm_mov 18. vm_je 23. vm_store
4. vm_subi 9. vm_jmp 14. vm_nop 19. vm_jne 24. vm_load
5. vm_mul 10. vm_inv 15. vm_exit 20. vm_jle 25. vm_input

Lười quá không làm nổi nữa!! Sau khi đọc bài này, mình đã học được rất nhiều, cũng như các viết script mình cũng sẽ có sự thay đổi. Các bạn nên đọc tại đây.

permut_byte_array = b'\x13\x19\x0F\x0A\x07\x00\x1D\x0E\x16\x10\x0C\x01\x0B\x1F\x18\x14\x08\x09\x1C\x1A\x21\x04\x22\x12\x05\x1B\x11\x20\x06\x02\x15\x17\x0D\x1E\x23\x03'
Xor_Key_byte_array = b'\x16\xB0\x47\xB2\x01\xFB\xDE\xEB\x82\x5D\x5B\x5D\x10\x7C\x6E\x21\x5F\xE7\x45\x2A\x36\x23\xD4\xD7\x26\xD5\xA3\x11\xED\xE7\x5E\xCB\xDB\x9F\xDD\xE2'
Solution_Compare_String = b'\x31\x5D\x77\x4A\x33\x40\x56\x35\x75\x37\x5D\x35\x6E\x6E\x66\x32\x6C\x36\x70\x66\x61\x6A\x31\x79\x5D\x31\x70\x7F\x6C\x60\x33\x32\x36\x7B\x31\x5D'

PermutDict = {}
for i in range(len(permut_byte_array)) :
    PermutDict[permut_byte_array[i]] = i

def Xor(bytes_array_a,value) :
    return bytes(a^value for a in bytes_array_a)

def swapbytes(byte_array,i,j) :
    res = b''
    for c in range(len(byte_array)) :
        if c == i :
            res += bytearray( [byte_array[j]] )
        elif c == j :
            res += bytearray( [byte_array[i]] )
        else :
            res += bytearray( [byte_array[c]] )
    return res

def PermutByteArray(bytes_array) :
    byte_res = bytes_array
    for i in range(36)[::-1] :
        byte_res = swapbytes(byte_res,i,permut_byte_array[i])
    return byte_res

for i in range(36) :
    Solution_Compare_String = PermutByteArray(Xor(Solution_Compare_String,Xor_Key_byte_array[35-i]))
    print(Solution_Compare_String)

Flag: HTB{5w1rl_4r0und_7h3_4l13n_by73c0d3}

Challenge 12: Bombs Landed

Can you find the password?
Enter the password as flag in the following form: HTB{passwordhere}

Download Challenge Here

Solution

Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

image

IDA chưa thể decompile chương trình được. Ta sẽ tạo hàm từ 0x8048937 đến 0x08048AE6 để IDA có thể decompile hàm main().

image

Chương trình thực hiện kiểm tra đã được truyền bốn tham số chưa. Sau đó sub_80491A0() ^ 0x63 để tạo một hàm mới. Ta dùng IDAPython để viết patch script.

import ida_bytes
start_address = 0x080491A0
end_address = 0x08049336
for i in range(start_address,end_address):
    tmp = ida_bytes.get_byte(i)
    ida_bytes.patch_byte(i,tmp^0x63)

image

Chương trình giải mã các chuỗi thành các chuỗi đọc được như sau:

  • s ^ 0x14 nhằm tạo chuỗi input password:
  • v3 ^ 0x14 nhằm tạo chuỗi you win.
  • (v6 + v5) ^ 0xA để tạo và trả về chuỗi younevergoingtofindme
Flag: HTB{younevergoingtofindme}