Chapter 13 What time was a non-standard folder created on the FTP server on the 20th of April?

13.1 Objects in memory/packages loaded from preceding chapters

Objects available:

  • read_zeek_log() — helper function to read Zeek log files (Chapter 3)
  • packets — data frame of PCAP packet data (Chapter 4)
  • conn — Zeek conn.log data (Chapter 5)
  • hoststshark host/IP file (Chapter 8)
  • ftp — Zeek ftp.log data (Chapter 10)

Packages:

  • {jsonlite}
  • {stringi}
  • {glue}
  • {tidyverse}

13.2 Question Setup

We weren’t fibbing when we said we’d be back in FTP land sooner than later. As stated previously, FTP is a cleartext protocol so we can see everything that goes on between a client and server. If someone, say, asks for a directory listing (via the LIST command — ref: RFC 959) we’ll see whatever the server returned, which usually contains file/directory metadata. If we can find this response, we’ll be able to determine what time a non-standard folder was created on the FTP server on the 20th of April.

13.3 Solving the quest with tshark custom filters (and a wee bit of R)

Unfortunately, we do not have enough data in our Zeek ftp.log to answer this question. However, tshark has a plethora of FTP filters we can use. Let’s extract all of the FTP packets that have ftp-data elements (associated with the LIST request) since we know they’ll have the responses:

system("tshark -T json -r maze/maze.pcapng ftp-data and ftp-data.command == 'LIST' > maze/ftp-q1.json")

ftpq1 <- fromJSON("maze/ftp-q1.json", simplifyDataFrame = FALSE)

Let’s see what layers we have available:

names(ftpq1[[1]]$`_source`$layers)
##  [1] "frame"                              "eth"                               
##  [3] "ip"                                 "tcp"                               
##  [5] "ftp-data"                           "ftp-data.setup-frame"              
##  [7] "ftp-data.setup-method"              "ftp-data.command"                  
##  [9] "ftp-data.command-frame"             "ftp-data.current-working-directory"
## [11] "data-text-lines"

Sure enough, we have ftp-data element in there, including the data-text-lines responses which we can inspect:

ftpq1 %>% 
  bind_rows() %>%  # make a data frame out of the individual list elements
  glimpse() %>% 
  pull(`_source`) %>% 
  pluck("layers", "data-text-lines") %>% 
  names()
## Rows: 4
## Columns: 3
## $ `_index`  <chr> "packets-2021-04-29", "packets-2021-04-29", "packets-2021-04…
## $ `_type`   <chr> "doc", "doc", "doc", "doc"
## $ `_source` <named list> [["0", ["wlo1"], "1", "Apr 29, 2021 21:01:26.926740094 EDT",…
## [1] "drwxr-xr-x    2 1000     1000         4096 Feb 23 06:37 Desktop\\r\\n"  
## [2] "drwxr-xr-x    2 1000     1000         4096 Apr 29 16:42 Documents\\r\\n"
## [3] "drwxr-xr-x    2 1000     1000         4096 Feb 23 06:37 Downloads\\r\\n"
## [4] "drwxr-xr-x    2 1000     1000         4096 Feb 23 06:37 Music\\r\\n"    
## [5] "drwxr-xr-x    2 1000     1000         4096 Feb 23 06:37 Pictures\\r\\n" 
## [6] "drwxr-xr-x    2 1000     1000         4096 Feb 23 06:37 Public\\r\\n"   
## [7] "drwxr-xr-x    2 1000     1000         4096 Feb 23 06:37 Templates\\r\\n"
## [8] "drwxr-xr-x    2 1000     1000         4096 Feb 23 06:37 Videos\\r\\n"   
## [9] "dr-xr-x---    4 65534    65534        4096 Apr 20 17:53 ftp\\r\\n"

From that listing we can tell the odd ftp folder was created at 17:53