New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

broctl looks like an APT #259

Open
mpurzynski opened this Issue Jan 30, 2019 · 3 comments

Comments

Projects
None yet
3 participants
@mpurzynski
Copy link
Contributor

mpurzynski commented Jan 30, 2019

While doing Threat Hunting I saw an interesting string in our Audit Execve logs, only on my NSM fleet

python /usr/bin/python -c import zlib,base64; exec(zlib.decompress(base64.b64decode(beJxlU8Fu2zAMPUdfIehSGdOMJtgpgI459DCsh+7kGYFr060KWzIke05Q9N9HSvaaNAFiW+TjI/lIMdMPzo/cBRXO+J+eB+9qCPhpXmzVqQAd1KN6C86yp4efh1+/n/R2d89YAy2fZcj2bIOReRgbN4357M0I0sPg0cW/cfHHiuwK0XZTeJVZIoAT1Me6b4KkB3ENuijZpnWeG4U2biwHO/XgK+RdQZvRn+m1oWL1Z9H5oxvAEkylbFe+h8cDmcH7r2aeRbK8GjC8kdIo8mZkhVMNw8gP8WWc5VXgEHPPhJNbdXeHrF5Chj+28TBO3vKBsVkKD1Vzxv5r1/eVbQL1lnTNq67yvVwUzRg13BkL1C8qiOolxYzNiYRcSjTOAumJ6VfGtWSaT965CpUkLFbCqIWgLxReQrCcvjn21aDfP1h78RV0gBEnk8SncKom0mBGp9+FaU5ibxQXZBR7euIhSS32RZkOKPBymCszGvsi9rsPnGlMVVDQsguldsUaXd4AkGYFECMClrq/UNzaUyQRhnwaGtoceRGjLnAk1PxqOuAIxi69OqqjTkufp5dEj8J2ihLHS9q0cSs9LQGyDbhlLsQpITJvkcs6mant/e4HLZBpeULFpVl6bJtynZyLzriAtbMo1wQMD9iTXvtCNFqoGw+9+wuYh/DoLv5LXH7X25Tt2hyzXhLHKxMxcYjEHMZqnIKOslAg7kBsTT8Lkb85E2/U56TitcBLdOONYyIvXo1oo30plUz8CoNVlJw0l3Gb8W78A22ieEg=)))

I jumped in my seat and after some quick exchange got it decoded

import os,sys,subprocess,signal,select,json
TIMEOUT=120

def w(s):
	sys.stdout.write(repr(s) + "\n")
	sys.stdout.flush()

def exec_cmds(cmds):
	p=[]
	for i,cmd in enumerate(cmds):
		try:
			proc=subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE )
			p.append((i,proc))
		except Exception as e:
			w((i,(1,'',str(e))))
	return p

w("ready")
commands=[]
signal.alarm(TIMEOUT)
for line in iter(sys.stdin.readline,"done\n"):
	commands.append(json.loads(line))

procs=exec_cmds(commands)
cmd_map={}
fd_map={}
fds=set()
for i,proc in procs:
	o={"idx":i, "proc":proc, "stdout":[], "stderr":[], "waiting":2}
	fd_map[proc.stdout]=o["stdout"]
	fd_map[proc.stderr]=o["stderr"]
	cmd_map[proc.stdout]=o
	cmd_map[proc.stderr]=o
	fds.update((proc.stdout,proc.stderr))

while fds:
	r,_,_=select.select(fds,[],[])
	for fd in r:
		output=os.read(fd.fileno(),1024)
		if output:
			fd_map[fd].append(output)
			continue

		cmd=cmd_map[fd]
		fds.remove(fd)
		cmd["waiting"]-=1
		if cmd["waiting"]:
			continue

		proc=cmd["proc"]
		status=proc.wait()
		out=b"".join(cmd["stdout"])
		err=b"".join(cmd["stderr"])
		w((cmd["idx"],(status,out,err)))

w("done")

What I received was made me even more suspicious than before. I understand that this is part of the broctl, but does it really have to be this way?

@jsiwek

This comment has been minimized.

Copy link
Member

jsiwek commented Jan 30, 2019

Not sure. A quick suggestion would be to change the python -c to insert a no-op string like "This is BroControl" and also include a comment in the decoded python script of the same nature. There's nothing stopping an adversary from mimicking such a comment string to divert skepticism, but I guess it may still help initial impression/research?

@mpurzynski

This comment has been minimized.

Copy link
Contributor Author

mpurzynski commented Feb 6, 2019

Indeed, some form of identification would be nice. Any threat actor could use that, but at least it will not raise the blood pressure in the middle of the night.

The Zeek's roadmap shows broctl going away, anyway, so feel free to do whatever you feel like doing.

@JustinAzoff

This comment has been minimized.

Copy link
Contributor

JustinAzoff commented Feb 6, 2019

I'm sorry for writing that :-)

Older broctl opened one ssh connection for each remote command it would run, so if you had 30 workers a broctl start would run 30 ssh commands like ssh node ... run-bro

I had originally wanted to use ssh sessions to multiplex the commands over a single connection, but it turns out the sshd option 'MaxSessions' defaults to 10 so that would have required everyone to edit sshd_config to support more than 10 workers. Plan B was the multiplexer, and since there was no easy way to tell if the remote node had been setup yet, the program was just serialized onto the command line so it would always work.

@jsiwek jsiwek added this to the 2.7 milestone Feb 6, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment