[Hello-CTF]RCE-Labs超详细WP-Level 2

  • 进入题目网站, 直接给了 index.php 的源码

一段段分析源码

  • include("get_flag.php")
    • 使 get_flag.php 的源码包含进index.php中, 并且执行
  • 随后 global $flag;, 定义了一个全局变量 flag
    • 这个变量的值可能就是需要的Flag
    • 这里注意的是, 虽然 get_flag.php 的包含语句在 global $flag;之前, 但是其的执行顺序其实在整个文件之后, 所以 get_flag.php 可以对 global $flag; 进行赋值
  • session_start();
  • 然后就是 hello_ctf, get_fun, start 三个函数, 先不看它们
  • 接着就是 isset($_GET['action']) ? start($_GET['action']) : '';
    • 这其实是 if else 的简写, 即使用了3元运算符
    • isset($_GET['action']) 是条件
      • 是否GET是否传递了action这个参数
    • 问号后面是当条件为真时, 执行的语句
      • start($_GET['action'])
      • 调用 start 这个函数, 并把 GET 传入的参数 action 作为函数的参数
    • 冒号后面是当条件为假时, 执行的语句
      • 即 ‘’
      • 就是给出一个空字符串
      • 什么也不做
  • 最后是 highlight_file(__FILE__);
    • 这段代码使这个 php 的代码显示出来
  • 那接着把重点放在 即start($_GET['action'])
    • 进入 start 这个函数
      • 首先执行了 get_fun 这个函数, 并把函数的返回值赋予给 random_func 这个变量
      • 进入 get_fun 这个函数进行分析
        • 有个字符串数组 func_list
        • 然后判断 SESSION 中有没有 random_func 这个字段
        • 没有的话执行这个语句 $_SESSION['random_func'] = $func_list[array_rand($func_list)];
          • 主要看 array_rand($func_list), 它的意思是随机返回一个 func_list 这个数组的一个键值(即索引)
          • 总结来说就是把 func_list 随机一个成员赋值给 SESSION的 random_func 字段
        • 然后就是 $url_fucn = preg_replace('/_/', '-', $_SESSION['random_func']); 这个语句
          • 重点看 preg_replace('/_/', '-', $_SESSION['random_func']); 函数
            • 第一个参数 '/_/' 这是正则表达式, 表示要检索的字符串
              • / 是正则表达式的分隔符, 常用 /,也可以用 ~ #
              • _ 表示要匹配的字面字符下划线
            • 第二个参数 ’ -’ 表示要替换为的目标字符串
            • 第三个参数 $_SESSION['random_func'], 即被操作的字符串
            • 整个函数意思就是
              • $_SESSION['random_func'] 字符串的 _ 替换为 -
          • 最后将 preg_replace 替换后的 $_SESSION['random_func'] 赋值给 url_fucn 变量
          • 而其实这个操作, 只是为了方便下文输出 php 文档相关函数的url, 对 get_fun 函数的返回值没有影响
        • get_fun 函数最后返回 $_SESSION['random_func'] 的值
      • random_func 得到 get_fun 函数的返回值(即func_list数组中随机一个函数方法)
      • 然后就是判断传入的参数 act (即GET请求传入的action参数) 是不是 r
        • 是的话, 就执行 session_unset(), session_destroy()
        • 即清除当前 Session 的所有字段和删除当前Session对话
      • 然后接着就是判断 act 是不是 submit
        • 如果是的话, 就是把 POST 请求的 content 参数交给 user_content 变量
        • 然后执行 hello_ctf 函数, 并把 random_func, user_content 两个变量作为参数传递进去
    • 接着进入 hello_ctf 函数
      • 首先把全局变量 flag 声明进这个函数中, 使这个函数调用的 flag 变量为全局变量 flag
      • 然后对传进的参数 function(即 get_fun() 函数随机选择的函数) 和 contect(即 POST 请求的内容) 进行拼接字符串
        • 然后把拼接后的值传递给 code 变量
        • functioneval, contect"ls"
          • 那么 code 就是 eval("ls");
      • 然后输出 code 变量
      • 并且使用 eval($code); 执行 code 变量中的代码
  • 整个代码就这么讲完了, 总结一下就是
    • GET 请求中, 通过调节action的值, 是否等于 r, 可以刷新 Session 中的 random_func 的值, 然后如果action的值等于 submit 时, 就用 random_func 中的函数, 以 POST 请求中的 content 参数作为参数, 被 eval() 执行
  • 并且整个代码看下来, 似乎全局变量 $flag 就是我们需要获取的, 那我们的目的就是通过 GET 请求拿到我们想要的 random_func, 然后参数构造 POST 请求传入 content, 从而输出全局变量 $flag

最后解题步骤如下

  • 首先使用 BurpSuite 随便抓一个包, Ctrl+R->使报文发送到重放器, 记得发两份, 然后进入重放器(Repeater)

  • 第一份使用GET请求

    • 添加 GET 参数 action=r
      请添加图片描述
  • 第二份使用 POST 请求

    • 右键报文->修改请求方式
    • 此时, 原本的 GET 请求的参数会被移到底下来, 但是对于题目而言, 它依然是要为 GET 请求传入, 把它移到原来位置去, 即添加 GET 参数 action=submit
    • 然后添加 POST 参数 content="echo $flag"
      请添加图片描述
  • 然后轮流发送这两份报文, 追后就可以使 random_funcassert, 然后让 eval执行 assert("echo $flag"); , 得到 flag

    • 请添加图片描述
  • 这个解题步骤是基于只会一种方法的情况下

可能到这还会有些问题

  • 为什么是两份报文轮流发, 按照 整个代码就这么讲完了, 总结一下就是 的不是只要通过 action=r 调整 Session 中的函数为 assert, 然后再发 action=sbumit 报文就可以了吗?
    • 其实这是对整个PHP代码逻辑的误解
    • action=r 时, 虽然会刷新 Session, 但是是在最末尾进行刷新, 也就是在这个报文之后, 已经不存在 Session
    • 而只有当 action=submit 时才可以获取 Session, 但是这个报文又不会删除不要的 Session
    • 所有就要两个一起配合
  • 为什么会选择 assert 函数, 而不是其他的
    • 因为刚好这个会 🫠(请在学习中, 每种方法都去尝试)
    • 这里的函数其实都可以用来获取 flag
    • 具体示例如下(来自靶场官方WP)
      函数说明示例代码
      ${}用于复杂的变量解析,通常在字符串内用来解析变量或表达式。可以配合 eval 或其他动态执行代码的功能,用于间接执行代码。eval('${flag}');
      eval()用于执行一个字符串作为 PHP 代码。可以执行任何有效的 PHP 代码片段。没有返回值,除非在执行的代码中明确返回。eval('echo $flag;');
      assert()测试表达式是否为真。PHP 8.0.0 之前,如果 assertion 是字符串,将解释为 PHP 代码并通过 eval() 执行。PHP 8.0.0 后移除该功能。assert(print_r($flag));
      call_user_func()用于调用回调函数,可以传递多个参数给回调函数,返回回调函数的返回值。适用于动态函数调用。call_user_func('print_r', $flag);
      create_function()创建匿名函数,接受两个字符串参数:参数列表和函数体。返回一个匿名函数的引用。自 PHP 7.2.0 起被_废弃_,并自 PHP 8.0.0 起被_移除_。create_function('$a', 'echo $flag;')($a);
      array_map()将回调函数应用于数组的每个元素,返回一个新数组。适用于转换或处理数组元素。array_map(print_r($flag), $a);
      call_user_func_array()调用回调函数,并将参数作为数组传递。适用于动态参数数量的函数调用。call_user_func_array(print_r($flag), array());
      usort()对数组进行自定义排序,接受数组和比较函数作为参数。适用于根据用户定义的规则排序数组元素。usort($a,print_r($flag));
      array_filter()过滤数组元素,如果提供回调函数,仅包含回调返回真值的元素;否则,移除所有等同于false的元素。适用于基于条件移除数组中的元素。array_filter($a,print_r($flag));
      array_reduce()迭代一个数组,通过回调函数将数组的元素逐一减少到单一值。接受数组、回调函数和可选的初始值。array_reduce($a,print_r($flag));
      preg_replace()执行正则表达式的搜索和替换。可以是单个字符串或数组。适用于基于模式匹配修改文本内容。依赖 /e 模式,该模式自 PHP7.3 起被取消。preg_replace('/(.*)/ei', 'strtolower("\\1")', ${print_r($flag)});
      ob_start()ob_start — 打开输出控制缓冲,可选回调函数作为参数来处理缓冲区内容。ob_start(print_r($flag));
<li id="menu-item-23441" class="menu-item menu-item-type-custom menu-item-object-custom current-menu-item current_page_item menu-item-home menu-item-has-children menu-item-23441 item-level-0 menu-mega-dropdown wd-event-hover" style="--wd-dropdown-padding: 30px;"><a href="https://erosnest.com/" class="woodmart-nav-link"><span class="nav-link-text">Sex Toys</span></a><div class="color-scheme-dark wd-design-aside wd-dropdown-menu wd-dropdown wd-style-with-bg" style="left: -140.703px;"><div class="container wd-entry-content"><div class="wd-sub-menu-wrapp"> <ul class="wd-sub-menu color-scheme-dark" style=" height: 740px; "> <li id="menu-item-23925" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-23925 item-level-1 wd-event-hover"><a href="https://erosnest.com/best-sellers/sex-toys/" class="woodmart-nav-link">Best Sellers</a></li> <li id="menu-item-23938" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-23938 item-level-1 wd-event-hover menu-item-has-children"><a href="https://erosnest.com/sex-toys/vibrators/" class="woodmart-nav-link">Vibrators</a> <div class="wd-dropdown-menu wd-dropdown wd-design-default color-scheme-dark" style=""> <div class="container wd-entry-content"> <link rel="stylesheet" id="elementor-post-23884-css" href="https://erosnest.com/wp-content/uploads/elementor/css/post-23884.css?ver=1741920352" type="text/css" media="all"> <div data-elementor-type="wp-post" data-elementor-id="23884" class="elementor elementor-23884" data-elementor-post-type="cms_block"> <div class="elementor-element elementor-element-7e97312 e-flex e-con-boxed e-con e-parent e-lazyloaded" data-id="7e97312" data-element_type="container"> <div class="e-con-inner"> <div class="elementor-element elementor-element-483592f e-con-full e-flex e-con e-child" data-id="483592f" data-element_type="container"> <div class="elementor-element elementor-element-c6fdb86 elementor-widget__width-initial elementor-widget el
03-15
<think>好的,用户需要关于HTML/CSS代码片段或布局的帮助,特别是下拉菜单布局,包含巨型菜单(mega menu)和子菜单。首先,我需要回忆一下如何构建这样的导航菜单。通常,这种结构需要使用HTML的无序列表,结合CSS的定位和显示属性来实现下拉效果。 首先,确定HTML结构。主菜单用`<ul>`,每个菜单项是`<li>`,包含链接。对于有子菜单或巨型菜单的项,需要在`<li>`内部再嵌套一个`<ul>`或容器。巨型菜单通常包含多个子部分,可能需要用`<div>`来组织内容,比如分栏布局。 接下来考虑CSS部分。主菜单项应该水平排列,使用`display: flex`或者`float: left`。子菜单需要绝对定位,相对于父级`<li>`,所以父级`<li>`要设置`position: relative`。默认情况下,子菜单隐藏,当鼠标悬停时显示,使用`:hover`伪类控制`display`属性,从`none`切换到`block`或`flex`。 对于巨型菜单,可能需要设置较大的宽度,覆盖整个导航栏的宽度。这时候,可以设置子菜单容器的`width`为100%或者固定值,并调整`left`位置,使其左对齐或居中。同时,使用CSS Grid或Flexbox来分栏显示内容,比如分成多个列,每个列下有子菜单项。 还要注意层叠问题,确保子菜单出现在其他内容之上,可能需要调整`z-index`。过渡效果可以使用`transition`属性让下拉更平滑。另外,兼容性问题需要考虑,比如旧版浏览器的支持,但用户可能更关注现代浏览器的效果。 测试代码是否符合结构,确保所有子菜单在鼠标悬停时正确显示,并且布局不会错乱。可能需要调整padding、margin来美化外观,设置背景颜色、阴影等视觉效果,使菜单看起来更专业。 最后,提供示例代码,并解释各部分的作用,帮助用户理解如何修改和扩展。可能需要指出如何添加图标、调整颜色或响应式设计,但用户当前的问题集中在布局,所以先专注于核心结构。 现在,整理这些思路,写出HTML和CSS代码片段,并确保符合用户的要求,包括巨型菜单和子菜单的结构,同时遵循之前提到的格式要求,比如行内数学表达式的正确使用,但在这个问题中可能用不到数学公式。不过,需要注意代码的格式正确,使用正确的语法,比如转义字符等。</think>以下是一个支持巨型菜单和二级子菜单的响应式导航栏实现方案,包含详细注释和样式控制: ```html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <style> /* 基础菜单样式 */ .nav-menu { list-style: none; padding: 0; margin: 0; background: #2c3e50; position: relative; display: flex; } /* 一级菜单项 */ .nav-item { position: relative; padding: 15px 25px; color: white; cursor: pointer; transition: background 0.3s; } .nav-item:hover { background: #34495e; } /* 下拉内容容器 */ .dropdown { position: absolute; left: 0; top: 100%; display: none; min-width: 200px; background: #fff; box-shadow: 0 8px 16px rgba(0,0,0,0.2); z-index: 1000; } /* 巨型菜单特殊样式 */ .mega-menu { width: 100vw; left: 50%; transform: translateX(-50%); padding: 20px; display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; } /* 二级菜单样式 */ .submenu { left: 100%; top: 0; min-width: 200px; } /* 悬停显示菜单 */ .nav-item:hover > .dropdown { display: block; } /* 菜单内容区域 */ .menu-content { padding: 15px; } /* 响应式设计 */ @media (max-width: 768px) { .nav-menu { flex-direction: column; } .mega-menu { width: 100%; position: static; transform: none; } } </style> </head> <body> <ul class="nav-menu"> <!-- 普通下拉菜单 --> <li class="nav-item"> 产品 <div class="dropdown"> <div class="menu-content"> <ul> <li>手机</li> <li>笔记本 <ul class="dropdown submenu"> <li>游戏本</li> <li>轻薄本</li> </ul> </li> <li>配件</li> </ul> </div> </div> </li> <!-- 巨型菜单 --> <li class="nav-item"> 解决方案 <div class="dropdown mega-menu"> <div class="menu-content"> <div class="column"> <h4>企业方案</h4> <ul> <li>云服务</li> <li>数据安全</li> </ul> </div> <div class="column"> <h4>开发者工具</h4> <ul> <li>API 中心</li> <li>SDK 下载</li> </ul> </div> </div> </div> </li> </ul> </body> </html> ``` 关键特性说明: 1. **层级结构**:使用嵌套的`<ul>`和`<div>`组合实现多级菜单 2. **定位系统**:通过`position: relative/absolute`实现精确定位[^1] 3. **布局控制**:使用CSS Grid布局实现巨型菜单的分栏效果 4. **交互效果**:`:hover`伪类实现鼠标悬停显示,`transition`添加动画过渡 5. **响应式设计**:媒体查询适配移动端显示
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Haicaji

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值