- Check
풀이 과제 하면서 라업 몇 개 더 참고했었는데 그중에서 좀 흥미로웠던 문제가 하나 있다.
CRC를 조작할 예정이다.

스터디 시간에 썼던 만두를 재탕할 예정이다.
CRC 4 bytes가 만들어지는 원리는 다음과 같다.
CRC32 코드를 사용하여 chunk type+data로 검사한다. (chunk length는 제외)
내가 만들 문제는 chunk length+chunk type+data로 CRC 코드를 만들어줄거다.

해당 청크들 CRC를 모두 바꿔줄 것이다.
- 파이썬 크립토 코드가 맞는지 확인
```python
from zlib import crc32
data = open(“mandu.png”, ‘rb’).read()
index = 12 # IHDR chunk가 시작되는 인덱스
chunk = bytearray(data[index:index+17]) # IHDR 시작부터 CRC 전까지의 범위
print(hex(crc32(chunk)))
위 파이썬 코드의 결과이다.

hxd에 있는 CRC와 동일하다. 맞게 잘 짠 거 같다.
이제 각 인덱스를 알아야 한다.
| chunk | length 시작하는 index | CRC index |
|-------|-----------------------|-----------|
| IHDR | 8 | 29 |
| IDAT | 33 | 8233 |
| IDAT | 8237 | 16437 |
| IDAT | 16441 | 24641 |
| IEND | 24645 | 27627 |
오프셋 말고 인덱스를 이용해서 코드를 다시 짰다.
```python
from zlib import crc32
data = open("mandu.png", 'rb').read()
index = [8, 33, 8237, 16441, 24645] # length부터 시작하는 index
endindex = [29, 8233, 16437, 24641, 27627]
for i in range(5):
chunk = bytearray(data[index[i]:endindex[i]]) # size
print(hex(crc32(chunk)))
출력된 값은 위와 같다. 이제 HxD를 이용하여 값을 수정하고 저장하면 문제 파일 완성이다.

아니 근데 너무 잘 열린다. CRC를 바꿨는데 왜 파일이 잘 열리는걸까
1-1.
RACTF 2020에 나온 CRC 문제를 비슷하게 제작해보기로 했다…
문제 알고리즘은 IHDR 청크의 weight와 height를 맞춰야 하는 문제이다. CRC를 통해 weight, height를 추측하고 png를 바꿔준다.
문제 파일은 간단하게 IHDR 청크의 weight, height를 00 00 00 00으로 바꾸고 저장하면 된다.

이 문제를 풀어보자면..

weight와 height가 0이다. 이 값을 알아내기 위해 CRC를 이용해야 한다. 해당 이미지의 CRC는 58 A0 C4 3C 이다. 파이썬 코드로 어떤 값을 crc32로 돌렸을 때 58 A0 C4 3C가 되는 값을 찾아야 한다.
from zlib import crc32
data = open("size.png", 'rb').read()
index = 12 # IHDR chunk가 시작되는 인덱스
IHDR = bytearray(data[index:index+17]) # IHDR 시작부터 CRC 전까지의 범위
width_index = 7 # width 부분의 세 번째 바이트 인덱스
height_index = 11 # height 부분의 세 번째 바이트 인덱스
for x in range(1, 2000):
height = bytearray(x.to_bytes(2, 'big')) # to_bytes(length, byteorder, *, signed=False)
for y in range(1, 2000):
width = bytearray(y.to_bytes(2, 'big'))
for i in range(len(height)):
IHDR[height_index - i] = height[-i - 1]
for i in range(len(width)):
IHDR[width_index - i] = width[-i - 1]
if hex(crc32(IHDR)) == '0x58a0c43c': # crc 값
print("width: 0x{}, height: 0x{}".format(width.hex(), height.hex()))
for i in range(len(width)):
IHDR[width_index - i] = bytearray(b'\x00')[0]
파이썬 코드를 돌려주면 위 값이 나오는데 이걸

이 부분에 입력해주면

원래의 이미지가 나온다.
- 자바는 꼭 대문자를..

대충 이미지 하나 만들어줬다

해당 이미지를 TweakPNG로 열면 chunk 구조를 볼 수 있다.
gAMA랑 IDAT를 소문자로 바꿔보자.

이러면 문제 파일이 만들어진다.

저장하고 이미지 파일을 열면 만들었던 이미지가 정상적으로 나온다.
지원하지 않는 파일이라고 뜬다.
1주차에 배운 exif 문제, steg 문제 했으니 필시 시그니처 분석일 것이다.

PNG 시그니처가 섞여있다. 해당 파일을 PNG로 바꾸거나 JPG로 바꿔야 하는데 옆에 IHDR이 있는 걸 보아 일단 PNG 파일 구조로 맞춰줬다.




일반 미리보기는 아무것도 안 떠서 steg로 이어지나 싶었는데 뭔가 추가로 포맷을 맞춰줘야 하는 거 같다.

IHDR 청크부터 보겠다.

CRC 뒤 더미가 있길래 지워줬다.

IDAT를 봐야 한다. chunk type 앞 4 bytes는 length인데 이값이 맞는지 확인해줘야 한다.

청크 데이터를 긁어오니까 오프셋이 a5 b5이길래 수정해줬다.

a5 b0이라고 썼지만 후에 b5로 수정했다(그래도 안됐다)

IEND 청크는 그대로였다.
그래도 오류가 뜬다. 원본 파일 IDAT를 다시 검색해보니

두 개였다.

그래서 length 한 번 더 바꿨는데도 오류가 났다. 고민하다가 다른 툴을 써보았다.
010 에디터가 청크 분석을 해주는 거 같아서 깔아보았다.

청크 분석을 해주었는데 fcTL이 뭔지 몰라서 검색했다가 본 문제 라이트업을 발견했다..
tweakpng 툴로 바꿨다. 010 에디터는 파일이 온전할 때 제대로 분석해주는 거 같다.


위 순서를 지켜 바꿔줘야 한다. 그리고 IDAT는 크기가 큰 것부터 배열해야 한다.

티스토리에 사진으로 업로드 하니까 플래그가 나온다.
파일 이름부터 steg니까 지금 갖고 있는 stegsolve부터 돌려보았다.

해당 툴은 위와 같이 생겼고 file > open으로 사진을 불러와준 뒤, 하단에 있는 화살표를 돌려 여러 스테가노그래피를 수행하면 된다.

화살표로 돌리다 보니 사람 몸에 어떤 글자가 나왔다.

gray bits가 더 잘 보이는 거 같다.

1. PNG 파일 분석

PNG 파일 최근에 다운 받은 게 space ctf에서 썼던 empty.png 파일이 있었다. empty라서 하얀 사진이 특징이다.
먼저 이 파일이 PNG임을 알 수 있는 시그니처부터 살펴보려고 한다.

헤더 시그니처는 89 50 4E 47 0D 0A 1A 0A 이다.

푸터 시그니처는 49 45 4E 44 AE 42 60 82 이다.
이후에는 PNG 파일 구조에 대해 자세히 분석해봐야 한다. 먼저 chunk라는 개념에 대해 알고 가야 한다. PNG 파일 구조는 시그니처와 chunk들로 이루어져 있다. 중요한 청크로는 IHDR, IDAT, IEND가 존재하고, 모두 PNG 파일에 반드시 포함되어야 한다.
1. IHDR : 이미지 헤더 정보

하늘색 범위가 IHDR이 차지하는 청크 범위이다. 먼저 크게는 빨간색 분류를 봐야한다.
| 범위 |
표현값 |
+ |
| 00 00 00 0D (4bytes) |
Length (고정값) |
|
| 49 48 44 52 (4bytes) |
Chunk Type (IHDR) |
|
| 00 00 01 72 00 00 01 72 08 02 00 00 00 (13 bytes) |
Chunk Data |
|
| 67 46 C6 5E (4 bytes) |
CRC |
데이터 오류가 있는지 확인하는 값 |
Chunk Data는 여러 정보를 담고 있는데 해당 부분은 연두색을 기준으로 분류할 수 있다.
| 범위 |
표현값 |
+ |
| 00 00 01 72 (4 bytes) |
Width |
|
| 00 00 01 72 (4 bytes) |
Height |
가로, 세로가 같은 값인 걸 보아하니 해당 이미지는 정사각 파일이다. |
| 08 (1 bytes) |
Bit depth |
1 픽셀의 비트 양(Depth) |
| 02 (1 bytes) |
Color Type |
색 표현 유형 0: 회색조 2: RGB 3: 색인 4: 투명도가 존재하는 회색조 6: 투명도가 존재하는 RGB
해당 분석에서는 2번 RGB가 나왔는데 이때 allowed bit depths는 8 혹은 16이다. 때문의 위의 값이 08인 거 같다. |
| 00 (1 bytes) |
Compression method |
0 Deflate 하나 존재 |
| 00 (1 bytes) |
Filter method |
0 Adaptive filtering 하나 존재 |
| 00 (1 bytes) |
Interlace method |
0 No interlace, 1 Adam 7 interlace 두 개 존재 |
2. IDAT : 이미지 데이터 정보
해당 chunk는 여러 개일 수 있다.

해당 파일에서는 하나만 존재한다.

| 범위 |
표현값 |
+ |
| 00 00 07 24 (4 bytes) |
Length |
07 24를 10진수로 바꿔보면 1828 |
| 49 44 41 54 (4 bytes) |
Chunk Type (IDAT) |
|
| 78~ (Length bytes) |
Chunk Data |
|
| 3E 88 4E AB (4 bytes) |
CRC |
|
Chunk Data 부분만 새 파일에 복붙하고 offset 확인하면 724임을 확인할 수 있다.
3. IEND : 파일의 끝

| 범위 |
표현값 |
+ |
| 00 00 00 00 (4 bytes) |
Length (고정값) |
|
| 49 45 4E 44 (4 bytes) |
Chunk Type (IDAT) |
|
| AE 42 60 82 (4 bytes) |
CRC |
모든 부분이 고정값이라 footer signature로 받아들인다. |
2. zip 파일 분석
드림핵 워게임이 있는 zip파일인데 이름이 너무 길어서 실험대상으로 바꿨다. 안에 파일 하나 있다.
분석하기 쉬운 시그니처부터 알아보았다.

헤더 시그니처는 50 4B 03 04 이다.

푸터 시그니처는 50 4B 05 06이라고 하는데 후에 설명할 End of Central Directory Record 때문에 뒤에 값이 더 존재한다.

zip파일에 3개의 파일이 압축되었을 때 확인할 수 있는 구조라고 한다. 내가 분석하는 파일에는 1개의 파일만 존재하므로 재구성하면 다음과 같다.
| Local File Header |
File Name |
File Data |
| |
Central Directory |
File Name |
| |
|
End of Central Directory Record |
- Local File Header
- Central Directory File Header
- End of Central Directory Record
를 분석해야 하는데 모두 헤더 시그니처가 50 4b로 시작된다.

| 범위 |
표현값 |
+ |
| 50 4B 03 04 (4 bytes) |
Signature (고정값) |
|
| 14 00 (2 bytes) |
압축해제 시 필요한 버전 |
|
| 00 00 (2 bytes) |
Flags |
0: encrypted file 1: compression option 2: compression option 3: data descriptor 4: enhanced deflation 5: compressed patched data 6: strong encryption 7-10: unused 11: language encoding 12: reserved 13: mask header values 14-15: reserved |
| 08 00 (2 bytes) |
Compression Method |
0: no compression 1: shrunk 2: reduced with compression factor 1 3: reduced wtih compression factor 2 4: reduced with compression factor 3 5: reduced with compression factor 4 6: imploded 7: reserved 8: deflated 9: enhanced deflated A: PKWare DCL imploded B: reserved C: compressed using BZIP2 D: reserved E; LZMA F-11: reserved 12: compressed using IBM TERSE 13: IBM LZ77 z 62: PPMd version 1, Rev 1 |
| F8 26 (2 bytes) |
File Modification Time |
F8 26을 2진수 변환 해당 부분을 5비트(h), 6비트(m), 5비트(s)로.. 21시 1분 6초임을 알 수 있다. |
| 8E 57 (2 bytes) |
File Modification Date |
8E 57을 2진수 변환 해당 부분을 7비트(y), 4비트(m), 5비트(d)로.. 연도는 계산 후에 +1980 2051(엥?) / 2 / 23 |
| 25 70 0D BE (4 bytes) |
CRC |
|
| 29 01 00 00 (4 bytes) |
Compressed Size |
|
| 21 02 00 00 (4 bytes) |
Uncompressed Size |
|
| 0A 00 (2 bytes) |
File Name Length |
|
| 1C 00 (2 bytes) |
Extra Field Length |
|
이후에는 Extra Field 내용이 나오고, 이 공간에 데이터가 쓰인다. 해당 파일에는 주석이 없지만 header에 주석의 길이가 있다면 Extra Field 이후 File Comment가 달리게 된다.
두번째 header 시그니처 50 4B 01 02 여기부터는 Central Directory File Header이다.

| 범위 |
표현값 |
+ |
| 50 4B 01 02 (4 bytes) |
Signature (고정값) |
|
| 14 00 (2 bytes) |
압축할 때 사용한 버전 |
|
| 14 00 (2 bytes) |
압축해제 시 필요한 버전 |
|
| 00 00 (2 bytes) |
Flags |
|
| 08 00 (2 bytes) |
Compression Method |
|
| F8 E6 (2 bytes) |
File Modification Time |
|
| 8E 57 (2 bytes) |
File Modification Date |
|
| 25 70 0D BE (4 bytes) |
CRC |
|
| 29 01 00 00 (4 bytes) |
Compressed Size |
|
| 21 02 00 00 (4 bytes) |
Uncompressed Size |
|
| 0A 00 (2 bytes) |
File Name Length |
|
| 18 00 (2 bytes) |
Extra Field Length |
|
| 00 00 (2 bytes) |
File Comment Length |
파일 주석 길이 |
| 00 00 (2 bytes) |
Disk Start Number |
파일이 있는 디스크의 시작 넘버 |
| 01 00 (2 bytes) |
Internal Attribute |
0: Apparent ASCII/text file 1: Reserved 2: Control Field Records Precede Logical Records |
| 00 00 A4 81 (4 bytes) |
External Attribute |
|
| 00 00 00 00 (4 bytes) |
Local Header의 시작 오프셋 |
|
| 44 6F 63 6B 65 72 66 69 |
File Name |
|
3. End of Central Directory Record

| 범위 |
표현값 |
+ |
| 50 4B 05 06 (4 bytes) |
Signature (고정값) |
|
| 00 00 (2 bytes) |
Disk Start Number |
2번에 있는 값과 동일 |
| 00 00 (2 bytes) |
Disk # w/cd |
Central Directory가 시작되는 디스크 개수 |
| 01 00 (2 bytes) |
Disk Entry |
디스크의 Central Directory 개수 |
| 01 00 (2 bytes) |
Total Entry |
Central Directory 개수 |
| 50 00 00 00 (4 bytes) |
Size of Central Directory |
2번에서 살펴본 Central Header 크기 |
| 6D 01 00 00 (4 bytes) |
Central Header Offset |
2번에서 살펴본 Central Header 시작 위치 |
| 00 00 (2 bytes) |
Comment Length |
이 정보 다음에 ZIP File Comment가 나오는데 해당 코멘트 길이가 0이므로 없다. |
가장 쉬운 stegsolve부터 돌려보았지만 유의미한 건 없었다.
stegsolve 툴에는 analyse > format analysis 기능이 있다.

뭐라고 써져 있는데 가독성이 안 좋아서 HxD로 열어보았다.
now_youre_thinking_with_exif The flag you’re looking for is in another property
exif가 뭔지 찾아봤는데 사진 정보 메타데이터라 diary처럼 사진 우클릭 > 속성 > 자세히를 참조해야 한다.


now_youre_thinking_with_exif