# file-system-based strcmp go brrrr
We are given a FAT32 filesystem file strcmp.fat32
```➜  plaid> fatcat strcmp.fat32 -i            FAT Filesystem information
Filesystem type: fat32   OEM name: strcmp  Total sectors: 66057Total data clusters: 65664Data size: 33619968 (32.0625M)Disk size: 33821184 (32.2544M)Bytes per sector: 512Sectors per cluster: 1Bytes per cluster: 512Reserved sectors: 8Sectors per FAT: 513Fat size: 262656 (256.5K)FAT1 start address: 0000000000001000FAT2 start address: 0000000000041200Data start address: 0000000000041200Root directory cluster: 2Disk label: 
Free clusters: 126/65664 (0.191886%)Free space: 64512 (63K)Used space: 33555456 (32.001M)
```
Trying to navigate it using `fatcat strcmp.fat32 -l /` we got to know that every directory contains subdirectories for each character and then a file at the end indicating if the strcmp is matched or not.Files were `SORRY TOOBAD NOFLAG4U NOMATCH NEGATORY LOLNOPE TROLLOL and finally MATCH`
So reading about the FAT32 file structure
![fat_struct](fat_struct.png)
```Sector =  ((N – 2) * BPB_SecPerClus) + FirstDataSector;```
The root directory starts at N=2, so information about the root directory should be stored at first sector index that we can get from the earlier info `Data start address: 0000000000041200``FirstDataSector = 521`
So, the plan was to start reading at N=2 and then continue (not follow) reading the entire file for directory table entries.The directory table is of the following structure.
![dir_table](dir_table.png)
```def parse_fat_directory_row(chunk_32):    x = struct.unpack("<11sccchhhhhhhI",chunk_32)    name = x[0].decode("utf-8").strip()    location = x[7] + x[10]    return (name,location) ``` Now we find all the files that are named MATCH and backtrack using the mapping the mapping created during parsing the directory table```def s(N):    return ((N-2) + 521)*512
def read_directory(fat,sector_index):    dir_index = sector_index    while s(sector_index) <= len(fat):        if (sector_index - 2) % 4 == 0:            dir_index = sector_index        sector_start = s(sector_index)        sector_end = sector_start + SECTOR_SIZE        current_sector = fat[sector_start:sector_end]        if sector_index not in dir_tree.keys():            dir_tree[sector_index] = []        for chunk in split_chunk(current_sector,32):            if chunk != b'\x00'*32:                parsed = parse_fat_directory_row(chunk)                parsed += (dir_index,)                next_chunk_location = parsed[2]                dir_tree[sector_index].append(parsed[2])                if next_chunk_location not in reverse_mapping.keys():                    reverse_mapping[next_chunk_location] = []                if parsed not in reverse_mapping[next_chunk_location]:                    reverse_mapping[next_chunk_location].append(parsed)                positions[sector_index] = parsed        sector_index += 1 ```But for some reason that just gave me half the flag.
So I started thinking of alternate approaches. I knew the flag started with `PCTF{` and I was under the assumption that only one path will lead to acorrect strcmp, so why don't I make a blacklist of all the locations that I know I should not go to, for example at directory `/` I knew the next directory was `P` so all other next locations were blacklisted.Doing so my options at the end of `/P/C/T/F/{/` would only be handful that I can search recursively.
```def next_opts(fat,sector_index):    i = sector_index    opts = []    while s(sector_index) <= len(fat):        sector_start = s(sector_index)        sector_end = sector_start + SECTOR_SIZE        current_sector = fat[sector_start:sector_end]        for chunk in split_chunk(current_sector,32):            if chunk != b'\x00'*32:                parsed = parse_fat_directory_row(chunk)                opts.append(parsed)        sector_index += 1        if sector_index - i == 4:            return opts
def find_flag(fat,start_flag=['P','C','T','F','{']):    next=2    opts = []    for x in start_flag:        for opt in next_opts(fat,next):            if opt[0] == x:                next = opt[2]            opts.append(opt[2])    for opt in next_opts(fat,next):        if opt[1] not in opts:            new_start_flag = start_flag + [opt[0]]            print("".join(new_start_flag))            if opt[0] != "}":                find_flag(fat,start_flag=new_start_flag)
```
I got the flag
```PCTF{WHAT_IN_TARNATION_IS_TH1S_FIPCTF{WHAT_IN_TARNATION_IS_TH1S_FILPCTF{WHAT_IN_TARNATION_IS_TH1S_FILEPCTF{WHAT_IN_TARNATION_IS_TH1S_FILESPCTF{WHAT_IN_TARNATION_IS_TH1S_FILESYPCTF{WHAT_IN_TARNATION_IS_TH1S_FILESYSPCTF{WHAT_IN_TARNATION_IS_TH1S_FILESYSPPCTF{WHAT_IN_TARNATION_IS_TH1S_FILESYSPCPCTF{WHAT_IN_TARNATION_IS_TH1S_FILESYSPCTPCTF{WHAT_IN_TARNATION_IS_TH1S_FILESYSPCTFPCTF{WHAT_IN_TARNATION_IS_TH1S_FILESYSPCTF{PCTF{WHAT_IN_TARNATION_IS_TH1S_FILESYSTPCTF{WHAT_IN_TARNATION_IS_TH1S_FILESYSTEPCTF{WHAT_IN_TARNATION_IS_TH1S_FILESYSTEMPCTF{WHAT_IN_TARNATION_IS_TH1S_FILESYSTEM!PCTF{WHAT_IN_TARNATION_IS_TH1S_FILESYSTEM!}```