Created
June 17, 2021 10:18
-
-
Save dialluvioso/43dc0e17e903215c93d53234e6ae72fb to your computer and use it in GitHub Desktop.
FAT32 dissector for SSTIC 2021 CTF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| # -*- coding: utf-8 -*- | |
| import struct | |
| u8 = lambda x: struct.unpack("<B", x)[0] | |
| u16 = lambda x: struct.unpack("<H", x)[0] | |
| u32 = lambda x: struct.unpack("<I", x)[0] | |
| OFFSET_BYTSPERSEC = 11 | |
| OFFSET_SECPERCLUS = 13 | |
| OFFSET_RSVDSECCNT = 14 | |
| OFFSET_NUMFATS = 16 | |
| OFFSET_ROOTENTCNT = 17 | |
| OFFSET_HIDDENSEC = 28 | |
| OFFSET_TOTSEC32 = 32 | |
| OFFSET_FATZ32 = 36 | |
| OFFSET_ROOTCLUS = 44 | |
| OFFSET_FSINFO = 48 | |
| f = open("bootsector.raw", "rb") | |
| # parse bytes per sector | |
| f.seek(OFFSET_BYTSPERSEC) | |
| byts_per_sec = u16(f.read(2)) | |
| # parse sectors per cluster | |
| f.seek(OFFSET_SECPERCLUS) | |
| sec_per_clus = u8(f.read(1)) | |
| # parse number of sectors in reserved area | |
| f.seek(OFFSET_RSVDSECCNT) | |
| rsvd_sec_cnt = u16(f.read(2)) | |
| # parse number of FATs | |
| f.seek(OFFSET_NUMFATS) | |
| num_fats = u8(f.read(1)) | |
| # parse number of number of 32-byte directory entries inside root directory | |
| f.seek(OFFSET_ROOTENTCNT) | |
| root_ent_cnt = u16(f.read(2)) | |
| # parse the number of hidden sectors preceding FAT partition | |
| f.seek(OFFSET_HIDDENSEC) | |
| hidden_sec = u32(f.read(4)) | |
| # parse number of sectors of the FAT volume | |
| f.seek(OFFSET_TOTSEC32) | |
| tot_sec_32 = u32(f.read(4)) | |
| # parse the size of a FAT unit of sector | |
| f.seek(OFFSET_FATZ32) | |
| fat_sz_32 = u32(f.read(4)) | |
| # parse the first cluster number of the root directory | |
| f.seek(OFFSET_ROOTCLUS) | |
| root_clus = u32(f.read(4)) | |
| # parse the sector of FSInfo (offset from top of FAT32 volume) | |
| f.seek(OFFSET_FSINFO) | |
| fs_info = u16(f.read(2)) | |
| print(f"bytes per sector: {byts_per_sec}") | |
| print(f"sectors per cluster: {sec_per_clus}") | |
| print(f"number of sectors in reserved area: {rsvd_sec_cnt}") | |
| print(f"number of FATs: {num_fats}") | |
| print(f"number of entries inside root directory: {root_ent_cnt}") | |
| print(f"number of hidden sectors preceding FAT: {hidden_sec}") | |
| print(f"number of sectors of FAT: {tot_sec_32}") | |
| print(f"size of FAT unit: {fat_sz_32}") | |
| print(f"cluster number of root directory: {root_clus}") | |
| print(f"sector of FSInfo: {fs_info}") | |
| # calculare size of FAT area | |
| fat_area_sz = fat_sz_32 * num_fats | |
| print(f"FAT area size: {fat_area_sz}") | |
| # calculare where data region starts | |
| first_data_sec = rsvd_sec_cnt + fat_area_sz | |
| print(f"First data sector: {first_data_sec}") | |
| def get_sect(n): | |
| return hidden_sec + first_data_sec + ((n-2) * sec_per_clus) | |
| def get_fat_by_clus(n): | |
| fat_sec_num = hidden_sec + rsvd_sec_cnt + ((n * 4) / byts_per_sec) | |
| fat_ent_off = (n * 4) % byts_per_sec | |
| return (int(fat_sec_num), fat_ent_off) | |
| # calculate where root directory starts inside data region | |
| rootdir_clus_sec = get_sect(root_clus) | |
| print(f"First sector of cluster (root directory) is: {rootdir_clus_sec:08x}") | |
| clus_chall1 = u32(b"\x6e\x00\x00\x00") | |
| clus2_chall1 = u32(b"\x6f\x00\x00\x00") | |
| clus3_chall1 = u32(b"\x70\x00\x00\x00") | |
| clus4_chall1 = u32(b"\x71\x00\x00\x00") | |
| clus_chall7 = u32(b"\x72\x00\x00\x00") | |
| clus2_chall7 = u32(b"\x73\x00\x00\x00") | |
| clus3_chall7 = u32(b"\x74\x00\x00\x00") | |
| clus4_chall7 = u32(b"\x75\x00\x00\x00") | |
| clus_chall5 = u32(b"\x76\x00\x00\x00") | |
| clus2_chall5 = u32(b"\x77\x00\x00\x00") | |
| clus3_chall5 = u32(b"\x78\x00\x00\x00") | |
| clus4_chall5 = u32(b"\x79\x00\x00\x00") | |
| clus_chall3 = u32(b"\x7a\x00\x00\x00") | |
| clus2_chall3 = u32(b"\x7b\x00\x00\x00") | |
| clus3_chall3 = u32(b"\x7c\x00\x00\x00") | |
| clus4_chall3 = u32(b"\x7d\x00\x00\x00") | |
| clus_chall6 = u32(b"\x7e\x00\x00\x00") | |
| clus2_chall6 = u32(b"\x7f\x00\x00\x00") | |
| clus3_chall6 = u32(b"\x80\x00\x00\x00") | |
| clus4_chall6 = u32(b"\x81\x00\x00\x00") | |
| clus_chall4 = u32(b"\x82\x00\x00\x00") | |
| clus2_chall4 = u32(b"\x83\x00\x00\x00") | |
| clus3_chall4 = u32(b"\x84\x00\x00\x00") | |
| clus4_chall4 = u32(b"\x85\x00\x00\x00") | |
| clus_chall2 = u32(b"\x86\x00\x00\x00") | |
| clus2_chall2 = u32(b"\x87\x00\x00\x00") | |
| clus3_chall2 = u32(b"\x88\x00\x00\x00") | |
| clus4_chall2 = u32(b"\x89\x00\x00\x00") | |
| clus_chall8 = u32(b"\x8a\x00\x00\x00") | |
| clus2_chall8 = u32(b"\x8b\x00\x00\x00") | |
| clus = clus_chall4 | |
| sec_clus = get_sect(clus) | |
| print(f"{sec_clus:08x}") | |
| fat, off = get_fat_by_clus(clus) | |
| print(f"fat=>{fat:08x} off=>{off:x}") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment