关于python安全性的问题
收集总结了⼀下python安全⽅⾯的知识点以及近年来的相关漏洞,如果有需要修正或补充的地⽅,欢迎各位师傅的指出。常见web漏洞在python中的⽰例。
xss
python下的xss其原理跟php是⼀样的,django近年的例⼦如下:
CVE-2017-12794,此例中通过抛出异常造成xss。
sql注⼊
⼀般来说使⽤django⾃带的操作数据库api是不会造成sql注⼊的,如下:
1Person.objects.filter(first_name=('user'))
不过django依然⽀持原⽣sql语法的使⽤⽅法,如下:
1 2 3 4 def index(request, *args, **kwargs):
for e in Person.objects.raw('select * from FIRST_Person '): print(e.first_name,e.last_name)
return render(request, 'home.html')
控制台结果如下:
1 2 3 asd sdf
mapl0 ppp
admin hahaha
如果代码如下:
1 2 3 4 def index(request, *args, **kwargs):
for e in Person.objects.raw('select * from FIRST_Person WHERE first_name = '+'"' + ('user') + '"'): print(e.last_name)
return render(request, 'home.html')
访问127.0.0.1:8000/?user=admin后控制台返回hahaha
⽽访问127.0.0.1:8000/?user=qqq%22%20or%20%221,控制台直接返回了
1 2 3 sdf
ppp
hahaha
代码/命令执⾏
除内建的模块,还有os,commands,subprocess,multiprocessing,pty,Cpickle/pickle,PyYAML等模块能代码/命令执⾏,详细可看下⽂。CSRF
django这类的框架⾃带csrf防护,不过在去年依然爆出csrf漏洞(知道创宇这篇分析很细致),如果django使⽤了Google Analytics则可能绕过django⾃带的csrf防护机制。
Django对于CSRF的防护就是判断cookie中的csrftoken和提交的csrfmiddlewaretoken的值是否相等,但是Google Analytics可以通过referer 帮我们设置⽤户的cookie,cookie⼀般如下:
1 utmz=123456.123456789.11.2.utmcsr=[HOST]|utmccn=(referral)|utmcmd=referral|utmcct=[PATH]
其中[HOST]和[PATH]是由Referer确定的,也就是说当
1Referer: x/helloworld
时,cookie如下:
1 z=123456.123456789.11.2.utmcsr=x|utmccn=(referral)|utmcmd=referral|utmcct=helloworld
django在当时的版本有cookie解析漏洞,当Cookie.SimpleCookie()解析a=hello]b=world这样的字符串时,就会取得a=hello和b=world,所以当Referer为x/hello]csrftoken=world,csrftoken就被成功赋值。
详细的,值得⼀看。
⽂件上传
在php环境下如果不限制上传⽂件后缀会导致getshell,但在django下,如果上传的⽂件能覆盖类似url.py,__init__.py的⽂件,攻击者能顺利getshell。参考。还有django只有在development server的模式下才会修改了⽂件就⽴刻重启,否则修改了⽂件也暂时⽆法⽣效。
当然除此之外还有其他⽅法,例如写cron(前提是有权限),和模板⽂件。
简单说⼀下写模板⽂件的过程:
需要在templatetags和templates分别写⼊⼀个⽂件(可能也不叫templatetags,可⾃⾏定义),templatetags⽂件夹内存放⾃定义标签,上传⽂件rce.py,代码如下:
1 2 3 4 5 6 7 from django import template
import os
register =template.Library()
@register.simple_tag
def some_function(value):
shell =os.system('touch mapl0') return shell
templates⽂件夹存放静态html⽂件,上传⽂件home.html如下:1
2 3 4 5 6 7 8 9 10 11 12 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% load rce %}
{% some_function "%s" as func %} <p> command is {{ func }} </p>
</body>
</html>
在view⾥,index会使⽤这个模板:
1 2 def index(request, *args, **kwargs): return render(request, 'home.html')
访问后,就在项⽬⽬录⽣成了mapl0⽂件。
可见使⽤限制很⼤,还需要⼀定的权限。⾸先,⽂件后缀没有限制,其次上传路径没有限制,templatetags⽬录已知,另外还需要有view使⽤这个模板。
另外xml和html⽂件的⾃由上传依然可以造成xxe和xss。
⽂件包含
相⽐之下⽂件包含⽐php少得多
重定向
django在今年爆出了两个重定向漏洞其中的CVE-2017-7233与urlparse有关,漏洞的说明可查看下⽂。
不安全模块及函数
内建函数
input():
python input() 相等于 eval(raw_input(prompt)) ,⽤来获取控制台的输⼊,在python3.0以后的版本中
取消raw_input,并⽤input代替.
1 2 value =input("hello ")
print("welcome %s"%(value,))
python2命令⾏下:
1 2 hello dir()
welcome ['__builtins__', '__doc__', '__file__', '__name__', '__package__']
python3命令⾏下:
1 2 hello dir()
welcome dir()
assert():
assert断⾔是声明其布尔值必须为真的判定,如果发⽣异常就说明表达⽰为假。
1 2 3 4 Traceback (most recent call last):
File"/Users/mapl0/Desktop/资料/sec.py", line 3, in<module> assert os.system('touch test')
AssertionError
报了个错误,但test⽂件已被建⽴
代码执⾏函数
eval:计算字符串中的表达式
exec:执⾏字符串中的语句
execfile:⽤来执⾏⼀个⽂件#python3中已⽆此函数
1 2 3 4 a ="print('eval:hello')"
b ="print('exec:hello')" eval(a)
exec(b)
python2和python3下结果⼀样
eval:hello
exec:hello
execfile('temp.bin')#temp.bin内容为print('execfile:hello')
结果
execfile:hello
os模块:
os.system
os.popen#和os.system的区别在于popen会把命令的输出作为返回值os.spawn
commands模块 :
subprocess模块 :
subprocess.Popen
subprocess.call通过⼦进程进⾏外壳注⼊
1 2 3 4 from subprocess import call
unvalidated_input ='/bin/true'#true命令啥都不做,只设置退出码为0
unvalidated_input +='; cut -d: -f1 /etc/passwd'
call(unvalidated_input, shell=True)#当shell=true时,shell命令可被当做多句执⾏。
运⾏结果
nobody
root
........ multiprocessing多进程模块 :
1 2 3 4 import multiprocessing
p =multiprocessing.Process(target=print, args=("hello"))#target参数为函数名,args为函数所需参数 p.start()
p.join()
运⾏结果
h e l l o
pty :
只能在linux\mac下使⽤的伪终端
1 2 import pty
pty.spawn('ls')
在python2\3下均可执⾏命令
其他有安全问题模块及函数
codecs :
codecs作⽤于各种编码之间的相互转换
1 2 3 4 5 6 7 8 9 10 import codecs
import io
b =b'\x41\xF5\x42\x43\xF4'
print("Correct-String %r") %((repr(b.decode('utf8', 'replace'))))
with open('temp.bin', 'wb') as fout:
fout.write(b)
with codecs.open('temp.bin', encoding='utf8', errors='replace') as fin: print("CODECS-String %r") %(ad()))
with io.open('temp.bin', 'rt', encoding='utf8', errors='replace') as fin: print("IO-String %r") %(ad()))
当b以⼆进制⽅式写⼊⽂件后,⽤codecs在进⾏读取,如果errors='replace'且编码形式为utf-8时,则对于xF5和xF4这类不能编码的都会被替换为\ufffd。
在python2下:
1 2 3 Correct-String "u'A\\ufffdBC\\ufffd'" CODECS-String "u'A\\ufffdBC'"
IO-String "u'A\\ufffdBC\\ufffd'"
在Python3下会报错:
1 2 print("Correct-String %r") %((repr(b.decode('utf8', 'replace'))))
TypeError: unsupported operand type(s) for%: 'NoneType'and'str'
ctypes :
ctypes是⼀个提供和C语⾔兼容的数据类型的外部库,当出现x00的空字符就会出现截断
1 2 3 4 5 import ctypes
ate_string_buffer(8) buffer.value='ab\x00c1234'
print(buffer.value)
print(buffer.raw)
在python2命令⾏下: ab
abc1234
在python3下回报错:
url编码和utf8区别1 2 buffer.value='ab\x00c1234'
TypeError: bytes expected instead of str instance
Python Interpreter :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!python
try:
if0:
yield5
print("T1-FAIL")
except Exception as e: print("T1-PASS")
pass
try:
if False:
yield5
print("T2-FAIL")
except Exception as e: print(repr(e))
pass
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论