Implement detection of monkey on island or locally

Fix UI issue of cleanup
Kill all monkeys works
Implemented logic for V ticking
This commit is contained in:
Itay Mizeretz 2017-09-20 15:55:02 +03:00
parent 8bada60fcd
commit 95d35fc8aa
9 changed files with 84 additions and 26 deletions

View File

@ -5,6 +5,7 @@ from flask import Flask, send_from_directory, redirect, make_response
import flask_restful import flask_restful
from cc.database import mongo from cc.database import mongo
from cc.resources.client_run import ClientRun
from cc.resources.monkey import Monkey from cc.resources.monkey import Monkey
from cc.resources.local_run import LocalRun from cc.resources.local_run import LocalRun
from cc.resources.telemetry import Telemetry from cc.resources.telemetry import Telemetry
@ -75,6 +76,7 @@ def init_app(mongo_url):
api.add_resource(Root, '/api') api.add_resource(Root, '/api')
api.add_resource(Monkey, '/api/monkey', '/api/monkey/', '/api/monkey/<string:guid>') api.add_resource(Monkey, '/api/monkey', '/api/monkey/', '/api/monkey/<string:guid>')
api.add_resource(LocalRun, '/api/local-monkey', '/api/local-monkey/') api.add_resource(LocalRun, '/api/local-monkey', '/api/local-monkey/')
api.add_resource(ClientRun, '/api/client-monkey', '/api/client-monkey/')
api.add_resource(Telemetry, '/api/telemetry', '/api/telemetry/', '/api/telemetry/<string:monkey_guid>') api.add_resource(Telemetry, '/api/telemetry', '/api/telemetry/', '/api/telemetry/<string:monkey_guid>')
api.add_resource(MonkeyConfiguration, '/api/configuration', '/api/configuration/') api.add_resource(MonkeyConfiguration, '/api/configuration', '/api/configuration/')
api.add_resource(MonkeyDownload, '/api/monkey/download', '/api/monkey/download/', api.add_resource(MonkeyDownload, '/api/monkey/download', '/api/monkey/download/',

View File

@ -0,0 +1,22 @@
from flask import request, jsonify
import flask_restful
from cc.services.node import NodeService
__author__ = 'itay.mizeretz'
class ClientRun(flask_restful.Resource):
def get(self):
client_ip = request.remote_addr
if client_ip == "127.0.0.1":
monkey = NodeService.get_monkey_island_monkey()
else:
monkey = NodeService.get_monkey_by_ip(client_ip)
NodeService.update_dead_monkeys()
if monkey is not None:
is_monkey_running = not monkey["dead"]
else:
is_monkey_running = False
return jsonify(is_running=is_monkey_running)

View File

@ -48,7 +48,14 @@ def run_local_monkey():
class LocalRun(flask_restful.Resource): class LocalRun(flask_restful.Resource):
def get(self): def get(self):
return jsonify(is_running=(NodeService.get_monkey_island_monkey() is not None)) NodeService.update_dead_monkeys()
island_monkey = NodeService.get_monkey_island_monkey()
if island_monkey is not None:
is_monkey_running = not island_monkey["dead"]
else:
is_monkey_running = False
return jsonify(is_running=is_monkey_running)
def post(self): def post(self):
body = json.loads(request.data) body = json.loads(request.data)

View File

@ -1,5 +1,5 @@
import json import json
from datetime import datetime, timedelta from datetime import datetime
import dateutil.parser import dateutil.parser
from flask import request from flask import request
@ -14,19 +14,9 @@ __author__ = 'Barak'
# TODO: separate logic from interface # TODO: separate logic from interface
def update_dead_monkeys():
# Update dead monkeys only if no living monkey transmitted keepalive in the last 10 minutes
if mongo.db.monkey.find_one({'dead': {'$ne': True}, 'keepalive': {'$gte': datetime.now() - timedelta(minutes=10)}}):
return
mongo.db.monkey.update(
{'keepalive': {'$lte': datetime.now() - timedelta(minutes=10)}, 'dead': {'$ne': True}},
{'$set': {'dead': True, 'modifytime': datetime.now()}}, upsert=False, multi=True)
class Monkey(flask_restful.Resource): class Monkey(flask_restful.Resource):
def get(self, guid=None, **kw): def get(self, guid=None, **kw):
update_dead_monkeys() # refresh monkeys status NodeService.update_dead_monkeys() # refresh monkeys status
if not guid: if not guid:
guid = request.args.get('guid') guid = request.args.get('guid')
timestamp = request.args.get('timestamp') timestamp = request.args.get('timestamp')

View File

@ -5,6 +5,7 @@ import flask_restful
from cc.database import mongo from cc.database import mongo
from cc.services.config import ConfigService from cc.services.config import ConfigService
from cc.services.node import NodeService
from cc.utils import local_ip_addresses from cc.utils import local_ip_addresses
@ -30,10 +31,11 @@ class Root(flask_restful.Resource):
elif action == "killall": elif action == "killall":
mongo.db.monkey.update({}, {'$set': {'config.alive': False, 'modifytime': datetime.now()}}, upsert=False, mongo.db.monkey.update({}, {'$set': {'config.alive': False, 'modifytime': datetime.now()}}, upsert=False,
multi=True) multi=True)
return 200 return jsonify(status='OK')
else: else:
return make_response(400, {'error': 'unknown action'}) return make_response(400, {'error': 'unknown action'})
def get_completed_steps(self): def get_completed_steps(self):
# TODO implement is_any_exists = NodeService.is_any_monkey_exists()
return dict(run_server=True, run_monkey=False, infection_done=False) is_any_alive = NodeService.is_any_monkey_alive()
return dict(run_server=True, run_monkey=is_any_exists, infection_done=(is_any_exists and not is_any_alive))

View File

@ -1,4 +1,4 @@
from datetime import datetime from datetime import datetime, timedelta
from bson import ObjectId from bson import ObjectId
from cc.database import mongo from cc.database import mongo
@ -236,3 +236,22 @@ class NodeService:
{"_id": node_id}, {"_id": node_id},
{"$set": {"exploited": True}} {"$set": {"exploited": True}}
) )
@staticmethod
def update_dead_monkeys():
# Update dead monkeys only if no living monkey transmitted keepalive in the last 10 minutes
if mongo.db.monkey.find_one(
{'dead': {'$ne': True}, 'keepalive': {'$gte': datetime.now() - timedelta(minutes=10)}}):
return
mongo.db.monkey.update(
{'keepalive': {'$lte': datetime.now() - timedelta(minutes=10)}, 'dead': {'$ne': True}},
{'$set': {'dead': True, 'modifytime': datetime.now()}}, upsert=False, multi=True)
@staticmethod
def is_any_monkey_alive():
return mongo.db.monkey.find_one({'dead': False}) is not None
@staticmethod
def is_any_monkey_exists():
return mongo.db.monkey.find_one({}) is not None

View File

@ -47,7 +47,8 @@ class MapPageComponent extends React.Component {
this.state = { this.state = {
graph: {nodes: [], edges: []}, graph: {nodes: [], edges: []},
selected: null, selected: null,
selectedType: null selectedType: null,
killPressed: false
}; };
} }
@ -111,6 +112,12 @@ class MapPageComponent extends React.Component {
} }
} }
killAllMonkeys = () => {
fetch('/api?action=killall')
.then(res => res.json())
.then(res => this.setState({killPressed: (res.status=="OK")}));
}
render() { render() {
return ( return (
<div> <div>
@ -132,6 +139,12 @@ class MapPageComponent extends React.Component {
Kill All Monkeys Kill All Monkeys
</button> </button>
</div> </div>
{this.state.killPressed ?
<div className="alert alert-info">
<i className="glyphicon glyphicon-info-sign" style={{'marginRight': '5px'}}/>
Kill command sent to all monkeys
</div>
: ''}
<PreviewPane item={this.state.selected} type={this.state.selectedType} /> <PreviewPane item={this.state.selected} type={this.state.selectedType} />
</Col> </Col>

View File

@ -28,6 +28,13 @@ class RunMonkeyPageComponent extends React.Component {
.then(res => this.setState({ .then(res => this.setState({
isRunningOnIsland: res['is_running'] isRunningOnIsland: res['is_running']
})); }));
fetch('/api/client-monkey')
.then(res => res.json())
.then(res => this.setState({
isRunningLocally: res['is_running']
}));
this.props.onStatusChange(); this.props.onStatusChange();
} }
@ -99,16 +106,16 @@ class RunMonkeyPageComponent extends React.Component {
className="btn btn-default" className="btn btn-default"
disabled={this.state.isRunningOnIsland}> disabled={this.state.isRunningOnIsland}>
Run on C&C Server Run on C&C Server
{ !this.state.isRunningOnIsland ? { this.state.isRunningOnIsland ?
<Icon name="check" className="text-success" style={{'marginLeft': '5px'}}/> <Icon name="check" className="text-success" style={{'marginLeft': '5px'}}/>
: ''} : ''}
</button> </button>
<a href="/download-monkey" <a href="/download-monkey"
className="btn btn-default" className="btn btn-default"
disabled={this.state.isRunningLocally} disabled={this.state.isRunningLocally}
style={{'margin-left': '1em'}}> style={{'marginLeft': '1em'}}>
Download and run locally Download and run locally
{ !this.state.isRunningLocally ? { this.state.isRunningLocally ?
<Icon name="check" className="text-success" style={{'marginLeft': '5px'}}/> <Icon name="check" className="text-success" style={{'marginLeft': '5px'}}/>
: ''} : ''}
</a> </a>

View File

@ -41,18 +41,14 @@ class StartOverPageComponent extends React.Component {
); );
} }
cleanup() { cleanup = () => {
// TODO: fix
/*
this.setState({ this.setState({
cleaned: false cleaned: false
}); });
*/
fetch('/api?action=reset') fetch('/api?action=reset')
.then(res => res.json()) .then(res => res.json())
.then(res => { .then(res => {
if (res["status"] == "OK") { if (res["status"] == "OK") {
// TODO: fix this
this.setState({ this.setState({
cleaned: true cleaned: true
}); });