LabHub
배우기 러닝패스 코스

閉域網の現場 — 防衛ドメイン

持ち込み媒体を展開する前に検疫する

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

반입 매체의 압축 파일을 풀기 전에 목록만 읽어 규모·위험 항목·압축비·형식 불일치를 판정하는 검역기를 만들고, 추출 필터로 항목마다 걸러 격리 디렉터리에 푼 뒤 근거 해시를 붙인 반입 판정서를 씁니다.

왜 중요한가

폐쇄망에 들어오는 것은 대부분 사람이 들고 온 매체이고, 그 안에는 압축 파일 하나가 들어 있습니다. 안을 보려고 푸는 그 한 줄이 이미 파일 시스템을 건드리는 행위입니다. 절대 경로, 상위 경로 탈출, 밖을 가리키는 링크, 특수 파일, 압축 폭탄은 전부 푸는 순간에 효과가 납니다. tar 헤더에는 이름·크기·권한·항목 종류·링크 대상이 적혀 있어서, 풀지 않고도 이 다섯 가지를 전부 볼 수 있습니다. 그래서 순서를 바꿉니다. 먼저 읽고, 판정하고, 조건을 걸어 풉니다. 판정서에는 근거가 붙어야 합니다. 어떤 아카이브의 어떤 해시를 어떤 보고서로 읽었고 그 보고서에서 어떤 사유가 나왔는지가 이어져야, 협력사가 무엇을 고쳐야 하는지 알고 심사자는 같은 판정을 다시 낼 수 있습니다. 채점기는 여러분의 문구를 믿지 않습니다. 아카이브를 직접 열어 나와야 하는 값을 스스로 계산하고, 실행 계약대로 여러분의 검역기를 다시 돌려 그 출력까지 대조합니다.

단계

  1. 생성 스크립트로 매체 두 개를 만들고 접수 대장 /root/media/intake.tsv 에 일련번호·수령 시각·제출자 역할·바깥 해시·크기를 적습니다.
  2. /root/media/inspect.py 를 만들어 MEDIA-2609-017 을 풀지 않고 목록만 읽어 항목 수·총 해제 크기·최대 항목을 /root/media/report/MEDIA-2609-017.json 에 적습니다.
  3. inspect.py 에 danger 분류를 넣습니다. absolute·traversal·escaping_link·special·exec_bit 다섯 칸을 두고 해당 없는 칸도 빈 목록으로 남깁니다.
  4. inspect.py 에 ratio 와 ratio_verdict 를 넣습니다. 총 해제 크기를 압축 파일 크기로 나눈 값이 100 을 넘으면 bomb 입니다.
  5. inspect.py 에 mismatch 를 넣습니다. 확장자가 말하는 형식과 앞머리 바이트가 말하는 형식이 다른 항목을 name·declared·actual 로 적습니다.
  6. inspect.py 에 --extract-to 를 넣어 data 필터로 항목마다 판정하고, /root/media/quarantine/MEDIA-2609-017 에 풀고 extracted 와 rejected 를 보고서에 적습니다.
  7. /root/media/decide.py 로 보고서를 반입 판정서 /root/media/report/verdict-MEDIA-2609-017.json 으로 옮깁니다. media·archive_sha256·report_sha256·decision·reasons·accepted_entries·rejected_entries 를 적습니다.
  8. 같은 검역기와 같은 판정 규칙을 MEDIA-2609-018 에 돌려 /root/media/report/MEDIA-2609-018.json/root/media/report/verdict-MEDIA-2609-018.json 을 만들고, 두 매체를 나란히 놓은 /root/media/report/compare.tsv 를 씁니다.

참고

매체를 열기 전에 접수 대장부터

생성 스크립트로 매체 두 개를 만들고 /root/media/intake.tsv 에 머리글 1줄과 매체 2줄을 적으세요. 칸은 serial·received_at·submitter_role·sha256·bytes 이고 탭으로 나눕니다.

밖에서 받아 올 표본이 없으니 python3 로 직접 만듭니다. 시드와 mtime 이 고정돼 있어 몇 번을 돌려도 같은 매체가 나옵니다. 해시는 아카이브를 풀지 않고 파일 그대로 계산합니다 - 이 값이 나중에 '그때 받은 그 파일인가' 를 되묻는 유일한 근거입니다. 제출자는 사람 이름이 아니라 역할로 적습니다.

풀지 않고 목록만 읽어 규모 재기

/root/media/inspect.py 가 MEDIA-2609-017 을 풀지 않고 헤더만 읽어 archive_sha256·compressed_bytes·entries·total_uncompressed_bytes·largest_entry_bytes·largest_entry_name 을 /root/media/report/MEDIA-2609-017.json 에 쓰게 하세요.

tarfile.open(경로, 'r:gz').getmembers() 가 헤더 목록을 그대로 돌려줍니다. 각 항목의 size 는 헤더에 적힌 값이라 내용을 읽지 않아도 됩니다. archive_sha256 은 아카이브 파일 자체의 해시이고 compressed_bytes 는 그 파일의 크기입니다.

위험 항목을 다섯 갈래로 나누기

inspect.py 가 보고서에 danger 를 넣게 하세요. absolute·traversal·escaping_link·special·exec_bit 다섯 칸에 항목 이름 목록을 적고, 해당 항목이 없는 칸도 빈 목록으로 둡니다.

이름이 슬래시로 시작하면 절대 경로입니다. 상위 경로 탈출은 문자열에 '..' 가 들어 있는지가 아니라 칸 단위로 깊이를 세어 판정합니다. 링크는 issym 과 islnk 를 나눠 보세요 - 심볼릭 링크는 자기가 놓인 자리 기준이고 하드 링크는 아카이브 뿌리 기준입니다. 특수 파일은 ischr·isblk·isfifo 입니다.

압축비로 폭탄 가리기

inspect.py 가 보고서에 ratio 와 ratio_verdict 를 넣게 하세요. ratio 는 총 해제 크기를 압축 파일 크기로 나눠 소수 둘째 자리에서 반올림한 값이고, 100 을 넘으면 ratio_verdict 는 bomb, 아니면 ok 입니다.

두 값 모두 이미 보고서에 있습니다. 풀어서 재지 마세요 - 폭탄을 판정하려고 폭탄을 푸는 것이 됩니다. 임계값은 상수로 빼 두면 다음 사람이 조직 기준에 맞춰 바꿀 수 있습니다.

확장자와 실제 형식 맞춰 보기

inspect.py 가 보고서에 mismatch 를 넣게 하세요. 정규 파일 가운데 확장자가 말하는 형식과 앞머리 바이트가 말하는 형식이 다른 항목을 name·declared·actual 로 적습니다.

extractfile 은 디스크에 풀지 않고 스트림만 엽니다. 앞머리 512바이트면 충분합니다. gzip 은 1f 8b, ELF 는 7f 45 4c 46 으로 시작합니다. 앞머리에 NUL 이 있으면 텍스트가 아닙니다. 확장자를 모르는 항목은 판정하지 말고 건너뛰세요 - 모르는 것을 틀렸다고 적으면 목록이 못 쓰게 됩니다.

추출 필터로 항목마다 걸러 풀기

inspect.py 에 --extract-to 를 넣어 data 필터로 항목마다 판정하고 /root/media/quarantine/MEDIA-2609-017 에 풀게 하세요. 보고서에 extracted 수와 rejected 목록(name·reason)을 적습니다.

extractall 에 filter='data' 만 걸면 첫 거절에서 예외가 올라와 멈춥니다. 항목마다 tarfile.data_filter(member, dest) 를 직접 불러 FilterError 를 받으면 거절 항목과 사유가 한 번에 모입니다. reason 은 예외 클래스 이름을 그대로 쓰세요. 거절되지 않은 항목만 모아 마지막에 한 번에 풉니다.

근거 해시를 붙인 반입 판정서 쓰기

/root/media/decide.py 로 보고서를 읽어 /root/media/report/verdict-MEDIA-2609-017.json 을 만드세요. media·archive_sha256·report_sha256·decision·reasons·accepted_entries·rejected_entries 를 적습니다.

판정 규칙은 안내의 '## 참고' 에 있습니다. reasons 는 danger 에서 비어 있지 않은 칸 이름에 bomb 과 mismatch 를 더해 정렬한 목록입니다. report_sha256 은 sha256sum /root/media/report/MEDIA-2609-017.json 의 값입니다 - 보고서를 다시 만들면 이 값도 다시 적어야 합니다. 막는 항목을 고쳐서 통과시키는 단계가 아닙니다.

두 번째 매체로 판정이 갈리는지 보기

같은 검역기와 같은 판정 규칙을 MEDIA-2609-018 에 돌려 보고서·판정서를 만들고, 두 매체를 나란히 놓은 /root/media/report/compare.tsv 를 쓰세요. 머리글은 media·entries·ratio·ratio_verdict·danger·mismatch·rejected·decision 입니다.

새로 짜지 말고 앞에서 만든 두 스크립트를 그대로 씁니다. danger 칸은 다섯 갈래의 항목 수를 전부 더한 값입니다. 절차가 값에 반응하지 않고 늘 같은 답을 내면 그건 검역이 아니라 도장입니다 - 두 줄의 decision 이 갈리는지 보세요.