Gallopsled / pwntools

CTF framework and exploit development library
http://pwntools.com
Other
11.98k stars 1.7k forks source link

Terminal cannot print ANSI color after importing `pwn` #2421

Closed Dilrevx closed 3 months ago

Dilrevx commented 3 months ago

Background

I was under sh.interactive() mode without setting debug context. I entered ls command, pressed enter, and the output was empty linebreaks.

This is the pwntools script. 25be675266017997b09c9230f8d1ba2

This is the pwntools.interactive output 5d137444e17648cc592b95be6ae5711

This is the nc output that I expected image

environment

Further information

I attach a breakpoint and dump the strings. Below is the returned string for a ls.

image

I write a test script as following:

# from pwn import *

a = " ls\r\n\x1b[1;34mbin\x1b[m         \x1b[1;34metc\x1b[m         \x1b[1;36mlinuxrc\x1b[m     \x1b[1;34mproc\x1b[m        \x1b[1;34msys\x1b[m         \x1b[1;34musr\x1b[m\r\n\x1b[1;34mdev\x1b[m         \x1b[1;32minit\x1b[m        \x1b[1;34mlost+found\x1b[m  \x1b[1;34msbin\x1b[m        \x1b[1;34mtmp\x1b[m\r\n/ "
print(a)

It seems that print CAN translate ASNI codes with first line commented, but CANNOT with pwn imported. Why is this happening and what should I do with it?

peace-maker commented 3 months ago

The \r carriage-return is causing the line to be erased. The remote server you're communicating with uses \r\n to signal line ends like windows does instead of \n. Try specifying the desired newline using context.newline = b'\r\n' globally or using p.newline = b'\r\n' for the remote tube only.

Dilrevx commented 3 months ago

The \r carriage-return is causing the line to be erased. The remote server you're communicating with uses \r\n to signal line ends like windows does instead of \n. Try specifying the desired newline using context.newline = b'\r\n' globally or using p.newline = b'\r\n' for the remote tube only.

Many thx. Setting p.newline=\r\n fix the problem for interactive. But now I am confused. What is happening here? I once thought that interactive just recv and print the bytes transmitted through the socket, without modifying the stream, unlike dropend. Is that wrong?

upd: I have checked the recv_thread in interactive. Its implementation replaces all occurrence of newline with \n, so
\r is eliminated. Another fun fact is that the recv timeout is 50ms, which might introduce a break before \r. This is why part of the output can be shown under debug log level.

Yet another problem remains unfixed. The script I wrote in further information section simply print the \r string with python built-in function. With pwn imported, setting context.newline = \r\n still leaves the output to be empty. And without pwn the output is correct even \r is contained in string. So I am confused:

peace-maker commented 3 months ago

Which pwntools version are you running? There were changes in the terminal handling in the beta. pwn version in the console.

pwntools takes over the terminal like curses apps do to allow for fancy spinning loggers and interactive editing features like gnu readline when imported from pwn. Using features directly from pwnlib doesn't touch the terminal.

Printing \r directly causes it to be interpreted by pwntools' terminal which apparently differs from your default one. @Arusekk can tell you more

Dilrevx commented 3 months ago

My version is 4.10.0. Indeed, I didn't notice the terminal change, which tells everything.

Your explanation is useful enough for me, curses is a good example. Thanks :)