乐趣区

关于python:保姆级Python教学万物皆可-API

明天看到一个开源我的项目,叫做 Command2API,感觉挺有意思的,分享给大家。

起源

对于这个我的项目为什么诞生,原 Repo 有这么一段:

以近期 Log4j 的 RCE 举例,在内网的平安测试中,因为网络环境限度导致没有 DNSLog 平台可用,这时候做 Log4j 的破绽验证就思考间接查看 LDAP 服务是否有连贯进来,然而现成的 JNDI 注入工具开启服务并没有 API 能够间接拉取对应服务的后果,这就导致须要人工去查看,很费时间,再加上曾经写好 BurpSuite 被动插件进行扫描了,为了节省时间就简略写了这个脚本用于获取 JNDI 工具的执行后果并通过 API 的模式返回,便于插件拉取后果进行破绽验证。

反正粗心就是说,有些命令的执行后果如果可能通过 HTTP 的 API 裸露进去,咱们就能更不便地获取到命令的执行后果,在某些场景下会十分不便。

所以,这里作者写了这个我的项目。

原理

这个原理其实非常简单,就是用一个 Python 线程开启 Web 服务,一个线程执行命令,通过全局变量与 Web 服务共享执行命令的后果。

运行

这里咱们来运行下看看成果吧。

首先须要下载下我的项目:

git clone https://github.com/gh0stkey/Command2API.git

而后接着指定想运行的命令和 API 运行的端口就好了,样例如下:

python Command2Api.py "执行的命令" Web 运行的端口 

留神,这里的 python 应用的 Python2,而不是 Python3,因为原我的项目援用了一个包叫 BaseHTTPServer,Python3 是没有的。

这里咱们执行一个 ping 命令来试试:

python Command2Api.py "ping www.baidu.com" 8888 

运行后果如下:

能够看到,这里首先输入了一个运行的地址:

URL: http://HOST:8888/c1IvlLF9

这时候咱们关上 http://localhost:8888/c1IvlLF9 看下。

能够看到控制台后果就出现在网页外面了。

然而这个页面没法主动刷新,须要点击刷新来获取最新的后果。

介绍完了。

所以,这个我的项目在某些状况下还是挺有用的。

比如说:

  • 内网平安测试中,能够用于获取 JNDI 工具的执行后果并通过 API 的模式返回,能够更不便地观测执行后果。
  • 咱们想监控或实时获取某个命令行程序的输入后果,比方 Scrapy 爬虫、比方 Web Server 等等,能够将其裸露进去。
  • 咱们想疾速分享某个程序的执行后果,则能够通过这个命令配合 Ngrok 生成一个网站分享进来。

等等。

源码解析

咱们再来看看源码吧,其实非常简单,一共就这些代码:

import subprocess
import BaseHTTPServer
import SimpleHTTPServer
import cgi
import threading
import sys
import string
import random

l = []

uri = '/' + ''.join(random.sample(string.ascii_letters+string.digits,8))

class thread(threading.Thread):
  def __init__(self, threadname, command):
    threading.Thread.__init__(self, name='Thread_' + threadname)
    self.threadname = int(threadname)
    self.command = command

  def run(self):
    global l
    ret = subprocess.Popen(
      self.command,
      shell=True,
      stdin=subprocess.PIPE,
      stdout=subprocess.PIPE,
      stderr=subprocess.PIPE
    )
    for i in iter(ret.stdout.readline, b""):
      res = i.decode().strip()
      print(res)
      l.append(res)

class ServerHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
  def do_GET(self):
    global l
    if self.path == uri:
      self.send_response(200)
      self.send_header('Content-Type', 'text/plain')
      self.end_headers()
      self.wfile.write(l)

if __name__ == '__main__':
  # New Thread: Get Command Result
  t1 = thread('1', sys.argv[1])
  t1.start()
  # Webserver
  port = int(sys.argv[2])
  print("URL: http://HOST:{0}{1}".format(port, uri))
  Handler = ServerHandler
  httpd = BaseHTTPServer.HTTPServer(('0.0.0.0', port), Handler)
  httpd.serve_forever()

能够看到这个命令就是 Popen 执行的,而后通过 PIPE 将后果捕捉进去赋值为变量,而后同时另外一个线程启动服务器,将这个后果写入到 Response 外面。

就是这么简略的代码,实现了如此便捷的性能。

优化

不过我看这个我的项目还是有很多优化空间的,简略总结下:

  • 当初反对的是 Python2 而不是 Python3。
  • 网页后果不能主动刷新。
  • 网页后果是一个列表,和控制台的后果格局不太对立。
  • 不能通过 pip 来平安这个工具包。
  • 输入后果的 HOST 能够优化一下,间接复制进去不好拜访。
  • 能够配合 Ngrok 将后果进行公开裸露。
  • 如果能通过网页来对命令进行交互管制就更好了。

我看看如果有工夫的话,我能够试着将这个我的项目改写下并实现如上的一些优化性能哈,到时候写完了收回来。

谢谢浏览~

退出移动版