/var/log/gitlab/gitlab-workhouse 아래에 current 라는 로그파일이 있습니다. 해당 파일에서 grep 을 이용하여 “exiftool command failed” 를 검색하면 되는데요.
느낌이 쎄하다,,, stderr 을 보아하니 뭔가 다운을 받은것 같다,,,,
대충 뭔갈 다운받은듯한데, 뭔가 수상쩍은 stderr 혹은 stdout 부분이 발견되신다면 일단 내 서버가 털렸을 것에 집중을 하셔야 합니다.
해당 시간에 맞는 nginx 의 로그를 확인해 보셔도 좋습니다.
uploads/user 쪽으로 post 가 하나 날아들어온게 포착…
일단 빼박,, 저는 뭔가 느낌이 좋지 않습니다..
공격 당한것 같은데 어찌 해야 합니까?
지금 저도 공격 벡터 찾아서 분석중인데, 시간이 좀 걸릴것 같습니다.
확실한건 이번주 주말(11월 13일) 까지 상세하게 찾아보고 글을 써서 공유해볼 예정입니다.
패치는 어찌하면 좋습니까….
일단 가장 좋은 방법은 최신버전의 Gitlab CE로 업그레이드 하는겁니다만,,,
아시다시피,, 코드 저장소를 함부로 업그레이드를 갑자기 진행하기엔 좀 곤란한 부분이 있습니다.
하나의 솔루션으로는 ExifTool 부분의 소스코드만 별도로 패치하는것입니다만.
sudo su cd ~
curl -JLO https://gitlab.com/gitlab-org/build/CNG/-/raw/master/gitlab-ruby/patches/allow-only-tiff-jpeg-exif-strip.patch
cd /opt/gitlab/embedded/lib/exiftool-perl
patch -p2 < ~/allow-only-tiff-jpeg-exif-strip.patch
일단 제가 해봤는데요, 왜인지 모르겠으나 저는 안되더라구요 (되시는 분들은 여기서 멈추시면 됩니다.)
이상하게 저는 FAILED 가 뜹니다. 그래서 저는 그냥 ExifTool이 돌지 못하게 막도록 하기로 했습니다. (그렇게 되면 자동으로 EXIF 를 처리하는 로직이 사라지니 혹시 필요하신 분은 좀 다른 방법을 찾으셔야 할듯 합니다)
/opt/gitlab/embedded/bin/exiftool 를 에디터 (VIM,등)으로 여시고,
#!/bin/bash
cat -
위 처럼 파일을 덮어 버리시기 바랍니다.
(저는 exiftool.bak 이라고 별도로 백업파일 만들어 두고 진행했습니다.)
패치가 잘 되었는지?
역시 직접 공격 넣어보시면 됩니다. 해당 CVE 코드를 기반으로 Git 에 돌아다니는 python 소스코드를 이용하여 테스트 해보실 수 있습니다.
일단, 저는 혹시나,,,, 하는 마음에 이 블로그에는 공유하지 않겠습니다. 별도로 잘 찾아보시기 바랍니다.
하,,,,, 제가 멍청했습니다. 하위 클러스터 바이트가 0076 이면, 데이터영역 시작이 2번 클러스터 이니까. 데이터 영역 기준으로 74클러스터 만큼 이동해야 하는데, 76클러스터만큼 이동해서 시그니처를 찾지 못했군요,,,
그래서, 아래에 FAT32 파일 추출을 한번 설명해볼까 합니다. 이미지파일은 해캠에서만 배포하였고, 해당이미지는 트레이닝을 위한 어느 한 포렌식 트레이닝 사이트에서 받은 이미지 내부에 FAT32 영역 500메가만 불러왔어요. 저작권이나 뭐나 그럴 수 있으니, 따로 공유하지는 않겠습니다.
순서는 다음과 같습니다
VBR 영역에서 1섹터당 몇바이트인지 알아오기 (off = 0x0B , 2Byte)
VBR 영역에서 1클러스터당 몇 섹터인지 알아오기 (off = 0x0D , 1Byte)
VBR 영역 에서 예약된 섹터 수가 몇개인지 알아오기 (off = 0x0E , 2Byte)
VBR 영역에서 FAT 영역이 몇개인지 알아오기 (off = 0x10, 1Byte)
VBR 영역에서 하나의 FAT 영역의 크기는 몇 섹터인지 알아오기 (off = 0x24, 4byte)
VBR 영역에서 루트디렉터리(루트 클러스터) 번호 알아오기(off = 0x2C, 4byte).
Dir Entry 영역 에서 파일명(off = 0x00, 11Byte)
Dir Entry 영역에서 상위 클러스터 2바이트(off=0x20, 2Byte)
Dir Entry 영역에서 하위 클러스터 2바이트(off=0x30, 2Byte)
** 각 영역에서부터 오프셋이 시작되니 착오 없으시길 바랍니다.
여기서 알 수 있는것은
FAT 시작 오프셋 = (예약된 섹터 수 * 1섹터당 바이트 수)
DATA영역 시작 오프셋 = (FAT 시작 오프셋 + FAT영역갯수 * FAT 1개 영역 크기 * FAT 영역 갯수)
파일의 시작 오프셋 = (DATA영역 시작 오프셋 + ( (시작 클러스터 번호 4바이트 – 루트클러스터번호) * 1클러스터 당 섹터수 * 1섹터당 바이트 수) )
파일의 끝 오프셋 = 일단, FAT시작 오프셋으로 갑니다. 그 위치는 0번 클러스터를 가르치는 부분입니다. 그렇다면, 76번 클러스터니까, 4byte * 76 하면 76클러스터의 할당정보가 나오죠. 해당 클러스터 할당정보에 적힌 다음 클러스터번호로 넘어갑니다. 당연히 해당위치는 FAT시작 오프셋에서 4Byte * 해당 다음 클러스터 번호가 되겠죠 쭉 가다보면 FFFFFF0F 가 보일것입니다. EOF 입니다. 드디어 해당 위치의 오프셋에서 FAT 시작 오프셋을 빼고 4로 나누면, 몇번째 클러스터 인지 알 수 있습니다. 해당 클러스터가 마지막 클러스터 입니다. 그 마지막클러스터 오프셋은 (DATA영역 시작 오프셋 + ( (마지막 클러스터 번호 4바이트 – 루트클러스터번호) * 1클러스터 당 섹터수 * 1섹터당 바이트 수) ) 이며, 해당 위치에서 (1클러스터 당 섹터수 * 1섹터당 바이트 수) 만큼만 더 가면 그 위치가 파일의 끝 오프셋이 됩니다.
발표에서 실패했던 이유가 DATA 영역 시작 위치는 2번 클러스터니까, 76번 클러스터로 가려면, 당연히 74번 클러스터를 뛰어 넘어가야 하는데, 제가 멍청하게 76번 뛰어넘어가면서 78번 클러스터를 보여드렸습니다.