Date created: Sunday, September 29, 2013 3:35:17 PM. Last modified: Sunday, September 29, 2013 4:00:19 PM

PHP Goto Replicator

This PHP code is a basic metamorphic code example, although it is a script and not a compiled binary. After initially running the script it copies itself to a new file with a random file name, with the lines of code in a new random order, it then forks a new process which is executing the new copy of the script file and the original copy exits. Now there is a new copy of the script running, which is a copy of the original file but with a random file name and the lines of code are in a different order. So this is a perpetual process; reordering and replicating, then executing a new instance (process) killing the previous one.

It is a basic example of replicating metamorphic code. The new file is always in the same directory as this is just a proof of concept. Where the new file is stored could be more random or covert, this is just one improvement that could be made for example, but those type of steps lean towards malicious intentions rather than purely educational exercises for a PoC.

A simple `killlall php` will stop the script running.

This PHP script is based on the original idea of using goto statements by user "James Holderness" on this Stack Overflow post; http://stackoverflow.com/questions/10113254/metamorphic-code-examples

The script is in three sections, "a", "l" and "f". Section "a" generates a random new file name and opens the file for writing. In section "l" the script copies its self to that new file name and this is where the lines of the code are reordered. Finally in section "f" the script forks off a child process, which is the new copy of the script, and the original copy exits. The process ID is always changing. This is why there is the “sleep(10)” statement.

polymorph-jamesholderness-javano.php

<?php goto a01;
//
// Extension of PHP code snippet for polymorphic code examples given by
// James Holderness on Stack Overflow post:
// http://stackoverflow.com/a/16379982/560065
// Extended by Javano / jwbensley@gmail.com (please send me new ideas!)
//
// This script used Process Control to fork, check if PCNTL is disabled
// `php -m | grep pcntl` see php.ini section: "disable_functions"
//
// This was written on Linux, if it doesn't work on another OS I can't help
// 
// Lines that start with double slash "//" for a comment are not copied
//
a01: $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';    goto a02;
a02: $randomString = __DIR__."/";                                                       goto a03;
a03: $i = 0;                                                                            goto a04;
a04: if ($i < 10)                                                                       goto a05; else goto a07;
a05:   $randomString .= $characters[rand(0, strlen($characters) - 1)];                  goto a06;
a06:   $i++;                                                                            goto a04;
a07: $randomString .= ".php";                                                           goto a08;
a08: $ARGS=Array("-f",$randomString);                                                   goto a09;
a09: $handle_out = fopen("$randomString", "w");  goto l01;
l01: $filename = __FILE__;                       goto l02;
l02: $contents = file_get_contents($filename);   goto l03;
l03: $lines = explode("\n",$contents);           goto l04;
l04: $collection = array();                      goto l05;
l05: $pattern = '%^[^:]+:.*goto [^;]+;$%';       goto l06;
l06: $i = 0;                                     goto l07;
l07: if ($i < count($lines)-1)                   goto l08; else goto l23;
l08:   $line = $lines[$i];                       goto l09;
l09:   $line = trim($line);                      goto l10;
l10:   if (substr($line,0,2) != '//')            goto l11; else goto l22;
l11:     if (preg_match($pattern, $line) === 1)  goto l12; else goto l13;
l12:       $collection[] = $line;                goto l22;
l13:       shuffle($collection);                 goto l14;
l14:       $j = 0;                               goto l15;
l15:       if ($j < count($collection))          goto l16; else goto l19;
l16:         echo $collection[$j]."\n";          goto l17;
l17:         fwrite($handle_out, $collection[$j]."\n");    goto l18;
l18:         $j++;                               goto l15;
l19:       $collection = array();                goto l20;
l20:       fwrite($handle_out, $line."\n");      goto l21;
l21:       echo $line."\n";                      goto l22;
l22:   $i++;                                     goto l07;
l23: fclose($handle_out);                        goto f01;
f01: $pid = pcntl_fork();                        goto f02;
f02: if ($pid == -1)                             goto f03; else goto f04;
f03:   die("Could not fork a new child\n");      goto f03;
f04: if ($pid)                                   goto f05; else goto f06;
f05:   exit(0);                                  goto f05;
f06: $sid = posix_setsid();                      goto f07;
f07: if ($sid < 0)                               goto f08; else goto f09;
f08:   die("Child posix_setsid error\n");        goto f08;
f09: sleep(10);                                  goto f10;
f10: pcntl_exec(PHP_BINARY, $ARGS);
l24: exit(0);                                    goto l24;
?> 

Script output;

Below after initially starting the script, a scrambled version is printed to the screen (this is something to show that the script is actually running!). After that, 10 seconds later a different scrabmled version is printed to the screen. This process repeats, with a different order of code being printed each time. Each time that happens, a new file has been created, executed, and a new fork is launched.

bensley@bensley-n2:/media/EXT3DATA/Home/php$ ls -l
-rw-rw-r-- 1 bensley bensley 3511 Sep 29 14:47 polymorph-jamesholderness-javano.php

bensley@bensley-n2:/media/EXT3DATA/Home/php$ /opt/lampp/bin/php -f ./polymorph-jamesholderness-javano.php 

<?php goto a01;
f09: sleep(10);                                  goto f10;
l18:         $j++;                               goto l15;
l14:       $j = 0;                               goto l15;
l12:       $collection[] = $line;                goto l22;
f07: if ($sid < 0)                               goto f08; else goto f09;
a07: $randomString .= ".php";                                                           goto a08;
l05: $pattern = '%^[^:]+:.*goto [^;]+;$%';       goto l06;
f02: if ($pid == -1)                             goto f03; else goto f04;
a03: $i = 0;                                                                            goto a04;
a08: $ARGS=Array("-f",$randomString);                                                   goto a09;
l15:       if ($j < count($collection))          goto l16; else goto l19;
l04: $collection = array();                      goto l05;
l23: fclose($handle_out);                        goto f01;
a01: $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';    goto a02;
l11:     if (preg_match($pattern, $line) === 1)  goto l12; else goto l13;
f01: $pid = pcntl_fork();                        goto f02;
f06: $sid = posix_setsid();                      goto f07;
l09:   $line = trim($line);                      goto l10;
l08:   $line = $lines[$i];                       goto l09;
a09: $handle_out = fopen("$randomString", "w");  goto l01;
f03:   die("Could not fork a new child\n");      goto f03;
l19:       $collection = array();                goto l20;
f05:   exit(0);                                  goto f05;
f08:   die("Child posix_setsid error\n");        goto f08;
a02: $randomString = __DIR__."/";                                                       goto a03;
l22:   $i++;                                     goto l07;
l13:       shuffle($collection);                 goto l14;
a04: if ($i < 10)                                                                       goto a05; else goto a07;
l01: $filename = __FILE__;                       goto l02;
l10:   if (substr($line,0,2) != '//')            goto l11; else goto l22;
l17:         fwrite($handle_out, $collection[$j]."\n");    goto l18;
a06:   $i++;                                                                            goto a04;
l06: $i = 0;                                     goto l07;
l16:         echo $collection[$j]."\n";          goto l17;
l02: $contents = file_get_contents($filename);   goto l03;
a05:   $randomString .= $characters[rand(0, strlen($characters) - 1)];                  goto a06;
l21:       echo $line."\n";                      goto l22;
l07: if ($i < count($lines)-1)                   goto l08; else goto l23;
l20:       fwrite($handle_out, $line."\n");      goto l21;
f04: if ($pid)                                   goto f05; else goto f06;
l03: $lines = explode("\n",$contents);           goto l04;
f10: pcntl_exec(PHP_BINARY, $ARGS);
l24: exit(0);                                    goto l24;
?>

<?php goto a01;
a04: if ($i < 10)                                                                       goto a05; else goto a07;
f02: if ($pid == -1)                             goto f03; else goto f04;
l16:         echo $collection[$j]."\n";          goto l17;
l21:       echo $line."\n";                      goto l22;
f04: if ($pid)                                   goto f05; else goto f06;
l09:   $line = trim($line);                      goto l10;
a09: $handle_out = fopen("$randomString", "w");  goto l01;
l06: $i = 0;                                     goto l07;
l23: fclose($handle_out);                        goto f01;
f08:   die("Child posix_setsid error\n");        goto f08;
l02: $contents = file_get_contents($filename);   goto l03;
f09: sleep(10);                                  goto f10;
l13:       shuffle($collection);                 goto l14;
f06: $sid = posix_setsid();                      goto f07;
a05:   $randomString .= $characters[rand(0, strlen($characters) - 1)];                  goto a06;
l01: $filename = __FILE__;                       goto l02;
l11:     if (preg_match($pattern, $line) === 1)  goto l12; else goto l13;
f01: $pid = pcntl_fork();                        goto f02;
l10:   if (substr($line,0,2) != '//')            goto l11; else goto l22;
f03:   die("Could not fork a new child\n");      goto f03;
l17:         fwrite($handle_out, $collection[$j]."\n");    goto l18;
a08: $ARGS=Array("-f",$randomString);                                                   goto a09;
l03: $lines = explode("\n",$contents);           goto l04;
a03: $i = 0;                                                                            goto a04;
l20:       fwrite($handle_out, $line."\n");      goto l21;
f07: if ($sid < 0)                               goto f08; else goto f09;
l15:       if ($j < count($collection))          goto l16; else goto l19;
l08:   $line = $lines[$i];                       goto l09;
l19:       $collection = array();                goto l20;
l12:       $collection[] = $line;                goto l22;
l05: $pattern = '%^[^:]+:.*goto [^;]+;$%';       goto l06;
a02: $randomString = __DIR__."/";                                                       goto a03;
a01: $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';    goto a02;
a06:   $i++;                                                                            goto a04;
a07: $randomString .= ".php";                                                           goto a08;
l22:   $i++;                                     goto l07;
l04: $collection = array();                      goto l05;
l14:       $j = 0;                               goto l15;
l07: if ($i < count($lines)-1)                   goto l08; else goto l23;
f05:   exit(0);                                  goto f05;
l18:         $j++;                               goto l15;
f10: pcntl_exec(PHP_BINARY, $ARGS);
l24: exit(0);                                    goto l24;
?>

<?php goto a01;
l22:   $i++;                                     goto l07;
l16:         echo $collection[$j]."\n";          goto l17;
l18:         $j++;                               goto l15;
l17:         fwrite($handle_out, $collection[$j]."\n");    goto l18;
f05:   exit(0);                                  goto f05;
a02: $randomString = __DIR__."/";                                                       goto a03;
f07: if ($sid < 0)                               goto f08; else goto f09;
l02: $contents = file_get_contents($filename);   goto l03;
l07: if ($i < count($lines)-1)                   goto l08; else goto l23;
f03:   die("Could not fork a new child\n");      goto f03;
l04: $collection = array();                      goto l05;
a01: $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';    goto a02;
a05:   $randomString .= $characters[rand(0, strlen($characters) - 1)];                  goto a06;
l23: fclose($handle_out);                        goto f01;
l12:       $collection[] = $line;                goto l22;
l10:   if (substr($line,0,2) != '//')            goto l11; else goto l22;
l20:       fwrite($handle_out, $line."\n");      goto l21;
l03: $lines = explode("\n",$contents);           goto l04;
f09: sleep(10);                                  goto f10;
l13:       shuffle($collection);                 goto l14;
l15:       if ($j < count($collection))          goto l16; else goto l19;
a06:   $i++;                                                                            goto a04;
l01: $filename = __FILE__;                       goto l02;
l08:   $line = $lines[$i];                       goto l09;
l09:   $line = trim($line);                      goto l10;
l11:     if (preg_match($pattern, $line) === 1)  goto l12; else goto l13;
l05: $pattern = '%^[^:]+:.*goto [^;]+;$%';       goto l06;
f06: $sid = posix_setsid();                      goto f07;
l14:       $j = 0;                               goto l15;
l19:       $collection = array();                goto l20;
f08:   die("Child posix_setsid error\n");        goto f08;
a08: $ARGS=Array("-f",$randomString);                                                   goto a09;
a07: $randomString .= ".php";                                                           goto a08;
f02: if ($pid == -1)                             goto f03; else goto f04;
a03: $i = 0;                                                                            goto a04;
a04: if ($i < 10)                                                                       goto a05; else goto a07;
f01: $pid = pcntl_fork();                        goto f02;
a09: $handle_out = fopen("$randomString", "w");  goto l01;
l06: $i = 0;                                     goto l07;
f04: if ($pid)                                   goto f05; else goto f06;
l21:       echo $line."\n";                      goto l22;
f10: pcntl_exec(PHP_BINARY, $ARGS);
l24: exit(0);                                    goto l24;
?>

bensley@bensley-n2:/media/EXT3DATA/Home/php$ ls -l
-rw-rw-r-- 1 bensley bensley 2975 Sep 29 14:51 CHut3A9wRp.php
-rw-rw-r-- 1 bensley bensley 2975 Sep 29 14:51 fbk9PZtYju.php
-rw-rw-r-- 1 bensley bensley 2975 Sep 29 14:52 FUBwI73Bfl.php
-rw-rw-r-- 1 bensley bensley 3511 Sep 29 14:47 polymorph-jamesholderness-javano.php

Previous page: QuakeIII
Next page: MySQL Admin Notes