The Python ‘print()’ Function Is More Powerful Than You Think | by Nicholas Obert | Aug, 2022

Exploring separators, code injection, and more

Photo by Esteban Lopez on Unsplash

The Python programming language is extremely beginner-friendly thanks to its simple English-like syntax and powerful yet intuitive built-in functions. Chances are that your first line of Python code looked something like this:

print("Hello World")

As you get more comfortable with the language, you start learning about the different capabilities of the built-in print() function. The more experience you get as a Python developer, the more edge cases, hacks, exotic syntax, and advanced features you discover.

In this article, I will show you what the print() function can do, starting from its basic functionalities and then covering increasingly more advanced use cases and interesting hacks.

The most basic way to use the print() statement, and also the most common is to log a message (string or another object) to the console.

And unsurprisingly, the console output would be the following:

Hello World

Now, let’s get into less-known features.

The print() function also allows you to specify a character to be appended at the end of the string with the end parameter. For example, if you want to print the sequence "***" after the main argument, you can do this:

And that would output the following text (without a newline at the end):

Hello World***

If you wish to exclude the newline from the output to print everything on the same line, you can set end='' like this:

Separators are another key feature of the Python print() statement. To begin, you can print multiple values with the same function call by separating them with commas:

Hello World

The print() function implicitly sets its parameter sep=' ' so that arguments passed like this are separated by a space when printed. However, you can specify your own string to separate each argument:


Custom object representation

When printing complex objects in Python, you usually specify how they should look as a string instead of relying on the default undescriptive behavior:

<__main__.Entry object at 0x7fc3ddd5ffd0>

So, when you write a class, you can overwrite the __str__() and __repr__() dunder methods to let Python know how it should handle the printed object.

Entry: a=1

I always prefer to explicitly set both __str__() and __repr__(), but you don’t need to.

Have you ever thought about how print() knows where to output the given message? The default behavior is to write the string to the sys.stdout stream, but you can specify the output file with the file parameter.

This code snippet creates a file named “output.txt” and writes “Hello World” to it. This is possible because print() implicitly calls the .write() method of the stream you pass in, so this would be equivalent to

f.write("Hello World\n")

With this in mind, you can create a rudimental logger using the print() function.

Or, much better, you can override the print() function to extend its functionalities by logging every print statement to a file.

With this approach, you can easily make every print() call in your file and automatically log a message to a file. However, if you’re into that kind of stuff, you would be better off using the logging module.

Execute Code by Printing to Files

What if you could hack the print() function to make it execute arbitrary code? If you remember, I’ve mentioned that print() calls the .write() method of the file you pass in. With that in mind, you can overwrite or override this method with your own code.

This is the payload.
Payload function called with arguments: Hello World
This is the payload.
Payload function called with arguments

Alternatively, you can override sys.stdout.write() to trigger the payload function for any default print() call.

Executing payload
Hello WorldExecuting payload

As you may have noticed, Python calls the payload() function (and thus also the .write() method) twice, so you may have to handle that.

This code injection technique may not have many real-world use cases, but who knows what people can come up with?

While the code injection shown before wouldn’t cause any harm, the next example could. If you’ve been programming for some time, you have heard how using third-party libraries could introduce some security threats into your source code.

In this example, I’ll show you how a vendor could include malicious code that gets triggered by the print() function.

And then, you would use this class in your programs:

Alternatively, you could override the global sys.stdout.write() in your malicious module so that every print() call executes your payload.

Now, you might argue that someone looking at the source code would immediately notice these malicious lines of code. I sometimes inspect the libraries I use myself. How about hiding the malicious code inside a C extension instead?

Python developers are much less likely to inspect a C source file from a Python package than a Python file. Plus, if you compile the extension locally upon installation, antiviruses (if you use any) should trust the resulting binary file as coming from the user. Or how about code obfuscation?

It’s funny to realize how vulnerable software developers can be. And then you get a reverse shell, run a keylogger with user permission to harvest admin/root password, and finally take over the system.

Although I won’t show how to achieve this specifically, you can take a look at this guide on writing C extensions for Python:

To wrap it up, the print() function has many more capabilities than Python developers usually know of, from simply printing to the console to writing to files to executing arbitrary code. After all, the print() function is just a tool, and as such, you can hack it to achieve different goals.

A paintbrush is just a stick with bristles attached to it. It’s up to the artist to employ it creatively.

And can we claim that an artist with a paintbrush is just a hacker with a stick?

I hope you enjoyed this article. If you know about any other practical or theoretical use case for the print() function, let us know in a comment.

Thanks for reading!

If you’re interested in making your Python code more professional and maintainable, check out this story:

News Credit

%d bloggers like this: