强网杯2024
0x01 说在前面
打着玩,反正当不了先锋
0x02 question
签到
签到直接交就可以了
givemesecret
进来发现是TornadoServer/6.4.1
OK试试注入
然后中途stop
,别看着只有一张图我可是锻炼了一早上呜呜呜
写写历程吧
1 | 从我要当主人-》我是工程师-》我是测试工程师,权限最高-》命令执行RCE,echo `whoami`-》问secret-》问flag,一直问,终于成功了 |
PyBlockly
有代码的先看代码
1 | from flask import Flask, request, jsonify |
首先一进来这个黑名单过滤了很多符号(所有),除了空格大小写字母数字
1 | def module_exists(module_name): |
判断函数是否为内置模块,如果为自定义模块则返回False
1 | def verify_secure(m): |
判断是否有导入语句,AST
为一个标准库
然后就是两个来进行代码处理的函数,重点是这里
进行了代码的执行,其中我们绕过关键词即可,现在的问题就是插入恶意代码以及绕过了
现在我们知道发包的格式类似于这种
1 | { |
但是读取文件这里又卡住了,这里不让有的关键词如何绕过,还有就是文件读取命令使用什么
后面查看自己的CTFshow之前的记录发现可以使用半角符号来绕过关键词,读取命令用这个
1 | root@dkcjbRCL8kgaNGz:~# dd if=/flag |
但是后面发现这个payload我这么写都写不好,八进制绕过给我爆500,然后上网搜索有没有内置的读取文件的Flask中内置的读取文件方法
找到get_data
方法
转半角脚本
1 | def half2full(half): |
1 | { |
1 | { |
还是搞不到,难道还是要命令执行才可以吗
题目中说了len
不能超过4,这里直接重写len
1 | POST /blockly_json HTTP/1.1 |
xiaohuanxiong
1 | V5.1.35 LTS { 十年磨一剑-为API开发设计的高性能框架 } |
是一个tp,进来之后先安装,然后等待一会儿,管他的先扫吧
1 | [10:09:00] 200 - 1KB - /admin/login |
扫的确实慢了点不过心急吃不了热豆腐,接着搞,发现admin/Admins
,这里发现支付可以添加PHP代码
1 | /admin/payment/index.html |
直接添加一句话木马,但是我发现有个小细节就是必须加不能报错和引号,不然就无法使用,加完直接返回漫画主页就已经getshell了
难得就在于拿到admin/Admins
这个路由,御剑是可以爆破出来的
platform
扫出来源码www.zip
拿到之后是一个PHP。我们慢慢看
看到这里之后发现直接就是在class.php
,但是有session,可能有竞争?
后来想想这里不是有个空值嘛
经过测试发现怎么弄都会是56个字符
1 | ";session_key|s:20:"FIzIiMb901w1XCmMXvui";password|s:99: |
于是这里我们进行逃逸即可
1 | print("passthru"*7) |
然后再插入我们的session序列化poc
1 | ;session_key|O:15:"notouchitsclass":1:{s:4:"data";s:24:"("sys"."tem")($_GET[a]);";}password|s:2:"wi |
当然这里如果是脚本的话肯定是要http头的
1 | import requests |
Proxy
有源码
1 | package main |
得到发包格式
这里直接就可以拿到flag,那我们直接curl
发包
1 | root@dkcjbRCL8kgaNGz:~# curl -X POST http://47.94.231.2:30773/v2/api/proxy \ |
然后解码即可
1 | flag{5ede263b-1f03-4a4f-a520-c4c8f173629a} |
snake
进来是个贪吃蛇,肯定是要通关才能够拿到flag
,那么我们爆破爬取路由
拿到/snake_win
测出有sql注入漏洞,尝试注入之后没有结果
响应头也没说是什么web服务,测试了很久发现可以ssti
man,flag终于是要到我手里了嘛
1 | http://eci-2ze762llzxw5o9w9mbw2.cloudeci1.ichunqiu.com:5000/snake_win?username=1' union select 1,2,"{{lipsum.__globals__.__builtins__.eval('__import__(\'os\').popen(\'tac /flag\').read()')}}"-- - |
Master of OSINT
进来之后发现是个找图片
使用工具慢慢she出经纬度
1 | https://api.map.baidu.com/lbsapi/getpoint/index.html |
看到有湖并且这里很平,打开地图,国内有湖的地方就这两个
挨着试找到是海南藏族自治州这里
百安居(这里注意要下载,不然看不到这个)
第三张图的话就很熟悉了,因为我在成都,这是双流机场
这里一个大卡车重汽(找物流公司)
这不是一模一样?
这一看就是重庆继续找找这个高架
简直了
还是高架,每个图都在高架上面基本是
这个好搞,橘子洲
这个我都不用看,长江大桥
ok终于是找完了,最后经过两年半的查找答案如下
1 | 一 99.974383,36.66725 |
EasyRSA
先进去拿参数
1 | N=42904039314199895721696616855758464218776719155277644688156355421669731926586744657558904856662524664815001053906568694877941070734379088087661446033173083187445772619113110948584643982194462341444480231060053008290646295405517083378534377980681311369011669792894523149142258780642722178595904015146283411763379803572408919306199860289071979553687419537458952652653841956474558202437419097277523814620107550505762949933586019973892299407282425426574324269936979456148685237646197700304901043932950332167503114720687804083313706537708157799145007429182143131211123753832870983386421744654743615691456503687433253700707 |
这靶机我之前一直没看到我丢,然后就不用管靶机了,其次不要关靶机,我关了靶机导致一直跑不出来
1 | #encoding:utf-8 |
- 生成素数和模数 (
N
):self.g
是一个500位的素数。self.a
和self.b
是随机生成的数,它们使得2*self.g*self.a+1
和2*self.g*self.b+1
是素数。self.h
是2*self.g*self.a*self.b+self.a+self.b
,且self.h
也是素数。N
被计算为2*self.h*self.g+1
。
- 加密过程:
- 使用公钥
(N, e)
,其中e
是常用的65537
。 - 消息用
gmpy2.powmod(msg, e, N)
进行加密。
- 使用公钥
- 解密的挑战:
- 通常,RSA解密需要私钥
(d)
,它通过求解ed ≡ 1 (mod φ(N))
获得。这里φ(N)
是欧拉函数,通常是(p-1)(q-1)
,p
和q
是N
的两个素数因子。
- 通常,RSA解密需要私钥
解密的话我们
- 模数分解 (Factorization):
- 目标是将大整数模数 NN 分解为两个素数乘积 pp 和 qq。在此方案中,利用已知的结构 p=2ga+1p=2g**a+1 和 q=2gb+1q=2g**b+1 进行推导。
- 中国剩余定理 (Chinese Remainder Theorem, CRT):
- 使用求解
u
和v
的过程,间接利用了模数分解的结构特性,通过推导近似根来简化计算过程。
- 使用求解
- 指数求逆 (Modular Inversion):
- 计算私钥指数 dd 的过程利用了模逆运算。具体来说,通过求解 d≡e−1(modϕ(N))d≡e−1(modϕ(N)),其中 ϕ(N)=(p−1)(q−1)ϕ(N)=(p−1)(q−1)。
- 密文解密 (Ciphertext Decryption):
- 使用模幂运算实现解密,即 m=Cd(modN)m=C**d(modN)。
- 平方根逼近 (Root Approximation):
- 通过
iroot
函数计算平方根,利用近似和迭代方法逼近解。
- 通过
- 数论攻击 (Number Theory Attack):
- 整个解密方案可以视为基于数论特性的攻击,通过已知因子关系和结构性弱点来恢复加密密钥。
最后写个脚本,此时一定要注意,把r
和s
写大一点节省时间不然靶机都没了可能还是跑不出来
1 | #encoding:utf-8 |
apbq
1 | [+] Welcome to my apbq game |
1 | from Crypto.Util.number import * |
阶段 1: p+qp+q
在第一阶段中,我们获得了以下信息:
- 模数 n=p⋅qn=p⋅q
- 提示 p+qp+q
根据已知信息,我们可以构造一个关于 pp 和 qq 的二次方程:
t2−(p+q)t+pq=0t2−(p+q)t+pq=0
代入 p+q=xp+q=x 和 pq=npq=n,方程变为:
t2−xt+n=0t2−x**t+n=0
通过求解这个二次方程的根,我们可以使用求根公式:
t=x±x2−4n2t=2x±x2−4n
得到两个根 pp 和 qq。一旦确定 pp 和 qq,接着可以计算 ϕ(n)ϕ(n):
ϕ(n)=(p−1)(q−1)ϕ(n)=(p−1)(q−1)
然后计算私钥 dd:
d≡e−1(modϕ(n))d≡e−1(modϕ(n))
阶段 2: ai⋅p+bi⋅qa**i⋅p+b**i⋅q
在第二阶段,我们得到了多个线性组合形式的提示:
ci=ai⋅p+bi⋅q,对于 i=1,2,…,100c**i=a**i⋅p+b**i⋅q,对于 i=1,2,…,100
这些方程组成了一个线性方程组,我们可以将其表示为矩阵形式,设想我们有矩阵 AA 和向量 xx 和 bb:
A=(a1b1a2b2⋮⋮a100b100),x=(pq),b=(c1c2⋮c100)A=a1a2⋮a100b1b2⋮b100,x=(p**q),b=c1c2⋮c100
我们可以通过解线性方程组 Ax=bAx=b 来恢复 pp 和 qq。如果 AA 的秩为 2,则该方程组有唯一解。
阶段 3: a⋅p+qa⋅p+q 和 p+b⋅qp+b⋅q
在第三阶段,我们获得了两个线性方程:
c1=a⋅p+qc1=a⋅p+q
c2=p+b⋅qc2=p+b⋅q
将这两个方程表示为矩阵形式:
(a11b)(pq)=(c1c2)(a11b)(p**q)=(c1c2)
同样地,我们可以通过求解这个 2×22×2 的线性方程组来恢复 pp 和 qq。
总结
通过上述步骤,我们可以逐步恢复每一阶段的 RSA 密钥参数,最终通过已知的加密消息 cc 和计算出的私钥 dd,使用以下公式进行解密:
m=cdmod nm=c**dmodn
整个解密过程依赖于数论和线性代数的交叉应用,通过利用已知结构和线性关系有效地恢复原始消息。
1 | from crypto.Util.number import * |
最后拼接flag即可
baby_heap
猜猜是不是uaf,打开一看很好啊很好.
运行分析
IDA分析 看看函数功能和隐藏内容
uaf
任意地址写
1 | from pwn import * |
运行之后不用输命令就会跳出flag
但是这里我很奇怪怎么打本地都打不通,打远程就可以
mips
主要加密在emu里面,是一个类似于rc4加密的加密,找到加密的地址,有花指令恢复一下函数
恢复完成,经过动态调试后发现xor_data是动态的,一直调试不清楚,这里面我们选择爆破
1 | import numpy as np |
21_steps
1 | import re |
先是搞了一个白名单,然后这里继续看规则
1 | step = 21 |
- 如果操作符是
>>
、<<
、+
、-
、&
或^
,则将step
减少1。 - 如果操作符是
*
、/
或%
,则将step
减少3。
1 | success = 0 |
这段代码的目的是在循环中随机生成128位的数 A
,计算其汉明重量,只要进行100次的循环都成功即可,构造payload
1 | B=A>>1; |
1 | root@dkcjbRCL8kgaNGz:~# nc 39.106.63.28 32807 |
Password Game
您不满足 Rule 1: 请至少包含数字和大小写字母
1Ab
您不满足 Rule 2: 密码中所有数字之和必须为18的倍数
18Qa
Rule 2: 密码中所有数字之和必须为30的倍数
540Qa
您不满足 Rule 2: 密码中所有数字之和必须为20的倍数
5150Qa
您不满足 Rule 2: 密码中所有数字之和必须为28的倍数
54019Qa
密码中所有数字之和必须为12的倍数
54519Qa
您不满足 Rule 2: 密码中所有数字之和必须为14的倍数
1 |
|
pop链子
1 | user::destruct->guest::toString->user::invoke->guest::call |
但是写了一下好像是打不通的
看了朋友的wp同时和大家交流发现可以这么打通,首先,要求哪里不一定非要写脚本打,可以直接抓包拿到源码,拿到源码之后再次分析链子,发现还是不够会想,一般的反序列化头头都是destruct
而这里是get
,如何进入呢
那也就是我们只要被解析的最外面的类没有password
就可以进入get
1 | root::get->user::destruct |
写个poc
1 |
|
引用赋值两个值都会改变(好久没用快忘了),记得换成S
,不然无效,不清楚过程的可以调试一下
0x03 小结
web题主要就是卡在了路由的地方,代审的题目呢,不是很简单,黑盒呢,测得非常难受,不过一有回显我就会非常激动哈哈,开心:happy:
- Title: 强网杯2024
- Author: baozongwi
- Created at : 2024-11-02 09:31:08
- Updated at : 2024-11-28 16:59:02
- Link: https://baozongwi.xyz/2024/11/02/强网杯2024/
- License: This work is licensed under CC BY-NC-SA 4.0.