JSFuck XSS

JSFuck을 이용한 XSS와 동작 원리 살펴보기

혹시 이런 XSS 코드 많이들 사용하시나요? 저는 개인적으로 Js 코드 탈출 이후 특수문자~문자열 등 원하는 구문 삽입이 어려울 떄 종종 사용하는 방법입니다.

// alert(1)
this[(+{}+[])[+!![]]+(![]+[])[!+[]+!![]]+([][+[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]](++[[]][+[]])

// alert(1)
this[(+{}+[])[-~[]]+(![]+[])[-~-~[]]+([][+[]]+[])[-~-~-~[]]+(!![]+[])[-~[]]+(!![]+[])[+[]]]((-~[]+[]))

필터링 규칙에 따라 페이로드를 숨기는 방법이 여러가지가 있지만 이 방법은 [ ] ( ) + ! 등으로만 코드를 구성할 수 있기 때문에 때에따라 요긴하게 사용되기도 합니다. 그냥 Js가 동작할 수 있는 하나의 구문이구나 하고 넘기고, 테스트할 때 사용하기만 했었느데 오늘은 어떻게 저런 코드가 동작할 수 있는 코드가 되었는지 정리해볼까 합니다.

JSFuck

처음 제가 저 코드를 봤을때 생각났던게 바로 아희 같다 라는 느낌이였습니다.

helloworld..
뱔뿌둬뱺쀠더빠뚜
터벚봃떠빠뷹붏뼤
나퍄따쀄븈뵳두받
붏타볻뚜벓탸볐밢
떠볽뻐뷦투희맣어

정말 난해한 언어지요? 이렇게 난해한 언어가 여러가지가 존재하며 나름대로 쭉 이어져오고 있습니다. JSFuck도 이런 언어들 중 하나입니다. Martin Kleppe가 만든 난해한 스타일 언어이며 별도의 컴파일러, 인터프리터 없이 Javascript engine 으로 동작 가능한 언어입니다.

알파벳 없이 아래 특수문자(( ) [ ] + ! .)들로만 코드를 작성할 수 있고 각 문자나 기호를 저런식으로 표현할 수 있습니다.

Char JS Fuck
+ (+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]])+[])[!+[]+!+[]]
. (+(+!+[]+[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+[!+[]+!+[]]+[+[]])+[])[+!+[]]
0 +[]
1 +!![] or +!+[]
2 !![]+!![] or !+[]+!+[]
3 !![]+!![]+!![] or !+[]+!+[]+!+[]
4 !![]+!![]+!![]+!![] or !+[]+!+[]+!+[]+!+[]
5 !![]+!![]+!![]+!![]+!![] or !+[]+!+[]+!+[]+!+[]+!+[]
6 !![]+!![]+!![]+!![]+!![]+!![] or !+[]+!+[]+!+[]+!+[]+!+[]+!+[]
7 !![]+!![]+!![]+!![]+!![]+!![]+!![] or !+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]
8 !![]+!![]+!![]+!![]+!![]+!![]+!![]+!![] or !+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]
9 !![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![] or !+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]
a (![]+[])[+!+[]]
d ([][[]]+[])[!+[]+!+[]]
e (!![]+[])[!+[]+!+[]+!+[]]
f (![]+[])[+[]]
i ([![]]+[][[]])[+!+[]+[+[]]]
I (+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+(+!+[])+(+[])+(+[])+(+[]))+[])[+[]]
l (![]+[])[!+[]+!+[]]
N (+[![]]+[])[+[]]
n ([][[]]+[])[+!+[]]
r (!+[]+[])[+!+[]]
s (![]+[])[!+[]+!+[]+!+[]]
t (!!+[]+[])[+[]]
u ([][[]]+[])[+[]]
y (+[![]]+[+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+(+!+[])+(+[])+(+[])+(+[]))])[+!+[]+[+[]]]
false ![]
true !![]
undefined [][[]]
NaN +[![]]
0 +[]
1 +!+[]
2 !+[]+!+[]
10 [+!+[]]+[+[]]
Array []
Number +[]
String []+[]
Boolean ![]
Function [][“filter”]
eval [][“filter”]“constructor”()
window [][“filter”]“constructor”()

이를 이용하면 위에서 보셨던 payload 구성이 가능해지는거죠.

Why is it working?

제가 가장 궁금증이 든 부분은 바로 이거입니다.

Javascript에서 의도한 언어 포맷은 아닌데 어떻게 동작할 수 있을까?

알고보니 생각보다 심플했는데 JS 자체의 기능들을 이용해서 문자를 만들고 더해 Javascript 구문으로 사용하는 것이였습니다. 대표적인게 괄호를 문자열로 바꾸는 방법입니다.

  []        +[] // "" - empty string
 +[]        +[] // "0"
  [][[]]    +[] // "undefined"
++[][[]]    +[] // "NaN
++[[]][+[]] +[] // "1"

10["toString"](36) // "a"
11["toString"](36) // "b"
...
34["toString"](36) // "y"
35["toString"](36) // "z"

  "undefined"          [  0] // "u"
[ "undefined"    ][  0][  0] // "u"
[  undefined +[] ][+[]][+[]] // "u"
[  [][+[]]   +[] ][+[]][+[]] // "u"  => 풀어서 보면 [  [][+[]]   +[] ] 의 [0][0] 값, 즉 u를 가져오도록..

숫자도 가능하겠지요

true >> false         // 1
true << true          // 2
true << true << true  // 4

타입도 이렇게 가능합니다. 이거 보니깐 alert 우회패턴들 생각나네요 :D

0       ["constructor"] // Number
""      ["constructor"] // String
[]      ["constructor"] // Array
false   ["constructor"] // Boolean
[].find ["constructor"] // Function

이외에는 많은 방법들이 있으며 아래 링크들 참고하시면 도움됩니다.

References