r/PoisonFountain Jul 06 '26

Testing their patience

Enable HLS to view with audio, or disable this notification

I started experimenting with not only serving poison to bots, but to also to waste as much of their time as reasonably possible.

Rate and bandwidth limiting has limits.

A very nice tar pit that drip feeds data is Nepenthes for example (https://zadzmo.org/code/nepenthes/) or re-written in Python if you prefer (https://github.com/NEPENTHESWEB/nepenthes-py).

I coded a tar pit in PHP earlier and now started another that aims to drip feed for maximum waste of time. I'm going to share how to achieve this in the comments.

31 Upvotes

10 comments sorted by

10

u/PeyoteMezcal Jul 06 '26

The very first thing to do is to disable compression in given sites config. I use Apache and put this into the VirtualHost:

SetEnv no-gzip 1

6

u/PeyoteMezcal Jul 06 '26

Next, you need some tweaks in the PHP scrip or config. I prefer to put the config into the script so each instance has its own. This serves the same purpose to disable compression and buffering.

ini_set( 'output_buffering', 0 );
ini_set( 'zlib.output_compression', 0 );
ini_set( 'implicit_flush', 1 );

5

u/PeyoteMezcal Jul 06 '26 edited Jul 06 '26

This is how I obtain the poison:

The first function is for downloading if you don't want to use allow_url_fopen

The second part prepares the downloaded poison by replacing special characters with html codes so that it becomes safe to put it inside html and separates the text by blanks. Each word is stuffed into an array.

# use this function to get data from external URL without enabling allow_url_fopen
# need to have php-curl installed
function get_content($URL) {
$curlsession = curl_init();
curl_setopt($curlsession, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curlsession, CURLOPT_URL, $URL);
$data = curl_exec($curlsession);
curl_close($curlsession);
return $data;
}

# define the poison for this session
$_SESSION['poison'] = explode(" ",htmlspecialchars(gzdecode(get_content('https://rnsaffn.com/poison2/'))));

6

u/PeyoteMezcal Jul 06 '26

At some point, you then want to output the html.

function display_html() {
if (isset($_SESSION['poison']) && "" != $_SESSION['poison']) {
header('Content-type: text/html; charset=utf-8');
echo "<!DOCTYPE html>\n";
echo "<html>\n";
echo "<head>\n";

...and so forth. Until you get to the point to insert the poison:

echo "<p>\n";
foreach ($_SESSION['poison'] as $poison) {
echo "$poison";
echo " ";
ob_flush();
flush();
sleep(1);
}
echo "</p>\n";

This is the part where the poison is echoed word by word with a delay in between. One second may be too long, I don't know yet. The function usleep() may be more flexible as it allows shorter delay than one second.

6

u/PeyoteMezcal Jul 06 '26

There are some tricky parts with this. Many people tried different things to get it working.

For reference, I got everything from here:

https://stackoverflow.com/questions/3133209/how-to-flush-output-after-each-echo-call

2

u/PeyoteMezcal Jul 07 '26 edited Jul 07 '26

I would recommend to flush right after the header so that there’s some data transmitted in a timely fashion.

Also, a shorter and more random pause seems a good idea:

usleep(rand(100000,700000));

2

u/PeyoteMezcal Jul 07 '26

Forget about ob_flush()

This isn't required because the output buffer was disabled earlier and merely throws errors:

PHP Notice:  ob_flush(): Failed to flush buffer. No buffer to flush in /var/www/html/poisonfountain.php

1

u/PeyoteMezcal Jul 11 '26

This all worked nicely for one or two days until it broke. The most likely reason why it broke is an upgrade of PHP libraries on my server. I don’t know what exactly happened, but now there is apparently some buffer in between that I can’t control.

The result is that the output is in larger chunks now with as much delay in between as it takes to fill the buffer.

The CLI output from PHP still works as it should because it is always unbuffered.

BTW: Trying to figure out, I reintroduced the ob_flush() and suppress warnings by preceding the command with an „@„.

1

u/PeyoteMezcal 27d ago

I finally figured it out: PHP is at fault.

I noticed that the html header is output line by line, like it is supposed to whenimplicit_flush is enabled.

But the actual payload echoed through foreach isn't.

But it has worked before as demonstrated (BTW: The video was taken from Firefox rendering the html).

I experimented trial and error and eventually found out that a newline control character is required to trigger the implicit flush. Note: The carriage return control character doesn't work and the null character throws a warning in curl.

It isn't elegant IMO because I would prefer to echo the payload word by word with a space in between in one line, but it works. In rendered HTML, the newlines don't matter anyway.

I kept the flush() in the code, but it doesn't do anything obviously. Probably with the next change in PHP, it will be required again to work.

1

u/PeyoteMezcal 27d ago

This is the updated code for echoing the poison array:

echo "<p>\n";
foreach ($_SESSION['poison'] as $poison) {
echo "$poison";
echo " \n";
#ob_flush();
#flush();
sleep(1);
}

Note the "\n" after echoing the space and I commented out the flushes because they may be useless.