├── secuinside2017 └── triplerotate │ ├── encrypt │ ├── prob │ ├── sol.pl │ ├── sol.py │ └── solution.md ├── sha2017_teaser ├── follow_stream.png ├── protocol_hierarchy.png ├── website_attack.md └── websiteattack.tar └── trendmicro2017 ├── for100 ├── README.md ├── output.pcap ├── scapy.py └── wireshark.png └── for200 ├── README.md ├── files10.enc └── unicorn_emulator.py /secuinside2017/triplerotate/encrypt: -------------------------------------------------------------------------------- 1 | 0 0 1 0 0 0 1 0 1 1 0 1 0 1 1 0 1 1 1 0 0 0 1 0 1 0 1 1 1 0 1 0 0 0 0 1 0 0 0 1 1 0 1 1 0 1 1 0 0 0 0 0 1 1 0 1 1 1 0 0 1 0 1 0 1 0 1 1 0 0 1 0 1 0 1 0 1 0 0 0 0 1 1 1 0 1 0 0 1 1 0 0 0 0 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 1 1 1 0 1 1 1 0 1 0 1 1 0 1 0 1 0 0 1 0 0 0 1 0 0 0 1 1 0 0 1 0 1 0 0 1 0 0 1 1 0 0 0 1 1 0 1 1 1 0 0 1 0 0 1 0 1 1 0 0 1 1 0 1 1 1 1 0 1 1 1 0 1 0 1 1 0 0 1 0 0 1 0 0 0 1 0 1 0 0 0 1 -------------------------------------------------------------------------------- /secuinside2017/triplerotate/prob: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koffiedrinker/writeups/4954bcd0db55422ca0ba874f49d8827cc8539fb3/secuinside2017/triplerotate/prob -------------------------------------------------------------------------------- /secuinside2017/triplerotate/sol.pl: -------------------------------------------------------------------------------- 1 | print 'SECU['; 2 | print pack("B*", ); 3 | print "]\n"; 4 | 5 | __DATA__ 6 | 010010010101111101001100001100000111011000110011010111110111101001000101 7 | -------------------------------------------------------------------------------- /secuinside2017/triplerotate/sol.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | length = 201 4 | s = Solver() 5 | 6 | arr_encrypted = "0 0 1 0 0 0 1 0 1 1 0 1 0 1 1 0 1 1 1 0 0 0 1 0 1 0 1 1 1 0 1 0 0 0 0 1 0 0 0 1 1 0 1 1 0 1 1 0 0 0 0 0 1 1 0 1 1 1 0 0 1 0 1 0 1 0 1 1 0 0 1 0 1 0 1 0 1 0 0 0 0 1 1 1 0 1 0 0 1 1 0 0 0 0 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 1 1 1 0 1 1 1 0 1 0 1 1 0 1 0 1 0 0 1 0 0 0 1 0 0 0 1 1 0 0 1 0 1 0 0 1 0 0 1 1 0 0 0 1 1 0 1 1 1 0 0 1 0 0 1 0 1 1 0 0 1 1 0 1 1 1 1 0 1 1 1 0 1 0 1 1 0 0 1 0 0 1 0 0 0 1 0 1 0 0 0 1".split(" ") 7 | arr0 = [] 8 | arr1 = [] 9 | arr2 = [] 10 | arr3 = [] 11 | for i in range(202): 12 | print(i) 13 | arr0.append(BitVec("arr0_%i" % i, 8)) 14 | arr1.append(BitVec("arr1_%i" % i, 8)) 15 | arr2.append(BitVec("arr2_%i" % i, 8)) 16 | arr3.append(BitVec("arr3_%i" % i, 8)) 17 | 18 | print("Adding conditions...") 19 | i = 0 20 | for str_bit in arr_encrypted: 21 | arr0[i] = ord(str_bit) - 0x30 # Make it either 0x00 or 0x01... 22 | i += 1 23 | 24 | i = 0 25 | while(length - 0x17 > i): 26 | s.add(arr1[i + 0x17] == arr1[i] ^ arr1[i + 5]) 27 | i += 1 28 | 29 | i = 0 30 | while(length - 0x18 > i): 31 | s.add(arr2[i + 0x18] == arr2[i] ^ (arr2[i + 1] ^ (arr2[i + 3] ^ arr2[i + 4]))) 32 | i += 1 33 | 34 | i = 0 35 | while(length - 0x19 > i): 36 | s.add(arr3[i + 0x19] == arr3[i] ^ arr3[i + 3]) 37 | i += 1 38 | 39 | for i in range(202): 40 | s.add(arr0[i] == ((arr1[i] & arr2[i]) ^ (arr2[i] & arr3[i])) ^ arr3[i]) 41 | s.add(arr0[i] < 2) 42 | s.add(arr0[i] >= 0) 43 | s.add(arr1[i] < 2) 44 | s.add(arr1[i] >= 0) 45 | s.add(arr2[i] < 2) 46 | s.add(arr2[i] >= 0) 47 | s.add(arr3[i] < 2) 48 | s.add(arr3[i] >= 0) 49 | 50 | print("Checking if solvable...") 51 | print(s.check()) 52 | print("Printing model...") 53 | print(s.model()) 54 | m = s.model() 55 | for i in range(0x17): 56 | print(m[arr1[0x16 - i]]) 57 | for i in range(0x18): 58 | print(m[arr2[0x17 - i]]) 59 | for i in range(0x19): 60 | print(m[arr3[0x18 - i]]) 61 | -------------------------------------------------------------------------------- /secuinside2017/triplerotate/solution.md: -------------------------------------------------------------------------------- 1 | # TripleRotate 2 | 3 | > Decrypt it! 4 | 5 | `encrypt` file contains: 6 | ``` 7 | [koffiedrinker@ctf TripleRotate]$ cat encrypt 8 | 0 0 1 0 0 0 1 0 1 1 0 1 0 1 1 0 1 1 1 0 0 0 1 0 1 0 1 1 1 0 1 0 0 0 0 1 0 0 0 1 1 0 1 1 0 1 1 0 0 0 0 0 1 1 0 1 1 1 0 0 1 0 1 0 1 0 1 1 0 0 1 0 1 0 1 0 1 0 0 0 0 1 1 1 0 1 0 0 1 1 0 0 0 0 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 1 1 1 0 1 1 1 0 1 0 1 1 0 1 0 1 0 0 1 0 0 0 1 0 0 0 1 1 0 0 1 0 1 0 0 1 0 0 1 1 0 0 0 1 1 0 1 1 1 0 0 1 0 0 1 0 1 1 0 0 1 1 0 1 1 1 1 0 1 1 1 0 1 0 1 1 0 0 1 0 0 1 0 0 0 1 0 1 0 0 0 1 9 | ``` 10 | 11 | `prob` file: 12 | ``` 13 | [koffiedrinker@ctf TripleRotate]$ file prob 14 | prob: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=26a87d66cee9849e606408ca0d67f2023af31da4, stripped, with debug_info 15 | ``` 16 | 17 | Playing around: 18 | ``` 19 | [koffiedrinker@ctf TripleRotate]$ ./prob 20 | Input : encrypt 21 | check your input 22 | [koffiedrinker@ctf TripleRotate]$ ./prob 23 | Input : 0 0 1 0 0 0 1 0 1 1 0 1 0 1 1 0 1 1 1 0 0 0 1 0 1 0 1 1 1 0 1 0 0 0 0 1 0 0 0 1 1 0 1 1 0 1 1 0 0 0 0 0 1 1 0 1 1 1 0 0 1 0 1 0 1 0 1 1 0 0 1 0 1 0 1 0 1 0 0 0 0 1 1 1 0 1 0 0 1 1 0 0 0 0 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 1 1 1 0 1 1 1 0 1 0 1 1 0 1 0 1 0 0 1 0 0 0 1 0 0 0 1 1 0 0 1 0 1 0 0 1 0 0 1 1 0 0 0 1 1 0 1 1 1 0 0 1 0 0 1 0 1 1 0 0 1 1 0 1 1 1 1 0 1 1 1 0 1 0 1 1 0 0 1 0 0 1 0 0 0 1 0 1 0 0 0 1 24 | check your input 25 | [koffiedrinker@ctf TripleRotate]$ cat encrypt | perl -ne 's/ //g;print' | ./prob 26 | Input : check your input 27 | *** stack smashing detected ***: ./prob terminated 28 | Segmentation fault (core dumped) 29 | ``` 30 | 31 | Some more info about `prob`: 32 | ``` 33 | [koffiedrinker@ctf TripleRotate]$ r2 -A prob 34 | [x] Analyze all flags starting with sym. and entry0 (aa) 35 | [x] Analyze len bytes of instructions for references (aar) 36 | [x] Analyze function calls (aac) 37 | [ ] [*] Use -AA or aaaa to perform additional experimental analysis. 38 | [x] Constructing a function name for fcn.* and sym.func.* functions (aan)) 39 | -- Use 'e asm.offset=true' to show offsets in 16bit segment addressing mode. 40 | [0x00400640]> afl 41 | 0x00400578 3 36 sub.__gmon_start___224_578 42 | 0x004005b0 2 16 -> 32 sym.imp.puts 43 | 0x004005c0 2 16 -> 48 sym.imp.__stack_chk_fail 44 | 0x004005d0 2 16 -> 48 sym.imp.printf 45 | 0x004005e0 2 16 -> 48 sym.imp.fputc 46 | 0x004005f0 2 16 -> 48 sym.imp.__libc_start_main 47 | 0x00400600 2 16 -> 48 loc.imp.__gmon_start__ 48 | 0x00400610 2 16 -> 48 sym.imp.malloc 49 | 0x00400620 2 16 -> 48 sym.imp.fopen 50 | 0x00400630 2 16 -> 48 sym.imp.__isoc99_scanf 51 | 0x00400640 1 41 entry0 52 | 0x00400670 6 100 fcn.00400670 53 | 0x004006e0 4 34 fcn.004006e0 54 | 0x00400704 13 370 main 55 | 0x00400876 10 290 sub.malloc_876 56 | 0x00400998 12 311 fcn.00400998 57 | 0x00400c70 4 54 fcn.00400c70 58 | [0x00400640]> iz 59 | vaddr=0x00400cbc paddr=0x00000cbc ordinal=000 sz=9 len=8 section=.rodata type=ascii string=Input : 60 | vaddr=0x00400cc8 paddr=0x00000cc8 ordinal=001 sz=17 len=16 section=.rodata type=ascii string=check your input 61 | vaddr=0x00400cd9 paddr=0x00000cd9 ordinal=002 sz=10 len=9 section=.rodata type=ascii string=Length : 62 | vaddr=0x00400ce6 paddr=0x00000ce6 ordinal=003 sz=18 len=17 section=.rodata type=ascii string=check your length 63 | vaddr=0x00400cfb paddr=0x00000cfb ordinal=004 sz=8 len=7 section=.rodata type=ascii string=encrypt 64 | ``` 65 | 66 | It turns out that writing a write-up for a Reverse Engineering challenge is really boring. So I will just explain how the program worked and show my solution script. The decompiled code can be found at the end of this write-up if you're interested in that. 67 | 68 | The main function takes a input string of length 9 and then asks for a length. The length is used as the output length of the `encrypt` file. Our received `encrypt` file has 201 non-whitespace chars. `malloc_876` creates three buffers of this length which will be used to for manipulations and later on they are merged in the final encrypted buffer that is written to `encrypt`. `fcn.00400998` takes our input string of 9 characters and creates a bit string from it with each bit as a 8-bit number. So for example the letter "a" would become `00 01 01 00 00 00 00 01`. This leads to a buffer of size 0x48 (9 times 8) since we have an input string of size 9. This string is then chopped up in three pieces: the first 0x17 bytes go to array 1, the next 0x18 go to array 2 and the last 0x19 go to array 3 but all in reverse. 69 | 70 | Each of these arrays is then passed to a function where the original content (0x17 bytes for array 1 for example) is extended to the full length of the buffer (your input length). For example, array 2 is passed to `fcn.00400b22`. After extending the arrays, they are merged in one final buffer that is written to the `encrypt` file. 71 | 72 | Since all operations on the input are reversible, we can use a SAT solver to find us an input that matches the `encrypt` file. The code below does just that and prints out a bit string which I then quickly manipulated with Perl to give the final flag. 73 | 74 | ```python 75 | from z3 import * 76 | 77 | length = 201 78 | s = Solver() 79 | 80 | arr_encrypted = "0 0 1 0 0 0 1 0 1 1 0 1 0 1 1 0 1 1 1 0 0 0 1 0 1 0 1 1 1 0 1 0 0 0 0 1 0 0 0 1 1 0 1 1 0 1 1 0 0 0 0 0 1 1 0 1 1 1 0 0 1 0 1 0 1 0 1 1 0 0 1 0 1 0 1 0 1 0 0 0 0 1 1 1 0 1 0 0 1 1 0 0 0 0 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 1 1 1 0 1 1 1 0 1 0 1 1 0 1 0 1 0 0 1 0 0 0 1 0 0 0 1 1 0 0 1 0 1 0 0 1 0 0 1 1 0 0 0 1 1 0 1 1 1 0 0 1 0 0 1 0 1 1 0 0 1 1 0 1 1 1 1 0 1 1 1 0 1 0 1 1 0 0 1 0 0 1 0 0 0 1 0 1 0 0 0 1".split(" ") 81 | arr0 = [] # Output array 82 | arr1 = [] # The three arrays used in the program... 83 | arr2 = [] 84 | arr3 = [] 85 | for i in range(202): 86 | print(i) 87 | arr0.append(BitVec("arr0_%i" % i, 8)) 88 | arr1.append(BitVec("arr1_%i" % i, 8)) 89 | arr2.append(BitVec("arr2_%i" % i, 8)) 90 | arr3.append(BitVec("arr3_%i" % i, 8)) 91 | 92 | i = 0 93 | for str_bit in arr_encrypted: 94 | arr0[i] = ord(str_bit) - 0x30 # Make it either 0x00 or 0x01... 95 | i += 1 96 | 97 | print("Adding conditions...") 98 | 99 | # Conditions from fcn.00400acf 100 | i = 0 101 | while(length - 0x17 > i): 102 | s.add(arr1[i + 0x17] == arr1[i] ^ arr1[i + 5]) 103 | i += 1 104 | 105 | # Conditions from fcn.00400b22 106 | i = 0 107 | while(length - 0x18 > i): 108 | s.add(arr2[i + 0x18] == arr2[i] ^ (arr2[i + 1] ^ (arr2[i + 3] ^ arr2[i + 4]))) 109 | i += 1 110 | 111 | # Conditions from fcn.00400b9b 112 | i = 0 113 | while(length - 0x19 > i): 114 | s.add(arr3[i + 0x19] == arr3[i] ^ arr3[i + 3]) 115 | i += 1 116 | 117 | for i in range(202): 118 | # The merge that happens in malloc_876, maps the 3 arrays to the output (encrypt file) 119 | s.add(arr0[i] == ((arr1[i] & arr2[i]) ^ (arr2[i] & arr3[i])) ^ arr3[i]) 120 | # Each number is either 0 or 1 121 | s.add(arr0[i] < 2) 122 | s.add(arr0[i] >= 0) 123 | s.add(arr1[i] < 2) 124 | s.add(arr1[i] >= 0) 125 | s.add(arr2[i] < 2) 126 | s.add(arr2[i] >= 0) 127 | s.add(arr3[i] < 2) 128 | s.add(arr3[i] >= 0) 129 | 130 | print("Checking if solvable...") 131 | print(s.check()) 132 | print("Printing model...") 133 | print(s.model()) 134 | 135 | m = s.model() 136 | print("Bitstring...") 137 | # Print first 0x17 bits of input string 138 | for i in range(0x17): 139 | print(m[arr1[0x16 - i]]) 140 | 141 | # Print second 0x18 bits of input string 142 | for i in range(0x18): 143 | print(m[arr2[0x17 - i]]) 144 | 145 | # Print final 0x19 bits of input string 146 | for i in range(0x19): 147 | print(m[arr3[0x18 - i]]) 148 | ``` 149 | 150 | Since I'm most comt comfortable with Perl, I quickly switch to it to do the final conversion to a string: 151 | ```perl 152 | print 'SECU['; 153 | print pack("B*", ); 154 | print "]\n"; 155 | 156 | __DATA__ 157 | 010010010101111101001100001100000111011000110011010111110111101001000101 158 | ``` 159 | 160 | ```bash 161 | koffiedrinker$ perl sol.pl 162 | SECU[I_L0v3_zE] 163 | ``` 164 | 165 | Flag: SECU[I_L0v3_zE] 166 | 167 | ## Decompiled code 168 | 169 | All done by hand because I cannot afford IDA Pro. 170 | 171 | ``` 172 | func main() { 173 | 174 | printf("Input :"); 175 | scanf("%s", local_20h); // Store string at local_20h 176 | 177 | // Calculate length in assembly, see http://www.int80h.org/strlen/ 178 | rax = assembly_calculations(local_20h); 179 | 180 | if(rax != 9) { // if length != 9 181 | puts("check your input\n"); 182 | // Do stack smash detection 183 | return; 184 | } 185 | 186 | printf("Length :"); 187 | scanf("%d", local_2ch); // Store number at local_2ch 188 | if(local_2ch <= 0xc8) { // Has to be more than 200! "encrypt" file is just 201 bytes! 189 | puts("check your length\n"); 190 | // Do stack smash detection 191 | return; 192 | } 193 | 194 | local_40h = malloc(local_2ch); 195 | 196 | // So our input, length and malloced buffer 197 | malloc_876(&local_20h, local_2ch, &local_40h); 198 | 199 | local_38h = fopen("encrypt", "wb"); 200 | local_28h = 0; 201 | while(local_28h < local_2ch) { 202 | meh = local_40h[local_28h]; // Get a char from stringbuf 203 | if(meh == '\x00') { 204 | eax = 0x30; // "0" 205 | } else { 206 | eax = 0x31; // "1" 207 | } 208 | 209 | fputc(eax, local_38h); 210 | fputc("\x20", local_38h); 211 | 212 | local_28h++; 213 | } 214 | 215 | } 216 | 217 | func malloc_876(inputbuf, length, allocbuf) { 218 | // Function pointers... 219 | ptr_1 = 0x400acf; 220 | ptr_2 = 0x400b22; 221 | ptr_3 = 0x400b9b; 222 | ptrs[] = {ptr_1, ptr_2, ptr_3}; // local_60h 223 | 224 | 225 | // Create three buffers of size length and store in local_40h array 226 | local_1ch = 0; 227 | QWORD local_40h[3] = (); // Array of 3 qwords 228 | while(local_1ch <= 2) { 229 | local_40h[local_1ch] = malloc(length); 230 | local_1ch++; 231 | } 232 | 233 | fcn.00400998(&local_40h, &inputbuf); 234 | 235 | local_18h = 0; 236 | while(local_18h <= 2) { 237 | ptrs[local_18h](local_40h[local_18h], length); // Jump to address 238 | local_18h++; 239 | } 240 | 241 | i = 0; 242 | while(i < length) { 243 | // Does stuff on local_40h qwords and allocbuf 244 | // Probably mapping it... 245 | ecx = local_40h[0][i]; 246 | edx = local_40h[1][i]; 247 | edi = ecx & edx; 248 | 249 | ecx = local_40h[1][i]; 250 | edx = local_40h[2][i]; 251 | edx = edx & ecx; 252 | 253 | ecx = edi ^ edx; 254 | 255 | edx = local_40h[2][i]; 256 | allocbuf[i] = ecx ^ edx; 257 | 258 | // Or shorter: ((0 & 1) ^ (1 & 2)) ^ 2 259 | // allocbuf[i] = ((bufs[0][i] & bufs[1][i]) ^ (bufs[1][i] & bufs[2][i])) ^ local_40h[2][i]; 260 | 261 | i++; 262 | } 263 | } 264 | 265 | func fcn.00400998(bufs, inputbuf) { 266 | local_50h = some buf of size 0x48, i think. 267 | dword[] local_80h = {0x00, 0x17, 0x18, 0x19}; 268 | 269 | // This loop manipulates the inputbuf and stores the manipulated 270 | // result in local_50h. 271 | i = 0; 272 | 273 | // Convert our input into bit representation: 274 | // "a" = 00 01 01 00 00 00 00 01 => 01100001 => bin('a') 275 | while(i <= 0x47) { // 71 276 | // Manipulating the index because our input is only 9 bytes 277 | // But we need to make the input 0x48 bytes... 278 | eax = i; 279 | edx = 7 + i; 280 | eax = edx if eax < 0; 281 | eax = eax >> 3; 282 | 283 | // They get a byte from the inputbuf 284 | inputbuf[eax]; 285 | // They do some trickery on the byte... 286 | 287 | local_50h[i] = the byte after manipulations. 288 | } 289 | 290 | // This loop does trickery on the 3 bufs... 291 | j = 0; k = 0; 292 | while(j <= 2) { 293 | k = local_80h[j] + k; 294 | local_54h = local_80h[j + 1]; 295 | 296 | while(local_54 not signed) { // local_54 >= 0? 297 | bufs[j][local_54h] = local_50h; 298 | local_50h++; // Move ptr to next char in buffer 299 | local_54h--; 300 | } 301 | 302 | 303 | j++; 304 | } 305 | } 306 | 307 | func fcn.00400acf(buf, length) { 308 | i = 0; 309 | while(length - 0x17 > i) { 310 | ecx = buf[i + 5]; 311 | edx = buf[i]; 312 | buf[i + 0x17] = edx ^ ecx; 313 | 314 | i++; 315 | } 316 | } 317 | 318 | func fcn.00400b22(buf, length) { 319 | i = 0; 320 | while(length - 0x18 > i) { 321 | ecx = buf[i + 4]; 322 | edx = buf[i + 3]; 323 | ecx = ecx ^ edx; 324 | 325 | edx = buf[i + 1]; 326 | ecx = ecx ^ edx; 327 | 328 | edx = buf[i]; 329 | ecx = ecx ^ edx; 330 | 331 | buf[i + 0x18] = ecx; 332 | 333 | i++; 334 | } 335 | } 336 | 337 | func fcn.00400b9b(buf, length) { 338 | i = 0; 339 | while(length - 0x19 > i) { 340 | ecx = buf[i + 3]; 341 | edx = buf[i]; 342 | buf[i + 0x19] = edx ^ ecx; 343 | 344 | i++; 345 | } 346 | } 347 | ``` 348 | 349 | ### Dynamic analysis 350 | 351 | Some output from r2 debugger: 352 | ``` 353 | [0x7f1102610d70]> db 0x004008e2 354 | [0x7f1102610d70]> dc 355 | Selecting and continuing: 460 356 | Input : abcdefghi 357 | Length : 201 358 | hit breakpoint at: 4008e2 359 | [0x004008e2]> px @ rsp 360 | - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 361 | 0x7fffe4657700 0000 0000 0000 0000 30f8 9900 0000 0000 ........0....... 362 | 0x7fffe4657710 5b00 0000 c900 0000 c077 65e4 ff7f 0000 [........we..... 363 | 0x7fffe4657720 cf0a 4000 0000 0000 220b 4000 0000 0000 ..@.....".@..... 364 | 0x7fffe4657730 9b0b 4000 0000 0000 e0aa 6002 117f 0000 ..@.......`..... 365 | 0x7fffe4657740 10f9 9900 0000 0000 f0f9 9900 0000 0000 ................ 366 | 0x7fffe4657750 d0fa 9900 0000 0000 0000 0000 0000 0000 ................ 367 | 0x7fffe4657760 0000 0000 0300 0000 44cd 2e02 117f 0000 ........D....... 368 | 0x7fffe4657770 0000 0000 0000 0000 0000 0000 0000 0000 ................ 369 | 0x7fffe4657780 e077 65e4 ff7f 0000 ee07 4000 0000 0000 .we.......@..... 370 | 0x7fffe4657790 0000 0000 0000 0000 ffff ffff ffff ffff ................ 371 | 0x7fffe46577a0 30f8 9900 0000 0000 230c 4000 0000 0000 0.......#.@..... 372 | 0x7fffe46577b0 0000 0000 c900 0000 0000 0000 0000 0000 ................ 373 | 0x7fffe46577c0 6162 6364 6566 6768 6900 4000 0000 0000 abcdefghi.@..... 374 | 0x7fffe46577d0 c078 65e4 ff7f 0000 000e 796f 51ea 2c4b .xe.......yoQ.,K 375 | 0x7fffe46577e0 f00b 4000 0000 0000 9122 2902 117f 0000 ..@......")..... 376 | 0x7fffe46577f0 0000 0000 0000 0000 c878 65e4 ff7f 0000 .........xe..... 377 | [0x004008e2]> dm 378 | sys 4K 0x0000000000400000 * 0x0000000000401000 s -r-x /data/TripleRotate/prob /data/TripleRotate/prob ; map._data_TripleRotate_prob._r_x 379 | sys 4K 0x0000000000601000 - 0x0000000000602000 s -r-- /data/TripleRotate/prob /data/TripleRotate/prob ; map._data_TripleRotate_prob._rw_ 380 | sys 4K 0x0000000000602000 - 0x0000000000603000 s -rw- /data/TripleRotate/prob /data/TripleRotate/prob ; reloc.puts_0 381 | sys 132K 0x000000000099f000 - 0x00000000009c0000 s -rw- [heap] [heap] 382 | ... 383 | [0x004008e2]> px @ 0x099f910 384 | - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 385 | 0x0099f910 0100 0000 0101 0000 0100 0000 0101 0001 ................ 386 | 0x0099f920 0000 0000 0101 0000 0000 0000 0000 0000 ................ 387 | 0x0099f930 0000 0000 0000 0000 0000 0000 0000 0000 ................ 388 | 0x0099f940 0000 0000 0000 0000 0000 0000 0000 0000 ................ 389 | 0x0099f950 0000 0000 0000 0000 0000 0000 0000 0000 ................ 390 | 0x0099f960 0000 0000 0000 0000 0000 0000 0000 0000 ................ 391 | 0x0099f970 0000 0000 0000 0000 0000 0000 0000 0000 ................ 392 | 0x0099f980 0000 0000 0000 0000 0000 0000 0000 0000 ................ 393 | 0x0099f990 0000 0000 0000 0000 0000 0000 0000 0000 ................ 394 | 0x0099f9a0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 395 | 0x0099f9b0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 396 | 0x0099f9c0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 397 | 0x0099f9d0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 398 | 0x0099f9e0 0000 0000 0000 0000 e100 0000 0000 0000 ................ 399 | 0x0099f9f0 0101 0000 0101 0001 0001 0000 0101 0000 ................ 400 | 0x0099fa00 0001 0000 0101 0001 0000 0000 0000 0000 ................ 401 | [0x004008e2]> px @ 0x099f9f0 402 | - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 403 | 0x0099f9f0 0101 0000 0101 0001 0001 0000 0101 0000 ................ 404 | 0x0099fa00 0001 0000 0101 0001 0000 0000 0000 0000 ................ 405 | 0x0099fa10 0000 0000 0000 0000 0000 0000 0000 0000 ................ 406 | 0x0099fa20 0000 0000 0000 0000 0000 0000 0000 0000 ................ 407 | 0x0099fa30 0000 0000 0000 0000 0000 0000 0000 0000 ................ 408 | 0x0099fa40 0000 0000 0000 0000 0000 0000 0000 0000 ................ 409 | 0x0099fa50 0000 0000 0000 0000 0000 0000 0000 0000 ................ 410 | 0x0099fa60 0000 0000 0000 0000 0000 0000 0000 0000 ................ 411 | 0x0099fa70 0000 0000 0000 0000 0000 0000 0000 0000 ................ 412 | 0x0099fa80 0000 0000 0000 0000 0000 0000 0000 0000 ................ 413 | 0x0099fa90 0000 0000 0000 0000 0000 0000 0000 0000 ................ 414 | 0x0099faa0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 415 | 0x0099fab0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 416 | 0x0099fac0 0000 0000 0000 0000 e100 0000 0000 0000 ................ 417 | 0x0099fad0 0100 0001 0001 0100 0000 0001 0001 0100 ................ 418 | 0x0099fae0 0101 0100 0001 0100 0000 0000 0000 0000 ................ 419 | [0x004008e2]> px @ 0x099fad0 420 | - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 421 | 0x0099fad0 0100 0001 0001 0100 0000 0001 0001 0100 ................ 422 | 0x0099fae0 0101 0100 0001 0100 0000 0000 0000 0000 ................ 423 | 0x0099faf0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 424 | 0x0099fb00 0000 0000 0000 0000 0000 0000 0000 0000 ................ 425 | 0x0099fb10 0000 0000 0000 0000 0000 0000 0000 0000 ................ 426 | 0x0099fb20 0000 0000 0000 0000 0000 0000 0000 0000 ................ 427 | 0x0099fb30 0000 0000 0000 0000 0000 0000 0000 0000 ................ 428 | 0x0099fb40 0000 0000 0000 0000 0000 0000 0000 0000 ................ 429 | 0x0099fb50 0000 0000 0000 0000 0000 0000 0000 0000 ................ 430 | 0x0099fb60 0000 0000 0000 0000 0000 0000 0000 0000 ................ 431 | 0x0099fb70 0000 0000 0000 0000 0000 0000 0000 0000 ................ 432 | 0x0099fb80 0000 0000 0000 0000 0000 0000 0000 0000 ................ 433 | 0x0099fb90 0000 0000 0000 0000 0000 0000 0000 0000 ................ 434 | 0x0099fba0 0000 0000 0000 0000 6104 0200 0000 0000 ........a....... 435 | 0x0099fbb0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 436 | 0x0099fbc0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 437 | ``` 438 | 439 | So this is what we get after fcn.00400998... 440 | 441 | And after the calling of the three functions: 442 | ``` 443 | [0x004008e2]> db 0x00400913 444 | [0x004008e2]> dc 445 | Selecting and continuing: 460 446 | hit breakpoint at: 400913 447 | [0x004008e2]> px @ 0x099f910 448 | - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 449 | 0x0099f910 0100 0000 0101 0000 0100 0000 0101 0001 ................ 450 | 0x0099f920 0000 0000 0101 0000 0000 0101 0100 0100 ................ 451 | 0x0099f930 0001 0001 0100 0001 0000 0001 0001 0100 ................ 452 | 0x0099f940 0101 0100 0000 0100 0101 0101 0001 0101 ................ 453 | 0x0099f950 0100 0001 0001 0001 0001 0101 0100 0000 ................ 454 | 0x0099f960 0000 0000 0100 0100 0001 0101 0001 0000 ................ 455 | 0x0099f970 0101 0101 0000 0100 0100 0000 0100 0001 ................ 456 | 0x0099f980 0101 0001 0001 0001 0001 0000 0001 0101 ................ 457 | 0x0099f990 0001 0100 0001 0100 0101 0101 0100 0101 ................ 458 | 0x0099f9a0 0001 0001 0001 0101 0001 0101 0000 0101 ................ 459 | 0x0099f9b0 0000 0100 0000 0101 0001 0101 0000 0100 ................ 460 | 0x0099f9c0 0000 0100 0101 0100 0100 0001 0100 0100 ................ 461 | 0x0099f9d0 0001 0100 0101 0101 0100 0000 0000 0000 ................ 462 | 0x0099f9e0 0000 0000 0000 0000 e100 0000 0000 0000 ................ 463 | 0x0099f9f0 0101 0000 0101 0001 0001 0000 0101 0000 ................ 464 | 0x0099fa00 0001 0000 0101 0001 0101 0100 0100 0001 ................ 465 | [0x004008e2]> px @ 0x099f9f0 466 | - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 467 | 0x0099f9f0 0101 0000 0101 0001 0001 0000 0101 0000 ................ 468 | 0x0099fa00 0001 0000 0101 0001 0101 0100 0100 0001 ................ 469 | 0x0099fa10 0001 0101 0000 0100 0001 0100 0001 0101 ................ 470 | 0x0099fa20 0101 0100 0001 0101 0000 0100 0000 0101 ................ 471 | 0x0099fa30 0101 0100 0100 0001 0001 0100 0000 0100 ................ 472 | 0x0099fa40 0001 0000 0001 0001 0101 0100 0001 0100 ................ 473 | 0x0099fa50 0100 0001 0000 0000 0100 0101 0101 0101 ................ 474 | 0x0099fa60 0001 0101 0001 0100 0000 0101 0101 0101 ................ 475 | 0x0099fa70 0101 0000 0101 0001 0001 0000 0100 0000 ................ 476 | 0x0099fa80 0001 0000 0000 0100 0101 0100 0100 0001 ................ 477 | 0x0099fa90 0000 0001 0101 0100 0101 0101 0101 0100 ................ 478 | 0x0099faa0 0101 0100 0000 0100 0000 0101 0100 0101 ................ 479 | 0x0099fab0 0000 0001 0100 0100 0000 0000 0000 0000 ................ 480 | 0x0099fac0 0000 0000 0000 0000 e100 0000 0000 0000 ................ 481 | 0x0099fad0 0100 0001 0001 0100 0000 0001 0001 0100 ................ 482 | 0x0099fae0 0101 0100 0001 0100 0000 0001 0000 0101 ................ 483 | [0x004008e2]> px @ 0x099fad0 484 | - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 485 | 0x0099fad0 0100 0001 0001 0100 0000 0001 0001 0100 ................ 486 | 0x0099fae0 0101 0100 0001 0100 0000 0001 0000 0101 ................ 487 | 0x0099faf0 0001 0001 0000 0000 0101 0100 0100 0101 ................ 488 | 0x0099fb00 0001 0000 0001 0000 0101 0100 0100 0101 ................ 489 | 0x0099fb10 0101 0001 0100 0000 0100 0101 0000 0001 ................ 490 | 0x0099fb20 0101 0001 0100 0100 0100 0000 0101 0100 ................ 491 | 0x0099fb30 0100 0001 0101 0101 0100 0000 0001 0101 ................ 492 | 0x0099fb40 0001 0101 0101 0001 0000 0101 0000 0001 ................ 493 | 0x0099fb50 0101 0001 0101 0100 0001 0000 0100 0100 ................ 494 | 0x0099fb60 0001 0001 0101 0101 0100 0001 0001 0100 ................ 495 | 0x0099fb70 0000 0000 0101 0000 0001 0001 0000 0001 ................ 496 | 0x0099fb80 0100 0001 0000 0101 0000 0101 0001 0101 ................ 497 | 0x0099fb90 0001 0100 0101 0100 0100 0000 0000 0000 ................ 498 | 0x0099fba0 0000 0000 0000 0000 6104 0200 0000 0000 ........a....... 499 | 0x0099fbb0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 500 | 0x0099fbc0 0000 0000 0000 0000 0000 0000 0000 0000 ................ 501 | ``` 502 | 503 | So these three functions spread the "randomness" over the full buffer... 504 | 505 | ``` 506 | [0x004008e2]> px @ 0x099f910 507 | - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 508 | 0x0099f910 0100 0000 0101 0000 0100 0000 0101 0001 ................ 509 | 0x0099f920 0000 0000 0101 0000 0000 0000 0000 0000 ................ 510 | 0x0099f930 0000 0000 0000 0000 0000 0000 0000 0000 ................ 511 | 0x0099f940 0000 0000 0000 0000 0000 0000 0000 0000 ................ 512 | [0x004008e2]> px @ 0x099f910 513 | - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 514 | 0x0099f910 0100 0000 0101 0000 0100 0000 0101 0001 ................ 515 | 0x0099f920 0000 0000 0101 0000 0000 0101 0100 0100 ................ 516 | 0x0099f930 0001 0001 0100 0001 0000 0001 0001 0100 ................ 517 | 0x0099f940 0101 0100 0000 0100 0101 0101 0001 0101 ................ 518 | 0x0099f950 0100 0001 0001 0001 0001 0101 0100 0000 ................ 519 | 0x0099f960 0000 0000 0100 0100 0001 0101 0001 0000 ................ 520 | 0x0099f970 0101 0101 0000 0100 0100 0000 0100 0001 ................ 521 | 0x0099f980 0101 0001 0001 0001 0001 0000 0001 0101 ................ 522 | 0x0099f990 0001 0100 0001 0100 0101 0101 0100 0101 ................ 523 | 0x0099f9a0 0001 0001 0001 0101 0001 0101 0000 0101 ................ 524 | 0x0099f9b0 0000 0100 0000 0101 0001 0101 0000 0100 ................ 525 | 0x0099f9c0 0000 0100 0101 0100 0100 0001 0100 0100 ................ 526 | 0x0099f9d0 0001 0100 0101 0101 0100 0000 0000 0000 ................ 527 | 0x0099f9e0 0000 0000 0000 0000 e100 0000 0000 0000 ................ 528 | 0x0099f9f0 0101 0000 0101 0001 0001 0000 0101 0000 ................ 529 | 0x0099fa00 0001 0000 0101 0001 0101 0100 0100 0001 ................ 530 | ``` 531 | 532 | Note that the original bytes in the beginning stay the same... 533 | 534 | Breaking down what 0x00400998 does: 535 | ``` 536 | [0x00400a47]> px @ rsp 537 | - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 538 | 0x7ffea61bd4a0 00d6 1ba6 fe7f 0000 80d5 1ba6 fe7f 0000 ................ 539 | 0x7ffea61bd4b0 0000 0000 1700 0000 1800 0000 1900 0000 ................ 540 | 0x7ffea61bd4c0 5b00 0000 6e00 0000 e0d4 1ba6 fe7f 0000 [...n........... 541 | 0x7ffea61bd4d0 4800 0000 0000 0000 7700 0000 7c00 0000 H.......w...|... 542 | 0x7ffea61bd4e0 0001 0100 0000 0001 0001 0100 0000 0100 ................ 543 | 0x7ffea61bd4f0 0001 0100 0000 0101 0001 0100 0001 0000 ................ 544 | 0x7ffea61bd500 0001 0100 0001 0001 0001 0100 0001 0100 ................ 545 | 0x7ffea61bd510 0001 0100 0001 0101 0001 0100 0100 0000 ................ 546 | 0x7ffea61bd520 0001 0100 0100 0001 00e3 3c8f 6ee8 2b55 ..........<.n.+U 547 | 0x7ffea61bd530 c0d5 1ba6 fe7f 0000 e208 4000 0000 0000 ..........@..... 548 | 0x7ffea61bd540 0000 0000 0000 0000 30f8 9500 0000 0000 ........0....... 549 | 0x7ffea61bd550 5b00 0000 c900 0000 00d6 1ba6 fe7f 0000 [............... 550 | 0x7ffea61bd560 cf0a 4000 0000 0000 220b 4000 0000 0000 ..@.....".@..... 551 | 0x7ffea61bd570 9b0b 4000 0000 0000 e08a f705 817f 0000 ..@............. 552 | 0x7ffea61bd580 10f9 9500 0000 0000 f0f9 9500 0000 0000 ................ 553 | 0x7ffea61bd590 d0fa 9500 0000 0000 0000 0000 0000 0000 ................ 554 | ``` 555 | 556 | We convert "abcdefghi" into "bit strings": a is "00 01 01 00 00 00 00 01" above at 0x...bd4e0. 557 | 558 | We take the first 0x17 bytes and put them in reverse in arr 1, then we take the next 0x18 bytes and put them in reverse in arr 2, etc..... 559 | ``` 560 | local_50h 561 | 0x7ffea61bd4e0 0001 0100 0000 0001 0001 0100 0000 0100 ................ 562 | 0x7ffea61bd4f0 0001 0100 0000 01 563 | 564 | arr1 565 | - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 566 | 0x0099f910 0100 0000 0101 0000 0100 0000 0101 0001 ................ 567 | 0x0099f920 0000 0000 0101 00 568 | ``` 569 | 570 | 571 | -------------------------------------------------------------------------------- /sha2017_teaser/follow_stream.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koffiedrinker/writeups/4954bcd0db55422ca0ba874f49d8827cc8539fb3/sha2017_teaser/follow_stream.png -------------------------------------------------------------------------------- /sha2017_teaser/protocol_hierarchy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koffiedrinker/writeups/4954bcd0db55422ca0ba874f49d8827cc8539fb3/sha2017_teaser/protocol_hierarchy.png -------------------------------------------------------------------------------- /sha2017_teaser/website_attack.md: -------------------------------------------------------------------------------- 1 | # SHA2017 CTF - Network challenge (Network attack) 2 | 3 | _Small print: I solved this challenge for the OpenToAll CTF team._ 4 | 5 | Opening the PCAP with Wireshark and looking at the Protocol Hierarchy, we see that the full PCAP is GSM over IP protocol. 6 | 7 | ![protocol hierarchy](protocol_hierarchy.png) 8 | 9 | Selecting these GSM IPA packets and following the stream we see that it's just good old HTTP traffic, which we can easily handle. 10 | 11 | ![follow_stream.png](follow_stream.png) 12 | 13 | Looking at the first HTTP GET requests and responses gives us this: 14 | ``` 15 | GET /?action=search&words=kl&sort=stock HTTP/1.1 16 | 17 | 18 | HTTP/1.1 302 FOUND 19 | 20 | Location: http://10.5.5.208:5000/?action=display&what=ce3926706794d911 21 | 22 | GET /?action=display&what=ce3926706794d911 HTTP/1.1 23 | 24 | 25 | GET /?action=search&words=Trad&sort=stock HTTP/1.1 26 | 27 | 28 | HTTP/1.1 302 FOUND 29 | 30 | Location: http://10.5.5.208:5000/?action=display&what=f1274d671988ce151a0b 31 | 32 | GET /?action=display&what=f1274d671988ce151a0b HTTP/1.1 33 | 34 | 35 | HTTP/1.1 200 OK 36 | ............................. shows only the Traditional klomp..... 37 | 38 | GET /?action=search&words=-Trad&sort=stock HTTP/1.1 39 | 40 | 41 | HTTP/1.1 200 OK 42 | 43 | Please use only letters and digits 44 | 45 | GET /?action=search&words=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&sort=stock HTTP/1.1 46 | 47 | 48 | HTTP/1.1 302 FOUND 49 | 50 | Location: http://10.5.5.208:5000/?action=display&what=e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a74799edb6fda5b44 51 | ``` 52 | 53 | So we see some HTTP requests to filter the results (action=search) and a redirect (action=display) with a cryptic "what" parameter to go to the results page. 54 | 55 | The first idea I got was immediately the correct one. XORing the input with the cryptic hex output gives us the XOR key: 56 | ``` 57 | koffiedrinker$ perl -MPwn::Crypto -e 'print fixed_xor(hr("e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a74799edb6fda5b44"), "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")' 58 | Pwn::Crypto::XOR::fixed_xor(): strings do not have equal length... 59 | koffiedrinker$ # Padding 6 bytes to the input... 60 | koffiedrinker$ perl -MPwn::Crypto -e 'print rh(fixed_xor(hr("e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a74799edb6fda5b44"), "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")) . "\n"' 61 | a5552c0313fbba7a79606cb0c7083b353894a81bb5382f3432e71f2908d46173a5552c0313fbba7a79606cb0c7083b353894a81bb5382f3432e71f2908d46173a5552c0313fbba7a79606cb0c7083b353894a81bb5382f3432e71f2908d46173a5552c0313fbba7a79606cb0c7083b353894a81bb5382f3432e71f2908d46173a5552c0313fbba7a79606cb0c7083b3538df9a2e9b1a05 62 | ``` 63 | 64 | Because we have the XOR key and other plaintext and ciphertext, I was able to determine that the full plaintext is the value of the "words" parameter, a newline and the value of the "sort" parameter (which explains the six extra bytes of input I needed to match the hexstring length). So for example, searching for Trad gave us "f1274d671988ce151a0b". The plaintext that generates this is: 65 | ``` 66 | Trad\x0astock 67 | ``` 68 | 69 | Now we just extract all the GET requests from the PCAP, XOR it with our key and see what we got. I used a quick Perl one-liner for this: 70 | ``` 71 | koffiedrinker$ strings website-attack.pcap | grep 'GET /?action=display&what=' | perl -nle '/what=(\w+)\s/; print $1' > what.txt 72 | ``` 73 | 74 | A quick Perl script later: 75 | ```perl 76 | use strict; 77 | use warnings; 78 | 79 | use Pwn::Crypto; 80 | 81 | my $long = hr("e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a74799edb6fda5b44"); 82 | my $aaa = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x0astock"; 83 | my $key = fixed_xor($aaa, $long); 84 | print "Key: " . rh($key) . "\n"; 85 | open(WHAT, 'what.txt'); 86 | while() { 87 | chomp; 88 | my $query = hr($_); 89 | my $trimmed_key = $key; 90 | if(length($query) < length($key)) { 91 | # We can trim it 92 | $trimmed_key = substr $key, 0, length($query); 93 | } else { 94 | print "Woah! Query is longer than key!\n"; 95 | die "Bluh\n"; 96 | } 97 | print "Result: " . fixed_xor($query, $trimmed_key) . "\n"; 98 | } 99 | 100 | ``` 101 | 102 | Let's see what that gives us... 103 | ``` 104 | koffiedrinker$ perl network.pl 105 | Key: a5552c0313fbba7a79606cb0c7083b353894a81bb5382f3432e71f2908d46173a5552c0313fbba7a79606cb0c7083b353894a81bb5382f3432e71f2908d46173a5552c0313fbba7a79606cb0c7083b353894a81bb5382f3432e71f2908d46173a5552c0313fbba7a79606cb0c7083b353894a81bb5382f3432e71f2908d46173a5552c0313fbba7a79606cb0c7083b353894a81bb5382f 106 | Result: 107 | (CASE WHEN (SELECT SUBSTR(sql,1,1) FROM SQLITE_MASTER LIMIT 1,1) = '0' THEN stock ELSE price END) 108 | Result: 109 | (CASE WHEN (SELECT SUBSTR(sql,1,1) FROM SQLITE_MASTER LIMIT 1,1) = '1' THEN stock ELSE price END) 110 | Result: 111 | (CASE WHEN (SELECT SUBSTR(sql,1,1) FROM SQLITE_MASTER LIMIT 1,1) = '2' THEN stock ELSE price END) 112 | Result: 113 | (CASE WHEN (SELECT SUBSTR(sql,1,1) FROM SQLITE_MASTER LIMIT 1,1) = '3' THEN stock ELSE price END) 114 | Result: 115 | (CASE WHEN (SELECT SUBSTR(sql,1,1) FROM SQLITE_MASTER LIMIT 1,1) = '4' THEN stock ELSE price END) 116 | Result: 117 | (CASE WHEN (SELECT SUBSTR(sql,1,1) FROM SQLITE_MASTER LIMIT 1,1) = '5' THEN stock ELSE price END) 118 | ``` 119 | 120 | So we are dealing with a SQLinjection attack on the webserver. It's easy to find the flag from this output. We just wait until the attacker goes to the next character in SUBSTR and get the character from the line above it. 121 | 122 | For example: 123 | ``` 124 | Result: 125 | (CASE WHEN (SELECT SUBSTR(sql,1,1) FROM SQLITE_MASTER LIMIT 1,1) = 'C' THEN stock ELSE price END) 126 | Result: 127 | (CASE WHEN (SELECT SUBSTR(sql,2,1) FROM SQLITE_MASTER LIMIT 1,1) = '0' THEN stock ELSE price END) 128 | ``` 129 | 130 | So the first character that matched what the attacker wanted is a 'C'. 131 | 132 | Coding this gives us the flag: 133 | ```perl 134 | use strict; 135 | use warnings; 136 | 137 | use Pwn::Crypto; 138 | 139 | my $long = hr("e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a7479d5e95af4796e7573a65e6849952032e4146d4252bafb3b38212df186497a74799edb6fda5b44"); 140 | my $aaa = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x0astock"; 141 | my $key = fixed_xor($aaa, $long); 142 | print "Key: " . rh($key) . "\n"; 143 | 144 | my $previous_str = ''; 145 | my $first_one = 1; 146 | my $flag = ''; 147 | open(WHAT, 'what.txt'); 148 | while() { 149 | chomp; 150 | my $query = hr($_); 151 | my $trimmed_key = $key; 152 | if(length($query) < length($key)) { 153 | # We can trim it 154 | $trimmed_key = substr $key, 0, length($query); 155 | } else { 156 | print "Woah! Query is longer than key!\n"; 157 | die "Bluh\n"; 158 | } 159 | my $r = fixed_xor($query, $trimmed_key); 160 | print "Result: $r\n"; 161 | if(!$first_one) { # Compare with previous one 162 | $previous_str =~ /SUBSTR\(([^\)]+)\)/; 163 | my $prev = $1; 164 | $r =~ /SUBSTR\(([^\)]+)\)/; 165 | my $cur = $1; 166 | if($prev ne $cur) { 167 | print "Different! $prev != $cur \n"; 168 | $previous_str =~ /\= \'(.)\' THEN stock/; 169 | $flag .= $1; 170 | } 171 | } 172 | 173 | $previous_str = $r; 174 | $first_one = 0 if $first_one; 175 | } 176 | 177 | print "FLAG: $flag\n"; 178 | ``` 179 | 180 | Running it: 181 | ``` 182 | koffiedrinker$ perl network.pl 183 | FLAG: CREATE TABLE secret_flag (flag text) 184 | 185 | 186 | flag{7307e3ee8da198ca4a7f9b1f8b018d8e} 187 | ``` 188 | 189 | Note: I am not proud of the code I have written but I did solve it pretty quickly (first blood even) so there's that. :) 190 | 191 | Flag: flag{7307e3ee8da198ca4a7f9b1f8b018d8e} 192 | -------------------------------------------------------------------------------- /sha2017_teaser/websiteattack.tar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koffiedrinker/writeups/4954bcd0db55422ca0ba874f49d8827cc8539fb3/sha2017_teaser/websiteattack.tar -------------------------------------------------------------------------------- /trendmicro2017/for100/README.md: -------------------------------------------------------------------------------- 1 | # For 100 2 | 3 | Opening the PCAP file in Wireshark, we are presented with hundreds of DNS queries and responses. 4 | 5 | ![Wireshark view](wireshark.png) 6 | 7 | After looking inside the DNS queries, I did not notice any weird values except for the query. So I extracted all queries and responses with Scapy. 8 | 9 | ```python 10 | from scapy.all import * 11 | from binascii import unhexlify 12 | import re 13 | 14 | pcap = PcapReader("output.pcap") 15 | for packet in pcap: 16 | if packet[DNS].ancount > 0: 17 | for answer in packet[DNS].an: 18 | print "Answer: " + answer.rdata 19 | else: # Query 20 | query = packet[DNSQR].qname 21 | p = re.match('([a-zA-Z0-9]+)\.gzpgs\..*', query) 22 | print("Query: " + p.group(1)) 23 | ``` 24 | 25 | This gives us something that looks like: 26 | ``` 27 | Query: ASfsbGivEQsT2aQPHzaB 28 | Answer: 126.100.179.228 29 | Query: 5GBJZEAWX7WJASGCg5Br 30 | Answer: 77.250.124.6 31 | Query: 9TvJjPCj9kRW9fk5XU2b 32 | Answer: 90.163.121.234 33 | Query: rvAptS4tZnjLwCNsXn5N 34 | Answer: 143.90.186.87 35 | Query: 9jUqipSo5xgNR6EM3Zpw 36 | Answer: 180.46.203.226 37 | ... 38 | ``` 39 | 40 | I noticed that the IP addresses were probably bogus or auto-generated because the output contains invalid IP addresses. After try-and-error, I concatenated all the queries together, since all queries are the same length except for the last one which indicated that it might be the remainder of some file or text. 41 | 42 | ``` 43 | koffiedrinker$ perl -ne 'chomp;s/^Query: (.+)$/$1/;print if ! /Answer: /} END {print "\n"' for100/parsed_output.txt 44 | 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 45 | ``` 46 | 47 | Since base64 decoding failed, I checked if the output did not contain any of the following characters which would indicate base58: 48 | 49 | > Compared to Base64, the following similar-looking letters are omitted: 0 (zero), O (capital o), I (capital i) and l (lower case L) as well as the non-alphanumeric characters + (plus) and / (slash). 50 | Source: [Wikipedia](https://en.wikipedia.org/wiki/Base58) 51 | 52 | And what do you know, it doesn't. A quick google leads us to an [online base58 decoder](https://www.browserling.com/tools/base58-decode) and the text decodes as the hacker manifesto with the flag: 53 | ``` 54 | ==Phrack Inc.== 55 | 56 | Volume One, Issue 7, Phile 3 of 10 57 | 58 | =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 59 | The following was written shortly after my arrest... 60 | 61 | \/\The Conscience of a Hacker/\/ 62 | 63 | by 64 | 65 | +++The Mentor+++ 66 | 67 | Written on January 8, 1986 68 | =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 69 | 70 | Another one got caught today, it's all over the papers. "Teenager 71 | Arrested in Computer Crime Scandal", "Hacker Arrested after Bank Tampering"... 72 | Damn kids. They're all alike. 73 | 74 | But did you, in your three-piece psychology and 1950's technobrain, 75 | ever take a look behind the eyes of the hacker? Did you ever wonder what 76 | made him tick, what forces shaped him, what may have molded him? 77 | I am a hacker, enter my world... 78 | Mine is a world that begins with school... I'm smarter than most of 79 | the other kids, this crap they teach us bores me... 80 | Damn underachiever. They're all alike. 81 | 82 | I'm in junior high or high school. I've listened to teachers explain 83 | for the fifteenth time how to reduce a fraction. I understand it. "No, Ms. 84 | Smith, I didn't show my work. I did it in my head..." 85 | Damn kid. Probably copied it. They're all alike. 86 | 87 | I made a discovery today. I found a computer. Wait a second, this is 88 | cool. It does what I want it to. If it makes a mistake, it's because I 89 | screwed it up. Not because it doesn't like me... 90 | Or feels threatened by me... 91 | Or thinks I'm a smart ass... 92 | Or doesn't like teaching and shouldn't be here... 93 | Damn kid. All he does is play games. They're all alike. 94 | 95 | And then it happened... a door opened to a world... rushing through 96 | the phone line like heroin through an addict's veins, an electronic pulse is 97 | sent out, a refuge from the day-to-day incompetencies is sought... a board is 98 | found. 99 | "This is it... this is where I belong..." 100 | I know everyone here... even if I've never met them, never talked to 101 | them, may never hear from them again... I know you all... 102 | Damn kid. Tying up the phone line again. They're all alike... 103 | 104 | You bet your ass we're all alike... we've been spoon-fed baby food at 105 | school when we hungered for steak... the bits of meat that you did let slip 106 | through were pre-chewed and tasteless. We've been dominated by sadists, or 107 | ignored by the apathetic. The few that had something to teach found us will- 108 | ing pupils, but those few are like drops of water in the desert. 109 | 110 | This is our world now... the world of the electron and the switch, the 111 | beauty of the baud. We make use of a service already existing without paying 112 | for what could be dirt-cheap if it wasn't run by profiteering gluttons, and 113 | you call us criminals. We explore... and you call us criminals. We seek 114 | after knowledge... and you call us criminals. We exist without skin color, 115 | without nationality, without religious bias... and you call us criminals. 116 | You build atomic bombs, you wage wars, you murder, cheat, and lie to us 117 | and try to make us believe it's for our own good, yet we're the criminals. 118 | 119 | Yes, I am a criminal. My crime is that of curiosity. My crime is 120 | that of judging people by what they say and think, not what they look like. 121 | My crime is that of outsmarting you, something that you will never forgive me 122 | for. 123 | 124 | I am a hacker, and this is my manifesto. You may stop this individual, 125 | but you can't stop us all... after all, we're all alike. 126 | 127 | +++The Mentor+++ 128 | 129 | TMCTF{DNSTunnelExfil} 130 | 131 | ``` 132 | 133 | Flag: TMCTF{DNSTunnelExfil} 134 | -------------------------------------------------------------------------------- /trendmicro2017/for100/output.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koffiedrinker/writeups/4954bcd0db55422ca0ba874f49d8827cc8539fb3/trendmicro2017/for100/output.pcap -------------------------------------------------------------------------------- /trendmicro2017/for100/scapy.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | from binascii import unhexlify 3 | import re 4 | 5 | pcap = PcapReader("output.pcap") 6 | for packet in pcap: 7 | if packet[DNS].ancount > 0: 8 | for answer in packet[DNS].an: 9 | print "Answer: " + answer.rdata 10 | else: # Query 11 | query = packet[DNSQR].qname 12 | p = re.match('([a-zA-Z0-9]+)\.gzpgs\..*', query) 13 | print("Query: " + p.group(1)) 14 | -------------------------------------------------------------------------------- /trendmicro2017/for100/wireshark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koffiedrinker/writeups/4954bcd0db55422ca0ba874f49d8827cc8539fb3/trendmicro2017/for100/wireshark.png -------------------------------------------------------------------------------- /trendmicro2017/for200/README.md: -------------------------------------------------------------------------------- 1 | # For 200 2 | 3 | > We got memory image from victim pc. Please analyze malicious indicator. 7z password : novirus 4 | 5 | ```bash 6 | openssl enc -d -aes-256-cbc -k BnKUyuHfJf31804OmzkO -in files10.enc -out files10.zip 7 | ``` 8 | 9 | The contents of the zip file is a 7z compressed file: 10 | 11 | ``` 12 | koffiedrinker$ unzip -v ../../../trendmicro2017/for200/files10.zip 13 | Archive: ../../../trendmicro2017/for200/files10.zip 14 | Length Method Size Ratio Date Time CRC-32 Name 15 | -------- ------ ------- ----- ---- ---- ------ ---- 16 | 57290506 Stored 57290506 0% 06-05-17 17:39 78534fd4 VictimMemory.7z 17 | -------- ------- --- ------- 18 | 57290506 57290506 0% 1 file 19 | ``` 20 | 21 | Uncompressing with `unzip files10.zip` and `7za e VictimMemory.7z`, we are left with `VictimMemory.img`. 22 | 23 | Since we're dealing with a memory dump, let's use Volatility to analyze it. 24 | 25 | ``` 26 | [koffiedrinker@ctf for200]$ ./vol.py -f VictimMemory.img imageinfo 27 | Volatility Foundation Volatility Framework 2.6 28 | INFO : volatility.debug : Determining profile based on KDBG search... 29 | Suggested Profile(s) : Win7SP1x86_23418, Win7SP0x86, Win7SP1x86 30 | AS Layer1 : IA32PagedMemoryPae (Kernel AS) 31 | AS Layer2 : FileAddressSpace (/data/for200/VictimMemory.img) 32 | PAE type : PAE 33 | DTB : 0x185000L 34 | KDBG : 0x8333ec28L 35 | Number of Processors : 1 36 | Image Type (Service Pack) : 1 37 | KPCR for CPU 0 : 0x8333fc00L 38 | KUSER_SHARED_DATA : 0xffdf0000L 39 | Image date and time : 2017-04-11 02:35:28 UTC+0000 40 | Image local date and time : 2017-04-11 11:35:28 +0900 41 | ``` 42 | 43 | Let's use the suggested `Win7SP1x86_23418` profile to list the processes. I prefer using `pstree` because it already shows visually parent-child relationships. 44 | 45 | ``` 46 | [koffiedrinker@ctf for200]$ ./vol.py -f VictimMemory.img --profile=Win7SP1x86_23418 pstree 47 | Volatility Foundation Volatility Framework 2.6 48 | Name Pid PPid Thds Hnds Time 49 | -------------------------------------------------- ------ ------ ------ ------ ---- 50 | 0x89d8a530:wininit.exe 412 344 3 78 2017-04-11 02:27:45 UTC+0000 51 | . 0x88a0c030:lsass.exe 516 412 7 547 2017-04-11 02:27:48 UTC+0000 52 | . 0x88a056d8:services.exe 508 412 7 220 2017-04-11 02:27:47 UTC+0000 53 | .. 0x869fa6c0:VSSVC.exe 2304 508 12 194 2017-04-11 02:33:08 UTC+0000 54 | .. 0x89d91030:svchost.exe 1288 508 17 304 2017-04-11 02:28:00 UTC+0000 55 | .. 0x86d7b030:VGAuthService. 1424 508 3 87 2017-04-11 02:28:03 UTC+0000 56 | .. 0x89d6b030:mscorsvw.exe 3096 508 6 74 2017-04-11 02:30:34 UTC+0000 57 | .. 0x88bd3a98:msdtc.exe 1420 508 14 150 2017-04-11 02:28:28 UTC+0000 58 | .. 0x88a4bcd8:vmacthlp.exe 676 508 3 53 2017-04-11 02:27:52 UTC+0000 59 | .. 0x88a808a0:svchost.exe 808 508 20 465 2017-04-11 02:27:53 UTC+0000 60 | ... 0x88aa7130:audiodg.exe 952 808 4 122 2017-04-11 02:27:55 UTC+0000 61 | .. 0x869b6030:msiexec.exe 3612 508 9 278 2017-04-11 02:34:25 UTC+0000 62 | .. 0x89c0fb78:svchost.exe 1668 508 8 92 2017-04-11 02:28:12 UTC+0000 63 | .. 0x86986030:sppsvc.exe 3264 508 4 146 2017-04-11 02:30:44 UTC+0000 64 | .. 0x89a3b8e0:SearchIndexer. 2376 508 12 576 2017-04-11 02:29:03 UTC+0000 65 | .. 0x88a87518:svchost.exe 844 508 18 419 2017-04-11 02:27:53 UTC+0000 66 | ... 0x88b91030:dwm.exe 568 844 3 70 2017-04-11 02:28:22 UTC+0000 67 | .. 0x86dcf2d0:vmtoolsd.exe 1484 508 8 289 2017-04-11 02:28:07 UTC+0000 68 | ... 0x89a73d40:cmd.exe 3880 1484 0 ------ 2017-04-11 02:35:27 UTC+0000 69 | .... 0x869b8d40:ipconfig.exe 3900 3880 0 ------ 2017-04-11 02:35:28 UTC+0000 70 | .. 0x89d0b030:spoolsv.exe 1232 508 12 326 2017-04-11 02:27:59 UTC+0000 71 | .. 0x86400838:taskhost.exe 1976 508 9 165 2017-04-11 02:28:18 UTC+0000 72 | .. 0x8697fa58:svchost.exe 3300 508 9 299 2017-04-11 02:30:45 UTC+0000 73 | .. 0x89a131f8:WmiApSrv.exe 3728 508 5 111 2017-04-11 02:31:41 UTC+0000 74 | .. 0x88add030:svchost.exe 1116 508 16 391 2017-04-11 02:27:57 UTC+0000 75 | .. 0x88a5e528:svchost.exe 720 508 7 284 2017-04-11 02:27:53 UTC+0000 76 | .. 0x88a8baf8:svchost.exe 868 508 42 1017 2017-04-11 02:27:53 UTC+0000 77 | .. 0x88a47130:svchost.exe 616 508 10 359 2017-04-11 02:27:51 UTC+0000 78 | ... 0x89b5b5b0:WmiPrvSE.exe 2108 616 10 294 2017-04-11 02:28:37 UTC+0000 79 | ... 0x88be3300:WmiPrvSE.exe 204 616 10 204 2017-04-11 02:28:31 UTC+0000 80 | .. 0x88ab6c88:svchost.exe 1008 508 13 282 2017-04-11 02:27:56 UTC+0000 81 | .. 0x8697bd40:svchost.exe 3324 508 5 66 2017-04-11 02:33:09 UTC+0000 82 | .. 0x8694bd40:svchost.exe 3192 508 9 126 2017-04-11 02:30:40 UTC+0000 83 | . 0x88a0ba38:lsm.exe 524 412 10 143 2017-04-11 02:27:48 UTC+0000 84 | 0x86d1d7e8:csrss.exe 352 344 9 470 2017-04-11 02:27:43 UTC+0000 85 | . 0x86784030:conhost.exe 3888 352 0 ------ 2017-04-11 02:35:28 UTC+0000 86 | 0x8594b7e0:System 4 0 91 490 2017-04-11 02:27:39 UTC+0000 87 | . 0x86dd0d40:smss.exe 268 4 2 29 2017-04-11 02:27:39 UTC+0000 88 | 0x89d83478:csrss.exe 404 396 10 199 2017-04-11 02:27:45 UTC+0000 89 | . 0x86938030:conhost.exe 1868 404 3 100 2017-04-11 02:32:03 UTC+0000 90 | 0x89da3530:winlogon.exe 444 396 3 114 2017-04-11 02:27:45 UTC+0000 91 | 0x88bbaab8:explorer.exe 940 356 31 865 2017-04-11 02:28:23 UTC+0000 92 | . 0x8691c030:cmd.exe 4080 940 1 20 2017-04-11 02:32:02 UTC+0000 93 | .. 0x88abfa78:svchost.exe 3828 4080 1 7 2017-04-11 02:35:18 UTC+0000 94 | . 0x88bca030:vmtoolsd.exe 2216 940 6 191 2017-04-11 02:28:51 UTC+0000 95 | ``` 96 | 97 | Near the bottom we note an interesting chain: `Explorer.exe -> cmd.exe -> svchost.exe`. That doesn't look right. 98 | 99 | Let's dump how `svchost.exe` was executed: 100 | 101 | ``` 102 | [koffiedrinker@ctf for200]$ ./vol.py -f VictimMemory.img --profile=Win7SP1x86_23418 cmdline --pid=940,4080,3828 103 | Volatility Foundation Volatility Framework 2.6 104 | ************************************************************************ 105 | explorer.exe pid: 940 106 | Command line : C:\Windows\Explorer.EXE 107 | ************************************************************************ 108 | cmd.exe pid: 4080 109 | Command line : "C:\Windows\system32\cmd.exe" 110 | ************************************************************************ 111 | svchost.exe pid: 3828 112 | Command line : svchost.exe 1.tmp 0x0 1 113 | ``` 114 | 115 | So `svchost.exe` takes as arguments: `1.tmp 0x0 1`, that's kinda unusual... 116 | 117 | Note that `cmdscan` would have also told us this (since it was started by `cmd.exe`): 118 | 119 | ``` 120 | [koffiedrinker@ctf for200]$ ./vol.py -f VictimMemory.img --profile=Win7SP1x86_23418 cmdscan 121 | Volatility Foundation Volatility Framework 2.6 122 | ************************************************** 123 | CommandProcess: conhost.exe Pid: 1868 124 | CommandHistory: 0x31e818 Application: svchost.exe Flags: Allocated 125 | CommandCount: 0 LastAdded: -1 LastDisplayed: -1 126 | FirstCommand: 0 CommandCountMax: 50 127 | ProcessHandle: 0x190 128 | Cmd #11 @ 0x10000: ????? 129 | Cmd #37 @ 0x10000: ????? 130 | ************************************************** 131 | CommandProcess: conhost.exe Pid: 1868 132 | CommandHistory: 0x33a338 Application: cmd.exe Flags: Allocated, Reset 133 | CommandCount: 2 LastAdded: 1 LastDisplayed: 1 134 | FirstCommand: 0 CommandCountMax: 50 135 | ProcessHandle: 0x58 136 | Cmd #0 @ 0x33a700: cd %temp% 137 | Cmd #1 @ 0x2d3b38: svchost.exe 1.tmp 0x0 1 138 | ``` 139 | 140 | Let's dump the `svchost.exe` and dump `1.tmp` since this is probably some kind of input file. 141 | 142 | ``` 143 | [koffiedrinker@ctf for200]$ ./vol.py -f VictimMemory.img --profile=Win7SP1x86_23418 procdump --pid=3828 --dump-dir=dump_files/ 144 | Volatility Foundation Volatility Framework 2.6 145 | Process(V) ImageBase Name Result 146 | ---------- ---------- -------------------- ------ 147 | 0x88abfa78 0x00ed0000 svchost.exe OK: executable.3828.exe 148 | [koffiedrinker@ctf for200]$ ./vol.py -f VictimMemory.img --profile=Win7SP1x86_23418 dumpfiles --regex=1.tmp --pid=3828 --dump-dir=dump_files/ 149 | Volatility Foundation Volatility Framework 2.6 150 | DataSectionObject 0x88bb47c0 3828 \Device\HarddiskVolume1\Users\Taro\AppData\Local\Temp\1.tmp 151 | SharedCacheMap 0x88bb47c0 3828 \Device\HarddiskVolume1\Users\Taro\AppData\Local\Temp\1.tmp 152 | ``` 153 | 154 | Taking a look at `1.tmp` leaves us without a clue of what the contents mean: 155 | ``` 156 | [koffiedrinker@ctf dump_files]$ xxd -c32 file.3828.0x86c8dec0.dat | head -n20 157 | 0000000: 9090 9090 9090 9090 9090 9090 9090 9090 5589 e583 ec60 c645 daa8 c645 dbff c645 ................U....`.E...E...E 158 | 0000020: dc88 c645 ddd0 c645 deb2 c645 dff6 c645 e0f8 c645 e1ea c645 e2ff c645 e3ff c645 ...E...E...E...E...E...E...E...E 159 | 0000040: e4d2 c645 e5ff c645 e6ff c645 e7c2 c645 e8dc c645 e9c2 c645 ead8 c645 ebff c645 ...E...E...E...E...E...E...E...E 160 | 0000060: ecf6 c645 edff c645 eefa c645 efff c645 bc55 c645 bd8b c645 beec c645 bf51 c645 ...E...E...E...E.U.E...E...E.Q.E 161 | 0000080: c0e8 c645 c100 c645 c200 c645 c300 c645 c400 c645 c558 c645 c62d c645 c752 c645 ...E...E...E...E...E.X.E.-.E.R.E 162 | 00000a0: c81f c645 c934 c645 ca01 c645 cb2d c645 cc52 c645 cd1f c645 ce34 c645 cf01 c645 ...E.4.E...E.-.E.R.E...E.4.E...E 163 | 00000c0: d0e8 c645 d100 c645 d200 c645 d300 c645 d400 c645 d590 c645 d690 c645 d7c9 c645 ...E...E...E...E...E...E...E...E 164 | 00000e0: d8c3 c645 d9cc c645 a600 c645 a75b c645 a800 c645 a900 c645 aa00 c645 ab00 c645 ...E...E...E.[.E...E...E...E...E 165 | 0000100: ac00 c645 ad00 c645 ae2b c645 af17 c645 b000 c645 b119 c645 b23f c645 b300 c645 ...E...E.+.E...E...E...E.?.E...E 166 | 0000120: b400 c645 b500 c645 b600 c645 b703 c645 b800 c645 b913 c645 ba00 c645 bb05 c745 ...E...E...E...E...E...E...E...E 167 | 0000140: fc16 0000 00c7 45f4 0000 0000 c745 f000 0000 008b 45f0 83f8 1673 708d 55da 8b45 ......E......E......E....sp.U..E 168 | 0000160: f001 d00f b600 0fb6 c089 45f8 8d55 a68b 45f0 01d0 0fb6 000f b6c0 8945 f483 7df4 ..........E..U..E..........E..}. 169 | 0000180: 007e 0a83 45f8 0183 6df4 01eb f08b 45fc 83e8 010f b644 05bc 0fb6 c029 45f8 8b45 .~..E...m.....E......D.....)E..E 170 | 00001a0: fc83 e801 0fb6 4405 bc0f b6c0 3145 f8d1 7df8 8b45 f889 c18d 55da 8b45 f001 d088 ......D.....1E..}..E....U..E.... 171 | 00001c0: 0883 6dfc 0183 45f0 01eb 8890 c9c3 0000 0000 0000 0000 0000 0000 0000 0000 0000 ..m...E......................... 172 | 00001e0: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ................................ 173 | 0000200: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ................................ 174 | 0000220: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ................................ 175 | 0000240: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ................................ 176 | 0000260: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ................................ 177 | ``` 178 | 179 | The remainder of the file is full of zero bytes, the "file" is basically just a memory page with the file contents in the beginning. 180 | 181 | It's highly likely that we'll know what to do with the file once we know what `svchost.exe` does with it. Time to fire up radare2. 182 | 183 | ``` 184 | [koffiedrinker@ctf dump_files]$ r2 -A executable.3828.exe 185 | [x] Analyze all flags starting with sym. and entry0 (aa) 186 | [x] Analyze len bytes of instructions for references (aar) 187 | [x] Analyze function calls (aac) 188 | [ ] [*] Use -AA or aaaa to perform additional experimental analysis. 189 | [x] Constructing a function name for fcn.* and sym.func.* functions (aan)) 190 | -- Your project name should contain an uppercase letter, 8 vowels, some numbers, and the first 5 numbers of your private bitcoin key. 191 | [0x00ed1406]> afl 192 | 0x00ed1000 9 398 sub.MSVCR120.dll_printf_0 193 | 0x00ed118e 3 15 -> 266 fcn.00ed118e 194 | 0x00ed1406 25 10 -> 340 entry0 195 | 0x00ed1410 3 61 sub.KERNEL32.dll_IsDebuggerPresent_410 196 | 0x00ed144d 3 251 loc.00ed144d 197 | 0x00ed1598 1 6 sub.MSVCR120.dll__XcptFilter_598 198 | 0x00ed159e 1 6 sub.MSVCR120.dll__amsg_exit_59e 199 | 0x00ed15b0 7 67 fcn.00ed15b0 200 | 0x00ed1600 3 137 fcn.00ed1600 201 | 0x00ed16c0 5 49 fcn.00ed16c0 202 | 0x00ed16f1 9 156 sub.KERNEL32.dll_GetSystemTimeAsFileTime_6f1 203 | 0x00ed178d 1 3 fcn.00ed178d 204 | 0x00ed17cc 4 157 sub.KERNEL32.dll_DecodePointer_7cc 205 | 0x00ed186c 1 9 fcn.00ed186c 206 | 0x00ed1875 1 21 fcn.00ed1875 207 | 0x00ed188a 6 32 fcn.00ed188a 208 | 0x00ed18ca 3 39 fcn.00ed18ca 209 | 0x00ed18f2 1 6 sub.MSVCR120.dll__initterm_e_8f2 210 | 0x00ed18f8 1 6 sub.MSVCR120.dll__initterm_8f8 211 | 0x00ed1900 1 69 fcn.00ed1900 212 | 0x00ed1945 1 20 fcn.00ed1945 213 | 0x00ed197c 1 6 sub.MSVCR120.dll__crt_debugger_hook_97c 214 | 0x00ed1982 1 6 sub.MSVCR120.dll___crtUnhandledException_982 215 | 0x00ed1988 1 6 sub.MSVCR120.dll___crtTerminateProcess_988 216 | 0x00ed198e 1 6 sub.MSVCR120.dll__terminate__YAXXZ_98e 217 | 0x00ed1994 1 6 sub.MSVCR120.dll___crtSetUnhandledExceptionFilter_994 218 | 0x00ed199a 1 6 sub.MSVCR120.dll__lock_99a 219 | 0x00ed19a0 1 6 sub.MSVCR120.dll__unlock_9a0 220 | 0x00ed19a6 1 6 sub.MSVCR120.dll___dllonexit_9a6 221 | 0x00ed19ac 1 6 sub.MSVCR120.dll__invoke_watson_9ac 222 | 0x00ed19b2 1 6 sub.MSVCR120.dll__controlfp_s_9b2 223 | 0x00ed19b8 1 6 sub.MSVCR120.dll__except_handler4_common_9b8 224 | 0x00ed19be 1 6 sub.KERNEL32.dll_IsProcessorFeaturePresent_9be 225 | 0x00ed19d0 4 43 fcn.00ed19d0 226 | ``` 227 | 228 | The first function is actually `main()`, or at least contains the overall logic of the program. 229 | 230 | Printing the strings in rodata, we find the usage string so we now know what the arguments to `svchost.exe` (more or less) mean: 231 | ``` 232 | [0x00ed1000]> iz 233 | vaddr=0x00ed2120 paddr=0x00000f20 ordinal=001 sz=53 len=52 section=.rdata type=ascii string=usage: this.exe \n 234 | vaddr=0x00ed2158 paddr=0x00000f58 ordinal=002 sz=19 len=18 section=.rdata type=ascii string=offset eg) 0xFFFF\n 235 | vaddr=0x00ed216c paddr=0x00000f6c ordinal=003 sz=17 len=16 section=.rdata type=ascii string=file name is %s\n 236 | vaddr=0x00ed2184 paddr=0x00000f84 ordinal=004 sz=14 len=13 section=.rdata type=ascii string=offset is %x\n 237 | ... 238 | ``` 239 | 240 | Looking at the calls in main: 241 | ``` 242 | [0x00ed1000]> pdf~call 243 | | 0x00ed1008 e8c3090000 call fcn.00ed19d0 244 | | | 0x00ed102e ffd6 call esi 245 | | | 0x00ed1035 ffd6 call esi 246 | | | 0x00ed103c ff159820ed00 call dword [sym.imp.MSVCR120.dll_exit] ; 0xed2098 247 | | 0x00ed1051 ffd7 call edi 248 | | 0x00ed1062 ff15b020ed00 call dword [sym.imp.MSVCR120.dll_sscanf] ; 0xed20b0 249 | | 0x00ed1073 ffd7 call edi 250 | | 0x00ed107b ff15a420ed00 call dword [sym.imp.MSVCR120.dll_fopen] ; 0xed20a4 251 | | 0x00ed1096 ff15a020ed00 call dword [sym.imp.MSVCR120.dll_fread] ; 0xed20a0 252 | | 0x00ed10af ff150820ed00 call dword [sym.imp.KERNEL32.dll_VirtualAlloc] ; 0xed2008 253 | | | 0x00ed10c0 ffd7 call edi 254 | | | 0x00ed10d0 e8b9000000 call fcn.00ed118e 255 | | 0x00ed10e7 ff15ac20ed00 call dword [sym.imp.MSVCR120.dll_memmove] ; 0xed20ac 256 | | 0x00ed1102 ff15b020ed00 call dword [sym.imp.MSVCR120.dll_sscanf] ; 0xed20b0 257 | | | 0x00ed1119 ff150420ed00 call dword [sym.imp.KERNEL32.dll_Sleep] ; 0xed2004 ; "F\xba\fv\xb6/\rv]7\rv\xde/\rv\x80\xbb\fv\xc4\xca\fv\x9f\xbb\fv\xb5v\rv\xa8>\fv\x95\xa2[w\x10\xcd[w" 258 | | 0x00ed112f ff150c20ed00 call dword [sym.imp.KERNEL32.dll_CreateThread] ; 0xed200c ; "]7\rv\xde/\rv\x80\xbb\fv\xc4\xca\fv\x9f\xbb\fv\xb5v\rv\xa8>\fv\x95\xa2[w\x10\xcd[w" 259 | | | 0x00ed1140 ffd7 call edi 260 | | | 0x00ed1150 e839000000 call fcn.00ed118e 261 | | 0x00ed115e ffd7 call edi 262 | | 0x00ed1166 ff150020ed00 call dword [sym.imp.KERNEL32.dll_WaitForSingleObject] ; 0xed2000 263 | | 0x00ed1172 ff159c20ed00 call dword [sym.imp.MSVCR120.dll_fclose] ; 0xed209c 264 | | 0x00ed1185 e804000000 call fcn.00ed118e 265 | ``` 266 | 267 | To make a long story short, this function opens the "1.tmp" file, reads it, moves it to it's own memory page and then executes the contents of it by calling `CreateThread()` with the memory page as starting address. So let's open "1.tmp" in radare2 and disassemble it. :) (Suddenly the 0x90's begin to make sense in "1.tmp") 268 | 269 | ``` 270 | [koffiedrinker@ctf dump_files]$ r2 file.3828.0x86c8dec0.dat 271 | -- You crackme up! 272 | [0x00000000]> pd 139 273 | 0x00000000 90 nop 274 | 0x00000001 90 nop 275 | 0x00000002 90 nop 276 | 0x00000003 90 nop 277 | 0x00000004 90 nop 278 | 0x00000005 90 nop 279 | 0x00000006 90 nop 280 | 0x00000007 90 nop 281 | 0x00000008 90 nop 282 | 0x00000009 90 nop 283 | 0x0000000a 90 nop 284 | 0x0000000b 90 nop 285 | 0x0000000c 90 nop 286 | 0x0000000d 90 nop 287 | 0x0000000e 90 nop 288 | 0x0000000f 90 nop 289 | 0x00000010 55 push rbp 290 | 0x00000011 89e5 mov ebp, esp 291 | 0x00000013 83ec60 sub esp, 0x60 ; '`' 292 | 0x00000016 c645daa8 mov byte [rbp - 0x26], 0xa8 293 | 0x0000001a c645dbff mov byte [rbp - 0x25], 0xff 294 | 0x0000001e c645dc88 mov byte [rbp - 0x24], 0x88 295 | 0x00000022 c645ddd0 mov byte [rbp - 0x23], 0xd0 296 | 0x00000026 c645deb2 mov byte [rbp - 0x22], 0xb2 297 | 0x0000002a c645dff6 mov byte [rbp - 0x21], 0xf6 298 | 0x0000002e c645e0f8 mov byte [rbp - 0x20], 0xf8 299 | 0x00000032 c645e1ea mov byte [rbp - 0x1f], 0xea 300 | 0x00000036 c645e2ff mov byte [rbp - 0x1e], 0xff 301 | 0x0000003a c645e3ff mov byte [rbp - 0x1d], 0xff 302 | 0x0000003e c645e4d2 mov byte [rbp - 0x1c], 0xd2 303 | 0x00000042 c645e5ff mov byte [rbp - 0x1b], 0xff 304 | 0x00000046 c645e6ff mov byte [rbp - 0x1a], 0xff 305 | 0x0000004a c645e7c2 mov byte [rbp - 0x19], 0xc2 306 | 0x0000004e c645e8dc mov byte [rbp - 0x18], 0xdc 307 | 0x00000052 c645e9c2 mov byte [rbp - 0x17], 0xc2 308 | 0x00000056 c645ead8 mov byte [rbp - 0x16], 0xd8 309 | 0x0000005a c645ebff mov byte [rbp - 0x15], 0xff 310 | 0x0000005e c645ecf6 mov byte [rbp - 0x14], 0xf6 311 | 0x00000062 c645edff mov byte [rbp - 0x13], 0xff 312 | 0x00000066 c645eefa mov byte [rbp - 0x12], 0xfa 313 | 0x0000006a c645efff mov byte [rbp - 0x11], 0xff 314 | 0x0000006e c645bc55 mov byte [rbp - 0x44], 0x55 ; 'U' 315 | 0x00000072 c645bd8b mov byte [rbp - 0x43], 0x8b 316 | 0x00000076 c645beec mov byte [rbp - 0x42], 0xec 317 | 0x0000007a c645bf51 mov byte [rbp - 0x41], 0x51 ; 'Q' 318 | 0x0000007e c645c0e8 mov byte [rbp - 0x40], 0xe8 319 | 0x00000082 c645c100 mov byte [rbp - 0x3f], 0 320 | 0x00000086 c645c200 mov byte [rbp - 0x3e], 0 321 | 0x0000008a c645c300 mov byte [rbp - 0x3d], 0 322 | 0x0000008e c645c400 mov byte [rbp - 0x3c], 0 323 | 0x00000092 c645c558 mov byte [rbp - 0x3b], 0x58 ; 'X' 324 | 0x00000096 c645c62d mov byte [rbp - 0x3a], 0x2d ; '-' 325 | 0x0000009a c645c752 mov byte [rbp - 0x39], 0x52 ; 'R' 326 | 0x0000009e c645c81f mov byte [rbp - 0x38], 0x1f 327 | 0x000000a2 c645c934 mov byte [rbp - 0x37], 0x34 ; '4' 328 | 0x000000a6 c645ca01 mov byte [rbp - 0x36], 1 329 | 0x000000aa c645cb2d mov byte [rbp - 0x35], 0x2d ; '-' 330 | 0x000000ae c645cc52 mov byte [rbp - 0x34], 0x52 ; 'R' 331 | 0x000000b2 c645cd1f mov byte [rbp - 0x33], 0x1f 332 | 0x000000b6 c645ce34 mov byte [rbp - 0x32], 0x34 ; '4' 333 | 0x000000ba c645cf01 mov byte [rbp - 0x31], 1 334 | 0x000000be c645d0e8 mov byte [rbp - 0x30], 0xe8 335 | 0x000000c2 c645d100 mov byte [rbp - 0x2f], 0 336 | 0x000000c6 c645d200 mov byte [rbp - 0x2e], 0 337 | 0x000000ca c645d300 mov byte [rbp - 0x2d], 0 338 | 0x000000ce c645d400 mov byte [rbp - 0x2c], 0 339 | 0x000000d2 c645d590 mov byte [rbp - 0x2b], 0x90 340 | 0x000000d6 c645d690 mov byte [rbp - 0x2a], 0x90 341 | 0x000000da c645d7c9 mov byte [rbp - 0x29], 0xc9 342 | 0x000000de c645d8c3 mov byte [rbp - 0x28], 0xc3 343 | 0x000000e2 c645d9cc mov byte [rbp - 0x27], 0xcc 344 | 0x000000e6 c645a600 mov byte [rbp - 0x5a], 0 345 | 0x000000ea c645a75b mov byte [rbp - 0x59], 0x5b ; '[' 346 | 0x000000ee c645a800 mov byte [rbp - 0x58], 0 347 | 0x000000f2 c645a900 mov byte [rbp - 0x57], 0 348 | 0x000000f6 c645aa00 mov byte [rbp - 0x56], 0 349 | 0x000000fa c645ab00 mov byte [rbp - 0x55], 0 350 | 0x000000fe c645ac00 mov byte [rbp - 0x54], 0 351 | 0x00000102 c645ad00 mov byte [rbp - 0x53], 0 352 | 0x00000106 c645ae2b mov byte [rbp - 0x52], 0x2b ; '+' 353 | 0x0000010a c645af17 mov byte [rbp - 0x51], 0x17 354 | 0x0000010e c645b000 mov byte [rbp - 0x50], 0 355 | 0x00000112 c645b119 mov byte [rbp - 0x4f], 0x19 356 | 0x00000116 c645b23f mov byte [rbp - 0x4e], 0x3f ; '?' 357 | 0x0000011a c645b300 mov byte [rbp - 0x4d], 0 358 | 0x0000011e c645b400 mov byte [rbp - 0x4c], 0 359 | 0x00000122 c645b500 mov byte [rbp - 0x4b], 0 360 | 0x00000126 c645b600 mov byte [rbp - 0x4a], 0 361 | 0x0000012a c645b703 mov byte [rbp - 0x49], 3 362 | 0x0000012e c645b800 mov byte [rbp - 0x48], 0 363 | 0x00000132 c645b913 mov byte [rbp - 0x47], 0x13 364 | 0x00000136 c645ba00 mov byte [rbp - 0x46], 0 365 | 0x0000013a c645bb05 mov byte [rbp - 0x45], 5 366 | 0x0000013e c745fc160000. mov dword [rbp - 4], 0x16 367 | 0x00000145 c745f4000000. mov dword [rbp - 0xc], 0 368 | 0x0000014c c745f0000000. mov dword [rbp - 0x10], 0 369 | .-> 0x00000153 8b45f0 mov eax, dword [rbp - 0x10] 370 | | 0x00000156 83f816 cmp eax, 0x16 371 | ,==< 0x00000159 7370 jae 0x1cb 372 | || 0x0000015b 8d55da lea edx, [rbp - 0x26] 373 | || 0x0000015e 8b45f0 mov eax, dword [rbp - 0x10] 374 | || 0x00000161 01d0 add eax, edx 375 | || 0x00000163 0fb600 movzx eax, byte [rax] 376 | || 0x00000166 0fb6c0 movzx eax, al 377 | || 0x00000169 8945f8 mov dword [rbp - 8], eax 378 | || 0x0000016c 8d55a6 lea edx, [rbp - 0x5a] 379 | || 0x0000016f 8b45f0 mov eax, dword [rbp - 0x10] 380 | || 0x00000172 01d0 add eax, edx 381 | || 0x00000174 0fb600 movzx eax, byte [rax] 382 | || 0x00000177 0fb6c0 movzx eax, al 383 | || 0x0000017a 8945f4 mov dword [rbp - 0xc], eax 384 | .---> 0x0000017d 837df400 cmp dword [rbp - 0xc], 0 385 | ,====< 0x00000181 7e0a jle 0x18d 386 | |||| 0x00000183 8345f801 add dword [rbp - 8], 1 387 | |||| 0x00000187 836df401 sub dword [rbp - 0xc], 1 388 | |`===< 0x0000018b ebf0 jmp 0x17d 389 | `----> 0x0000018d 8b45fc mov eax, dword [rbp - 4] 390 | || 0x00000190 83e801 sub eax, 1 391 | || 0x00000193 0fb64405bc movzx eax, byte [rbp + rax - 0x44] 392 | || 0x00000198 0fb6c0 movzx eax, al 393 | || 0x0000019b 2945f8 sub dword [rbp - 8], eax 394 | || 0x0000019e 8b45fc mov eax, dword [rbp - 4] 395 | || 0x000001a1 83e801 sub eax, 1 396 | || 0x000001a4 0fb64405bc movzx eax, byte [rbp + rax - 0x44] 397 | || 0x000001a9 0fb6c0 movzx eax, al 398 | || 0x000001ac 3145f8 xor dword [rbp - 8], eax 399 | || 0x000001af d17df8 sar dword [rbp - 8], 1 400 | || 0x000001b2 8b45f8 mov eax, dword [rbp - 8] 401 | || 0x000001b5 89c1 mov ecx, eax 402 | || 0x000001b7 8d55da lea edx, [rbp - 0x26] 403 | || 0x000001ba 8b45f0 mov eax, dword [rbp - 0x10] 404 | || 0x000001bd 01d0 add eax, edx 405 | || 0x000001bf 8808 mov byte [rax], cl 406 | || 0x000001c1 836dfc01 sub dword [rbp - 4], 1 407 | || 0x000001c5 8345f001 add dword [rbp - 0x10], 1 408 | |`=< 0x000001c9 eb88 jmp 0x153 409 | `--> 0x000001cb 90 nop 410 | 0x000001cc c9 leave 411 | 0x000001cd c3 ret 412 | ``` 413 | 414 | Looks like executable code alright. Since this code is simply executing CPU instructions without any library calls or anything (just a small stack to keep state), we can easily emulate this with [Unicorn](https://github.com/unicorn-engine/unicorn). So after compiling and installing (with Python bindings) Unicorn, I wrote this small script which is entirely based upon the `shellcode.py` example script. I just did some small modifications to print the stack at the end since it contains (hopefully) the juicy bits. 415 | 416 | ```python 417 | #!/usr/bin/env python 418 | # Sample code for X86 of Unicorn. Nguyen Anh Quynh 419 | 420 | from __future__ import print_function 421 | from unicorn import * 422 | from unicorn.x86_const import * 423 | 424 | from binascii import * 425 | 426 | SIKRIT_CODE = unhexlify("909090909090909090909090909090905589e583ec60c645daa8c645dbffc645dc88c645ddd0c645deb2c645dff6c645e0f8c645e1eac645e2ffc645e3ffc645e4d2c645e5ffc645e6ffc645e7c2c645e8dcc645e9c2c645ead8c645ebffc645ecf6c645edffc645eefac645efffc645bc55c645bd8bc645beecc645bf51c645c0e8c645c100c645c200c645c300c645c400c645c558c645c62dc645c752c645c81fc645c934c645ca01c645cb2dc645cc52c645cd1fc645ce34c645cf01c645d0e8c645d100c645d200c645d300c645d400c645d590c645d690c645d7c9c645d8c3c645d9ccc645a600c645a75bc645a800c645a900c645aa00c645ab00c645ac00c645ad00c645ae2bc645af17c645b000c645b119c645b23fc645b300c645b400c645b500c645b600c645b703c645b800c645b913c645ba00c645bb05c745fc16000000c745f400000000c745f0000000008b45f083f81673708d55da8b45f001d00fb6000fb6c08945f88d55a68b45f001d00fb6000fb6c08945f4837df4007e0a8345f801836df401ebf08b45fc83e8010fb64405bc0fb6c02945f88b45fc83e8010fb64405bc0fb6c03145f8d17df88b45f889c18d55da8b45f001d08808836dfc018345f001eb8890") # removed c9 (leave) and c3 (ret) at the end 427 | 428 | # memory address where emulation starts 429 | ADDRESS = 0x1000000 430 | 431 | # Test X86 32 bit 432 | def test_i386(mode, code): 433 | print("Emulate x86 code") 434 | try: 435 | # Initialize emulator 436 | mu = Uc(UC_ARCH_X86, mode) 437 | 438 | # map 2MB memory for this emulation 439 | mu.mem_map(ADDRESS, 2 * 1024 * 1024) 440 | 441 | # write machine code to be emulated to memory 442 | mu.mem_write(ADDRESS, code) 443 | 444 | # initialize stack 445 | mu.reg_write(UC_X86_REG_ESP, ADDRESS + 0x200000) 446 | 447 | # emulate machine code in infinite time 448 | mu.emu_start(ADDRESS, ADDRESS + len(code)) 449 | 450 | # now print out some registers 451 | esp = mu.reg_read(UC_X86_REG_ESP) 452 | rbp = mu.reg_read(UC_X86_REG_RBP) 453 | print("ESP: 0x%x, RBP: 0x%x" % (esp, rbp)) 454 | bytes_to_read = 0x60 # The size of our stack... 455 | try: 456 | buf = mu.mem_read(esp, bytes_to_read) 457 | print(">>> buffer = 0x%x, size = %u, content = " \ 458 | %(esp, bytes_to_read), end="") 459 | for i in buf: 460 | print("%c" %i, end="") 461 | print("") 462 | except UcError as e: 463 | print(">>> buffer = 0x%x, size = %u, content = \n" \ 464 | %(esp, bytes_to_read)) 465 | print(">>> Emulation done") 466 | 467 | except UcError as e: 468 | print("ERROR: %s" % e) 469 | 470 | 471 | 472 | if __name__ == '__main__': 473 | test_i386(UC_MODE_64, SIKRIT_CODE) 474 | ``` 475 | 476 | We thus just emulate all instructions and then print the memory area that contains the stack. This gives us... 477 | 478 | ```bash 479 | [koffiedrinker@ctf for200]$ python2 unicorn_emulation_small.py 480 | Emulate x86 code 481 | ESP: 0x11fff98, RBP: 0x11ffff8 482 | >>> buffer = 0x11fff98, size = 96, content = [+?U??Q?X-R4-R4??????TMCTF{static_analyzer}} 483 | >>> Emulation done 484 | ``` 485 | 486 | ... the flag. 487 | 488 | Flag: TMCTF{static_analyzer} 489 | -------------------------------------------------------------------------------- /trendmicro2017/for200/files10.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koffiedrinker/writeups/4954bcd0db55422ca0ba874f49d8827cc8539fb3/trendmicro2017/for200/files10.enc -------------------------------------------------------------------------------- /trendmicro2017/for200/unicorn_emulator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Sample code for X86 of Unicorn. Nguyen Anh Quynh 3 | 4 | from __future__ import print_function 5 | from unicorn import * 6 | from unicorn.x86_const import * 7 | 8 | from binascii import * 9 | 10 | SIKRIT_CODE = unhexlify("909090909090909090909090909090905589e583ec60c645daa8c645dbffc645dc88c645ddd0c645deb2c645dff6c645e0f8c645e1eac645e2ffc645e3ffc645e4d2c645e5ffc645e6ffc645e7c2c645e8dcc645e9c2c645ead8c645ebffc645ecf6c645edffc645eefac645efffc645bc55c645bd8bc645beecc645bf51c645c0e8c645c100c645c200c645c300c645c400c645c558c645c62dc645c752c645c81fc645c934c645ca01c645cb2dc645cc52c645cd1fc645ce34c645cf01c645d0e8c645d100c645d200c645d300c645d400c645d590c645d690c645d7c9c645d8c3c645d9ccc645a600c645a75bc645a800c645a900c645aa00c645ab00c645ac00c645ad00c645ae2bc645af17c645b000c645b119c645b23fc645b300c645b400c645b500c645b600c645b703c645b800c645b913c645ba00c645bb05c745fc16000000c745f400000000c745f0000000008b45f083f81673708d55da8b45f001d00fb6000fb6c08945f88d55a68b45f001d00fb6000fb6c08945f4837df4007e0a8345f801836df401ebf08b45fc83e8010fb64405bc0fb6c02945f88b45fc83e8010fb64405bc0fb6c03145f8d17df88b45f889c18d55da8b45f001d08808836dfc018345f001eb8890") # removed c9 (leave) and c3 (ret) at the end 11 | 12 | # memory address where emulation starts 13 | ADDRESS = 0x1000000 14 | 15 | # Test X86 32 bit 16 | def test_i386(mode, code): 17 | print("Emulate x86 code") 18 | try: 19 | # Initialize emulator 20 | mu = Uc(UC_ARCH_X86, mode) 21 | 22 | # map 2MB memory for this emulation 23 | mu.mem_map(ADDRESS, 2 * 1024 * 1024) 24 | 25 | # write machine code to be emulated to memory 26 | mu.mem_write(ADDRESS, code) 27 | 28 | # initialize stack 29 | mu.reg_write(UC_X86_REG_ESP, ADDRESS + 0x200000) 30 | 31 | # emulate machine code in infinite time 32 | mu.emu_start(ADDRESS, ADDRESS + len(code)) 33 | 34 | # now print out some registers 35 | esp = mu.reg_read(UC_X86_REG_ESP) 36 | rbp = mu.reg_read(UC_X86_REG_RBP) 37 | print("ESP: 0x%x, RBP: 0x%x" % (esp, rbp)) 38 | bytes_to_read = 0x60 # The size of our stack... 39 | try: 40 | buf = mu.mem_read(esp, bytes_to_read) 41 | print(">>> buffer = 0x%x, size = %u, content = " \ 42 | %(esp, bytes_to_read), end="") 43 | for i in buf: 44 | print("%c" %i, end="") 45 | print("") 46 | except UcError as e: 47 | print(">>> buffer = 0x%x, size = %u, content = \n" \ 48 | %(esp, bytes_to_read)) 49 | print(">>> Emulation done") 50 | 51 | except UcError as e: 52 | print("ERROR: %s" % e) 53 | 54 | 55 | 56 | if __name__ == '__main__': 57 | test_i386(UC_MODE_64, SIKRIT_CODE) 58 | 59 | --------------------------------------------------------------------------------