-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
239 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
# pwnboard | ||
# PWNboard | ||
CCDC Red Team PWNboard | ||
|
||
![PWNboard](https://raw.githubusercontent.com/ztgrace/pwnboard/master/img/PWNboard.png) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#!/usr/bin/env python | ||
|
||
import redis | ||
import random | ||
from pwnboard import getTimeDelta | ||
import datetime as dt | ||
import time | ||
import string | ||
|
||
r = redis.StrictRedis(host='localhost') | ||
for team in range(21, 31): | ||
for host in (3, 9, 11, 23, 27, 39, 240, 241, 254): | ||
if random.randint(1, 10) % 2 == 0: | ||
continue | ||
|
||
ip = "172.25.%i.%i" % (team, host) | ||
status = dict() | ||
status['host'] = "RT%i" % random.randint(1,5) | ||
if random.randint(1, 10) % 3 == 0: | ||
status['type'] = "meterpreter" | ||
status['session'] = random.randint(1,100) | ||
status['last_seen'] = None | ||
elif random.randint(1, 10) % 2 == 0: | ||
status['type'] = "backdoor" | ||
status['session'] = random.choice(('root', 'admin' 'nobody')) | ||
status['last_seen'] = time.mktime((dt.datetime.now() - dt.timedelta(minutes=random.randint(1, 10))).timetuple()) | ||
else: | ||
status['type'] = "empire" | ||
status['session'] = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(8)) | ||
status['last_seen'] = time.mktime((dt.datetime.now() - dt.timedelta(minutes=random.randint(1, 10))).timetuple()) | ||
|
||
r.hmset(ip, status) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
#!/usr/bin/env python2 | ||
|
||
from flask import Flask, request, render_template, flash, url_for, make_response | ||
import redis | ||
import datetime | ||
|
||
TEAMS = range(21, 33) | ||
HOSTS = (3,9,11,23,27,39,100) | ||
NETWORK = "172.25" | ||
|
||
r = redis.StrictRedis(host='localhost') | ||
app = Flask(__name__, static_url_path='/static') | ||
app.debug = True | ||
|
||
@app.route('/', methods=['GET']) | ||
def index(): | ||
error = "" | ||
board = getBoardDict() | ||
resp = make_response(render_template('index.html', error=error, board=board, teams=sorted(TEAMS), hosts=sorted(HOSTS), network=NETWORK)) | ||
return resp | ||
|
||
def getBoardDict(): | ||
board = dict() | ||
for team in TEAMS: | ||
board[team] = dict() | ||
for host in HOSTS: | ||
ip = NETWORK + ".%i.%i" % (team, host) | ||
h, s, t, last = r.hmget(ip, ('host', 'session', 'type', 'last_seen')) | ||
status = dict() | ||
status['host'] = h | ||
status['session'] = s | ||
status['type'] = t | ||
if isinstance(last, type(None)): | ||
#print "last: %s" % last | ||
status['last_seen'] = None | ||
else: | ||
print "last: %s" % last | ||
status['last_seen'] = getTimeDelta(last) | ||
board[team][ip] = status | ||
|
||
return board | ||
|
||
def getTimeDelta(ts): | ||
try: | ||
checkin = datetime.datetime.fromtimestamp(float(ts)) | ||
except: | ||
return 0 | ||
diff = datetime.datetime.now() - checkin | ||
minutes = int(diff.total_seconds()/60) | ||
return minutes | ||
|
||
|
||
|
||
@app.route('/slack-events', methods=['POST']) | ||
def slack_events(): | ||
res = request.json | ||
if res.get('challenge', None): | ||
return request.json['challenge'] | ||
|
||
if res.get('event', None) and res.get('event')['channel'] == 'C92BL6PU4': | ||
process_shellz_event(res['event']) | ||
|
||
return "" | ||
|
||
|
||
def process_shellz_event(event): | ||
text = event['text'] | ||
if 'empire' in event['text']: | ||
parse_empire(event) | ||
else: | ||
parse_linux(event) | ||
|
||
def parse_linux(event): | ||
# "%s %s backdoor active on %s" | ||
text = event['text'] | ||
status = Status() | ||
status.ip = text.split(' ')[5] | ||
status.host = text.split(' ')[0] | ||
status.session = text.split(' ')[1] | ||
status.last_seen = event['ts'] | ||
|
||
print status | ||
status.save() | ||
|
||
def parse_empire(event): | ||
text = event['text'] | ||
status = Status(type='empire') | ||
if "new agent" in text: | ||
# kali new agent on 10.0.2.15; agent: HLT4VKEK; platform: Linux,kali,4.7.0-kali1-amd64,#1 SMP Debian 4.7.5-1kali3 (2016-09-29),x86_64; type: empire | ||
|
||
status.ip = text.split(' ')[4].replace(';', '') | ||
status.host = text.split(' ')[0] | ||
status.session = text.split(' ')[6].replace(';', '') | ||
status.last_seen = event['ts'] | ||
print status | ||
status.save() | ||
|
||
else: | ||
# kali empire agent EHUDM1C7 checked in | ||
session = text.split(' ')[3] | ||
status = Status(session=session, type='empire') | ||
status.ip = r.get(status.session) | ||
status.host, s, t, status.last_seen = r.hmget(status.ip, ('host', 'session', 'type', 'last_seen')) | ||
status.last_seen = event['ts'] | ||
print status | ||
status.save() | ||
|
||
|
||
class Status(object): | ||
def __init__(self, ip=None, host=None, session=None, type=None, last_seen=None): | ||
self.ip = ip | ||
self.host = host | ||
self.session = session | ||
self.type = type | ||
self.last_seen = last_seen | ||
|
||
self.redis = redis.StrictRedis(host='localhost') | ||
|
||
def __str__(self,): | ||
return "ip: %s, host: %s, session: %s, type: %s, last_seen: %s" % (self.ip, self.host, self.session, self.type, self.last_seen) | ||
|
||
def save(self,): | ||
r.hmset(self.ip, {'host': self.host, 'session': self.session, 'type': self.type, 'last_seen': self.last_seen}) | ||
if self.type == 'empire': | ||
r.set(self.session, self.ip) | ||
|
||
|
||
|
||
if __name__ == '__main__': | ||
app.run(host='0.0.0.0', port=80) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#!/usr/bin/env python | ||
|
||
import redis | ||
r = redis.StrictRedis(host='localhost') | ||
r.flushdb() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<html> | ||
<head> | ||
<title>PWNboard</title> | ||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha256-LA89z+k9fjgMKQ/kq4OO2Mrf8VltYml/VES+Rg0fh20=" crossorigin="anonymous"> <!-- Latest compiled and minified Bootstrap CSS --> | ||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> | ||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script> <!-- Latest compiled and minified JavaScript --> | ||
<link href='https://fonts.googleapis.com/css?family=Titillium+Web:600,400' rel='stylesheet' type='text/css' /> | ||
<link href='https://fonts.googleapis.com/css?family=Jura:400,600' rel='stylesheet' type='text/css' /> | ||
<link rel='stylesheet' href='/static/pwnboard.css' type='text/css' /> | ||
<meta http-equiv="refresh" content="10"> | ||
</head> | ||
<body> | ||
<div class="container text-center"> | ||
{% if error %} | ||
<p id="error" class="alert alert-danger">{{ error }}</p> | ||
{% endif %} | ||
{% block content %} | ||
{% endblock %} | ||
<h1 class="title">PWNboard</h1> | ||
</div> | ||
<div class="" style="width:100%"> | ||
<table class="table table-dark table-bordered"> | ||
<tr> | ||
<thead> | ||
<td>Hosts</td> | ||
{% for team in teams %} | ||
<td>Team {{ team - 20}}</td> | ||
{% endfor %} | ||
</tr> | ||
{% for host in hosts %} | ||
<tr> | ||
{% if host == 3 %} | ||
<td><b>2012</b></td> | ||
{% elif host == 9 %} | ||
<td><b>FILESERVER1</b></td> | ||
{% elif host == 11 %} | ||
<td><b>e-comm</b></td> | ||
{% elif host == 23 %} | ||
<td><b>Ubuntu DNS</b></td> | ||
{% elif host == 27 %} | ||
<td><b>DC</b></td> | ||
{% elif host == 39 %} | ||
<td><b>mail</b></td> | ||
{% elif host == 100 %} | ||
<td><b>PAN</b></td> | ||
{% else %} | ||
<td><b>Host</b></td> | ||
{% endif %} | ||
{% for team in teams %} | ||
{% set ip = network + ".%i.%i" % (team, host) %} | ||
{% if board.get(team, None) and board[team][ip]['type'] and board[team][ip]['last_seen'] < 5 %} | ||
<td class="bg-success"> | ||
{% else %} | ||
<td class="bg-danger"> | ||
{% endif %} | ||
<b>{{ip}}</b><br/> | ||
{% if board[team][ip]['type'] %} | ||
<span style="font-size: 0.8em;">host: {{ board[team][ip]['host']}}, session: {{board[team][ip]['session']}}, type: {{board[team][ip]['type']}}</span> | ||
<span style="font-size: 0.8em;">last seen: {{ board[team][ip]['last_seen'] }}m</span> | ||
{% endif %} | ||
</td> | ||
{% endfor %} | ||
</tr> | ||
{% endfor %} | ||
</table> | ||
</div> | ||
</body> | ||
</html> | ||
|