import jsonimport ctypeslib ='./crashMe.so'funcs = ctypes.cdll.LoadLibrary(lib)# void init()init = funcs.init# int setString(char *data);setString = funcs.setStringsetString.argtypes = [ctypes.c_char_p]setString.restype = ctypes.c_int# int getString();getString = funcs.getStringgetString.restype = ctypes.c_int# int delString();delString = funcs.delStringdelString.restype = ctypes.c_int# int setNum(uint64_t data);setNum = funcs.setNumsetNum.argtypes = [ctypes.c_uint64]setNum.restype = ctypes.c_int# int getNum();getNum = funcs.getNumgetNum.restype = ctypes.c_int# int delNum();delNum = funcs.delNumdelNum.restype = ctypes.c_intinit()print("Hello! CrashMe!")whileTrue: argc =0 args =None received =input()try: received = json.loads(received)if received['callNum']isNone:raiseException("Invalid Parameter") callNum = received['callNum']if received['args']isnotNone: argc =len(received['args']) args = received['args']if callNum ==1:if argc !=1:raiseException("Invalid Parameter") data = ctypes.c_char_p(args[0].encode())setString(data)elif callNum ==2:getString()elif callNum ==3:delString()elif callNum ==4:if argc !=1:raiseException("Invalid Parameter")setNum(ctypes.c_uint64(args[0]))elif callNum ==5:getNum()elif callNum ==6:delNum()else:raiseException("Invalid Parameter")print("Done")except json.decoder.JSONDecodeError:print("The input must be in JSON format")exit()exceptExceptionas e:print(e)exit()
It provides functionality for getting, setting and deleting strings, as well as getting, setting and deleting numbers. Our input must be in JSON format. These functions are implemented in the crashMe.so library. We actually only need to understand the string functions to solve the challenge. The important functions are as shown below:
On initialisation, the program calls setSigHandler which does signal(0xb, getflag). So on triggering a segmentation fault we can get the flag.
str is a global variable which points to the string we saved.
getString dereferences the address of the string, which is in str + 8, and prints it.
setString first does a check to see if str is NULL. If it is, it allocates 16 bytes of memory and assigns str to point to its address. Then, it checks if str + 8 is NULL. If it is, it allocates another 16 bytes of memory, then str + 8 is made to store the address of the new 16 bytes. This new 16 bytes is also initialised to 0. Finally, 15 bytes of the input string are copied into the string at the address stored in str + 8.
delString frees str and the other 16 bytes, whose address is at str + 8. However, notice that the function does not set str to NULL. In other words, its address remains as that of the memory region we have freed.
We can trigger a segmentation fault by calling setString to allocate the memory, delString to free it, then getString to access the freed memory region. This gets the flag, which is CDDC24{Y0u_L34rN3D_US3_4f73r_Fr33}