pwntools icon indicating copy to clipboard operation
pwntools copied to clipboard

Nested invocation outputs ANSI escape codes and hangs

Open berdav opened this issue 5 years ago • 2 comments

Update Pwntools First

The issue was tested on version 4.2.1, Python3 and Python2 version in ubuntu 18.04 Vagrant box.

Target/Description

Invoking a pwntools-based script using pwntools will cause read* to output ANSI color escapes and then hangs.

To reproduce the bug I've used the following script:

#!/usr/bin/env python3
from pwn import *

# Target script to analyze
target_script = """
import pwn
p = pwn.process(["/bin/echo", "ciao"])
print(p.recvline().decode("ascii"))
p.close()
"""

# Where to put the analyzed script
target_path = "./pexpect-bug.py"

exec_string = "/usr/bin/env python3 {} SILENT=1".format(target_path)

# Write it to the disk
with open(target_path, "w") as f:
    f.write(target_script)

p = process(exec_string.split(" "))
while True:
    try:
        print(p.recv(1))
    except:
        break
p.close()

Debug Output / Results

The output, launching the script above with

$ python3 test.py DEBUG

Will result in:

[+] Starting local process '/usr/bin/env' argv=[b'/usr/bin/env', b'python3', b'./pexpect-bug.py', b'SILENT=1'] : pid 12679
[DEBUG] Received 0x11 bytes:
    00000000  1b 5b 3f 32  35 6c 1b 5b  3f 31 68 1b  3d 1b 5b 36  │·[?2│5l·[│?1h·│=·[6│
    00000010  6e                                                  │n│
    00000011
b'\x1b'
b'['
b'?'
b'2'
b'5'
b'l'
b'\x1b'
b'['
b'?'
b'1'
b'h'
b'\x1b'
b'='
b'\x1b'
b'['
b'6'
b'n'

Executing directly the generated pexpect-bug.py file will return the correct output:

$ python3 pexpect-bug.py SILENT=1
ciao

Workaround

The problem seems to be related with the stdout = PTY default in the process class constructor. Modifying the process invocation (of the main script) to

p = process(exec_string.split(" "), stdout=PIPE)

Will result in the correct output of the script:

[+] Starting local process '/usr/bin/env' argv=[b'/usr/bin/env', b'python3', b'./pexpect-bug.py', b'SILENT=1'] : pid 12714
[DEBUG] Received 0x6 bytes:
    b'ciao\n'
    b'\n'
b'c'
b'i'
b'a'
b'o'
b'\n'
b'\n'
[*] Process '/usr/bin/env' stopped with exit code 0 (pid 12714)

Misc

This issue was discovered by @Bonfee during a CTF.

berdav avatar Sep 21 '20 10:09 berdav

You need to set PWNLIB_NOTERM=1 as environment to the child process, or to parse those escape codes (or assume their meaning) and report cursor position to the child, like this (hope this works, but you get the idea):

p.stdout.write(b'\33[1;1R')

Not stdin, because it is a pipe by default, if you didn't pass stdin=PTY as argument to process creation. There will be one day an option for escape codes to be interpreted by pwntools itself, but for now it does not emulate the terminal and exposes raw bytestream I/O interface.

Arusekk avatar Sep 21 '20 12:09 Arusekk

I think this is intended. You could try running vim or nano or top as a process, you would probably see the same results. Pwntools-based exploits are ncurses applications (so that they can draw fancy spinners in log.progress() and many more). It would be possible to defer the curses (or maybe just this CSI 6 n / CSI <i> ; <j> R) initialisation until the first fancy term call is made (pwntools.ui or log.progress). Feel free to contribute such a deferring mechanism.

Arusekk avatar Nov 12 '20 21:11 Arusekk