티스토리 뷰
최종 수정: 2015-11-08
hackability@TenDollar
안녕하세요. Hackability 입니다.
이번에 포스팅 할 내용은 2015 School CTF 의 Reverse 400 문제 입니다.
개인적으로 이번 School CTF 에서 가장 흥미로웠던 문제였습니다.
문제에 HTML과 Javascript 파일을 제공하는데 이 javascript 를 리버싱 하는것이 문제였습니다.
문제 HTML 코드는 다음과 같습니다. (HTML 코드는 별거 없음)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <html> <head> <title>JSMachine</title> <meta charset="UTF-8"> <script type='text/javascript' src='Machine.js'></script> </head> <body> <h1>Secret key</h1><br/> <h2>Test your luck! Enter valid string and you will know flag!</h2><br/> <input type='text'></input><br/> <br/> <input type='button' onclick="check()" value='Проверить'></button> </body> </html> | cs |
문제의 Javascript 코드는 다음과 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | function createRegisters(obj){ obj.registers = []; for(i=0; i < 256; ++i){ obj.registers.push(0); } }; function Machine() { createRegisters(this); this.code = [0] this.PC = 0; this.callstack = []; this.pow = Math.pow(2,32) }; Machine.prototype = { opcodesCount: 16, run: run, loadcode: function(code){this.code = code}, end: function(){this.code=[]} }; function run(){ while(this.PC < this.code.length){ var command = parseCommand.call(this) command.execute(this); } //this.end() } function getOpcodeObject(){ var opNum = (this.code[this.PC] % this.opcodesCount); this.PC += 1; return eval('new Opcode'+opNum); } function parseCommand(){ var opcode = getOpcodeObject.call(this); opcode.consumeArgs(this); return opcode; } var opcCreate = ""; for(i=0;i<16;++i){ opcCreate += "function Opcode"+i+"(){this.args=[]}\n"; } eval(opcCreate); function makeFromImm(obj) { var res = obj.code[obj.PC + 2]; res <<=8; res += obj.code[obj.PC + 1]; res <<=8; res += obj.code[obj.PC]; res <<=8; res += obj.code[obj.PC+3]; res = res >>> 0; return res; } function getRegImm(obj){ this.args[0] = obj.code[obj.PC]; obj.PC += 1; this.args[1] = makeFromImm(obj); obj.PC += 4; } function getImm(obj){ this.args[0] = makeFromImm(obj); obj.PC += 4; } function getTwoRegs(obj){ this.args[0] = obj.code[obj.PC]; obj.PC += 1; this.args[1] = obj.code[obj.PC]; obj.PC += 1; } function getThreeRegs(obj){ this.args[0] = obj.code[obj.PC]; obj.PC += 1; this.args[1] = obj.code[obj.PC]; obj.PC += 1; this.args[2] = obj.code[obj.PC]; obj.PC += 1; } function getRegString(obj){ this.args[0] = obj.code[obj.PC]; obj.PC += 1; this.args[1] = getString(obj); } function getRegRegString(obj){ this.args[0] = obj.code[obj.PC]; obj.PC += 1; this.args[1] = obj.code[obj.PC]; obj.PC += 1; this.args[2] = getString(obj); } function getRegTwoString(obj){ this.args[0] = obj.code[obj.PC]; obj.PC += 1; this.args[1] = getString(obj); this.args[2] = getString(obj); } function getString(obj){ var res = ""; while(obj.code[obj.PC] != 0) { res += String.fromCharCode(obj.code[obj.PC]); obj.PC += 1; } obj.PC += 1; return res; } Opcode0.prototype = { consumeArgs : function(obj){}, execute: function(){} }; Opcode1.prototype = { consumeArgs: getRegImm, execute: function(obj){ obj.registers[this.args[0]] = (obj.registers[this.args[0]] + this.args[1]) % 0x100000000; } } Opcode2.prototype = { consumeArgs: getTwoRegs, execute: function(obj){ obj.registers[this.args[0]] = (obj.registers[this.args[0]] + obj.registers[this.args[1]]) % 0x100000000; } } Opcode3.prototype = { consumeArgs: getRegImm, execute: function(obj){ obj.registers[this.args[0]] = ((obj.registers[this.args[0]] - this.args[1]) % 0x100000000) >>> 0; } } Opcode4.prototype = { consumeArgs: getTwoRegs, execute: function(obj){ obj.regsiters[this.args[0]] = ((obj.registers[this.args[0]] - this.registers[this.args[1]])%100000000) >>> 0 } } Opcode5.prototype = { consumeArgs: getThreeRegs, execute: function(obj){ var mult = obj.registers[this.args[0]] * obj.registers[this.args[1]]; console.log(mult.toString(16)); obj.registers[this.args[2]] = (mult / obj.pow) >>> 0; obj.registers[this.args[2]+1] = (mult & 0xffffffff) >>> 0; } } Opcode6.prototype = { consumeArgs: getThreeRegs, execute: function(obj){ var divs = obj.registers[this.args[0]] * obj.pow + obj.registers[this.args[0]+1]; obj.registers[this.args[2]] = (divs / obj.registers[this.args[1]]) >>> 0; obj.registers[this.args[2]+1]= (divs % obj.registers[this.args[1]]) >>> 0; } } Opcode7.prototype = { consumeArgs: getRegImm, execute: function(obj) { obj.registers[this.args[0]] = this.args[1]; } } Opcode8.prototype = { consumeArgs: getImm, execute: function(obj){ obj.callstack.push(obj.PC); obj.PC = this.args[0]; } } Opcode9.prototype = { consumeArgs: getImm, execute: function(obj){ obj.PC = (obj.PC + this.args[0]) % obj.code.length; } } Opcode10.prototype = { consumeArgs: function(){}, execute: function(obj){ obj.PC = obj.callstack.pop(); } } Opcode11.prototype = { consumeArgs: getRegString, execute: function(obj){ obj.registers[this.args[0]] = eval('new '+this.args[1]); } } Opcode12.prototype = { consumeArgs: getRegTwoString, execute: function(obj){ obj.registers[this.args[0]][this.args[1]] = Function(this.args[2]); } } Opcode13.prototype = { consumeArgs: getRegRegString, execute: function(obj){ obj.registers[this.args[0]] = obj.registers[this.args[1]][this.args[2]]; } } Opcode14.prototype = { consumeArgs: getRegRegString, execute: function(obj){ obj.registers[this.args[1]][this.args[2]] = obj.registers[this.args[0]]; } } Opcode15.prototype = { consumeArgs: getRegRegString, execute: function(obj){ obj.registers[this.args[0]] = obj.registers[this.args[1]][this.args[2]](); } } function check(){ machine = new Machine; machine.loadcode([11, 1, 79, 98, 106, 101, 99, 116, 0, 12, 1, 120, 0, 114, 101, 116, 117, 114, 110, 32, 100, 111, 99, 117, 109, 101, 110, 116, 46, 103, 101, 116, 69, 108, 101, 109, 101, 110, 116, 115, 66, 121, 84, 97, 103, 78, 97, 109, 101, 40, 39, 105, 110, 112, 117, 116, 39, 41, 91, 48, 93, 46, 118, 97, 108, 117, 101, 47, 47, 0, 15, 3, 1, 120, 0, 14, 3, 1, 117, 115, 101, 114, 105, 110, 112, 117, 116, 0, 12, 1, 121, 0, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 101, 110, 100, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, 41, 123, 116, 104, 105, 115, 46, 99, 111, 100, 101, 61, 91, 93, 59, 116, 104, 105, 115, 46, 80, 67, 61, 49, 55, 51, 125, 47, 47, 0, 15, 3, 1, 121, 0, 12, 1, 122, 0, 97, 108, 101, 114, 116, 40, 49, 41, 59, 47, 47, 11, 234, 79, 98, 106, 101, 99, 116, 255, 9, 255, 255, 255, 12, 10, 97, 108, 101, 114, 116, 40, 50, 41, 59, 47, 47, 12, 234, 120, 255, 118, 97, 114, 32, 102, 61, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 114, 101, 103, 105, 115, 116, 101, 114, 115, 91, 49, 93, 46, 117, 115, 101, 114, 105, 110, 112, 117, 116, 47, 47, 10, 118, 97, 114, 32, 105, 32, 61, 32, 102, 46, 108, 101, 110, 103, 116, 104, 47, 47, 10, 118, 97, 114, 32, 110, 111, 110, 99, 101, 32, 61, 32, 39, 103, 114, 111, 107, 101, 39, 59, 47, 47, 10, 118, 97, 114, 32, 106, 32, 61, 32, 48, 59, 47, 47, 10, 118, 97, 114, 32, 111, 117, 116, 32, 61, 32, 91, 93, 59, 47, 47, 10, 118, 97, 114, 32, 101, 113, 32, 61, 32, 116, 114, 117, 101, 59, 47, 47, 10, 119, 104, 105, 108, 101, 40, 106, 32, 60, 32, 105, 41, 123, 47, 47, 10, 111, 117, 116, 46, 112, 117, 115, 104, 40, 102, 46, 99, 104, 97, 114, 67, 111, 100, 101, 65, 116, 40, 106, 41, 32, 94, 32, 110, 111, 110, 99, 101, 46, 99, 104, 97, 114, 67, 111, 100, 101, 65, 116, 40, 106, 37, 53, 41, 41, 47, 47, 10, 106, 43, 43, 59, 47, 47, 10, 125, 47, 47, 10, 118, 97, 114, 32, 101, 120, 32, 61, 32, 32, 91, 49, 44, 32, 51, 48, 44, 32, 49, 52, 44, 32, 49, 50, 44, 32, 54, 57, 44, 32, 49, 52, 44, 32, 49, 44, 32, 56, 53, 44, 32, 55, 53, 44, 32, 53, 48, 44, 32, 52, 48, 44, 32, 51, 55, 44, 32, 52, 56, 44, 32, 50, 52, 44, 32, 49, 48, 44, 32, 53, 54, 44, 32, 53, 53, 44, 32, 52, 54, 44, 32, 53, 54, 44, 32, 54, 48, 93, 59, 47, 47, 10, 105, 102, 32, 40, 101, 120, 46, 108, 101, 110, 103, 116, 104, 32, 61, 61, 32, 111, 117, 116, 46, 108, 101, 110, 103, 116, 104, 41, 32, 123, 47, 47, 10, 106, 32, 61, 32, 48, 59, 47, 47, 10, 119, 104, 105, 108, 101, 40, 106, 32, 60, 32, 101, 120, 46, 108, 101, 110, 103, 116, 104, 41, 123, 47, 47, 10, 105, 102, 40, 101, 120, 91, 106, 93, 32, 33, 61, 32, 111, 117, 116, 91, 106, 93, 41, 47, 47, 10, 101, 113, 32, 61, 32, 102, 97, 108, 115, 101, 59, 47, 47, 10, 106, 32, 43, 61, 32, 49, 59, 47, 47, 10, 125, 47, 47, 10, 105, 102, 40, 101, 113, 41, 123, 47, 47, 10, 97, 108, 101, 114, 116, 40, 39, 89, 79, 85, 32, 87, 73, 78, 33, 39, 41, 59, 47, 47, 10, 125, 101, 108, 115, 101, 123, 10, 97, 108, 101, 114, 116, 40, 39, 78, 79, 80, 69, 33, 39, 41, 59, 10, 125, 125, 101, 108, 115, 101, 123, 97, 108, 101, 114, 116, 40, 39, 78, 79, 80, 69, 33, 39, 41, 59, 125, 47, 47, 255, 9, 255, 255, 255, 12, 10, 97, 108, 101, 114, 116, 40, 51, 41, 59, 47, 47, 15, 1, 234, 120, 255, 9, 255, 255, 255, 12, 10, 97, 108, 101, 114, 116, 40, 52, 41, 59, 47, 47, 10, 97, 108, 101, 114, 116, 40, 53, 41, 59, 47, 47, 10, 97, 108, 101, 114, 116, 40, 54, 41, 59, 47, 47, 10, 97, 108, 101, 114, 116, 40, 55, 41, 59, 47, 47, 0, 12, 1, 103, 0, 118, 97, 114, 32, 105, 32, 61, 48, 59, 119, 104, 105, 108, 101, 40, 105, 60, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 99, 111, 100, 101, 46, 108, 101, 110, 103, 116, 104, 41, 123, 105, 102, 40, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 99, 111, 100, 101, 91, 105, 93, 32, 61, 61, 32, 50, 53, 53, 32, 41, 32, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 99, 111, 100, 101, 91, 105, 93, 32, 61, 32, 48, 59, 105, 43, 43, 125, 47, 47, 0, 12, 1, 104, 0, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 80, 67, 61, 49, 55, 50, 47, 47, 0, 15, 0, 1, 103, 0, 15, 0, 1, 104, 0]) machine.run(); } | cs |
javascript code 로 어셈블리처럼 동작하도록 만든 코드 입니다. (EIP 개념도 있고 Register 개념도 있고...)
문제는 check 함수에서 loadcode 할 시 저 바이트 코드 시퀀스가 어떤 행동을 하는지 아는게 문제 였습니다.
그래서 저는 저 바이트 코드 시퀀스는 Operator (Opcode) 와 Operand (Argument)로 구성되어 있다고 가정하고 자바 스크립트의 모든 Opcode prototype에 있는 execute function쪽에 console.log 를 찍었습니다.
예를들어,
1 2 3 4 5 6 7 | Opcode1.prototype = { consumeArgs: getRegImm, execute: function(obj){ console.log("Opcode1 executed : [" + obj.registers[this.args[0]].toString() + " + " + this.args[1]); obj.registers[this.args[0]] = (obj.registers[this.args[0]] + this.args[1]) % 0x100000000; } } | cs |
이런식으로 console.log 를 두게 되면 크롬 F12를 눌러 Console tab 에서 임시적으로 디버깅이 가능합니다. 모든 Opcode에 저렇게 달아 놓고 실행을 시키면 어떤 Opcode들이 호출이 되었고 어떤 순서로 호출되었으며 어떤 argument 들이 들어 갓는지 알 수 있습니다.
이미 이 로그만으로도 풀기 충분해 보입니다. 키 길이는 ex 와 동일하다는 조건문이 있기 때문에 20 글자 이며 위에서 nonce 를 "groke" 라고 주었고 사용자 입력 값과 xor 시킵니다. 결과적으로
nonce 변수 = X
사용자 입력 변수 = Y
최종 결과 변수 = Z
라고 한다면
X[i % 5] ^ Y[i] = Z[i], {i | i = 0 ... 19}
Y[i] = Z[i] ^ X[i % 5]
이를 파이썬 코드로 작성하면 다음과 같습니다.
1 2 3 4 5 | ex = [1, 30, 14, 12, 69, 14, 1, 85, 75, 50, 40, 37, 48, 24, 10, 56, 55, 46, 56, 60] nonce = "groke" for i in range(0, 20): print chr(ord(nonce[i%5]) ^ ex[i]), | cs |
f l a g i s : W O W _ s o _ E A S Y
'CTF_WriteUps > 2015_CTF' 카테고리의 다른 글
[2015_School_CTF] (Stegano 100) pure color (0) | 2015.11.08 |
---|---|
[2015_School_CTF] (Reverse 500) What's the hell?! (0) | 2015.11.08 |
[2015_School_CTF] (Reverse 300) Secret Galaxy (0) | 2015.11.08 |
[2015_School_CTF] (Reverse 200) Parallel Comparator (2) | 2015.11.08 |
[2015_School_CTF] (Exploit 500) Try to guess (0) | 2015.11.08 |
댓글
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- IE 10 리버싱
- expdev 번역
- 2014 SU CTF Write UP
- School CTF Write up
- IE 10 익스플로잇
- IE 11 UAF
- shellcode
- IE UAF
- IE 11 exploit
- School CTF Writeup
- 2015 School CTF
- IE 10 God Mode
- 윈도우즈 익스플로잇 개발
- TenDollar CTF
- IE 10 Exploit Development
- CTF Write up
- Windows Exploit Development
- 힙 스프레잉
- Use after free
- IE 11 exploit development
- shellcode writing
- Mona 2
- heap spraying
- UAF
- data mining
- TenDollar
- 데이터 마이닝
- 쉘 코드 작성
- WinDbg
- 쉘 코드
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
글 보관함