Skip to content

Commit

Permalink
Merge pull request #5 from D0g3-Lab/dev
Browse files Browse the repository at this point in the history
v1.0.2 release
  • Loading branch information
0akarma authored Dec 17, 2019
2 parents b047281 + dce437b commit 7eb45d3
Show file tree
Hide file tree
Showing 16 changed files with 132 additions and 97 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
1.0.2 / 2019-12-17
=================

* Fix error msgs when frpc is not start
* Change log-file name to plugin name
* Change get_mode() to an ext-function to avoid loop-call errors
* fix test challenge: `file-upl0ad` build error
* Change index logo to white
* Fix `Max Renewal Times` was set to constant 3600

1.0.1 / 2019-12-16
=================

* Adapt different mode for ctfd-matrix-scoreboard plugin
* Fix some bugs (#3)

1.0.0 / 2019-12-1
=================

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ <h1>Scoreboard has been frozen.</h1>
</th>
<th width="10%" rowspan="2"><b>Team</b>
</th>
<th width="5%" rowspan="2"><b>Affiliation</b>
</th>
<th width="5%" rowspan="2"><b>Score</b>
</th>
<!-- TODO: 可适应布局调整 -->
Expand Down
29 changes: 27 additions & 2 deletions CTFd/plugins/ctfd-owl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ named `ctfd-owl`.

**Max Renewal Time** 最大容器失效时间(超过会自动关闭容器)

![docker-setting-demo-w150](./assets/demo_img/owl-docker_shrink.png)


![docker-setting-demo-w150](./assets/demo_img/owl-docker_shrink.png)

**FRP Http Domain Suffix** FRP域名前缀(如开启动态域名转发必填)

Expand All @@ -35,10 +35,35 @@ named `ctfd-owl`.

**FRP Direct Maximum Port** 最大端口

**FRP Config Template** Frpc热重载配置头模版
**FRP Config Template** Frpc热重载配置头模版(如不会自定义,尽量按照默认配置)

```
[common]
token = random_this
server_addr = frps
server_port = 80
admin_addr = 0.0.0.0
admin_port = 7400
```

![frp-setting-demo-w150](./assets/demo_img/owl-frp_shrink.png)

### Add Challenge

**Challenge Type** 题目类型(选`dynamic_check_docker`)

**Deployment Type** 部署方式(选`SINGLE-DOCKER-COMPOSE`)

**Dirname** 题目所在文件夹(相对于`source`的相对路径)

**FRP Type** frp类型(`DIRECT`为ip直接访问,`HTTP`为域名访问)

**FRP Port** 题目内网端口(例子中为`80`)

![owl-challenges-demo-w150](./assets/demo_img/owl-challenges_shrink.png)



### Demo

![instance-demo-w150](./assets/demo_img/owl-instance_shrink.png)
Expand Down
44 changes: 27 additions & 17 deletions CTFd/plugins/ctfd-owl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import datetime, fcntl
from flask_apscheduler import APScheduler
import logging, os, sys
from .extensions import get_mode

def load(app):
# upgrade()
Expand All @@ -47,25 +48,25 @@ def load(app):
)

log_dir = app.config["LOG_FOLDER"]
logger_containers = logging.getLogger("containers")
logger_containers.setLevel(logging.INFO)
logger_owl = logging.getLogger("owl")
logger_owl.setLevel(logging.INFO)
logs = {
"containers": os.path.join(log_dir, "containers.log"),
"owl": os.path.join(log_dir, "owl.log"),
}
try:
for log in logs.values():
if not os.path.exists(log):
open(log, "a").close()
container_log = logging.handlers.RotatingFileHandler(
logs["containers"], maxBytes=10000
logs["owl"], maxBytes=10000
)
logger_containers.addHandler(container_log)
logger_owl.addHandler(container_log)
except IOError:
pass

stdout = logging.StreamHandler(stream=sys.stdout)
logger_containers.addHandler(stdout)
logger_containers.propagate = 0
logger_owl.addHandler(stdout)
logger_owl.propagate = 0

@owl_blueprint.route('/admin/settings', methods=['GET'])
@admins_only
Expand Down Expand Up @@ -108,15 +109,23 @@ def admin_expired_container():
ControlUtil.expired_container(user_id=user_id, challenge_id=challenge_id)
return jsonify({'success': True})

@owl_blueprint.route("/admin/containers", methods=['DELETE'])
@admins_only
def admin_delete_container():
user_id = request.args.get('user_id')
ControlUtil.destroy_container(user_id)
return jsonify({'success': True})

# instances
@owl_blueprint.route('/container', methods=['GET'])
@authed_only
def list_container():
user_id = ControlUtil.get_mode()
user_id = get_mode()
challenge_id = request.args.get('challenge_id')
ControlUtil.check_challenge(challenge_id, user_id)
data = ControlUtil.get_container(user_id=user_id)
configs = DBUtils.get_all_configs()
remain_time = int(configs.get("docker_max_renew_count"))
domain = configs.get('frp_http_domain_suffix', "")
if data is not None:
if int(data.challenge_id) != int(challenge_id):
Expand All @@ -129,31 +138,31 @@ def list_container():
if dynamic_docker_challenge.deployment == "single":
return jsonify({'success': True, 'type': 'redirect', 'ip': configs.get('frp_direct_ip_address', ""),
'port': data.port,
'remaining_time': 3600 - (datetime.datetime.utcnow() - data.start_time).seconds,
'remaining_time': remain_time - (datetime.datetime.utcnow() - data.start_time).seconds,
'lan_domain': lan_domain})
else:
if dynamic_docker_challenge.redirect_type == "http":
if int(configs.get('frp_http_port', "80")) == 80:
return jsonify({'success': True, 'type': 'http', 'domain': data.docker_id + "." + domain,
'remaining_time': 3600 - (datetime.datetime.utcnow() - data.start_time).seconds,
'remaining_time': remain_time - (datetime.datetime.utcnow() - data.start_time).seconds,
'lan_domain': lan_domain})
else:
return jsonify({'success': True, 'type': 'http',
'domain': data.docker_id + "." + domain + ":" + configs.get('frp_http_port', "80"),
'remaining_time': 3600 - (datetime.datetime.utcnow() - data.start_time).seconds,
'remaining_time': remain_time - (datetime.datetime.utcnow() - data.start_time).seconds,
'lan_domain': lan_domain})
else:
return jsonify({'success': True, 'type': 'redirect', 'ip': configs.get('frp_direct_ip_address', ""),
'port': data.port,
'remaining_time': 3600 - (datetime.datetime.utcnow() - data.start_time).seconds,
'remaining_time': remain_time - (datetime.datetime.utcnow() - data.start_time).seconds,
'lan_domain': lan_domain})
else:
return jsonify({'success': True})

@owl_blueprint.route('/container', methods=['POST'])
@authed_only
def new_container():
user_id = ControlUtil.get_mode()
user_id = get_mode()

if ControlUtil.frequency_limit():
return jsonify({'success': False, 'msg': 'Frequency limit, You should wait at least 1 min.'})
Expand All @@ -166,9 +175,10 @@ def new_container():
ControlUtil.check_challenge(challenge_id, user_id)
configs = DBUtils.get_all_configs()
current_count = DBUtils.get_all_alive_container_count()
print(configs.get("docker_max_container_count"))
if int(configs.get("docker_max_container_count")) <= int(current_count):
return jsonify({'success': False, 'msg': 'Max container count exceed.'})
# print(configs.get("docker_max_container_count"))
if configs.get("docker_max_container_count") != "None":
if int(configs.get("docker_max_container_count")) <= int(current_count):
return jsonify({'success': False, 'msg': 'Max container count exceed.'})

dynamic_docker_challenge = DynamicCheckChallenge.query \
.filter(DynamicCheckChallenge.id == challenge_id) \
Expand All @@ -183,7 +193,7 @@ def new_container():
@owl_blueprint.route('/container', methods=['DELETE'])
@authed_only
def destroy_container():
user_id = ControlUtil.get_mode()
user_id = get_mode()

if ControlUtil.frequency_limit():
return jsonify({'success': False, 'msg': 'Frequency limit, You should wait at least 1 min.'})
Expand Down
32 changes: 16 additions & 16 deletions CTFd/plugins/ctfd-owl/assets/create.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,23 @@
</label>
<input type="text" class="form-control" name="dirname" placeholder="Enter challenge dirname">
</div>
<div class="form-group">
<label for="value">CPU Limit<br>
<small class="form-text text-muted">
This is the cpu limit of container
</small>
</label>
<input type="text" class="form-control" name="cpu_limit" placeholder="Enter cpu limit of container" required>
</div>
<div class="form-group">
<label for="value">Memory Limit<br>
<small class="form-text text-muted">
This is the memory limit of container
</small>
</label>
<input type="text" class="form-control" name="memory_limit" placeholder="Enter memory limit of container" required>
<!-- <div class="form-group">-->
<!-- <label for="value">CPU Limit<br>-->
<!-- <small class="form-text text-muted">-->
<!-- This is the cpu limit of container-->
<!-- </small>-->
<!-- </label>-->
<!-- <input type="text" class="form-control" name="cpu_limit" placeholder="Enter cpu limit of container" required>-->
<!-- </div>-->
<!-- <div class="form-group">-->
<!-- <label for="value">Memory Limit<br>-->
<!-- <small class="form-text text-muted">-->
<!-- This is the memory limit of container-->
<!-- </small>-->
<!-- </label>-->
<!-- <input type="text" class="form-control" name="memory_limit" placeholder="Enter memory limit of container" required>-->

</div>
<!-- </div>-->
<div class="form-group">
<label for="value">FRP Type<br>
<small class="form-text text-muted">
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 16 additions & 16 deletions CTFd/plugins/ctfd-owl/assets/update.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@
</label>
<input type="text" class="form-control chal-name" name="deployment" value="{{ challenge.deployment }}">
</div>
<div class="form-group">
<label for="value">CPU Limit<br>
<small class="form-text text-muted">
This is the cpu limit of container
</small>
</label>
<input type="text" class="form-control" name="cpu_limit" placeholder="Enter cpu limit of container" value="{{ challenge.cpu_limit }}">
</div>
<div class="form-group">
<label for="value">Memory Limit<br>
<small class="form-text text-muted">
This is the memory limit of container
</small>
</label>
<input type="text" class="form-control" name="memory_limit" placeholder="Enter memory limit of container" value="{{ challenge.memory_limit }}">
<!-- <div class="form-group">-->
<!-- <label for="value">CPU Limit<br>-->
<!-- <small class="form-text text-muted">-->
<!-- This is the cpu limit of container-->
<!-- </small>-->
<!-- </label>-->
<!-- <input type="text" class="form-control" name="cpu_limit" placeholder="Enter cpu limit of container" value="{{ challenge.cpu_limit }}">-->
<!-- </div>-->
<!-- <div class="form-group">-->
<!-- <label for="value">Memory Limit<br>-->
<!-- <small class="form-text text-muted">-->
<!-- This is the memory limit of container-->
<!-- </small>-->
<!-- </label>-->
<!-- <input type="text" class="form-control" name="memory_limit" placeholder="Enter memory limit of container" value="{{ challenge.memory_limit }}">-->

</div>
<!-- </div>-->
<div class="form-group">
<label for="value">FRP Type<br>
<small class="form-text text-muted">
Expand Down
9 changes: 0 additions & 9 deletions CTFd/plugins/ctfd-owl/control_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,6 @@
from flask import session

class ControlUtil:
@staticmethod
def get_mode():
mode = utils.get_config("user_mode")
if mode == "teams":
user_id = current_user.get_current_user().team_id
else:
user_id = current_user.get_current_user().id
return user_id

@staticmethod
def new_container(user_id, challenge_id):
rq = DockerUtils.up_docker_compose(user_id=user_id, challenge_id=challenge_id)
Expand Down
11 changes: 5 additions & 6 deletions CTFd/plugins/ctfd-owl/docker_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def up_docker_compose(user_id, challenge_id):
configs = DBUtils.get_all_configs()
basedir = os.path.dirname(__file__)
challenge = DynamicCheckChallenge.query.filter_by(id=challenge_id).first_or_404()
port = configs.get("frp_direct_port_minimum") + int(user_id)
port = str(int(configs.get("frp_direct_port_minimum")) + int(user_id))
flag = DockerUtils.gen_flag()
socket = DockerUtils.get_socket()
sname = os.path.join(basedir, "source/" + challenge.dirname)
Expand All @@ -51,7 +51,7 @@ def up_docker_compose(user_id, challenge_id):
docker_id = str(uuid.uuid3(uuid.NAMESPACE_DNS, name)).replace("-","")
msg = name + " up."
log(
"containers",
"owl",
"[{date}] {name} {msg}",
msg=msg,
)
Expand All @@ -60,11 +60,10 @@ def up_docker_compose(user_id, challenge_id):
# print(e)
msg = name + " up error." + str(e)
log(
"containers",
"owl",
"[{date}] {name} {msg}",
msg=msg,
)
logger.info(msg)
return False


Expand All @@ -85,15 +84,15 @@ def down_docker_compose(user_id, challenge_id):
os.system("rm -rf " + dname)
msg = name + " down."
log(
"containers",
"owl",
"[{date}] {name} {msg}",
msg=msg,
)
return True
except Exception as e:
msg = name + " up." + str(e)
log(
"containers",
"owl",
"[{date}] {name} {msg}",
msg=msg,
)
Expand Down
10 changes: 10 additions & 0 deletions CTFd/plugins/ctfd-owl/extensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from CTFd.utils import user as current_user
from CTFd import utils

def get_mode():
mode = utils.get_config("user_mode")
if mode == "teams":
user_id = current_user.get_current_user().team_id
else:
user_id = current_user.get_current_user().id
return user_id
13 changes: 8 additions & 5 deletions CTFd/plugins/ctfd-owl/frp_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,12 @@ def update_frp_redirect():
frp_api_ip = "frpc"
frp_api_port = "7400"
# print(output)
if configs.get("frpc_config_template") is not None:
requests.put("http://" + frp_api_ip + ":" + frp_api_port + "/api/config", output,
timeout=5)
requests.get("http://" + frp_api_ip + ":" + frp_api_port + "/api/reload", timeout=5)
else:
try:
if configs.get("frpc_config_template") is not None:
requests.put("http://" + frp_api_ip + ":" + frp_api_port + "/api/config", output,
timeout=5)
requests.get("http://" + frp_api_ip + ":" + frp_api_port + "/api/reload", timeout=5)
else:
pass
except Exception as e:
pass
Loading

0 comments on commit 7eb45d3

Please sign in to comment.