SHCTF 2023 week2 web ez_rce
本文最后更新于:2024年10月23日 晚上
[SHCTF 2023] week2 web ez_rce
题目源码(附件)如下:
1 |
|
代码审计
以下内容来自文心一言
整体
这段代码是一个基于 Flask 的 web 服务程序,它允许用户通过 web 请求执行一些操作。以下是代码的逐行详细分析:
from flask import *
:从 Flask 模块导入所有内容。这将导入 Flask 框架的所有功能和类。import subprocess
:导入 subprocess 模块,这个模块允许你从 Python 代码中执行外部命令。app = Flask(__name__)
:创建一个 Flask web 服务实例。4-7.
def gett(obj,arg):
:定义一个函数 gett,它接收两个参数,一个对象和一个参数列表。函数通过 getattr 函数递归地获取对象的属性。8-12.
def sett(obj,arg,num):
:定义一个函数 sett,它接收一个对象,一个参数列表和一个数值。函数通过 getattr 函数递归地获取对象的属性,并使用 setattr 函数设置最后一个属性的值。13-19.
def hint(giveme,num,bol):
:定义一个函数 hint,它接收一个参数列表,一个数值和一个布尔值。函数首先使用 gett 函数获取 subprocess 模块的某个属性,然后修改这个属性的某个元素的值,并使用 sett 函数设置新的值。20-22.
def cmd(arg):
:定义一个函数 cmd,它接收一个参数列表,并使用 subprocess.call 函数执行外部命令。24-34.
@app.route('/',methods=['GET','POST'])
:定义一个路由,处理 ‘/‘ 路径的 GET 和 POST 请求。请求处理函数首先检查请求参数 ‘exec’,如果它的值为 ‘ok’,则执行外部命令。否则,它从请求的 JSON 数据中获取一个表达式列表,一个数值和一个布尔值,并使用 hint 函数修改 subprocess 模块的某个属性的值。35-37.
if __name__ == '__main__':
:如果代码作为主程序运行,则启动 Flask web 服务,监听所有 IP 地址的 5000 端口。总的来说,这段代码的功能比较模糊,它似乎允许用户通过 web 请求执行外部命令,并修改 subprocess 模块的某些属性的值。这可能是一个潜在的安全风险,因为恶意用户可以利用这个功能执行任意命令。
hint() 、gett()、sett()
hint
、gett
和sett
三个函数结合在一起,可以实现通过字符串形式的属性名来动态地获取和设置对象的属性值。
gett
函数通过递归调用getattr
函数,可以获取对象的嵌套属性。例如,如果有一个对象obj
,它有一个属性a
,属性a
又有一个属性b
,那么我们可以通过调用gett(obj, ['a', 'b'])
来获取obj.a.b
的值。
sett
函数和gett
函数类似,它也可以通过递归调用getattr
函数来获取对象的嵌套属性,然后使用setattr
函数来设置最后一个属性的值。例如,如果我们要将obj.a.b
的值设置为123
,可以通过调用sett(obj, ['a', 'b'], 123)
来实现。
hint
函数则是利用了gett
和sett
函数来实现对subprocess
模块的某个属性的修改。它首先用gett
函数获取到属性的值,然后修改其中的某个元素,最后再用sett
函数设置回去。举一个例子来说明这三个函数的结合使用:
假设我们有一个对象
obj
,它有一个嵌套属性a.b.c
,我们想要将其值设置为True
。可以先通过gett(obj, ['a', 'b'])
获取到obj.a.b
的值,然后将其属性c
设置为True
,最后再通过sett(obj, ['a', 'b'], new_value)
将新的值设置回去。其中,new_value
就是修改后的obj.a.b
的值。以上就是对
hint
、gett
和sett
三个函数的结合分析和例子说明。
subprocess.call()
执行由参数提供的命令,返回状态码
我们可以用数组作为参数运行命令,也可以用字符串作为参数运行命令(通过设置参数shell=True)
注意,参数shell默认为False
解题
执行命令
利用subprocess.call()
执行命令需要其默认参数shell=True
而hint()
函数恰好提供了对应的功能
接下来就是设法找到shell参数的位置
寻找shell参数的位置
在python中,函数也是一种对象
Python确实有一个内置类型叫做 “function”,它代表了Python中的函数对象。
函数对象在Python中是一等公民,这意味着它们可以被赋值给变量,作为参数传递给其他函数,以及作为返回值返回。函数对象还具有一些内置方法和属性,例如
__name__
、__doc__
和__call__
。
其中一个内置方法:
__defaults__
:函数的默认参数值的元组
然而,这还不够
1 |
|
None表示空
山重水复疑无路,柳暗花明又一村
查询subprocess
源码(subprocess.py):
1 |
|
注意到调用了Popen()
并把参数传了过去
popen
是一个对象(类)
这样操作会调用Popen
中的魔术方法__init__
其参数中同样有我们想要修改的shell
参数
1 |
|
1 |
|
经多次测试,其中下标为7处的元素为默认参数shell
的值
更改参数脚本:
1 |
|
获取回显
根据代码逻辑
命令执行是没有回显的
此时可以使用dns/http外带
dns/http外带
需要平台
比如CEYE - Monitor service for security testing
burpsuit也有类似功能
具体:带外攻击OOB(RCE无回显骚思路总结)-腾讯云开发者社区-腾讯云 (tencent.com)
payload:
1 |
|
命令执行过程:
1 |
|
Payload
先执行:
1 |
|
再执行:
1 |
|
引用
本文引用几乎全部来自文心一言 (baidu.com)