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
이외에는 많은 방법들이 있으며 아래 링크들 참고하시면 도움됩니다.