1. ExpertPNG

2. Explanation
우선 PNG extension을 가진 파일을 실행시켰을 때, 별다른 이상 없이 이미지 데이터가 출력되기에 HEX editor로 파일을 열어본다.


다음과 같이 PNG format의 header signature "89 50 4E 47 0D 0A 1A 0A"와 footer signature "49 45 4E 44 AE 42 60 82" 두 값 모두 제대로 존재한다. 처음 파일을 실행시켰을 때 나오는 이미지 데이터에 해당하는 Offset 'A7EA5'의 footer signature 까지의 HEX 데이터를 분석해 본 결과 PNG 구조, 각각의 필수 Chunk 유무(IHDR Chunk, IDAT Chunk, IEND Chunk)와 Chunk 형식, 특히 IHDR Chunk의 width과 height, bit depth, color type, filter type, interlace type에 해당하는 16진수 값들과 이에 따른 CRC(Cyclic Redundancy Check) 값 역시 확인해 보았을 때 특별한 이상은 없었으므로 이미지 데이터 자체에는 문제가 없다.
그러나 위의 사진과 같이 IEND Chunk 뒤에 PNG format에 해당하는 또 다른 signature 값이 있으므로 처음 출력된 이미지 데이터를 포함하여 총 4개의 숨겨진 PNG 파일이 있음을 유추해 볼 수 있었고, signature 값을 이용하여 시작 offset과 끝나는 offset을 구해 다음과 같이 데이터 순서대로 데이터 블록을 추출하여 저장한 뒤에 추출한 데이터 블록은 삭제하는 과정을 반복한다.
가. [extract_1.png]로 저장한 후 데이터 블록 삭제

나. [extract_2.png]로 저장한 후 데이터 블록 삭제

다. [extract_3.png]로 저장한 후 데이터 블록 삭제

라. [extract_4.png]로 저장한 후 데이터 블록 삭제


더이상 시그니처 값이 나오지 않도록 과정을 반복하여 수행한 결과 위 사진처럼 4개의 PNG 파일이 추출되며 각 파일의 HEX 데이터를 분석해보았을 때 특별히 이상한 점은 없었다.
따라서 데이터들을 추출한 뒤에 남은 처음 PNG 파일을 다시 HEX editor로 분석해 보았을 때

다음과 같이 빨간 네모 박스에는 PNG format의 footer signature 값이 거꾸로 뒤집혀 있으며, 파란 네모 박스에는 header signature 값이 거꾸로 뒤집혀 있는 것을 알 수있다. 이를 통하여 위의 정상적인 PNG format의 HEX 데이터의 값들이 뒤집힌 형태로 저장되어 있음을 유추해 볼 수 있다.
Python에서 sequence를 뒤집은 순서로 반환하는 'reversed' 함수와 byte sequence를 나타내는 자료형 'bytes'를 활용하여 데이터를 거꾸로 뒤집은 후에 그 데이터로 새로운 바이트 객체를 생성하는 다음과 같은 코드를 짜서 실행시켜보면
| def reverse_hex_data(input_file, output_file): with open(input_file, 'rb') as f: data = f.read() reversed_data = bytes(reversed(data)) with open(output_file, 'wb') as f: f.write(reversed_data) if __name__ == "__main__": input_file = 'ExpertPNG_copy.png' output_file = 'ExpertPNG_reversed.png' reverse_hex_data(input_file, output_file) print("파일의 Hex 데이터를 뒤집어서 파일에 저장했습니다.") |

위와 같이 정상적으로 코드가 동작하며

'ExpertPNG_reversed.png' 파일이 생성된다.
이 파일을 HEX editor로 분석해 보았을 때


위와 같이 수 많은 signature 값들이 존재하지만 이 중에서

위의 사진과 같이 IEND Chunk가 끝나는 '347959' offset 이후부터 PNG format의 header signature 값이 아닌 다른 값들이 오는 수상한 파일을 추출하여 복구해본다.

따라서 우선 '347959' offset에 해당하는 IEND Chunk 이후부터 다음 IEND Chunk가 오는 '3A5A6C' offset에 해당하는 IEND Chunk까지의 데이터 블록을 추출하여 'ExpertPNG_reversed_extract.png'로 저장한다.

이미지 데이터는 확인할 수 없으나 HEX editor로 분석해 본 결과 PNG format의 IDAT Chunk와 IEND Chunk는 존재하지만 데이터의 앞 부분에 header signature 값과 Decoded text에서 'IHDR'이 없는 것으로 보아 이 파일은 부분적인 IHDR Chunk의 데이터와 그 앞의 HEX 데이터들이 훼손된 PNG 파일이다. 따라서 PNG format의 header signature 값을 입력하고 IHDR Chunk를 복구한다.
우선 header signature 값을 입력한다.

IHDR Chunk안에서 Color type 값이 '06'일 때 RGB + alpha 값을 가지며 Bit depth 값에 '08'이 올 수 있다. 또한 뒤에 'sRGB' 가 존재하는 것으로 보아 IHDR Chunk는 Bit depth, Color type, Compression method, Filter method, Interlace method, CRC(Cyclic Redundancy Check) 값은 존재하지만 그 앞의 Length, Chunk Type, Width, Height 값이 손실되었음을 유추해 볼 수 있었고, 이를 근거로 HEX 데이터를 복구해본다.

위와 같이 IHDR Chunk의 Length에 해당하는 값과 Chunk Type 값을 입력해주고 width값과 height 값은 당장 구할 수 없기에 '00 00 00 00'으로 비워두고 저장한다.
그리고 Python의 'zlib' 모듈에서 'crc32' 함수를 import하여 CRC32 값을 계산하여 width 값과 height 값을 구하는 코드를 아래와 같이 실행시켜서 데이터를 수정한다.
| from zlib import crc32 file_name = input('파일 이름 입력: ') data = open(file_name, 'rb').read() index = 12 IHDR = bytearray(data[index:index + 17]) width_index = 7 height_index = 11 target_crc = input('CRC 값 입력: ') target_crc = int(target_crc, 16) # target_crc = 0x3CFA9C16 for width in range(1, 2000): width_bytes = bytearray(width.to_bytes(2, 'big')) for height in range(1, 2000): height_bytes = bytearray(height.to_bytes(2, 'big')) for i in range(len(height_bytes)): IHDR[height_index - i] = height_bytes[-i - 1] for i in range(len(width_bytes)): IHDR[width_index - i] = width_bytes[-i - 1] current_crc = crc32(IHDR) & 0xFFFFFFFF if current_crc == target_crc: print("width: {}, height: {}" .format(hex(width)[2:].upper(), hex(height)[2:].upper())) break else: continue break |


그럼에도

이미지 데이터가 제대로 출력되지 않기에 IDAT Chunk까지 손상되었음을 유추해 볼 수 있다. 따라서 다시 HEX editor로 분석한다.

첫번째 IDAT Chunk로 추청되는 IDAT Chunk에서 Chunk type 값의 'IDAT'가 아닌 '1DAT'가 위치하여 있기에 이를 수정하고 저장하면

이미지 데이터를 전부 복구하지는 않았지만 flag를 찾을 수 있다.
3. Reference
PNG file format:
swift - Not able to read IHDR chunk of a PNG file - Stack Overflow
Python CRC32 값을 이용한 IHDR Chunk width, height 값 계산 코드 수정 전 원본:
GitHub - W3rni0/RACTF_2020: Writeup for the challenges in Really Awesome CTF 2020
위 문제는 23년도에 DEBUG에서 출제한 CTF 문제입니다.
'Digital_forensic > CTF' 카테고리의 다른 글
| [TetCTF 2024] TET & 4N6 Write-up (1) | 2024.05.29 |
|---|---|
| [Dreamhack] Snowing! Write-up (0) | 2024.01.28 |
| [DEBUG] upgradepng1.png Write-up (1) | 2024.01.27 |
| [Sooboon] Sob_PNG_Lv1.5 Write-Up (0) | 2024.01.26 |
| [Sooboon] l'm s0o0o0o0o00o00o0o higH!!! Write-up (1) | 2024.01.26 |