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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://elijahchia.gitbook.io/ctf-blog/cddc-qualifiers-2024/crashme-pwn.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
