Skip to content

Commit

Permalink
Added chmod, chown, file-touch, file-append, and file-create quarks (#11
Browse files Browse the repository at this point in the history
)

* Added chmod, chown, file-touch, file-append, and file-create quarks

* fixed copy pasta error in readme
  • Loading branch information
int5-grey authored Feb 17, 2020
1 parent 2257c0c commit ef0cf6a
Show file tree
Hide file tree
Showing 9 changed files with 496 additions and 10 deletions.
55 changes: 53 additions & 2 deletions compose_reaction
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import sys
import stat
import traceback
import collections
from codecs import escape_decode
from json import loads, JSONDecoder
from struct import pack, calcsize
from argparse import ArgumentParser
Expand All @@ -13,10 +14,24 @@ SOCKET_TYPE_UDP = (1 << 1)
SOCKET_TYPE_IPV4 = (1 << 2)
SOCKET_TYPE_IPV6 = (1 << 3)

FILE_OP_FLAG_CREATE = (1 << 0)
FILE_OP_FLAG_TRUNCATE = (1 << 1)
FILE_OP_FLAG_PREPEND = (1 << 2)
FILE_OP_FLAG_APPEND = (1 << 3)
FILE_OP_FLAG_EXCL = (1 << 4)
FILE_OP_FLAG_BACKUP_AND_REVERT = (1 << 5)
FILE_OP_NO_DATA = (1 << 6)

METHOD_PATH = 1
METHOD_AT_DESCRIPTOR = 2
METHOD_DESCRIPTOR = 3
METHOD_DONT_FOLLOW = 4

import os

supported_quarks = ['execve', 'execveat', 'fork-and-rename',
'connect', 'listen', 'copy', 'remove']
'connect', 'listen', 'copy', 'remove', 'chown', 'fchown', 'fchownat', 'lchown',
'chmod', 'fchmod', 'fchmodat', 'file-touch', 'file-append', 'file-prepend', 'file-create' ]

class AtomDecoder(JSONDecoder):
def __init__(self, *args, **kwargs):
Expand Down Expand Up @@ -79,7 +94,7 @@ if __name__ == "__main__":
if k == 'execve' or k == 'execveat':
assert isinstance(v, list), '{} argument must be a list'.format(k)
assert len(v) > 0, '{} must have arguments'.format(k)
method = { 'execve' : 1, 'execveat' : 2 }.get(k)
method = { 'execve' : METHOD_PATH, 'execveat' : METHOD_AT_DESCRIPTOR }.get(k)
type = 'exec'
quark += pack("<L", method) + parse_argv(v)
elif k == 'fork-and-rename' or k == 'fork-and-rename-x86':
Expand All @@ -104,6 +119,42 @@ if __name__ == "__main__":
assert isinstance(v, list), '{} argument must be a list'.format(k)
assert len(v) > 0, '{} must have arguments'.format(k)
quark += pack("<L", 0) + parse_argv(v)
elif k in ['chown', 'fchown', 'fchownat', 'lchown']:
type = 'chown'
chown_type = { 'chown' : METHOD_PATH,
'fchown' : METHOD_DESCRIPTOR,
'fchownat' : METHOD_AT_DESCRIPTOR ,
'lchown' : METHOD_DONT_FOLLOW }.get(k)
group = v.get('group', b'').encode('utf8')
user = v.get('user', b'').encode('utf8')
quark += pack ("<L64s64s260s", chown_type, user, group, v.get('path').encode('utf8'))
elif k in ['chmod', 'fchmod', 'fchmodat']:
type = 'chmod'
chmod_type = {'chmod' : METHOD_PATH,
'fchmod' : METHOD_DESCRIPTOR,
'fchmodat' : METHOD_AT_DESCRIPTOR }.get(k)
mode = int(str(v.get('mode')), 8)
quark += pack('<LL260s', chmod_type, mode, v.get('path').encode('utf8'))
elif k in ['file-touch', 'file-append', 'file-prepend', 'file-create']:
type = 'file-op'
file_op_flags = { 'file-touch' : FILE_OP_FLAG_CREATE | FILE_OP_NO_DATA,
'file-append' : FILE_OP_FLAG_APPEND,
'file-prepend' : 0,
'file-create' : FILE_OP_FLAG_CREATE | FILE_OP_FLAG_TRUNCATE }.get(k)

if v.get('backup-and-revert', False):
file_op_flags |= FILE_OP_FLAG_BACKUP_AND_REVERT

data = v.get('data', b'')
if data:
if os.path.exists(data):
with open(data, 'rb') as f:
data = f.read()
else:
data = escape_decode(data)[0]

quark += pack("<L260sL", file_op_flags,
v.get('path').encode('utf8'), len(data)) + data
else:
raise Exception("unknown quark {}".format(k))

Expand Down
90 changes: 90 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,93 @@ Details:
- Any number of targets may be specified.
- No errors will be generated during this operation.
- Be careful when specifying paths, as this quark will indiscriminately delete everything specified in the list.

### chown, fchown, fchownat, lchown

Example:

```
{
"name" : "CHOWN-EXISTING-FILE",
"chown" : { "path" : "/tmp/cr.path.test", "user" : "1000", "group" : "nogroup" },
"fchown" : { "path" : "/tmp/cr.descriptor.test", "user" : "1000", "group" : "nogroup" },
"fchownat" : { "path" : "/tmp/cr.at.test", "user" : "1000", "group" : "nogroup" },
"lchown" : { "path" : "/tmp/cr.link.test", "user" : "1000", "group" : "nogroup" }
}
```

Details:
- Change the ownership of a file object
- `user` or `group` are both strings. If a named user or group does not exist,
an attempt will be made to convert the string to a number. In the example above
the `user` field will be translated into the `uid` of `1000`, while `group` will
is set to `nogroup` a common default group entry, and will be translated to the
correct value.
- It's common that changing ownership requires elevated privileges.

### chmod, fchmod, fchmodat

Example:

```
{
"name" : "CHMOD-EXISTING-FILE",
"chmod" : { "path" : "/tmp/cr.path.test", "mode" : "600" },
"fchmod" : { "path" : "/tmp/cr.descriptor.test", "mode" : "060" },
"fchmodat" : { "path" : "/tmp/cr.at.test", "mode" : "606" }
}
```

Details:
- Change the file permissions of a target file.
- `mode` should be a string in [octal format](http://man7.org/linux/man-pages/man2/chmod.2.html).

### file-touch

```
{
"name" : "TOUCH-TMP-NEW-FILE",
"file-touch" : { "path" : "/tmp/cr.test" }
}
```

Details:
- Creates a file if it doesn't exist at the target `path`.
- Does not error if the file already exists.

### file-create

```
{
"name" : "TOUCH-TMP-TRUNCATE-IF-EXISTS",
"file-create" : { "path" : "/tmp/cr.test", data : "Hello World!\n", backup-and-revert : false },
"file-create" : { "path" : "/etc/passwd", data : "/etc/passwd", backup-and-revert : true }
}
```

Details:
- Creates a file, truncating if it exits.
- `data` can a string or a file path. If `data` is a string, all escape sequences
will be turned into binary so `\n`, and `\x00` work correctly. When `data` is
a file path, that file will be read during composition time, and baked into
the chain reactor deliverable.
- `backup-and-revert` creates a backup of the target file specified by `path`.
If the target file does not exist, this field has no effect.

### file-append

```
{
"name" : "PERSIST_CRONTAB",
"file-append" : { "path" : "/etc/crontab", data : "\n1 * * * * root /var/www/malware-r-us/userkit\n", backup-and-revert : true },
}
```

Details:
- Appends to an existing file, fails if the file does not exist.
- `data` can a string or a file path. If `data` is a string, all escape sequences
will be turned into binary so `\n`, and `\x00` work correctly. When `data` is
a file path, that file will be read during composition time, and baked into
the chain reactor deliverable.
- `backup-and-revert` creates a backup of the target file specified by `path`.
If the target file does not exist, this field has no effect.
14 changes: 14 additions & 0 deletions examples/visibility/fs/create/visibility_fs_create_atoms.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"name" : "TOUCH-TMP-NEW-FILE",
"file-touch" : { "path" : "/tmp/cr.test" }
},
{
"name" : "TOUCH-TMP-TRUNCATE-IF-EXISTS",
"file-create" : { "path" : "/tmp/cr.test" }
},
{
"name" : "CLEANUP",
"remove" : [ "/tmp/cr.test" ]
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "visibility_fs_create",
"atoms": [
"TOUCH-TMP-NEW-FILE",
"TOUCH-TMP-TRUNCATE-IF-EXISTS",
"CLEANUP"
]
}
44 changes: 44 additions & 0 deletions examples/visibility/fs/modify/visibility_fs_modify_atoms.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[
{
"name" : "TOUCH-TMP-NEW-FILE",
"file-touch" : { "path" : "/tmp/cr.test" },
"file-touch" : { "path" : "/tmp/cr.path.test" },
"file-touch" : { "path" : "/tmp/cr.descriptor.test" },
"file-touch" : { "path" : "/tmp/cr.at.test" },
"file-touch" : { "path" : "/tmp/cr.link.test" }
},
{
"name" : "CLEANUP",
"remove" : [ "/tmp/cr.test", "/tmp/cr.path.test",
"/tmp/cr.descriptor.test", "/tmp/cr.at.test", "/tmp/cr.link.test"]
},
{
"name" : "APPEND-EXISTING-FILE",
"file-append" : { "path" : "/tmp/cr.test", "data": " World!\n\nGoodbye\n"}
},
{
"name" : "APPEND-EXISTING-FILE-REVERT",
"file-append" : { "path" : "/tmp/cr.path.test", "backup-and-revert" : true, "data": "World!\n\nGoodbye\n"}
},
{
"name" : "PREPEND-EXISTING-FILE",
"file-prepend" : { "path" : "/tmp/cr.test", "data": "Hello "}
},
{
"name" : "PREPEND-EXISTING-FILE-REVERT",
"file-prepend" : { "path" : "/tmp/cr.path.test", "backup-and-revert" : true, "data": "Hello "}
},
{
"name" : "CHOWN-EXISTING-FILE",
"chown" : { "path" : "/tmp/cr.path.test", "user" : "1000", "group" : "nogroup" },
"fchown" : { "path" : "/tmp/cr.descriptor.test", "user" : "1000", "group" : "nogroup" },
"fchownat" : { "path" : "/tmp/cr.at.test", "user" : "1000", "group" : "nogroup" },
"lchown" : { "path" : "/tmp/cr.link.test", "user" : "1000", "group" : "nogroup" }
},
{
"name" : "CHMOD-EXISTING-FILE",
"chmod" : { "path" : "/tmp/cr.path.test", "mode" : "600" },
"fchmod" : { "path" : "/tmp/cr.descriptor.test", "mode" : "060" },
"fchmodat" : { "path" : "/tmp/cr.at.test", "mode" : "606" }
}
]
12 changes: 12 additions & 0 deletions examples/visibility/fs/modify/visibility_fs_modify_reaction.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "visibility_fs_modify",
"atoms": [
"TOUCH-TMP-NEW-FILE",
"APPEND-EXISTING-FILE",
"PREPEND-EXISTING-FILE",
"APPEND-EXISTING-FILE-REVERT",
"PREPEND-EXISTING-FILE-REVERT",
"CHOWN-EXISTING-FILE",
"CHMOD-EXISTING-FILE"
]
}
15 changes: 15 additions & 0 deletions src/atoms.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ int quark_exec(pexec_t args);
void quark_fork_and_rename(pfork_and_rename_t args, int in_fork_and_rename);
void quark_rm_rf(prm_rf_t args);
int quark_copy(pcopy_t args);
int quark_chmod(pchmod_t args);
int quark_chown(pchown_t args);
int quark_file_op(pfile_op_t args);

int split_atom(patom_t atom, int in_fork_and_rename)
{
Expand Down Expand Up @@ -96,6 +99,18 @@ int split_atom(patom_t atom, int in_fork_and_rename)
if (-1 == quark_copy((pcopy_t)quark_body)) {
goto Exit;
}
} else if (!strcasecmp("file-op", quark->type)) {
if (-1 == quark_file_op((pfile_op_t)quark_body)) {
goto Exit;
}
} else if (!strcasecmp("chmod", quark->type)) {
if (-1 == quark_chmod((pchmod_t)quark_body)) {
goto Exit;
}
} else if (!strcasecmp("chown", quark->type)) {
if (-1 == quark_chown((pchown_t)quark_body)) {
goto Exit;
}
} else {
ERROR("unknown quark type %s\n", quark->type);
errno = EINVAL;
Expand Down
34 changes: 32 additions & 2 deletions src/atoms.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ THE SOFTWARE.

typedef char byte_t;

#define EXEC_METHOD_PATH 1
#define EXEC_METHOD_DESCRIPTOR 2
#define METHOD_PATH 1
#define METHOD_AT_DESCRIPTOR 2
#define METHOD_DESCRIPTOR 3
#define METHOD_DONT_FOLLOW 4

#define FORK_METHOD_X86 1
#define FORK_METHOD_LIBC 2
Expand All @@ -42,6 +44,14 @@ typedef char byte_t;
#define SOCKET_TYPE_IPV4 (1 << 2)
#define SOCKET_TYPE_IPV6 (1 << 3)

#define FILE_OP_FLAG_CREATE (1 << 0)
#define FILE_OP_FLAG_TRUNCATE (1 << 1)
#define FILE_OP_FLAG_PREPEND (1 << 2)
#define FILE_OP_FLAG_APPEND (1 << 3)
#define FILE_OP_FLAG_EXCL (1 << 4)
#define FILE_OP_FLAG_BACKUP_AND_REVERT (1 << 5)
#define FILE_OP_NO_DATA (1 << 6)

#pragma pack(push, 1)
typedef struct {
int method;
Expand All @@ -65,6 +75,26 @@ typedef struct {
byte_t argv[];
} rm_rf_t, *prm_rf_t, copy_t, *pcopy_t;

typedef struct {
int flags;
char path[260];
unsigned int cb_bytes;
char bytes[];
} file_op_t, *pfile_op_t;

typedef struct {
int method;
char user[64];
char group[64];
char path[260];
} chown_t, *pchown_t;

typedef struct {
int method;
unsigned int mode;
char path[260];
} chmod_t, *pchmod_t;

typedef struct {
unsigned int cb;
char type[64];
Expand Down
Loading

0 comments on commit ef0cf6a

Please sign in to comment.