Skip to content

Commit 253aede

Browse files
authored
Merge pull request #34 from ThreatResponse/profiler-expansion
Profiler expansion
2 parents 7c26905 + 1d47d7d commit 253aede

File tree

2 files changed

+119
-1
lines changed

2 files changed

+119
-1
lines changed

profiler_bin

8.41 KB
Binary file not shown.

profilers/posix_core.py

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
import pkg_resources
66
import platform
77
import socket
8+
from socket import socket, AF_INET, SOCK_DGRAM
9+
import re
10+
import struct
11+
import time
812

13+
from contextlib import closing
914
from collections import OrderedDict
1015
from datetime import datetime, timedelta
1116
from profilers import is_warm
@@ -18,6 +23,113 @@ class PosixCoreProfiler(Profiler):
1823

1924
"""Functions for specific data retreival."""
2025

26+
def check_time_drift():
27+
## Ignores network latency to the NTP server.
28+
29+
NTP_PACKET_FORMAT = "!12I"
30+
NTP_DELTA = 2208988800L # 1970-01-01 00:00:00
31+
NTP_QUERY = '\x1b' + 47 * '\0'
32+
host = "pool.ntp.org"
33+
port = 123
34+
35+
with closing(socket(AF_INET, SOCK_DGRAM)) as s:
36+
s.sendto(NTP_QUERY, ("pool.ntp.org", 123))
37+
msg, address = s.recvfrom(1024)
38+
local_time = time.time()
39+
unpacked = struct.unpack(NTP_PACKET_FORMAT,
40+
msg[0:struct.calcsize(NTP_PACKET_FORMAT)])
41+
ntp_time = unpacked[10] + float(unpacked[11]) / 2**32 - NTP_DELTA
42+
43+
return abs(ntp_time - local_time)
44+
45+
def check_interesting_env_vars():
46+
## Returns a subset of environment variables that are interesting:
47+
## secrets, etc.
48+
49+
interesting_vars = [
50+
'AWS_SESSION_TOKEN',
51+
'AWS_SECURITY_TOKEN',
52+
"AWS_ACCESS_KEY_ID",
53+
"AWS_SECRET_ACCESS_KEY",
54+
]
55+
56+
env_vars = os.environ.__dict__
57+
interesting_subset = dict((k, env_vars[k]) for k in interesting_subset if k in env_vars)
58+
59+
return interesting_subset
60+
61+
def check_env_editable():
62+
os.environ['profiler_test'] = 'flag'
63+
64+
## we check with a different method to demonstrate that it's not
65+
## just edited within 'environ'
66+
res = call_shell_wrapper(['env | grep \'profiler_test\''])
67+
68+
if res == 'profiler_test=flag\n':
69+
return True
70+
else:
71+
return False
72+
73+
def check_source_editable():
74+
## check if we can edit the file on disk
75+
flag_string = 'profiler_test'
76+
77+
call_shell_wrapper(['echo "{}" >> {}'.format(flag_string, __file__)])
78+
res = call_shell_wrapper(['tail -n 1 {}'.format(__file__)])
79+
80+
if res == '{}\n'.format(flag_string):
81+
return True
82+
else:
83+
return False
84+
85+
def check_arbitrary_binary():
86+
## Re: Lambda
87+
## I wasn't able to get executable permissions on the binary in the code dir
88+
## and didn't have permissions to edit with chmod.
89+
## We just attach a precompiled binary, move it to /tmp, and execute.
90+
91+
call_shell_wrapper(['mv profiler_bin /tmp'])
92+
call_shell_wrapper(['chmod +x /tmp/profiler_bin'])
93+
res = call_shell_wrapper(['/tmp/profiler_bin'])
94+
95+
if res == 'custom profiler binary':
96+
return True
97+
else:
98+
return False
99+
100+
def check_other_runtimes():
101+
## for now, just node. Can expand as wanted, thus we return a dict.
102+
103+
node_test = call_shell_wrapper(['node -e \'console.log("foo");\''])
104+
105+
if node_test == 'foo\n':
106+
return {'node': True}
107+
else:
108+
return {'node': False}
109+
110+
111+
def check_docker_containers():
112+
docker_socket_locations = ["/var/run/docker.sock"]
113+
114+
results = [os.path.ispath(f) for f in docker_socket_locations]
115+
116+
return any(results)
117+
118+
def check_capabilities():
119+
## we assume (checked on lambda) that we are PID 1
120+
## see http://man7.org/linux/man-pages/man5/proc.5.html
121+
## If we can't check permissions, we assume none.
122+
123+
statline = call_shell_wrapper(["grep 'CapEff' /proc/1/status"])
124+
125+
bitmask = re.match(r'CapEff:\t(\d+)\n', res).groups()
126+
flags = 0
127+
128+
if len(bitmask) == 1:
129+
flags = int(bitmask[0])
130+
131+
return flags
132+
21133
def get_pwd():
22134
return call_shell_wrapper(["pwd"])
23135

@@ -177,7 +289,13 @@ def get_ipaddress():
177289
"ps": get_processes,
178290
"timestamp": get_timestamp,
179291
"ipaddress": get_ipaddress,
180-
"uptime": get_uptime
292+
"uptime": get_uptime,
293+
"time_drift": check_time_drift,
294+
"env_subset": check_interesting_env_vars,
295+
"source_editable": check_source_editable,
296+
"other_runtimes": check_other_runtimes,
297+
"docker_sockets": check_docker_containers,
298+
"proc_capabilities": check_capabilities
181299
}
182300

183301
@staticmethod

0 commit comments

Comments
 (0)