HCMUS-CTF 2021 Writeups

NiceEars 25:

Dùng audacity view spectrogram của file key.mp3

Ta được password của file secret.zip: M0nK3y_doNkeY

Extract file secret.zip và ta có flag:

HCMUS-CTF{Just_give_you_some_points_from_audio_stuff}

metadata 25

$ docker pull vinhph2/hcmus-ctf-2021
[...] 
$ docker images -q vinhph2/hcmus-ctf-2021
b14934520afd
$ grep -r HCMUS /var/lib//docker/image/overlay2/imagedb/content/sha256/ b14934520afd*

Tìm đến flag có format HCMUS-CTF

Flag: HCMUS-CTF{d0ck6r_1mag6_1nsp6ct}

Maquerade 50

Mở file mitm.pcapng + apply filter HTTP

Dùng tính năng export object để export HTTP object

Nghe file OTP.mp3, ta được password của secret.zip: pwd785$

Mở secret.zip ta được part 1 của flag: HCMUS-CTF{Just_Network_Stuff_

Decode lại thuật toán trong file CheckPass.class, ta được part còn lại của flag: 897268$}

Flag: HCMUS-CTF{Just_Network_Stuff_897268$}

Memory 150

Dùng volatility scan clipboard thử :v tình cờ được part 1 của key: Sup3r

Sử dụng pslist để xem thử phát hiện có nhiều process Chrome đang chạy

Download plugin Chromehistory cho volatility và dùng, ta được đường dẫn đến flag.zip

flag.zip bị khóa nên cần tìm thêm part 2 của key để giải nén

Sau một hồi scan file thì phát hiện trên Desktop có một file tên là flag.txt.txt

Dùng option dumpfiles về ta được part 2 của key: P@ssw0rD

Giải nén flag.zip, ta được flag: HCMUS-CTF{simple_memory_forensics_stuff}

bank1 25

Thử làm tràn bộ đệm bằng cách gõ một tràng kí tự

Flag hiện ra: HCMUS-CTF{that_was_easy_xd}

CrackMe 50

Bỏ chuỗi hashed trong phase1 vô hash identifier online thử —-> có thể là SHA-512

Dùng john để crack, ta được chuỗi: playboy123

Đem đi base64 ta được key để mở phase2.zip: cGxheWJveTEyMw==

Google cách crack id_rsa, xài john luôn :3

Ta được chuỗi thứ 2: felecity

Đem base64 –> key cho flag.zip: ZmVsZWNpdHk=

Bingo :v Flag: HCMUS_CTF{cracking_for_fun}

LEARN FORENSIC DAY#9: NGÂM CỨU VỀ ĐỊNH DẠNG PNG THEO TÀI LIỆU CỦA PNG DEV GROUP (#7)

Đuối như trái chuối :v Nhưng sắp xong chương 4 rồi

Vạch tài liệu ra và chiến tiếp nào! Let’s goooooo!!!!

I. TEXTUAL INFORMATION (THÔNG TIN DẠNG VĂN BẢN):

Các chunks iTXt, tEXtzTXt được dùng để truyền tải thông tin dạng văn bản kèm trong hình ảnh. Nhờ đặc điểm này mà chúng được gọi chung là “text chunks”.

Mỗi text chunk chứa một trường đầu tiên, trường này chỉ ra loại thông tin được biểu thị bởi text string đó. Những keywords dưới đây được quy định sẵn và nên được sử dụng khi thích hợp:

Các bạn thấy phần thông tin này quen thuộc chứ :v Bộ phận của metadata í

Các keywords khác nhau có thể được tạo ra cho các mục đích khác nhau. Các từ khóa được sử dụng nhiều có thể được đăng ký với ban vận hành của PNG. Tuy nhiên, ta cũng có thể sử dụng các keywords riêng, chưa được đăng ký. Các keywords riêng phải tự giải thích một cách hợp lý, giảm thiểu khả năng nhiều người sử dụng cùng một keyword cho nhiều dạng thông tin khác nhau, không đúng mục đích.

Keyword phải chứa ít nhất 1 kí tự và tối đa ít hơn 80 kí tự. Để giảm thiểu nguy cơ con người đọc sai/không hiểu keywords, các khoảng trắng (space) đầu và cuối, cũng như các khoảng trống liên tiếp đều bị cấm.

Keywords cần phải được viết đúng như đã đăng ký, để trình decoders có thể dễ dàng so sánh khi nhìn vào keywords cụ thể. Điều này còn có nghĩa là keywords phân biệt chữ hoa/thường.

Số lượng text chunks trong ảnh là không giới hạn, và có thể sử dụng nhiều keywords giống nhau cùng lúc.

1. TEXT CHUNK PROCESSING (XỬ LÝ TEXT CHUNK):

Phần này của chương 9 mà mình thấy nó dẫn link cũng hay nên thôi quất lun :b

Mỗi text chunk phải được cung cấp ít nhất một nonempty keyword (đánh keyword gì cũng được, miễn đúng quy tắc và không bỏ trống). Keyword “Comment” thường được dùng nếu không biết mô tả text đó như thế nào. Nếu một keyword do user tạo ra (chưa được đăng ký) được dùng, phải check xem keyword đó có tuân thủ quy định tên keyword chưa.

Văn bản được lưu trữ trong chunks tEXtzTXt sẽ sử dụng bảng kí tự Latin-1. Các trình encoders nên cung cấp ánh xạ mã kí tự (character code) nếu bảng kí tự của hệ thống không phải Latin-1. Nếu trình encoders muốn lưu trữ các kí tự không được định dạng Latin-1 thì nên dùng iTXt chunk.

Bảng kí tự Latin-1

Encoders không nên khuyến khích người dùng tạo ra các dòng text đơn lẻ dài hơn 79 kí tự, để giúp cho thông tin dễ đọc hơn.

Các text items có dung lượng nhỏ hơn 1K (1024 bytes) nên được xuất ra (output) sử dụng các text chunks không nén (uncompressed text chunks).

Ví dụ:

Phần text của keywords titleauthor luôn nên được xuất ra bằng chunks không nén, trong khi disclaimers dài dòng hơn thì thích hợp cho việc nén.

Phần mềm nhận ra tác giả dựa vào keyword author

Việc đặt các text chunks lớn nằm sau chunk IDAT có thể tăng tốc quá trình hiển thị hình ảnh  trong một số trường hợp. Nguyên nhân là do trình decoders không cần phải đọc qua text chunks xong mới được sờ tới dữ liệu hình ảnh. Tuy nhiên, những text chunks nhỏ như image title nên được đặt trước IDAT.

2. tEXt TEXTUAL DATA:

Thông tin văn bản mà trình encoder muốn ghi lại để kẹp vô hình ảnh có thể được lưu trữ trong chunk tEXt.

Mỗi chunk tEXt gồm một keyword và một chuỗi text (text string), theo format:

Phần keywordchuỗi text được ngăn cách bởi một zero byte (kí tự null), nhưng keyword với chuỗi text thì không được chứa kí tự null nhe.

Cần lưu ý là text string không được kết thúc bằng null (null-terminated), vị trí kết thúc sẽ được xác định bằng thông tin độ dài chunk. Text string có thể có độ dài bất kì từ 0 byte đến kích thước tối đa cho phép của chunk size trừ đi độ dài của keyworddấu phân tách.

3. zTXt COMPRESSED TEXTUAL DATA (DỮ LIỆU DẠNG VĂN BẢN ĐÃ NÉN):

Chunk zTXt chứa dữ liệu văn bản giống như tEXt, tuy nhiên, zTXt có ưu điểm là nén được. Hai chunk zTXttEXt rất giống nhau, nhưng zTXt được khuyên dùng để lưu trữ lượng lớn text.

Chunk zTXt bao gồm:

Keyworddấu ngăn cách null (null seperator) giống hệt như trong tEXt chunk. Lưu ý là keyword sẽ không được nén. Theo sau byte phương pháp néndòng dữ liệu nén, tạo thành phần còn lại của chunk. Đối với phương pháp nén 0, dòng dữ liệu tuân theo định dạng dòng dữ liệu zlib. Giải nén dòng dữ liệu, ta thu được đoạn văn bản sử dụng Latin-1 tương tự như đoạn văn bản được lưu trữ trong một chunk tEXt tương đương. (Giống kiểu tEXt nhưng đem phần text đi nén thôi, giải nén thì được y chang tEXt )

4. iTXt INTERNATIONAL TEXTUAL DATA (DỮ LIỆU VĂN BẢN QUỐC TẾ):

Về ngữ nghĩa, iTXt giống với chunks tEXt, zTXt, nhưng phần dữ liệu văn bản sử dụng mã hóa UTF-8 với bảng kí tự Unicode thay vì Latin-1.

Chunk iTXt gồm có:

Các keywords

Trường compression flag mang giá trị 0 đối với phần text không nén, và 1 đối với text đã nén. Chỉ mỗi phần text có thể bị nén, keyword không thể. Như đã đề cập ở các bài trước, giá trị duy nhất hiện tại dành cho byte phương pháp nén0, nghĩa là dòng dữ liệu zlib được nén giảm phát. Đối với text không nén, trình encoders nên đặt phương pháp nén0 và trình decoder nên bỏ qua nó.

Trường language tag cho biết ngôn ngữ (tiếng Anh, Pháp, Đức,…v.v… chứ hong phải C, Java, Python nhe :v) mà keywordvăn bản đã được dịch sang. Trường này phân biệt chữ hoa/thường. Nó là một chuỗi ASCII, bao gồm các từ phân tách bằng dấu gạch nối, với độ dài mỗi từ từ 1 đến 8 chữ cái.

Ví dụ: cn, en-uk, no-bok, x-klingon

Nếu từ đầu tiên dài hai chữ cái, nó là ISO language code (ISO-639-1, sang ISO-639-2 3 chữ cũng có).

Tham khảo: ISO language code

Trường translated keyword text đều dùng mã hóa UTF-8 cùng bảng kí tự Unicode, và không được chứa zero byte (kí tự null). Phần text không được kết thúc bằng null, độ dài của nó được tính dựa trên chunk length.

“Ngắt dòng” không được phép xuất hiện trong translated keyword. Trong text, một dòng mới nên được giới thiệu bởi một single line feed character (\n hoặc 0x0A) (decimal 10). Những kí tự điều kiển còn lại (dec 1-9, 11-31 và 127-159) không được khuyến khích kể cả trong translated keyword hay text.

Lưu ý: Trong UTF-8, có sự khác biệt giữa characters 128-159 (không khuyến khích sử dụng) và bytes 128-159 (thường xuyên sử dụng).

Đối với translated keyword, nếu không bỏ trống, nên chứa bản dịch của keyword đó sang ngôn ngữ được chỉ ra bởi language tag. Các ứng dụng khi hiển thị keyword thì nên hiển thị thêm keyword đã được dịch.

Và đó là tất cả kiến thức của Day#9

Hẹn gặp lại các bạn vào Day#10!

Cảm ơn các bạn đã xem! CHim’s Out ❤

LEARN FORENSIC DAY#8: NGÂM CỨU VỀ ĐỊNH DẠNG PNG THEO TÀI LIỆU CỦA PNG DEV GROUP (#6)

Ok Day#8, nay lười giới thiệu :b Kiến thức nhiều lắm, hết thấy đường rồi

Let’s go!!!

I. CHUNK SPECIFICATIONS (P.3):

1. ANCILLARY CHUNKS:

Tất cả các chunk phụ trợ (ancillary) đều là tùy chọn (optional), điều này nghĩa là các trình encoders không cần phải ghi chúng và trình decoders có quyền bỏ qua chúng. Tuy nhiên, các trình encoders được khuyến khích ghi vào các ancillary chunks tiêu chuẩn khi mà có sẵn dữ liệu của các chunks đó, trình decoders cũng nên dịch những chunks đó khi thích hợp và khả thi.

Các bạn có thể thấy hai chunks phụ trợ tIME và pHYs

Những chunks phụ trợ tiêu chuẩn sẽ được đề cập đến ngay sau đây.

Lưu ý rằng đây không phải thứ tự mà chúng phải xuất hiện trong một luồng dữ liệu.

A. TRANSPARENCY INFORMATION (ĐỘ TRONG SUỐT):

Chunk này truyền đi các thông tin về độ trong suốt ở trong các luồng dữ liệu không bao gồm một full alpha channel

A.1. tRNS TRANSPARENCY:

Chunk tRNS chỉ rõ bức ảnh này dùng simple transparency(mình không biết dịch ra sao cho sát).

Nghĩa là: các giá trị alpha được liên kết với các palette entries (đối với các ảnh sử dụng indexed-color) hoặc một màu trong suốt (transparent color) duy nhất (đối với ảnh sử dụng grayscale hay true color).

Mặc dù simple transparency không đẹp như khi sử dụng full alpha channel, nhưng nó chiếm ít dung lượng bộ nhớ hơn, và đủ cho nhiều trường hợp thông dụng.

Đối với color type 3 (indexed color), tRNS chứa một chuỗi (series) các giá trị alpha 1-byte, tương ứng với các mục trong chunk PLTE. Ví dụ:

Alpha for palette index 0: 1 byte

Alpha for palette index 1: 1 byte

…etc…

Mỗi entry chỉ ra rằng các pixel của chỉ mục palette tương ứng phải được coi là có giá trị alpha được chỉ định. Cách dịch các giá trị alpha tương tự như trong một full alpha channel 8-bit:

0 là hoàn toàn trong suốt (fully transparent)

255 là hoàn toàn đục (fully opaque)

Bất kể bit depth là bao nhiêu.

Chunk tRNS có thể chứa ít giá trị alpha hơn số palette entries hiện có, tuy nhiên, tRNS không được chứa nhiều giá trị alpha hơn số palette entries.

Trong trường hợp chứa ít giá trị alpha hơn, giá trị alpha cho tất cả palette entries còn lại được giả định là 255. Trong trường hợp phổ biến mà ở đó chỉ có duy nhất mỗi palette index 0 cần được là trong suốt, ta chỉ cần một chunk tRNS 1-byte.

Đối với color type 0 (grayscale), tRNS bao gồm một giá trị độ xám (gray level value) duy nhất, sẽ được lưu trữ theo format như sau:

Gray: 2 bytes, range 0 .. (2^bitdepth)-1

(Nếu bit depth của ảnh nhỏ hơn 16, các LSB sẽ được dùng còn những bits khác sẽ mang gía trị 0). Các pixels của độ xám (gray level) được chỉ định sẽ được xem như trong suốt (tương đương với giá trị alpha bằng 0). Tất cả các pixels khác sẽ được xem như là hoàn toàn mờ đục (fully opaque) (tương đương với giá trị alpha 2^bitdepth).

Đối với color type 2 (true color), chunk tRNS chứa một giá trị RGB đơn lẻ, được lưu trữ theo format:

Red: 2 bytes, range 0 .. (2^bitdepth) -1

Green: 2 bytes, range 0 .. (2^bitdepth) -1

Blue: 2 bytes, range 0 .. (2^bitdepth) -1

(Tương tự như ở type 0, nếu bit depth của ảnh nhỏ hơn 16, các LSB sẽ được dùng còn những bits khác sẽ mang gía trị 0). Các pixels của màu sắc được chỉ định sẽ được xem như trong suốt (tương đương với giá trị alpha bằng 0). Tất cả các pixels khác sẽ được xem như là hoàn toàn mờ đục (fully opaque) (tương đương với giá trị alpha 2^bitdepth).

Chunk tRNS không được phép dử dụng cho color type 4 và 6, bởi vì hai type này đều đã có sẵn một full alpha channel nên không cần simple tranparency nữa.

Lưu ý: Khi xử lý dữ liệu 16-bit grayscale hay truecolor, cần phải so sánh cả hai bytes của cùng các giá trị mẫu (sample values) để phát hiện xem pixel đó có trong suốt hay không. Mặc dù trình decoders có thể bỏ (drop) các byte bậc thấp (low-order byte) của các samples để hiện thị, nhưng thao tác này chỉ được diễn ra sau khi dữ liệu đã được kiểm tra về độ trong suốt.

Ví dụ:

Nếu grayscale level 0x0001 được chỉ định là trong suốt, sẽ là một sai lầm nếu chỉ so sánh các byte bậc cao (high-order byte) và rồi bảo rằng 0x0002 cũng trong suốt. Tất cả đều phải được kiểm tra.

Nếu có trong file PNG, tRNS chunk sẽ đứng trước chunk IDAT đầu tiên và phải theo sau chunk PLTE, nếu có.

B. COLOR SPACE INFORMATION (THÔNG TIN KHÔNG GIAN MÀU):

Những chunks này liên hệ các samples hình ảnh với cường độ hiển thị mong muốn.

B.1. gAMA (IMAGE GAMMA):

Gamma ở đây miêu tả độ mượt mà khi chuyển từ đen sang trắng khi hiển thị trên màn hình điện tử.

Chunk gAMA chỉ ra mối liên hệ giữa các samples hình ảnhcường độ hiển thị đầu ra mong muốn dưới dạng hàm mũ (power function):

sample = light_out ^ gamma

Ở đây, samplelight_out được chuẩn hóa thành phạm vi từ 0.0 (cường độ tối thiểu) đến 1.0 (cường độ tối đa). Do đó:

sample = integer_sample / (2^bitdepth - 1)

Chunk gAMA bao gồm:

Gamma: 4 bytes

Giá trị được mã hóa như một số 4-byte không dấu, biểu diễn chỉ số gamma nhân 100 nghìn lần.

Ví dụ:

Gamma 1/2,2 ~ 0,45455 sẽ được lưu trữ là 45455

Giá trị gamma không ảnh hưởng gì đến alpha samples, các samples này luôn là một phần tuyến tính (linear fraction) của sự mờ đục hoàn toàn (full opacity).

Nếu trình encoder không biết giá trị gamma của bức ảnh, thì nó không nên ghi chunk gAMA vào, chunk gAMA không xuất hiện đồng nghĩa với việc chỉ số gamma không rõ.

Nếu chunk gAMA xuất hiện, nó phải nằm trước IDAT chunk đầu tiên, và trước luôn PLTE chunk (nếu có).

Trong trường hợp có chunk sRGB hay chunk iCCP xuất hiện, hai chunk này sẽ ghi đè lên gAMA chunk.

B.2. cHRM PRIMARY CHROMATICITIES (SẮC ĐỘ CHÍNH):

Các ứng dụng sử dụng đặc tính màu không phụ thuộc vào thiết bị trong một file PNG có thể sử dụng chunk cHRM để chỉ định sắc độ của red, green và blue được sử dụng chính trong ảnh, theo hệ CIE năm 1931 x,y, và điểm trắng tham chiếu (referenced white point).

Chunk cHRM bao gồm:

White Point x: 4 bytes

White Point y: 4 bytes

Red x: 4 bytes

Red y: 4 bytes

Green x: 4 bytes

Green y: 4 bytes

Blue x: 4 bytes

Blue y: 4 bytes

Mỗi giá trị được mã hóa như một số 4-byte không dấu, biểu diễn giá trị x, y nhân với 100 nghìn lần.

Ví dụ:

Giá trị 0,3127 sẽ được lưu là số nguyên 31270

Chunk cHRM được cho phép trong mọi file PNG, mặc dù nó có ít giá trị với các ảnh grayscale.

Nếu trình encoder không biết các giá trị sắc độ, nó không nên ghi chunk cHRM vào.

Chunk cHRM không xuất hiện đồng nghĩa với các màu sắc chính (primary colors) của bức ảnh phụ thuộc vào thiết bị (device-dependent).

Nếu chunk cHRM xuất hiện, nó phải nằm trước chunk IDAT đầu tiên, và trước cả chunk PLTE (nếu có).

Trong trường hợp có chunk sRGB hay chunk iCCP xuất hiện, hai chunk này sẽ ghi đè lên cHRM chunk.

B.3. sRGB STANDARD RGB COLOR SPACE:

Nếu chunk sRGB xuất hiện, các samples ảnh sẽ tuân theo không gian màu (color space) sRGB, và nên được hiển thị bằng các mục đích hiển thị (rendering intent) cụ thể được quy định bởi Tổ chức Màu sắc Quốc tế – ICC.

Chunk sRGB

Chunk sRGB bao gồm:

Rendering intent: 1 byte

Những giá trị sau là các thông số được định nghĩa cho Rendering Intent:

0: Perceptual (Tri giác)

1: Relative colorimetric (Đo lường màu tương đối)

2: Saturation (Độ bão hòa)

3: Absolute colorimetric (Đo lường màu chính xác)


Perceptual intent: dành cho những hình ảnh thích ứng tốt với gam màu của thiết bị đầu ra, dựa trên độ chính xác của phép đo màu. Ví dụ như ảnh chụp (mỗi người chụp có gu màu khác nhau trên thiết bị khác nhau, thử nhìn ảnh chụp trên 2 thiết bị khác nhau là thấy khác nhau rõ rệt về màu sắc).

Relative colorimetric intent: dành cho những hình ảnh yêu cầu sự tương đối về giao diện màu (liên quan đến white point của thiết bị đầu ra). Ví dụ như logo (chứ cùng một logo mà nhìn mỗi nơi một khác thì chết dở :v).

Saturation intent: Cho các bạn không chuyên về ảnh thì độ bão hòa là đại lượng đặc trưng cho màu sắc tương đối của vật thể so với màu gốc, hay hiểu đơn giản là cùng một màu nhưng mức độ đậm nhạt khác nhau. Dành cho các hình ảnh thích duy trì độ bão hòa bằng màu sắc (hue), độ sáng (lightness). Ví dụ như biểu đồ và đồ thị ( dạng như trình bày biểu đồ theo kiểu mức nguy hiểm thì màu đỏ đậm, rồi chuyển nhạt dần thành lại màu nhạt là mức bình thường í).

Absolute colorimetric intent: Dành cho các ảnh cần sự chính xác tuyệt đối về màu. Ví dụ như chứng cứ.

Khi một ứng dụng ghi chunk sRGB vào, nó cũng nên ghi thêm chunk gAMA (không thì chunk cHRM chũng được), để nếu ứng dụng khác không sử dụng chunk sRGB mà mở thì vẫn mở được. Trong trường hợp này, chỉ có những giá trị này có thể được sử dụng:

Khi chunk sRGB xuất hiện, những ứng dụng nhận ra nó và có khả năng quản lý màu sắc phải bỏ qua các chunk gAMA hay cHRM đi, và sử dụng chunk sRGB thay vào đó.

Những ứng dụng nhận ra chunk sRGB nhưng không có khả năng quản lý màu toàn diện cũng phải bỏ qua chunk gAMA cHRM luôn. Bởi vì ứng dụng đó đã biết giá trị mà những chunks đó chứa. Ứng dụng này phải vì thế mà sử dụng các giá trị của gAMAcHRM được cho ở trong chunk sRGB thay vì đọc chunk gAMAcHRM để lấy ra.

Nếu chunk sRGB xuất hiện, nó phải nằm trước chunk IDAT đầu tiên, và trước cả chunk PLTE (nếu có). Chunks sRGBchunk iCCP không được phép cùng xuất hiện.

B.4. iCCP EMBEDDED ICC PROFILE (HỒ SƠ ICC ĐƯỢC NHÚNG):

Nếu chunk iCCP xuất hiện, các samples ảnh sẽ tuân theo không gian màu (color space) được cung cấp bởi hồ sơ ICC (Tổ chức Màu sắc Quốc tế) nhúng trong nó.

Không gian màu của hồ sơ ICC phải là RGB đối với ảnh màu (PNG color type 2, 3 và 6), hoặc thang độ xám đơn sắc (monochrome grayscale) đối với ảnh graysacle (PNG color type 0 và 4).

Chunk iCCP gồm có:

Trường Profile name có thể là bất cứ tên nào thuận tiện cho việc gọi profile đó. Ở đây phân biệt chữ hoa/thường và tuân thủ các quy định như là từ khóa trong một văn bản. Giá trị duy nhất hiện được xác định cho byte phương pháp nén (compression method)0, có nghĩa là dòng dữ liều Zlib được nén giảm phát (deflate compression) (Có nghĩa là muốn extract data từ các chunk này thì có thể import thư viện zlib vào rồi quất :v). Giải nén phần còn lại của chunk sẽ thu được hồ sơ ICC (ICC profile).

Khi một ứng dụng ghi chunk iCCP vào, nó cũng nên ghi thêm chunk gAMAcHRM có ý nghĩa tương đương với profile cần truyền, để tăng khả năng tương thích với các ứng dụng không sử dụng iCCP.

Khi chunk iCCP xuất hiện, những ứng dụng nhận ra nó và có khả năng quản lý màu sắc phải bỏ qua các chunk gAMA hay cHRM đi, và sử dụng chunk iCCP thay vào đó.

Những ứng dụng nhận ra chunk sRGB nhưng không có khả năng quản lý màu toàn diện thì nên dùng chunk gAMAcHRM (nếu có).

Một file chỉ được chứa nhiều nhất là một profile được nhúng, dù là iCCP hay sRGB.

Nếu chunk iCCP xuất hiện, nó phải được đặt trước chunk IDAT đầu tiên và trước luôn cả chunk PLTE (nếu có)

Và đó là tất cả của ngày hôm nay :”) I’m snowed under knowledgeeeeee

Cám ơn các bạn đã xem! Chim’s Out ❤

LEARN FORENSIC DAY##: KIẾN THỨC ĐỂ CODE SCRIPT(#1)

Lại là mình đây :v

Mấy ngày nay mình đang bị hành vì task viết script do “mentor đẹp chai siu cấp” của mình cho, mà kiến thức về lập trình và các ngôn ngữ Script của mình còn yếu quá, nên mình nghĩ mình phải có một series như thế này để học tập thêm, cũng như lưu trữ lại kiến thức cần biết, để lỡ các bạn mới như mình muốn học viết script (cụ thể là script giải mã hình ảnh bằng python để chơi các dạng CTF stego) có thể biết được hướng đi và không mất nhiều thời gian cho việc lạc đường như mình.

Vì đây là series theo dạng học tới đâu ghi tới đó theo kiểu note lại í nên nếu các bạn nghĩ nó không theo trình tự nào thì các bạn đúng rồi đấy :))))

Và Day## đầu tiên bắt đầu thôi :v

###PYTHON###

1. HÀM OPEN():

Hàm open() mở một file và trả về nó dưới dạng một file object

Cú pháp:

>> open(file, mode)

Ví dụ: Để mở file đọc (read) thôi thì chỉ cần tên file là đủ

f = open(“demofile.txt”)

Thực chất, đoạn code trên đầy đủ như thế này:

f = open(“demofile.txt”, “rt”)

Tuy nhiên “r”“t” là các giá trị mặc định nên không cần chỉ rõ.

2. HÀM REPLACE():

Hàm này thay thế một cụm được chỉ định bằng một cụm được chỉ định khác.

Tất cả các lần cụm được chỉ định xuất hiện trong file, đều sẽ được thay thế hết nếu không có yêu cầu gì đặc biệt.

Cú pháp:

>> string.replace(oldvalue, newvalue, count)

Ví dụ: Thay từ “wrong” thành từ “correct” trong biến txt

 txt = “you are not wrong”
 x = txt.replace(“wrong”,”correct”) 
 print(x)
>> you are not correct

Code này sẽ thay tất cả các từ “wrong” thành “correct”. Nếu trong câu có nhiều từ “wrong” và bạn chỉ muốn thay đúng hai từ “wrong” đầu tiên thì thêm vào parameter “count” giá trị 2

x = txt.replace(“wrong”,”correct”,2)

3. HÀM READ():

Hàm read() trả về một số lượng bytes chỉ định, lấy từ file.

Cú pháp:

>> file.read()

Ví dụ: để đọc hết file “demo.txt”

f = open(“demo.txt”, “r”)
print(f.read())

Nếu chỉ muốn đọc 32 bytes đầu thì thêm vào param size có giá trị 32

print(f.read(32))

4. HÀM FROMHEX() CỦA CLASS BYTES

Hàm này tạo ra một bytes object từ một chuỗi (string) các kí tự hexa.

Để hàm hoạt động đúng, với mỗi byte trong string hai kí tự hexa phải được cho. Nếu không nó sẽ báo ValueError.

Sử dụng header của PNG để test thử

5. HÀM WRITE() VÀ SỬ DỤNG KẾT HỢP VỚI OPEN():

Hàm write() để ghi vào một file đã tồn tại, để sử dụng write() cần phải parameter “a” hoặc “w” vào hàm open()

Trong đó:

“a” – Append: ghi thêm vào vị trí cuối file, nếu file chưa có thì tạo file mới

“w” – Write: ghi đè lên nội dung cũ, nếu file chưa có thì tạo file mới

Ví dụ:

Tạo file demo.txt và ghi vào đó “aloalo”
Mở file demo.txt lên và ghi thêm ” tui la chim ne”

6. THAO TÁC CƠ BẢN VỚI THU VIỆN PIL:

Python cho phép giải quyết các vấn đề về xử lý hình ảnh thông qua thư viện Imaging(PIL)

Thư viện này hỗ trợ nhiều định dạng tập tin và cung cấp khả năng xử lý hình ảnh, đồ họa mạnh mẽ.

Hôm nay ta sẽ chỉ tìm hiểu về cách tạo và lưu hình ảnh trong Python thông qua PIL

(Phần này mình tham khảo bài viết trên stdio.vn, các bạn có thể ủng hộ bài viết gốc bằng link này, vô đó thả tym hay follow ảnh cũng được :>)

Ta sẽ bỏ qua bước cài đặt PIL, bởi thao tác cài đặt đã được nêu rất rõ trên trang chủ của PIL rồi.

Sau khi cài đặt thành công, ta cùng tiến đến phần tạo ảnh.

A. TẠO ẢNH VỚI PIL:

Đầu tiên ta cần phải import module Image từ thư viện PIL

from PIL import Image

Tiếp đó ta sử dụng lệnh new() từ module Image đã import

img = Image.new(mode, size)

Hoặc

img = Image.new(mode, size, color)

Ví dụ:

img = Image.new(“RGB”, (240, 320), “white”)

Hay cũng có thể sử dụng color code như

img = Image.new(“RGB”, (240, 320), (255, 255, 255))

Cách dạng format code khác Python PIL | Image.new() method – GeeksforGeeks

B. MỞ ẢNH:

Cho phép mở một tấm ảnh đã có sẵn lên để thực hiện các thao tác như: Sao chép, chỉnh sửa,…v.v…

Thao tác này khá giống với việc mở file đã nói ở trên.

Đầu tiên ta cũng cần phải import module Image từ thư viện PIL

from PIL import Image

Cú pháp:

>> img = Image.open(filename)

Ví dụ: Mở ảnh có tên “tuilachim.png”

 from PIL import Image
 img = Image.open(“tuilachim.png”) 

C. HIỂN THỊ ẢNH:

Thao tác này chủ yếu được dùng cho mục đích gỡ lỗi trong quá trình làm việc với các tấm ảnh.

Cú pháp:

>> img.show()

D. LƯU ẢNH:

Cho phép bạn lưu lại tấm ảnh dưới dạng tập tin

Cú pháp:

>> img.save(outfile_name, format, params)
Các giá trị params

Ví dụ: Lưu một bức ảnh tên “image.png” với định dạng là PNG

>> img.save(“image.png”, “PNG”)

Ví dụ 2: Lưu một bức ảnh có tên “flower1.jpg” thành “hoa.jpg”

from PIL import Image  
import PIL
img = Image.open(r"C:\Users\System-Pc\Desktop\flower1.jpg")
img = img.save("geeks.jpg")

Và đó là kiến thức của ngày hôm nay

Cảm ơn các bạn đã xem! Chim’s Out ❤

LEARN FORENSIC DAY#7: NGÂM CỨU VỀ ĐỊNH DẠNG PNG THEO TÀI LIỆU CỦA PNG DEV GROUP (#5)

Vậy là đã tròn một tuần ta tìm hiểu lĩnh vực này rồi.

Head up!!! Keep going on :vvv

Tiếp tục với phần còn dang dở của Day#6 thoy!

I. CHUNK SPECIFICATIONS (P.2):

  1. CRITICAL CHUNKS (P.2):

A. PLTE PALETTE:

PLTE chunk (viết tắt của Palette á :v) chứa từ 1 đến 256 mục bảng màu (palette entries), mỗi entry là một loạt (series) 3-byte có dạng:

Red: 1 byte (0 = black, 255 = red)

Green: 1 byte (0 = black, 22 = green)

Blue: 1 byte (0 = black, 255 = blue)

Nói cho dễ hiểu thì đây giống như dạng thanh màu của mode RGB thôi chứ không có gì đặc biệt :v

Số lượng các entries được tính toán từ chunk length. Nếu chunk length không chia hết cho 3 sẽ dẫn đến lỗi.

PLTE chunk phải xuất hiện trong color type 3 (khái niệm color type đã nói đến ở Day#6), có thể xuất hiện hoặc khôngcolor type 26, và không được xuất hiện type 04. Nếu chunk này xuất hiện thì nó sẽ nằm trước IDAT chunk đầu tiên. Không đượcnhiều hơn một PLTE chunk.

Phần dữ liệu đang được khối lại chính là PLTE chunk. Có thể nhìn thấy IDAT chunk đầu tiên nằm bên dưới.

Đối với color type 3 (indexed color), bắt buộc có PLTE chunk. Entry đầu tiên của PLTE được tham chiếu bởi pixel giá trị 0, entry thứ hai của PLTE được tham chiếu bởi pixel giá trị 1,…v.v… Số lượng các entries có thể ít hơn, nhưng không được vượt quá khoảng mà có thể được biểu diễn dưới dạng bit depth của ảnh.

Color type 3: Indexed colors

Ví dụ: 2^4 = 16 entries cho bit depth 4

Trong trường hợp thừa entries, thì gía trị của bất kì entries thừa (out-of-range) nào được tìm thấy, đều là một lỗi.

Đối với color type 26 (truecolor truecolor+alpha) (nó là RGB với RGB+alpha í), PLTE chunk là một tùy chọn. Nếu có, nó cung cấp một tập đề xuất (suggested set) từ 1 đến 256 màu mà hình ảnh sử dụng truecolor có thể được lượng hóa (quantized) nếu trình xem ảnh (viewer) không thể hiển thị trực tiếp màu truecolor.

Type 2 thì dạng màu giống bên trái, type 6 thì là trái phải gộp lại.

Ví dụ: có một bức ảnh truecolor 24-bit tầm 16 triệu màu, nhưng vì lí do kĩ thuật gì đó, thiết bị không hiển thị được 24-bit color, nó sẽ dựa trên PLTE chunk này (nếu có) để lược màu của bức ảnh về 256 màu để hiển thị.

Vì vậy, nếu không có Palette nào được chọn, trình xem ảnh sẽ phải tự chọn màu. Thường thì người ta khuyến cáo là việc chọn Palette này nên được thực hiện một lần bởi encoder.

Lưu ý rằng Palette sử dụng 8 bits (1 byte) cho mỗi sample, không cần quan tâm đến bit depth của bức ảnh. Cụ thể, Palette sẽ có độ sâu8 bits dù cho nó có là bảng lượng tử được đề xuất của một bức ảnh 16-bit màu.

Bên trái là bảng lượng tử được đề xuất của bên phải

Không bắt buộc tất cả các entries phải được sử dụng hết trong ảnh, hay là các entries phải khác nhau.

B. IDAT IMAGE DATA (DỮ LIỆU HÌNH ẢNH IDAT):

IDAT chunk chứa dữ liệu hình ảnh thật sự. Để tạo ra dữ liệu dạng này, ta làm như sau:

Đầu tiên sử dụng các scanlines như được miêu tả trong phần image layout (ví dụ bức ảnh có 16 pixels dạng 4×4, thì 4 pixel trong một hàng theo thứ tự từ trái qua phải sẽ là một scanline, bức ảnh đó có 4 scanlines như vậy, xếp từ trên xuống dưới). Bố cụctổng dung lượng của dữ liệu raw này được xác định bởi các trường IHDR.

Mỗi dòng đen/trắng là một scanline.

Lọc dữ liệu hình ảnh dựa trên phương pháp lọc (filtering method) được chỉ rõ trong chunk IHDR. Lưu ý rằng, khi sử dụng filter method 0, tức phương pháp duy nhất được định nghĩa hiện tại, nó sẽ ngầm thêm vào một byte loại lọc (filter-type) cho mỗi scanline

Nén dữ liệu đã lọc sử dụng phương pháp nén (compression method) cũng được chỉ rõ trong chunk IHDR luôn :v

Chunk IDAT chứa các dòng dữ liệu đầu ra (output datastream) thu được từ thuật toán nén (compression algorithm).

Để đọc dữ liệu hình ảnh ban đầu thì cứ đảo ngược quá trình này lại thôi :v

Có thể có nhiều chunks IDAT trong một bức ảnh. Nếu thế, chúng phải xuất hiện liên tụckhông bị các chunks khác gián đoạn. Lúc này, liên kết nội dung của các dòng IDAT chunks này lại sẽ thu được dòng dữ liệu đã nén. Trình encoders có quyền chia dòng dữ liệu đã nén thành các chunks IDAT theo  bất cứ kiểu nào nó muốn. Việc sử dụng nhiều chunks được cho phép để encoders có thể hoạt động trong một dung lượng bộ nhớ nhất định, thường thì kích thước của chunk sẽ tương thích với kích thước bộ đệm (buffer) của encoders.

Cần nhấn mạnh là các đoạn ngắt chunk (chunk boundaries) không có ý nghĩa ngữ nghĩa nào và có thể được triển khai tại bất kỳ điểm nào trong dòng dữ liệu được nén.

Dù cho file PNG mà mỗi chunk IDAT chỉ gồm một byte duy nhất hay thậm chí là 0 có byte nào (zero-length) thì cũng là hợp lệ, mặc dù nó sẽ làm lãng phí không gian

C. IEND IMAGE TRAILER:

IEND chunk phải xuất hiện cuối cùng. Nó đánh dấu sự kết thúc của dòng dữ liệu PNG. Trường dữ liệu của chunk này sẽ được bỏ trống.

Có thể thấy file PNG bắt đầu bằng PNG signature và kết thúc bằng IEND chunk. Đôi khi trong CTF, IEND chunk sẽ bị dời chỗ, làm cho bức ảnh bị corrupted, khi đó nhiệm vụ của ta là phải đưa IEND chunk về lại vị trí của nó và submit flag thôi.

Và đó là kết thúc của phần Critical Chunks cũng như Day#7. Hẹn gặp lại các bạn trong Ancillary Chunks trong các Day# sau!

Cảm ơn các bạn đã xem! Chim’s Out ❤

LEARN FORENSIC DAY#6: NGÂM CỨU VỀ ĐỊNH DẠNG PNG THEO TÀI LIỆU CỦA PNG DEV GROUP (#4)

Được đà lấn tới :v

Đang ngâm cứu header ngon nên nay đánh qua chương 4 luôn nha :v Cho tớ nợ lại thuật toán CRC hôm khác nhá (tại có hiểu nó viết cái gì đâu =)))

Được cái chương này khá liên quan đến chương trước nên các kiến thức mình nghĩ sẽ liên kết chặt chẽ với nhau :>

Okkkk bắt đầu thôi :v

I. CHUNK SPECIFICATIONS (ĐẶC ĐIỂM CỦA CHUNK) :

Chương này chủ yếu nói về các dạng tiêu chuẩn của một PNG chunk.

  1. CRITICAL CHUNKS (CHUNK TRỌNG YẾU):
Bảng liệt kê các chunk critical và ancillary

Khi triển khai dữ liệu, việc hiểu và kết xuất (render) thành công các critical chunks tiêu chuẩn là bắt buộc. Một bức ảnh PNG hợp lệ cần phải chứa:

Một chunk IHDR

Một hay nhiều chunks IDAT

Một chunk IEND

Ảnh này minh họa đủ các critical chunks nà :v

A. IHDR IMAGE HEADER:

Chunk IHDR bắt buộc phải xuất hiện đầu tiên.

Cấu trúc của chunk IHDR gồm có:

Width (Độ Rộng): 4 bytes

Height (Độ Cao): 4 bytes

Bit depth (Độ sâu màu): 1 byte

Color type (Dạng màu): 1 byte

Compression method (Phương pháp nén): 1 byte

Filter method (Phương pháp lọc): 1 byte

Interlace method (Phương pháp đan xen): 1 byte

Trong đó:

Thông số Width và Height cho ta biết kích thước của bức ảnh là bao nhiêu pixels. WidthHeight được thể hiện bằng các số nguyên 4-byte (nhưng số “0” là giá trị không được chấp nhận). Giá trị tối đa của chúng là 2^31, nhằm thích nghi với những ngôn ngữ gặp khó khăn trog việc xử lý các giá trị 4-byte không dấu (unsigned).

Bit Depth có giá trị là số nguyên 1-byte, cho ta biết số lượng bits trên mỗi mẫu (sample) hay mỗi chỉ số palete (palete index), chứ không phải số bits trên mỗi pixel (Ví dụ xét một khu vực mẫu nào trên bức ảnh thì nó xét số bits trên đó chứ không phải đo theo từng pixel). Nó chỉ đơn giản là thông tin về màu sắc được lưu trữ trong bức ảnh. Giá trị của Bit depth càng lớn thì lưu trữ được càng nhiều màu. Những giá trị Bit depth thường dùng là 1, 2, 4, 8 và 16, tuy nhiên không phải ở dạng màu (color type) nào cũng dùng được tất cả giá trị này.

Color Type mang giá trị là một số nguyên 1-byte, biểu diễn sự phiên dịch dữ liệu hình ảnh. Mã Color Type là tổng của các giá trị: 1 (Palete đã được sử dụng), 2 (Màu đã được sử dụng), và 4 (Alpha channel đã được sử dụng). Những giá trị hợp lệ là 0, 2, 3, 4 và 6

Các hạn chế của Bit Depth cho từng dạng màu (color type) được áp dụng nhằm đơn giản hóa việc triển khai và ngăn chặn các tổ hợp không có khả năng nén tốt. Decoders cần phải hỗ trợ tất cả các tổ hợp Bit depth và Color type hợp lệ. Những tổ hợp được cho phép là:

Độ sâu mẫu (Sample Depth) thường có giá trị bằng với Bit depth, trừ trường hợp color type 3, khi đó sample depth luôn là 8 bits

Phương pháp nén (Compression Method) là một số nguyên 1-byte, cho ta biết phương pháp được dùng để nén dữ liệu hình ảnh trong định dạng PNG. Hiện tại, chỉ có duy nhất một phương pháp nén số 0 (nén deflate/inflate với một thanh trượt (sliding window) với giá trị lớn nhất là 32768 bytes) là phương pháp được chọn. Tất cả các bức ảnh PNG tiêu chuẩn đều phải được nén bằng phương pháp này. Bây giờ thì trường Compression method này chưa có nhiều options nhưng mà vẫn phải có sẵn nó để trong tương lai update PNG lên thêm nhiều options thì có mà sử dụng. Trình Decoders phải luôn kiểm tra byte này và báo lỗi nếu phát hiện nó chứa mã không xác định (unregconized code). Chi tiết về deflate/inflate compression rất dài và sẽ được nói đến trong chương 5.

Phương pháp lọc (Filter Method) mang giá trị một số nguyên 1-byte, cho ta biết phương pháp tiền xử lý (preprocessing method) áp dụng cho dữ liệu hình ảnh trước khi nén (để cho dễ hiểu thì cứ coi như đây là bước sơ chế dữ liệu trước khi xào nấu :v). Hiện tại thì cũng chỉ có một phương pháp lọc duy nhấtphương pháp lọc số 0 (lọc thích ứng (adaptive filtering) bằng 5 loại bộ lọc cơ bản) là được sử dụng. Cũng giống như trường Compression method, trường này chưa có nhiều options nhưng mà vẫn phải có sẵn nó để trong tương lai update PNG lên thêm nhiều options thì có mà sử dụng, và decoders cũng phải kiểm tra trường này và báo lỗi nếu thấy code lạ không nhận diện được. Phần này cũng siêu dài nên cũng sẽ được hẳn một chương riêng là chương 6.

Phương pháp xen kẽ (Interlace Method) là một số nguyên 1-byte chỉ ra thứ tự truyền (transmission order) của dữ liệu hình ảnh. Hiện tại có hai giá trị có sẵn cho trường này: 0 (không xen kẽ)1 (xen kẽ theo quy tắc Adam7). Phần này dính đến chương 2 nên giờ mình sẽ đảo qua chương 2 để làm rõ luôn.

B. INTERLACED DATA ORDER (PHẦN NÀY CỦA CHƯƠNG 2):

Một bức ảnh PNG có thể được lưu trữ dưới dạng xen kẽ (interlaced) để có thể cho phép hiển thị liên tục (progressive display). Mục đích của tính năng này là để cho phép hình ảnh “mờ dần” (fade in) khi chúng được hiển thị một cách nhanh chóng (đọc xong mình cũng không hiểu người ta viết gì, nên mình lên youtube tìm thử thì có cái clip demo interlaced, các bạn xem qua là hiểu ngay)

Việc hiển thị theo cách xen kẽ này sẽ làm tăng kích thước của tệp lên một chút, tuy nhiên nếu ảnh load chậm thì người ta nhìn lúc đầu cũng sẽ dễ hiểu ảnh nó có nội dung gì hơn (cứ xem clip ở trên thì sẽ hiểu mình nói gì).

Cần lưu ý là decoders bắt buộc phải có khả năng đọc các ảnh sử dụng interlaced, không cần quan tâm là lúc hiển thị nó có thật sự interlaced hay là progressive.

Với phương thức xen kẽ số 0 (interlace method 0), các pixels được lưu trữ tuần tự từ trái qua phải và các dòng được quét từ trên xuống dưới (tức là không xen kẽ).

Còn với phương thức xen kẽ số 1 (interlace method 1), hay còn gọi là Adam7 (do tác giả của nó là Adam M. Costello), bao gồm 7 đường truyền khác biệt (seven distinct passes) trên một bức ảnh. Mỗi đường truyền (pass) truyền tải một tập hợp các pixels của bức ảnh. Mỗi pass được xác định bằng cách mô phỏng lại theo mô hình 8×8 của cả bức hình, bắt đầu từ góc trái trên cùng.

Đi từ trái qua phải, trên xuống dưới

Trong mỗi pass như vậy, các pixels được chọn sẽ được truyền từ trái qua phải theo các đường scan (scanline), và các đường scan được chọn này cũng sẽ xuất hiện tuần tự từ trên xuống dưới (coi clip demo trong link youtube ở trên là hiểu nên nhớ coi á).

Dữ liệu trong mỗi pass sẽ được trình bày như một bức ảnh hoàn chỉnh với kích thước phù hợp.

Mỗi lằn mấy bạn thấy được là 1 pass á :v

VÀ ĐÓ LÀ TẤT CẢ KIẾN THỨC MÌNH HỌC ĐƯỢC HÔM NAY

Cảm ơn các bạn đã xem nha!!! CHim’s out ❤

LEARN FORENSIC DAY#5: NGÂM CỨU VỀ ĐỊNH DẠNG PNG THEO TÀI LIỆU CỦA PNG DEV GROUP (#3)

Hôm nay mình lại cùng skip part :v hề hề :v

Mấy nay mình chơi thử CTF Forensics trên các web và làm bài mà “mentor đẹp trai siu cấp” của mình đưa, thì mình nhận ra phần kiến thức đang cần nhất là chương 3 này, nên mình sẽ đảo qua chương này trước rồi sau đó sẽ quay lại :v

Tạm skip chứ hong có bỏ chương 2 nhe, chương nào cũng cần biết hết :’

Okk bắt đầu thôi!!!

3. CẤU TRÚC FILE (FILE STRUCTURE):

Cấu trúc của file PNG bao gồm một PNG signature ở đầu, theo sau đó là một loạt các mảng nhỏ (chunks).

Chunk là một mảng (fragment) thông tin thường được dùng trong các định dạng file đa phương tiện như PNG, IFF, MP3, AVI,…v.v… Trong CNTT nói riêng, chunk là một tập hợp dữ liệu (a set of data) được gửi đến vi xử lí (processor) hoặc bộ phận nào đó của máy tính để xử lý.

Trong chương này, ta chỉ đi đến các định nghĩa của signaturecác đặc tính cơ bản của chunks. Từng loại chunk khác nhau sẽ được bàn tới ở chương 4.

3.1. PNG FILE SIGNATURE:

8 bytes đầu tiên của một file PNG luôn chứa giá trị sau:

89 50 4E 47 0D 0A 1A 0A (Nếu xem ở dạng Hex)

137 80 78 71 13 10 26 10 (Nếu xem ở dạng Dec)

\211 P N G \r \n \032 \n (Dạng ký hiệu ASCII của C)

Chuỗi này gọi là một signature. Signature này cho ta biết phần còn lại của file chứa một bức ảnh PNG, bao gồm một loạt các chunks bắt đầu bằng IHDR chunk và kết thúc bằng IEND chunk. Đặc tính của 2 chunks này sẽ được nêu ở chương 4

Để tra file signature của các đinh dạng file khác nhau, bạn có thể xem tại đây

Signature không chỉ giúp nhận diện file như một file PNG mà còn giúp nhận diện tức thì các vấn đề phổ biến trong truyền tải tập tin.

Hai bytes đầu tiên (80 50) phân biệt PNG với các định dạng khác trên hệ thống, hai bytes này cần phải là duy nhất và không trùng với các định dạng khác. Byte đầu tiên (80) được chọn là một giá trị non-ASCII để giảm thiểu khả năng mà text file bị nhận nhầm là PNG file, nó cũng giúp ích trong trường hợp quá trình truyền file diễn ra không như ý mà mất đi bit 7. Từ bytes thứ 2 đến byte thứ 4 (50 4E 47) nêu tên định dạng file. Tiếp đến là 2 byte CR (\r) – LF (\n) (Carriage Return – Line Feed, các kí tự điều khiển, đánh dấu ngắt dòng tệp văn bản) giúp nhận diện lỗi truyền kém (bad transfer) làm thay đổi trình tự dòng. Tiếp đó là kí tự “ctrl-Z” (1A) để ngưng hiển thị tệp trong MS-DOS. Cuối cùng là kí tự LF (\n) nữa để kiểm tra quá trình dịch CR-LF có bị đảo ngược hay không.

Một số decoder còn kiểm tra thêm 8 bytes kế tiếp có chứa IHDR chunk với độ dài chính xác hay không. Mục đích để hạn chế sự truyền kém dẫn đến việc đánh rớt (drop) hay thay thế null (zero) bytes.

Note: Dễ dàng nhận thấy không hề có đánh số phiên bản trong signature hay bất kì đâu trong file. Đó là việc làm có chủ đích, bởi cơ chế hoạt động của chunk cug cấp cho ta một cách linh hoạt hơn trong việc xử lí phần mở rộng (extensions) của định dạng, phần này sẽ được giải thích trong Quy ước đặt tên chunk (Chunk Naming Conventions).

3.2. CHUNK LAYOUT:

Cách bố trí chunk cho phép các trình decoders bỏ qua các chunks không nhận diện được hay không có thông tin quan trọng, đơn giản bằng cách bỏ qua số lượng bytes nhất định dựa trên trường Length (sẽ được nhắc bên dưới).

Mỗi chunk cấu tạo từ 4 phần:

Length (độ dài chunk): là một số nguyên 4-byte không dấu (unsigned), cho biết độ dài phần dữ liệu của chunk là bao nhiêu byte. Length chỉ đếm độ dài của phần dữ liệu chứ không tính chính nó, các đoạn code dưới dạng chunk hay CRC. “0” cũng được xem là độ dài hợp lệ. Mặc dù trình mã hóa (encoders) và giải mã (decoders) xử lí length như một số không dấu (unsigned), nhưng giá trị của nó không được vượt quá 2^31 bytes.

Chunk type (loại chunk): là một đoạn code dạng chunk 4-byte. Để thuận tiện cho việc mô tả và trong nghiên cứu file PNG, những dòng code phải thỏa mãn: sử dụng kí tự ASCII hoa hoặc thường (A-Z, a-z, 65-90 hay 97-122 trong hệ Dec). Tuy nhiên, các trình encoder và decoders phải xử lí những codes này như xử lí các giá trị nhị phân cố định (fixed binary values) chứ không phải như chuỗi kí tự (character strings). Quy ước đặt tên cho chunk types sẽ được nói đến trong phần sau.

Chunk data (dữ liệu): các bytes dữ liệu tương ứng với từng loại chunk, nếu có. Trường này cũng có thể có độ dài bằng 0.

CRC – Cyclic Redundancy Check (kiểm tra dự phòng theo chu kì): giá trị 4-byte CRC được tính dựa trên những bytes trước trong chunk, bao gồm chunk type code và chunk data, nhưng không tính trường length. Gía trị CRC luôn được hiển thị, bất chấp việc chunk có chứa dữ liệu hay không.

Mở rộng:

Độ dài của chunk data có thể là bất kì giá trị nào nhỏ hơn 2^31, do đó, trình triển khai (implementors) không thể giả định chunks được đặt trên bất kì đơn vị nào lớn hơn bytes. VIệc giới hạn độ dài này giúp tránh các vấn đề trong việc triển khai, khi không thể xử lý một cách thuận tiện một giá trị 4-byte không dấu. Trong thực tế, các chunks thường ngắn hơn nhiều nên không phải lo lắng.

Chunks có thể xuất hiện trong bất kỳ thứ tự nào, tùy thuộc vào sự giới hạn (restrictions) của mỗi chunk type.

Ví dụ: IHDR phải nằm ở đầu còn IEND nằm ở cuối file, IEND hoạt động như một dấu hiệu eof (kết thúc file)

Nhiều chunks cùng loại có thể xuất hiện cùng nhau, nhưng chỉ những loại có quyền (permission) như thế mới có thể xuất hiện như vậy.

Mỗi chunk đều được cấp một gái trị CRC nhằm phát hiện hiện tượng truyền kém càng nhanh càng tốt. Hay cụ thể hơn, dữ liệu quan trọng như kích thước ảnh (image dimensions) có thể được xác thực trước khi sử dụng.

Do chunk length nằm ngoài giá trị CRC nên có thể tính giá trị CRC khi dữ liệu đang được hình thành, mục đích là để hạn chế dữ liệu bị thông qua 2 lần khi mà chunk length không có. Việc tách rời hai thông số này giúp việc kiểm tra dữ liệu chính xác hơn, bởi nếu length bị sai, việc kiểm tra CRC cũng sẽ thất bại. Nguyên nhân là do nếu length sai, CRC sẽ được tính trên những vộ bytes sai, rồi sau đó đem giá trị CRC sai đó so với giá trị sai từ file, chắc chắn không khớp nhau.

3.3. CHUNK NAMING CONVENTIONS:

Những dòng codes dạng chunk được gán những quy luật đặt tên (naming conventions), để trình decoder có thể xác định vài thuộc tính của chunk đó, ngay cả khi nó không thể nhận diện mã phân loại (type code). Những quy định này nhằm hướng đến sự an toàn và linh hoạt của định dạng PNG, bằng cách cho phép các decoders quyết định nên làm gì khi gặp phải những chunk không biết rõ. Đôi khi, trình decoder có thể nhận diện được các loại chunk, thì khi đó các Quy định đặt tên (naming rules) thường không cần thiết.

4 bits của mã phân loại (type code), cụ thể là bit 5 (mang giá trị 32) của mỗi byte, được dùng để truyền tải các các đặc tính của chunk. Mục đính của việc lựa chọn bit 5 là để cho con người có thể đọc được các thuộc tính được chỉ định, dựa vào việc mỗi kí tự của mã phân loại (type code) viết hoa (bit 5 = 0) hay viết thường (bit 5 = 1).

Tuy nhiên, decoders vẫn nên kiểm tra đặc tính của một chuỗi chưa biết bằng cách kiểm thử số học các bits cụ thể. Bởi việc kiểm tra dựa kí tự viết hoa hay viết thường không hiệu quả, thậm chí là sai lầm nếu các “trường hợp cụ thể theo từng ngôn ngữ” (Locale-specific Case Definition) được sử dụng (kiểu như mỗi ngôn ngữ lập trình thì cách đếm chữ hoa thường dựa trên 0/1 nó khác nhau nên ở ngôn ngữ này đúng nhưng qua ngôn ngữ kia sai).

Cần nhớ rằng các bits đặc tính (property bits) là một phần vốn có của tên chunk, vì thế nên nó được cố định dù là trong bất kì loại chunk nào.

Lấy ví dụ, BLOBbLOb sẽ là 2 chunk type codes khác nhau chứ không phải 2 chunk giống nhau chỉ khác đặc tính (sorry nếu mình giải thích chỗ này làm các bạn rối). Decoders chắc chắn sẽ nhận diện được mã phân loại (type code) bằng một phép so sánh 4-byte đơn giản. Không được quy chiếu chữ hoa thường giống nhau hay chuyển đổi uppercase thành lowercase và ngược lại, bởi khi đó kết quả của phép so sánh sẽ bị sai lầm.

Ý nghĩa của property bits như sau:

A. ANCILLARY BIT (BIT PHỤ TRỢ): BIT 5 CỦA BYTE ĐẦU TIÊN

Giá trị:

0 (uppercase) = critical (quan trọng)

1 (lowercase) = ancillary (phụ trợ)

Những chunks không đóng vai trò bắt buộc trong việc thể hiện đầy đủ nội dung của file được gọi là những chunks phụ trợ. Khi decoder gặp một chunk mà nó không biết, nếu ancillary bit của chunk đó bằng 1, decoder có thể bỏ qua chunk đó một cách an toàn và hiển thị ảnh đó.

Ví dụ: chunk thời gian “tIME” là một ancillary chunk.

Những chunks đóng vai trò bắt buộc trong việc thể hiện đầy đủ nội dung của file được gọi là những chunks quan trọng (critical). Khi decoder gặp một chunk mà nó không biết, nếu ancillary bit của chunk đó bằng 0, decoder không thể bỏ qua chunk đó một cách an toàn và hiển thị ảnh đó, nó sẽ báo cho user rằng trong bức ảnh có chứa thông tin mà n1o không thể dịch được.

Ví dụ: chunk “IHDR” là một critical chunk

B. PRIVATE BIT (BIT RIÊNG TƯ): BIT 5 CỦA BYTE THỨ HAI

Giá trị:

0 (uppercase) = public (công khai)

1 (lowercase) = private (riêng tư)

Một chunk công khaibộ phận đặc trung của PNG hoặc được đăng ký trong danh sách các loại chunks công khai có công dụng đặc biệt. Các ứng dụng có thể định nghĩa các private (unregistered) chunks để dùng cho các mục đích riêng.

Để nhìn ra loại chunk này thì dễ thôi. Tên của private chunks phải có chữ thứ 2 viết thường (lowercase), trong khi tên của public chunks phải có chữ thứ 2 viết hoa (uppercase).

Lưu ý rằng, decoders không cần kiểm tra các private-chunk property bits bởi nó không có liên quan đến chức năng gì lớn, nó chỉ đơn giản là thủ tục giúp cho việc quản lý dễ dàng hơn, đảm bảo chunk name của public và private không xung đột lẫn nhau.

C. RESERVED BIT (BIT DỰ PHÒNG): BIT 5 CỦA BYTE THỨ 3

Phải là giá trị 0 (uppercase).

Hiện tại, việc upper/lower case của kí tự thứ 3 được dự phòng để nếu tương lai có update gì cần đến thì có sẵn bit này để dùng.

Bây giờ thì kí tự thứ 3 hoa hay thường cũng được nhưng mà nên ghi hoa để sau này lỡ có update lên PNG bản mới thì nó vẫn đúng, đỡ phải sửa.

D. SAFE-TO-COPY BIT (BIT BÁO HIỆU AN TOÀN ĐỂ SAO CHÉP): BIT 5 CỦA BYTE THỨ 4

Giá trị:

0 (uppercase) = unsafe (không an toàn)

1 (lowercase) = safe (an toàn)

Nếu sử dụng một decoder bình thường thì không cần quan tâm đến bit này. Bit này chỉ cần trong các trình chỉnh sửa PNG (PNG editors). Bit này cho biết phải xử lý như nào đối với các chunks không nhận diện được trong file đang được chỉnh sửa

Nếu mà STCB bằng 1, chunk có thể được sao chép tới file PNG đó mà không cần quan tâm phần mềm có nhận diện được loại chunk đó hay không hay bất kể mức độ sửa đổi tệp ra sao.

Ngược lại, nếu mà STCB bằng 0, nó chỉ ra là chunk phụ thuộc vào dữ liệu của bức ảnh. Nếu chương trình đã thực hiện bất kì sửa đổi nào lên critical chunks, bao gồm thêm vào (addition), chỉnh sửa (modification), xóa bỏ (deletion) hay sắp xếp lại trật tự của các critical chunks, thì các chunk không xác định được kí hiệu unsafe không được phép sao chép tới file đó (nếu mà chunk xác định được thì cứ sao chép ok :v không phải xoắn).

Một trình chỉnh sửa PNG sẽ cho phép sao chép tất cả chunks không nhận diện được (unregconized chunks) nếu editor này chỉ mới chỉnh sửa đến các chunk bổ sung (ancillary chunks). Từ đó, ta rút ra lưu ý là đừng bao giờ để các chunks phụ trợ phụ thuộc lẫn nhau, nếu lỡ có copy mấy cái chunk không nhận diện vô mà lỗi file thì mệt lắm.

Nếu cái PNG Editor mà không nhận diện được một critical chunk thì nó phải báo lỗi và từ chối xử lý file PNG đó. Cơ chế an toàn này được sử dụng khi có sự xuất hiện của các chunk phụ trợ. Đối với 1 critical chunk thì safe-to-copy bit sẽ luôn bằng 0.

Ví dụ: Giả sử ta có chunk type tên là bLOb có các bit đặc tính như sau:

Vì thế, đây là chunk phụ trợ (ancillary), công khai (public) và an toàn để copy (safe-to-copy).

Còn phần thuật toán CRC nữa nhưng hiện tại mình vẫn chưa hiểu người ta viết cái gì : D nên hẹn lại để ngâm cứu cho kỹ.

Well :v Và đó là tất cả những gì mình học được hôm nay!

Cảm ơn các bạn đã xem! CHim’s out ❤

DIGITAL FORENSIC WRITEUPS #1: SPONGEBOB SPONGEBOB

Okayyy và đây là series mới trên blog của mình. Mong các bạn thông cảm nếu có gì sai sót.

Và bài đầu tiên trong series, sẽ là writeup về một nhân vật không chỉ quen thuộc với các bạn xem hoạt hình, mà còn với cả các bạn chơi CTF Forensics.

Hãy cùng đến với SPONGEBOB SPONGEBOB!!!

Đề bài cho chúng ta một file image.zip, down về và giải nén nào. Nếu bạn nào muốn thử thì đây là link nhé

Sau khi giải nén ta được file có tên lsb_image.png với hình ảnh chàng bọt biển quen thuộc :v

Khởi động máy ảo Kali lên.

Thử scan bằng lệnh fileexiftool xem có manh mối gì không

Kết quả thu được không có gì đặc biệt.

Bây giờ manh mối duy nhất là ở tên file lsb_image.

Cho các bạn mới đến với Forensics, LSB là viết tắt của Least Significant Bit (Bit có trọng số nhỏ nhất). Nói nôm na là tách flag thành các bit nhỏ rồi ghi đè lên những bit mà nếu bị thay đổi giá trị cũng không ảnh hưởng nhiều đến tổng thể bức ảnh. Nếu muốn tìm hiểu chi tiết thêm về phần này các bạn có thể tham khảo bài giới thiệu về Forensics và Stego của mình.

Thử dùng LSB Steganography tool xem sao, mình sẽ lược bit của bức ảnh này về 1.

Ta thu được một bức ảnh kì quái

Bạn thấy phần màu đỏ đó giống như một hình ảnh gì đó chứ. Rõ ràng có thông điệp đang được giấu đằng sau.

Tới đây thì mình khá bí vì dù có sử dụng LSB Steganography tool để tăng giảm số bit sử dụng cho bức ảnh này thì cũng chỉ thu được đến đây.

Mình bèn dùng hạ sách là tool Decode Stego Online :v

Còn bạn nào muốn hardcore hơn thì có thể dùng Python tự viết script để tính flag luôn. Còn mình gà nên sẽ chơi tool làm sẵn :’)

Bỏ ảnh vào và nhấn decode thôi

Kết quả thu được thật bất ngờ. Các bạn thấy đoạn kí tự mình highlight đó chứ. Nghi ngờ đây là dạng mã Base64 nên cùng thử decode nào!

Mình sẽ sử dụng Base64 Decode and Encode – Online.

Bingo :b Và flag của chúng ta hiện ra.

Thực ra, nãy giờ mình múa hơi nhiều =)))) có một cách giải khác đơn giản hơn nhiều chính là sử dụng công cụ stegsolve

Nhưng mình sẽ để các bạn tự nghiên cứu về MSB-LSB để tự giải bằng phương pháp này :v mình chỉ spoil Flag thôi :b

Đây là một bài đơn giản để các bạn có cái nhìn rõ hơn về những việc cần làm trong một bài Forensics Basic. Hẹn gặp lại các bạn trong những bài căng thẳng hơn :v

Chim’s Out ❤

LEARN FORENSIC DAY#4: NGÂM CỨU VỀ ĐỊNH DẠNG PNG THEO TÀI LIỆU CỦA PNG DEV GROUP VÀ ÁP DỤNG VÀO CTF(#2)

OK tiếp tục phần dang dở của DAY#3 nào!!!

C. ĐIỀU KHIỂN DỮ LIỆU NHỊ PHÂN BẰNG PYTHON:

C.1. STRUCT MODULE (P.2):

Ta thấy được ở cấu trúc của 3 hàm pack(), unpack() calcsize() đều có sự xuất hiện của một argument gọi là fmt. “fmt” ở đây có nhiệm vụ định hướng cách mà những dữ liệu kia được đóng gói thành một byte stream, nơi chứa một loạt các chuỗi định dạng (format strings).

NOTE: Nếu các bạn đã xem qua bài viết của CTF wiki thì bạn sẽ thấy trong phần giải thích của họ có các kí tự đặc biệt. Sau khi hỏi google thì mình biết được đây chính là HTML character references. Mình sẽ chèn bảng ASCII ở đây cho mọi người tham khảo xem như là kiến thức mới cho bạn nào chưa biết (như mình chẳng hạn :b).

Ta có đoạn code:

>>> import struct
>>> struct.pack('>I',16) 

'\x00\x00\x00\x10'

Quan sát thấy, argument đầu tiên của hàm pack() là một chỉ thị xử lý (processing instruction).

Ta có ‘>I‘ nghĩa là: “>” chỉ ra byte order ở đây là Big-Endian (hay Network Byte Order) và I tượng trung cho một số nguyên 4-byte không dấu (unsigned).

Số lượng các thông số theo sau phải tương thích với chỉ thị xử lý.

Ví dụ:

Khi đọc 30 bytes đầu của một file BMP bằng hàm unpack() bằng code sau:

>>> import struct
>>> bmp = '\x42\x4d\x38\x8c\x0a\x00\x00\x00\x00\x00\x36\x00\x00\x00\x28\x00\x00\x00\x80\x02\x00\x00\x68\x01\x00\x00\x01\x00\x18\x00'
>>> struct.unpack('<ccIIIIIIHH',bmp) 

('B', 'M', 691256, 0, 54, 40, 640, 360, 1, 24)

Cấu trúc của file header thu được như sau:

(‘B’, ‘M’, 691256, 0, 54, 40, 640, 360, 1,24)

Giải mã theo tuần tự từ trái sang phải:

2 bytes: BM tức là Windows bitmap, nếu là BA thì là OS/2 bitmap

1 số 4-byte: chỉ ra kích thước bitmap

1 số 4-byte: bit dự trữ, luôn bằng 0

1 số 4-byte: phần bù (offset) của ảnh thực

1 số 4-byte: số lượng bytes trong Header

1 số 4-byte: độ rộng ảnh

1 số 4-byte: độ cao ảnh

1 số 2-byte: luôn là 1

1 số 2-byte: số màu

C.2. BYTEARRAY BYTE ARRAY:

Để đọc (read) file thành một mảng nhị phân, ta sử dụng:

Sau khi read ta có thể gọi các thành phần của mảng này như một mảng thông thường:

Mảng byte (Byte Array) là phiên bản biến đổi của byte.

D. MỘT SỐ TOOLS VÀ COMMANDS PHỔ BIẾN CHO DẠNG CTF NÀY:

D.1. HEX EDITOR:

Hex Editor (Binary file Editor hay Byte Editor) là một chương trình máy tính được dùng để vận dụng, mổ xẻ các “dữ liệu nhị phân cơ bản được dùng để cấu thành file”. Hex ở đây chính là Hexadecimal hay hệ cơ số 16, một định dạng số (numerical format) tiêu chuẩn dùng trong biểu diễn dữ liệu nhị phân.

Thông thường, một file máy tính làm việc trên nhiều khu vực của đĩa cứng, những thành phần đó sẽ nhập lại với nhau tạo thành một file. Hex Editor được thiết kế để phân tích và chỉnh sửa các khu vực dữ liệu trên. Hex Editor được dùng để xem, chỉnh sửa nôi dung thô và chính xác của một file.

Hex Editor cũng có thể được dùng để sửa những dữ liệu bị hư hỏng do hệ thống hoặc ứng dụng gây ra.

Đây là danh sách một vài Editors miễn phí

D.2. LỆNH FILE:

Lệnh file dùng để xác định định dạng file của một file dựa trên file header của file đó (hay còn gọi là magic byte). Đây là command có sẵn trong linux.

D.3. LỆNH STRINGS:

Lệnh strings dùng để trả về chuỗi các kí tự có thể in ra được (printable characters) trong files. Mục đích chính trong việc sử dụng strings là để nhắm đến nội dung và lấy ra các dữ liệu dạng text từ files nhị phân cũng như là files non-text. Thông thường, những dữ liệu này là các hint để chúng ta có thể điều tra thêm. Đây cũng là một lệnh có sẵn trong linux.

Ta có thể kết hợp strings cùng với lệnh grep để phát hiện những thông tin cụ thể:

Ví dụ: strings flag| grep -i CTFFLAG

Đọc thêm: Cách sử dụng lệnh grep trong Linux – VinaSupport

D.4. BINWALK:

Binwalk là một công cụ cho phép chúng ta phân tích một hoặc nhiều tập tin. Đặc biệt, công cụ này được thiết kế cho việc xác định files và code được nhúng bên trong firmware. Đây là công cụ cực kì hữu ích trong việc tìm hiểu và phân tích firmware.

D.5. VẬN DỤNG TRONG CTF:

DẠNG BÀI 1:

Đầu tiên mình sẽ sử dụng bài “Glory of the garden” từ PicoCTF. Đây cũng là một bài đơn giản thôi. Cùng xem nhé!

Đầu tiên đề bài cho chúng ta một file tên garden, download về thử xem.

Tiếp đó thử scan file bằng vài lệnh cơ bản như file hay exiftool

Vẫn chưa phát hiện điều gì đặc biệt.

Thử dump phần hex của file ra xem sao. Ở đây mình sử dụng lệnh xxd

Bingo! Flag hiện ra trong sự ngỡ ngàng :v

Nhìn chung bài này vẫn chưa phải đụng đến phần edit header.

DẠNG BÀI 2:

Giờ là một bài khác cũng ở mức cơ bản, chưa đi vào chỉnh sửa signature nhưng sẽ đánh vào kĩ năng phân biệt các định dạng file. Đó là bài Extensions của PicoCTF.

Đề bài cho chúng ta một file tên là Flag.txt, có lẽ đây là file text, download về thử xem.

Thử mở file

Xuất hiện lỗi => có mùi lừa ở đây :v => Ta dùng lệnh xxd dump file hex của nó ra đọc chơi

Ồ quaooo :))) Để ý phần mình highlight, có các kí tự như PNG, sRGB, GAMA => confirm luôn đây là file PNG. Đổi extension lại thành PNG thử xem.

Gotcha :v

Bài này đơn giản thôi vì chỉ là những kiến thức cơ bản về nhận diện định dạng file.

DẠNG BÀI 3:

Đây là là dạng bài sai file signature, đây có thể là dạng bài riêng lẻ chỉ cần sửa header là ra flag, nhưng đôi khi nó chỉ là bước đầu để khai thác tiếp được thông tin.

Mình không tìm được bài cụ thể của dạng riêng lẻ nên mình sẽ nêu case study cho các bạn dễ hình dung:

Đầu tiên, có một các bạn được cho một file dạng không xác định, ở đây là “mystery

Giả sử sau khi scan bằng lệnh fileexiftool các bạn không nhận thấy điều gì đặc biệt.

Bạn tiến hành dump phần hex của file ra để xem xét. Ở đây mình sử dụng trang web Hexed.it luôn cho tiện

Quan sát kĩ phần signature, gía trị 89 thường là của signature PNG, nhưng kì lạ là phần header được dịch ra bên tay phải màn hình lại là eeN4 chứ không phải PNG. Mình nghi ngờ có sai sót về file signature.

Lên tra bảng file signature trên Wiki thì file signature của PNG là:

89 50 4E 47 0D 0A 1A 0A

=> Dùng hexed.it sửa lại cho đúng => ta nhận được file PNG có thể mở được và trong đó chứa flag!!! Bingo :v

Tất nhiên đây chỉ là case study. Trong CTF thực tế, đây là phần đầu bài “c0rrupt” của mảng Forensics trên PicoCTF. Ở bài này, đi được đến đây chỉ mới là nửa chặng đường. Hầu hết các byte định dạng màu của file này đều bị sai lệch dẫn đến không mở được ảnh. Vậy nên nếu muốn tìm flag phải tìm hiểu thêm về các lệnh như pngcheckgiá trị CRC (hai thứ mà hiện tại mình vẫn chưa biết tới nhưng sẽ tìm hiểu sớm thôi : D) và kết hợp nhuần nhuyễn những kiến thức đó. BTW nếu ai tò mò về cách giải bài đó thì mình sẽ để luôn đường link Writeup

Và đó là những gì mình học được trong ngày hôm nay. Ngày mai mình sẽ ngâm cứu Writeups của bài c0rrupt được nêu ở trên nên các bạn nhớ đón xem nhé.

Mình sẽ cố gắng tự solve nó cùng với đó là chỉ ra các kiến thức mới từ đó cho các bạn! Chim’s out!

LEARN FORENSIC DAY#3: NGÂM CỨU VỀ ĐỊNH DẠNG PNG THEO TÀI LIỆU CỦA PNG DEV GROUP VÀ ÁP DỤNG VÀO CTF(#1)

Mình sẽ nói sơ qua về tài liệu mà mình ngâm cứu trong series này. Đây là bản sửa đổi từ “PNG 1.0 specification” và được phát hành bởi PNG Development Group. Link mình sẽ để ở đây: http://png.cybermirror.org/spec/1.2/PNG-Contents.html

Ở bài viết trước của DAY#2 mình đã đề cập tới PNG nên giờ mình sẽ tóm tắt lại như sau để các bạn tiện theo dõi. PNG là một định dạng phần mở rộng sử dụng phương thức nén ảnh lossless. PNG là sự thay thế cho định dạng GIF và thậm chí còn có thể thay thế định dạng TIFF trong một vài tác vụ khác. PNG được thiết kế để tương thích tốt với việc xem online, là một định dạng mạnh mẽ nên PNG cung cấp cả hai phương thức kiểm tra và phát hiện những lỗi truyền tải phổ biến.

Hôm nay chúng ta sẽ đi sâu hơn vào việc mổ xẻ định dạng này và ứng dụng nó vào trong CTF Forensic.

Mở tài liệu ra và skip phần introduction đi. Mình đã đọc qua và thấy nó không khác biệt gì so với phần mình viết về PNG ở DAY#2. Chúng ta sẽ đến thẳng với chương 2 là Data Representation.

I. DATA REPRESENTATION:

  1. INTERGERS VÀ BYTE ORDER:

Sau khi ngủ lên ngủ xuống tầm 2 3 lần khi đọc phần này, thì trong cơn mơ mình chợt recall lại LSB và MSB là gì. Nhắc cho các bạn đã quên thì LSB là viết tắt của Least Significant Bits, nhưng đó là ở bài trước. Nhưng khác với bài viết trước, ở bài này bits sẽ được thay bằng các bytes, do đó ta có LSB sẽ là Least Significant Bytes tức là những bytes có trọng số nhỏ nhất hay còn gọi là những bytes mà nếu thay đổi giá trị của chúng thì không làm ảnh hưởng nhiều đến toàn thể.

Ngược lại, ta có MSB hay Most Significant Bytes tức là những bytes mà nếu thay đổi giá trị, sẽ gây ra ảnh hưởng đáng kể đến cục bộ, ví dụ như làm sai lệch màu trầm trọng hoặc lệch tông màu một cách lộ liễu.

Byte Order theo tên gọi của nó chính là thứ tự của các bytes. Khi một số nguyên mà cần nhiều hơn một bytes để chứa thì các bytes đó cần phải theo trình tự byte trong mạng (Network Byte Order). Quy tắc Network Byte Order như sau: Khi một số quá lớn để có thể chứa vừa trong 1 byte, ta sẽ sử dụng nhiều bytes để mã hóa nó. Khi số đó được truyền qua giao thức định hướng byte (Byte-oriented Protocol) một quy tắc về sắp xếp thứ tự các bytes cần được lựa chọn để cả 2 đầu của Network đều có thể dịch số đó theo một cách giống nhau cho dù có khác biệt về phần cứng hay kiến trúc CPU. Khi các bytes được sắp xếp theo trình tự từ byte quan trọng nhất đối với dữ liệu đến byte ít quan trọng nhất, thứ tự đó được gọi là Network Byte Order hay Big Endian

Ví dụ: Trong hệ số nguyên 2-byte (từ -32,768 đến 32,767) , MSB đứng trước tiếp đó mới tới LSB. Hay trong hệ số nguyên 4-byte (từ -2,147,483,648 đến 2,147,483,647), thứ tự sẽ là B3 B2 B1 B0).

Trong đó, bit cao nhất (có giá trị 128) của 1 byte được đánh số là bit 7, bit thấp nhất (có giá trị 1) được đánh số là bit 0. Giá trị này thường sẽ không có dấu (unsigned) trừ khi có lưu ý khác. Những giá trị được ghi chú là có dấu (signed) sẽ được trình bày dưới dạng Kí hiệu bổ sung của 2 (Two’s Complement Notation)???

Sau một hồi google thì mình biết được là Two’s Complement Notation là một phép toán trong hệ nhị phân. Nó được dùng như một phương pháp biểu diễn các số có dấu (signed number).

Các bạn có thể tham khảo link ở đây để tìm hiểu chi tiết nhất: https://en.wikipedia.org/wiki/Two%27s_complement

Còn mình chỉ tìm hiểu cách tính thôi.

Ví dụ: ta có 1 số 3-bit là 010. Áp dụng công thức tính two’s complement bằng cách đảo ngược số đó và cộng thêm 1, ta có đảo ngược 010 thu được 101, cộng 1 vào => 110. Để thử lại, ta lấy 010 + 110 = 8 = 2^3. Hay nói đơn giản hơn là cho một số rồi chuyển sang hệ nhị phân, two’s complement là biểu diễn nhị phân của số đối với số đó.

Ở đây ta thấy team dev PNG giải thích vì sao lại chọn Network Byte Order để làm Byte Order cho PNG. Nguyên nhân do NBO có ưu điểm là hầu hết các nền tảng nào support TCP/IP đều có thói quen chuyển đổi các dạng khác về NBO hay từ NBO đi tiếp. Nên việc lựa chọn NBO giúp cho tương thích của PNG gần như là hoàn hảo trong thế giới số hiện nay.

2.INTEGERS, BYTE ORDER VÀ CTF:

Phần này được mình tìm hiểu và dịch lại từ một bài viết trên CTF wiki có tên là Prefix cộng với sự cung cấp kiến thức từ google và tài liệu về Python’s Struct Module trên trang web tên Edpresso. Mình chọn tìm hiểu bài viết này vì bài viết có đề cập đến dạng bài liên quan đến Byte Order và khái niệm Big Endian được nêu ở trên.

Link bài viết CTF wiki: https://ctf-wiki.github.io/ctf-wiki/misc/prefix/

Link bài viết Edpresso: https://www.educative.io/edpresso/what-is-the-python-struct-module

A. MỞ ĐẦU:

Trong hầu hết các cuộc thi CTF, Forensic và Steno không thể tách rời nhau, kiến thức cần cho 2 phần này luôn bổ trợ lẫn nhau. Vậy nên trong chương này, cả hai đều sẽ được giới thiệu ở đây.

B. NHỮNG KỸ NĂNG CẦN CÓ:

  • Học code cơ bản: Cần có khả năng đọc hiểu codes trong file và biết quan sát các chi tiết đặc biệt trong code như các hàm mã hóa (Base64, hexadecimal, binary, etc), chuyển đổi được chúng để lấy Flag.
  • Khả năng vận dụng dữ liệu nhị phân sử dụng các ngôn ngữ kịch bản (Scripting languages) như Python.
  • Quen thuộc với các định dạng file của các file phổ biến, đặc biệt là [file header], các giao thức, cấu trúc,…v.v…
  • Sử dụng thành thạo các tools phổ biến.

C. ĐIỀU KHIỂN DỮ LIỆU NHỊ PHÂN BẰNG PYTHON:

C.1. STRUCT MODULE:

Đôi khi bạn sẽ cần sử dụng Python để xử lý dữ liệu nhị phân, hoàn thành những tác vụ như truy cập file hay điều hành socket (socket operation). Những lúc đó, Python’s Struct Module là thứ bạn cần.

Lưu ý: module này chỉ có ở Python3 và cần được import bằng cách gõ lệnh:

Có 3 hàm quan trọng nhất đối với CTF trong Struct Module, đó là: pack(), unpack()calcsize()

Trong đó:

+ pack(fmt, v1, v2, …) có nhiệm vụ đóng gói (encapsulates) dữ liệu thành một string dựa trên format (fmt) được cho. String này thật ra là một luồng byte (byte stream) có cấu trúc giống trong ngôn ngữ C. Hàm này yêu cầu người dùng phải chỉ ra cụ thể format và thứ tự của những giá trị (values) cần được chuyển đổi.

Những dòng code này minh họa cách đóng gói dữ liệu được cho thành dạng nhị phân (binary) sử dụng hàm struct.pack():

Argument đầu tiên của hàm biểu diễn chuỗi format (format string). Format String chỉ rõ bố cục hướng đến khi đóng gói (pack) hay phân tích (unpack) dữ liệu. Các arguments còn lại biểu diễn dữ liệu cần được đóng gói.

Và đây là bảng các kí tự đại diện cho các format phổ biến trong argument đầu tiên

+ unpack(fmt, string) phân tích cú pháp của byte stream string dựa trên format đã cho và trả về “một bộ những giá trị đã được sắp xếp và bất biến” (tuple). Hay nói cách khác, hàm này chuyển đổi thông tin ở dạng chuỗi nhị phân trở lại dạng gốc của nó dựa trên format cụ thể. Dữ liệu trả về luôn là dạng tuple. Cũng có thể xem cách hoạt động của hàm này ngược lại với pack().

Đây code minh họa về cách sử dụng hàm struct.unpack():

+ calcsize(fmt) tính toán kích thước để biểu diễn string của struct với format đã cho??? : D Mình cũng hơi bối rối chỗ này.

Và đây là code minh họa:

Hôm nay chúng ta đến đây thôi, mình cần ngâm cứu thêm về các trường arguments trong 3 hàm này và ý nghĩa của chúng

Hẹn gặp các bạn vào DAY#4!
Tạo trang giống vầy với WordPress.com
Tham gia