Security Ripcord

Cutaway Security Blog and Projects

Review OSX Program File Interactions Using Fslogger-yaml-parser

For the tl;dr crowd: fslogger-yaml has been updated to provide better user interactions relating to outputing data to files or remote UDP servers. The python parser has also been updated to provide analysis of processes detected and the files that were modified. The parser is designed to be modular and easily extended by users.

Last we left fslogger-yaml it did not have a script to easily parse the data and provide analysis of the events. Actually, as I discovered during troubleshooting, last we left fslogger-yaml it did not work properly. Both of these issues have been addressed.

The development of fslogger-yaml has been an adventure in getting back into coding in C. Opening files, string manipulation, client server interactions, truncated events, and just basic troubleshooting when data “seems” correct but is not.

Diving into the troubleshooting process would not be as interesting as I would want it to be. You could follow along, if you really wanted to, by reviewing the history of changes in the tool and looking at each of the updates in Github’s history. But, does anybody actually do that? For large projects that have multiple input points and a large user group, possibly; but I doubt anyone reading this has the time to. Plus, I digress.

fslogger-yaml Compilation

Compilation of fslogger-yaml has changed slightly. The UDP client functionality was split into separate files. Partly because I needed to relearn how to use header and pulling in functionality from other files. Mostly so that I could re-use this functionality in other tools as necessary.

1
cutaway:> gcc -I./xnu/bsd -Wall -o fslogger-yaml udp_client.c fslogger-yaml.c

fslogger-yaml Usage

Running fslogger-yaml has also changed slightly. Before the output went straight to STDOUT. While convenient for debugging this model is not efficient for storing data for future analysis. Thus writing to a file and outputting to a remote server was added. fslogger-yaml’s help output outlines the new usage options.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cutaway:> ./fslogger-yaml -h
fslogger-yaml (2.1-yaml)
File system change logger for Mac OS X. Usage:

        sudo ./fslogger-yaml [output file]

                -h:            Print this help.
                -f <filename>: Output to a local file instead of STDOUT.
                -u:            Output to UDP instead of STDOUT. Default: 127.0.0.1:12345.
                -s <x.x.x.x>:  Remote IP address to send UDP data. Default: 127.0.0.1
                -p <#>:        Remote port number to send UDP data. Default: 12345.


This program must be run as root using sudo.
Happy Hunting, Cutaway.

Receiving the UDP output is as simple as setting up a Netcat listener on a remote host and running fslogger-yaml in UDP-mode.

1
cutaway:> sudo ./fslogger-yaml -s 127.0.0.1 -p 12345 -u

Next, configure a Netcat UDP listener at 127.0.0.1 on port 12345.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
cutaway:> nc -ul 127.0.0.1 12345
#fsevents device cloned (fd 5)
#fslogger ready
# => received 370 bytes
---
Event:
 type: FSE_STAT_CHANGED
 pid: 9037
 pname: firefox
Details:
 FSE_ARG_STRING_0:
   len: 119
   string: '/Users/cutaway/Library/Caches/Firefox/Profiles/ac6xddpc.default/cache2/entries/8C99BB8E7093365ECD4EA138681A891
706827716'
 FSE_ARG_DEV_0:
   len: 4
   dev: 0x040007 (major 0, minor 262151)
 FSE_ARG_INO_0:
   len: 4
   ino: 262154
 FSE_ARG_MODE_0:
   len: 4
   mode: ?-----x---  (0x040008, vnode type VNON)
 FSE_ARG_UID_0:
   len: 4
   uid: 262155 (?)
 FSE_ARG_GID_0:
   len: 4
   gid: 524293 (?)
 FSE_ARG_INT64:
   len: 8
   tstamp: 1322983071330545
 FSE_ARG_DONE:
   len: 0
   type: 45887
---
[snip for brevity]

fslogger-yaml Parsing

Once fslogger-yaml was stable /me shugs “-er”, it was time to update the parser. After all, the YAML functionality was not only added to make reading easier. It was added to make parsing and, thereby, analysis easier.

Cutting to the quick, fslogger-yaml-parser.py provides three basic functions.

  1. Print process numbers and names.
  2. Print processes and the files that were modified in some way (no action identification).
  3. Print action types and a list of files that that action occurred.
1
2
3
4
5
6
7
8
9
10
cutaway:> python fslogger-yaml-parser.py
fslogger-yaml-parser.py:  This script will take YAML output of fslogger data
                          and parse it for various information. Multiple options
                          can be selected.

-f <file>:       Input file (required)
-p:              Print process identifier numbers and a list of corresponding process names.
-n:              Print process identifier and then list the files associated with each process name.
-t:              Print action types and then list the files associated with each action.
-h:              Print help.

A list of possible actions can be found in the source code for fslogger-yaml. I will leave it as an exercise for the reader to research the meaning for each, even if most of them are self explanatory.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// event names
static const char *kfseNames[] = {
    "FSE_CREATE_FILE",
    "FSE_DELETE",
    "FSE_STAT_CHANGED",
    "FSE_RENAME",
    "FSE_CONTENT_MODIFIED",
    "FSE_EXCHANGE",
    "FSE_FINDER_INFO_CHANGED",
    "FSE_CREATE_DIR",
    "FSE_CHOWN",
    "FSE_XATTR_MODIFIED",
    "FSE_XATTR_REMOVED",
};

There is one part of the parser functionality that needs a bit of additional explanation. It seems that, at times, fslogger-yaml cannot keep up with the file changes or input from FSEvents. I have not determined the “why” but I did notice that the program consistently errors out on the timestamp field: “FSE_ARG_INT64”. Basically, the output is truncated immediately after that string. Since I couldn’t find a reason, and thereby update the C code to compensate, I added a compensating feature in fslogger-yaml-parser. For now, the parser performs a debugging run on the data. If an error is detected the output is updated to make the YAML formatting correct. It does this by adding “tagged” data to the truncated fields. This should help ensure that the data captured is still usable and future runs or monitor may not be necessary.

The following is an example of the output a user would see if input errors were detected and fixed.

1
2
3
4
5
6
7
8
9
10
11
12
13
cutaway:> python fslogger-yaml-parser.py -f test-fslogger_udp4.yaml -n
('Error detected in line %s: %s', 540613, ' FSE_ARG_INT64# => received 261 bytes')
Updating error with marked modifications. Look for -1 values in FSE_ARG_INT64 values.
('Error detected in line %s: %s', 543863, ' FSE_ARG_INT64# => received 261 bytes')
Updating error with marked modifications. Look for -1 values in FSE_ARG_INT64 values.
('Error detected in line %s: %s', 1533032, ' FSE_ARG_INT64# => received 261 bytes')
Updating error with marked modifications. Look for -1 values in FSE_ARG_INT64 values.
('Error detected in line %s: %s', 1535844, ' FSE_ARG_INT64# => received 261 bytes')
Updating error with marked modifications. Look for -1 values in FSE_ARG_INT64 values.
Error detected, data modified to compensate.
Detect Processes and Files

[snip for brevity]

Future Functionality

The Python parser can, obviously, be updated for additional and better analysis. Fork the repo, add your favorite analysis functionality, and then make a pull request. I’ll review it, pull it in, and then add you to the list of contributors (which is singularly auspicious at the moment).

While “neat,” updating the parser is not the most interesting possibility for this project. Now that I know a bit more about C programming and using fslogger to monitor FSEvents in OSX, I have been thinking of some possibilities.

  1. OSX HoneyToken Monitor - a monitor for events to specific files that are placed on a system to identify malicious activity. These are sometimes referred to as canaries.
  2. Process Recorder - a program that records program names of process that have interacted with files. This would provide a baseline of activity that could be evaluated over time. There are probably better methods for doing this.
  3. Process Reactor - an offensive program to wait for specific programs to execute and then start up keyloggers or record filenames for download and review by attackers.

Personally, as I am currently employed as a defender, I would rather see the first two implemented before the later. But, unless I get a request for these, I will not be working on them. I need to focus on the original project plan I had for detecting file modifications by malicious programs running on OSX. Maybe in the future. Let me know on Twitter or email if you think there is a need.

Go forth and do good things,
cutaway