> For the complete documentation index, see [llms.txt](https://elijahchia.gitbook.io/ctf-blog/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://elijahchia.gitbook.io/ctf-blog/cddc-qualifiers-2024/crashme-pwn.md).

# crashMe (pwn)

{% file src="/files/zIoyMHlQ7obkOvjvZaxu" %}

{% file src="/files/zo3uYBGbVNmtEoyABk6B" %}

The main Python code is as follows:

```python
import json
import ctypes

lib = './crashMe.so'
funcs = ctypes.cdll.LoadLibrary(lib)

# void init()
init = funcs.init

# int setString(char *data);
setString = funcs.setString
setString.argtypes = [ctypes.c_char_p]
setString.restype = ctypes.c_int

# int getString();

getString = funcs.getString
getString.restype = ctypes.c_int

# int delString();
delString = funcs.delString
delString.restype = ctypes.c_int

# int setNum(uint64_t data);
setNum = funcs.setNum
setNum.argtypes = [ctypes.c_uint64]
setNum.restype = ctypes.c_int

# int getNum();
getNum = funcs.getNum
getNum.restype = ctypes.c_int

# int delNum();
delNum = funcs.delNum
delNum.restype = ctypes.c_int

init()
print("Hello! CrashMe!")
while True:
    argc = 0
    args = None
    received = input()
    try:
        received = json.loads(received)
        if received['callNum'] is None:
            raise Exception("Invalid Parameter")

        callNum = received['callNum']
        if received['args'] is not None:
            argc = len(received['args'])
            args = received['args']
        
        if callNum == 1:
            if argc != 1:
                raise Exception("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:
                raise Exception("Invalid Parameter")
            setNum(ctypes.c_uint64(args[0]))

        elif callNum == 5:
            getNum()

        elif callNum == 6:
            delNum()

        else:
            raise Exception("Invalid Parameter")
        print("Done")

    except json.decoder.JSONDecodeError:
        print("The input must be in JSON format")
        exit()
        
    except Exception as 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:

```c
undefined8 getString(void)
{
  undefined8 uVar1;
  
  if (str == 0) {
    uVar1 = 0xffffffff;
  }
  else {
    printf("string @ %s\n",*(undefined8 *)(str + 8));
    uVar1 = 0;
  }
  return uVar1;
}
undefined8 setString(void *param_1)
{
  void *pvVar1;
  void *pvVar2;
  
  if (str == (void *)0x0) {
    str = malloc(0x10);
    memset(str,0,0x10);
  }
  pvVar1 = str;
  if (*(long *)((long)str + 8) == 0) {
    pvVar2 = malloc(0x10);
    *(void **)((long)pvVar1 + 8) = pvVar2;
    memset(*(void **)((long)str + 8),0,0x10);
  }
  memcpy(*(void **)((long)str + 8),param_1,0xf);
  return 0;
}
undefined8 delString(void)
{
  undefined8 uVar1;
  
  if (str == (void *)0x0) {
    uVar1 = 0xffffffff;
  }
  else {
    free(*(void **)((long)str + 8));
    free(str);
    uVar1 = 0;
  }
  return uVar1;
}
void getflag(void)
{
  int __fd;
  __fd = open("./flag",0,0);
  read(__fd,flag,0x100);
  puts(flag);
                    /* WARNING: Subroutine does not return */
  exit(0);
}
void setSigHandler(void)
{
  signal(0xb,getflag);
  return;
}
int init(EVP_PKEY_CTX *ctx)
{
  int iVar1;
  
  setvbuf(_stdout,(char *)0x0,2,0);
  setvbuf(_stderr,(char *)0x0,2,0);
  iVar1 = setSigHandler();
  return iVar1;
}

```

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.&#x20;

`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.&#x20;

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}`
