渗透第一次作业

第一天

就业简介

就业

CTF比赛、护网行动、实习(项目经历)

简历

1、是否有真实的渗透经历(自己从头到尾的渗透经历)

注意:渗透的合法性和授权性

众测平台:补天 国家漏洞库

补天 - 企业和白帽子共赢的漏洞响应平台,帮助企业建立SRC

国家信息安全漏洞库

未经授权边界:验证漏洞(用无害验证)

2、现在web漏洞 sql注入漏洞 dead

3、web漏洞 护网 整体基线检查 nulei (逐年减少) 前端加密

web前端逆向 加密函数------解密函数(插件:burpsuite autodecoder galaxy)

小程序/app 注意 抓包(app 双向证书绑定 绕过 app 模块 模拟器 真机 nexus5) 前端------后端服务器

云安全: 云安全------> docker k8s 80%

AI

MCP 号称 自动化测试 自动化解题 kali nmap sqlmap

看代码 exp

claude code codex geminicli

claude opus4.5 codex gpt-5.2 gemini3pro glm-4.7 minimax2.1

环境配置

debug调试(重要)

next2shell next.js 0-1分析

python pycharm python3.10 Python Releases for Windows | Python.org

conda env 虚拟环境 python2.7 python.3.10(不相互影响)

java idea jdk1.8 / jdk17(module 限制大部分java,反序列化漏洞 bypass) / jdk21 maven pip

Java 档案下载 - Java SE 8

虚拟机:kali Ubuntu Windows

lnmp lamp linux nginx mysql php

wnmp wamp windows nginx mysql php

中间件:nginx apache 大厂 tomcat 开源 idea java weblogic

linux ubuntu22 nginx php-fpm php7.3-php7.4

源码安装:apt安装

apt-get install php7.4-dev autoconf automake

1、源码调试 代码 php C语言(底层)

2、debug底层C语言 pwndbg / vscode

ubuntu安装nginx以及php的部署

1、安装依赖包

复制代码
apt-get install gcc
apt-get install libpcre3 libpcre3-dev
apt-get install zlib1g zlib1g-dev
sudo apt-get install openssl 
sudo apt-get install libssl-dev

2、安装nginx

复制代码
cd /usr/local
mkdir nginx
cd nginx
tar -xvf nginx-1.21.6.tar.gz

3、编译nginx

复制代码
/usr/local/nginx/nginx-1.21.6
# 执行命令
./configure     
./configure --prefix=/home/centos/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_sub_module
# 执行make命令
make
# 执行make install命令
make install

4、启动nginx

复制代码
cd /usr/local/nginx/sbin
# 启动nginx
./nginx

5、增加源地址

复制代码
执行三条命令,添加php的源地址,更新,安装
sudo apt-get install software-properties-common
sudo add-apt-repository -y ppa:ondrej/php
sudo apt-get update

6、安装php

复制代码
nginx使用php的话要用到php7.3-fpm,所以要安装php-fpm
sudo apt-get install php7.3 php7.3-mysql php7.3-fpm php7.3-curl php7.3-xml php7.3-gd php7.3-mbstring php-memcached php7.3-zip

7、配置php-fpm

复制代码
把监听端口改掉
listen = /run/php/php7.3-fpm.sock
listen = 127.0.0.1:9000

8、启动php-fpm

复制代码
sudo service php7.3-fpm start
netstat -lnt | grep 9000

第二天

php底层后门调试

代码层面是xdebug+vscode

1、pwndbg 命令行 不太直观 比较便捷

2、docker(第一你的电脑配置一般,第二 你不想在你系统上安装太多编译工具)

docker有别人的镜像分享

hub.docker.com

docker run -it --rm --name debug -p 8080:8080 -p 2222:22 tuwen/phpsrc

debug:8.1-backdoor

启动镜像成为一个容器 镜像iso->容器系统

ubuntu 容器 8080------> 8080 192.168.68.129:8080------>容器:8080 容器里22端口 2222

相当于可以利用本地2222登录他的容器

docker 便捷,调试;docker比本地调试稍微麻烦一点,但是省去了安装环境的环节

如何编辑docker容器里面的代码

  1. 直接进容器里编辑 不推荐 vim编辑器 我非常熟悉 70 80 90

  2. 把代码复制出来 把容器里的代码 复制到物理机 ubuntu 也不太方便

  3. 推荐方案 用vscode直接编辑
    linux系统登录的两种方案

  4. 密码

  5. 证书登录 私钥 公钥登录 RSA密码环境下最大破解了768

目前通用的RSA算法的密钥长度2048 4096

php8以后大量国际顶尖安全研究员假如php8研发行列,从8开始漏洞大幅度降低减少

C底层调试+PHP代码挑战赛

dns ip--->服务器的ip 三次握手 ---> ssl--->对称加密秘钥加密--->https request--->response

全局函数:$_SERVER(可以获取到所有的环境变量)

eg:$_SERVER http_x_forwarded_for

docker 别人创建好的8.1源码环境 来调试

  1. 下载源码

  2. 编译源码

  3. vscode链接ubuntu

  4. 安装c/c++插件

  5. 找到相应函数 下断调试

  6. 找到一个匹配的password 让这个password通过sha256 等于ca572756809c324632167240d208681a03b4bd483036581a6190789165e1387a

复制代码
<?php
$password = trim($_REQUEST['password'] ?? '');
$name = trim($_REQUEST['name'] ?? 'viewsource');
function viewsource() {show_source(__FILE__);}

if (strcmp(hash('sha256', $password), 'ca572756809c324632167240d208681a03b4bd483036581a6190789165e1387a') === 0) {
    function readflag() {
        echo 'flag';
    }
}
//无解 只扫从高级语言的代码层面上没有解法
//调试 看C语言代码
//顶层 vs 非顶层 问题 readflag 非顶层 viewsource 顶层 toplevel
//顶层函数 如何处理 非顶层函数 如何处理
//编译 执行
//1.2.3.4---->执行
//1.词法分析 语法分析    2.AST树的构建    3.将这个语法树 opcode数组 handler $a +$b c层函数
//执行调用

$name();
?>

PHP的执行分为两部分:

  1. 源代码编译成Zend虚拟机指令(PHP中叫opline)的过程
    1. 调用`zendparse`完成词法分析、语法分析,生成AST树
    2. 调用`init_op_array`, `zend_compile_top_stmt`来完成AST到opline数组的转化
    3. 调用`pass_two`完成编译时到运行时信息的转化,设置每个opcode对应的handler
  2. Zend虚拟机执行机器指令的过程
    1. 拿到编译完成后的opline array,依次执行每个opcode,其实就是执行每个opcode对应的handler,完成PHP脚本的执行。

编译函数的代码:PHP在编译"函数定义"的时候,会使用`zend_compile_func_decl`函数:

复制代码
void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /* {{{ */
{
    ...
    zend_ast_decl *decl = (zend_ast_decl *) ast;
    zend_bool is_method = decl->kind == ZEND_AST_METHOD;
    if (is_method) {
        zend_bool has_body = stmt_ast != NULL;
        zend_begin_method_decl(op_array, decl->name, has_body);
    } else {
        zend_begin_func_decl(result, op_array, decl, toplevel);
        if (decl->kind == ZEND_AST_ARROW_FUNC) {
            find_implicit_binds(&info, params_ast, stmt_ast);
            compile_implicit_lexical_binds(&info, result, op_array);
        } else if (uses_ast) {
            zend_compile_closure_binding(result, op_array, uses_ast);
        }
    }
}

这个函数有个挺关键的参数叫 'toplevel' :表示当前的函数定义是否在顶层作用域。跟进用于处理普通函数的 "zend_begin_func_decl"。

php闭包 匿名 箭头函数

匿名函数,也叫闭包函数,允许临时创建一个没有指定名称的函数。最经常用作回调函数callable参数的值。闭包函数也可以作为变量的值来使用,后面要加上分号。

匿名函数:$a() none(匿名函数目前是通过Closure类来实现的)

is_method 类方法 class XYZ{ }

function

复制代码
static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_ast_decl *decl, zend_bool toplevel) /* {{{ */
{
    ...
    zend_register_seen_symbol(lcname, ZEND_SYMBOL_FUNCTION);
    if (toplevel) {
        if (UNEXPECTED(zend_hash_add_ptr(CG(function_table), lcname, op_array) == NULL)) {
            do_bind_function_error(lcname, op_array, 1);
        }
        zend_string_release_ex(lcname, 0);
        return;
    }

    /* Generate RTD keys until we find one that isn't in use yet. */
    key = NULL;
    do {
        zend_tmp_string_release(key);
        key = zend_build_runtime_definition_key(lcname, decl->start_lineno);
    } while (!zend_hash_add_ptr(CG(function_table), key, op_array));

    ...
}

函数所在作用域造成的opline差异

toplevel为false时,PHP会调用get_next_op()来生成一个新的opline,而true时则不会.

复制代码
<?php
function func1() {
    echo 'func1';
}
func1();

这里并没有函数定义的opcode,从第5行开始的两个opcode是`INIT_FCALL`和`DO_FCALL`,用于执行函数。

复制代码
<?php
if (true) {
    function func2() {
        echo 'func2';
    }
}
func2();

PHP编译非顶级作用域函数时,原始函数名和生成的key将会顺序储存在 DECLARE_FUNCTION这个opline的属性中,在执行DECLARE_FUNCTION这个opcode时,才会将真正的原始函数名放进函数表中。

也就是说,作用域如果不是顶级的函数,在编译阶段会先以一个\0开头的函数名被放入函数表中,在执行阶段于DECLARE_FUNCTION的处理器中才会将真正的函数名放入函数表。

绕过trim过滤

trim函数在接收参数的时候会去除掉字符串首尾的空白字符。这里的空白字符包含如下六个字符:<space>\n\r\t\v\0。也就是说, 用户传入的name的第一个\0字符被trim过滤掉了,导致无法正常调用函数。

解决方法:

首先,动态函数调用使用的opcode是INIT_DYNAMIC_CALL,我们使用vld可以看到。然后在PHP源码中找到对应的handler:

复制代码
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    USE_OPLINE

    zval *function_name;
    zend_execute_data *call;

    SAVE_OPLINE();
    function_name = RT_CONSTANT(opline, opline->op2);

try_function_name:
    if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) {
        call = zend_init_dynamic_call_string(Z_STR_P(function_name), opline->extended_value);
    } else if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT)) {
        call = zend_init_dynamic_call_object(function_name, opline->extended_value);
    } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY)) {
        call = zend_init_dynamic_call_array(Z_ARRVAL_P(function_name), opline->extended_value);
    }
    ...
}

当函数名是一个字符串时,会执行zend_init_dynamic_call_string

复制代码
static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_string *function, uint32_t num_args) /* {{{ */
{
    if ((colon = zend_memrchr(ZSTR_VAL(function), ':', ZSTR_LEN(function))) != NULL &&
        colon > ZSTR_VAL(function) &&
        *(colon-1) == ':'
    ) {
        ...
    } else {
        if (ZSTR_VAL(function)[0] == '\\') {
            lcname = zend_string_alloc(ZSTR_LEN(function) - 1, 0);
            zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(function) + 1, ZSTR_LEN(function) - 1);
        } else {
            lcname = zend_string_tolower(function);
        }
        if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) {
            zend_throw_error(NULL, "Call to undefined function %s()", ZSTR_VAL(function));
            zend_string_release_ex(lcname, 0);
            return NULL;
        }
        ...
    }
    ...
}

PHP 函数编译源码解析

函数签名和参数

第一步:解析 AST 节点

第二步:初始化 op_array

第三步:设置函数属性

第四步:区分函数类型

第五步:处理类方法 vs 普通函数

第六步:隔离作用域

第七步:编译函数体

第八步:编译参数

第九步:生成器特殊处理

AST 类型 PHP 代码 标志
ZEND_AST_FUNC_DECL function foo() {} 普通函数
ZEND_AST_METHOD class A { function foo() {} } 类方法
ZEND_AST_CLOSURE $f = function() {}; 闭包
ZEND_AST_ARROW_FUNC $f = fn() => $x; 箭头函数

非对称加密 来传递 对称秘钥

第一 确认身份 不能伪造

第二点 解密

CA 公钥

非对称加密 私钥 公钥

server------> 将一些有消息新 公钥 sha384

dsadasdasdasdasdasdasdasdasdasdasdasda CA 私钥进行加密

客户端拿到后 用CA公钥解密后 dsadasdasdasdasdasdasdasdasdasdasdasda

明文公开公钥信息,其他信息

一个信息

身份认证 无法篡改

客户端 sha384 dsadasdasdasdasdasdasdasdasdasdasdasda

客户端生成一个对称秘钥 AES 用服务器的公钥 把客户端生成的对称秘钥 加密

发给服务端

中介人能否解密

安全传递给了服务端

第三、四天

php伪协议

PHP伪协议是PHP自己支持的一种协议与封装协议,简单来说就是PHP定义的一种特殊访问资源的方法。有些伪协议成功执行需要allow_url_fopen和allow_url_include的支持。

allow_url_fopen On/Off 允许或禁止打开URL文件

allow_url_include On/Off 允许或禁止引用URL文件

文件包含的时候,可能遇到的文件包含函数:

1、include

2、require

3、include_once

4、require_once

5、highlight_file

6、show_source

7、flie

8、readfile

9、file_get_contents

10、file_put_contents

11、fopen (比较常见)

常见的PHP伪协议

涉及的相关协议:file://、php://filter、php://input、zip://、compress.bzip2://、compress.zlib://、data://等

1、file:// 用于访问本地文件系统,在CTF中通常用来读取本地文件的且不受allow_url_fopen与allow_url_include的影响

file:// [文件的绝对路径和文件名]

file:// 协议在双off的情况下也可以正常使用;

allow_url_fopen :off/on

allow_url_include:off/on

2、php://协议

条件:

不需要开启allow_url_fopen,仅php://input、 php://stdin、 php://memory 和 php://temp 需要开启allow_url_include。

php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter和php://input,php://filter用于读取源码,php://input用于执行php代码。

(1)php://input(读取原始请求体)

php://input 是个可以访问请求的原始数据的只读流,获取POST请求数据的协议。当675enctype="multipart/form-data" 的时候 php://input 是无效的。php://input 伪协议 成功执行前提php.ini 中的 allow_url_include设置为On

(2)php://filter(编码解码文件)

php://filter可以获取指定文件源码。当它与包含zz函数结合时,php://filter流会被当作php文件执行。所以我们一般对其进行编码,让其不执行。从而导致任意文件读取。

php://filter在双off的情况下也可以正常使用;

allow_url_fopen :off/on

allow_url_include:off/o

3、zip://, bzip2://, zlib:// 均属于压缩流,可以访问压缩文件中的子文件,更重要的是不需要指定后缀名。

zip://, bzip2://, zlib://协议在双off的情况下也可以正常使用;

allow_url_fopen :off/on

allow_url_include:off/on

(1)zip://

作用:访问 ZIP 压缩包内部的文件,而 无需手动解压。

基本语法:zip://压缩包路径#内部文件路径

zip://中只能传入绝对路径。

要用#分隔压缩包和压缩包里的内容,并且#要用url编码%23(即下述POC中#要用%23替换)

只需要是zip的压缩包即可,后缀名可以任意更改。

相同的类型的还有zlib://和bzip2://

(2)bzip://协议(单文件流)

作用:用于 读取 .bz2 压缩文件,读取时自动解压。

基本语法:bzip2://文件路径(没有 #,因为 bzip2 只压缩一个流,不支持目录结构)

(3)zlib协议

作用:读取 gzip / deflate 压缩数据

基本语法:zlib://文件路径

文件包含漏洞

含义:通过PHP函数引入文件时,传入的文件名没有经过合理的验证,从而操作了预想之外的文件,就可能导致意外的文件泄漏甚至恶意代码注入。

环境要求

  • allow_url_fopen=On(默认为On) 规定是否允许从远程服务器或者网站检索数据
  • allow_url_include=On(php5.2之后默认为Off) 规定是否允许include/require远程文件

常见包含函数

php中常见的文件包含函数有以下四种:

  • include()
  • require()
  • include_once()
  • require()_once()

include与require基本是相同的,除了错误处理方面:

  • include(),只生成警告(E_WARNING),并且脚本会继续
  • require(),会生成致命错误(E_COMPILE_ERROR)并停止脚本
  • include_once()与require()_once(),如果文件已包含,则不会包含,其他特性如上

**php://input:**可以访问请求的原始数据的只读流,将post请求的数据当作php代码执行。当传入的参数作为文件名打开时,可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容。从而导致任意代码执行。

**php://filter:**可以获取指定文件源码。当它与包含函数结合时,php://filter流会被当作php文件执行。所以我们一般对其进行编码,让其不执行。从而导致任意文件读取。

**zip://:**可以访问压缩包里面的文件。当它与包含函数结合时,zip://流会被当作php文件执行。从而实现任意代码执行。

data:// :同样类似与php://input,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行。从而导致任意代码执行。

**phar://:**有点类似zip://同样可以导致 任意代码执行。

**包含APACHE日志文件:**WEB服务器一般会将用户的访问记录保存在访问日志中。那么我们可以根据日志记录的内容,精心构造请求,把PHP代码插入到日志文件中,通过文件包含漏洞来执行日志中的PHP代码。

包含SESSION:

利用条件:

  • 找到Session内的可控变量
  • Session文件可读写,并且知道存储路径

session常见存储路径:

  • /var/lib/php/sess_PHPSESSID
  • /var/lib/php/sess_PHPSESSID
  • /tmp/sess_PHPSESSID
  • /tmp/sessions/sess_PHPSESSID
  • session文件格式: sess_[phpsessid] ,而 phpsessid 在发送的请求的 cookie 字段中可以看到。
相关推荐
亚控科技2 小时前
智慧园区安全态势感知升级:从分散管控到全域协同的实践
安全·智慧园区·kingscada·亚控科技·信创scada
安当加密3 小时前
电力系统如何防“明文传输”?某电网公司用SM2+UKey构建“端到端加密”实战
服务器·数据库·安全·阿里云
sunlifenger4 小时前
上海兆越人员定位系统,多元技术赋能,精准守护工业安全
网络·人工智能·安全
独行soc4 小时前
2026年渗透测试面试题总结-3(题目+回答)
网络·python·安全·web安全·渗透测试
星幻元宇VR5 小时前
消防安全体验一体机|消防知识安全竞赛答题软件
安全·虚拟现实
咆哮的黑化肥5 小时前
文件包含漏洞(加DVWA靶场练习)
安全·web安全
KKKlucifer6 小时前
AI赋能与全栈适配:安全运维新范式的演进与实践
人工智能·安全
虹科网络安全6 小时前
艾体宝洞察 | “顶会”看安全(五):利用系统向量缓解LLM中的系统提示词泄露问题
安全
Fnetlink16 小时前
零信任安全架构基础与关键行业应用
安全·安全架构