HelloHarmony
当成 zip 拆开 ,ets/modules.abc 丢进 abc-decompiler ,libs/arm64-v8a/libentry.so 丢进 IDA ArkTS 层业务逻辑中 ,导⼊ Emmm.Eeee 进⾏凯撒加密 ,构造函数传参为 5 ,导⼊ testNapi
Native 层 sub_1F94 获得 UTF-8 字符串 ,从这⾥看起 ,进⾏了⼀系列算术运算 ,解密如下( IDA ⾥看 到的 this 指向⼀个 256 字节的 box ,this+256 指向派⽣的密钥)
#include <stdio.h>
#define u8 unsigned char
#define u32 unsigned int
=
{
0xF6, 0xB0, 0xA6, 0x36, 0x9A, 0xB3 , 0x2B , 0xBF , 0x94 , 0x54 ,
0x15, 0x97, 0x93, 0x59, 0xBF, 0x50 , 0x4D , 0xBF , 0x0A , 0x59 ,
0x06, 0xD7, 0x97, 0x50, 0xD6, 0x59 , 0x54 , 0xD7 , 0xCF , 0x06 ,
0x5D, 0x20, 0x1D, 0x5A, 0x22,
0xEE , 0x99 , 0x1F , 0xE1 , 0x18 ,
int main() {
{}; =
// banana
0; i < 256; ++i) =
(167 * i + 173) % 256; =
{}; =
"HelloSDS"; =
8; =
// bananana
0; i < 8; ++i) =
(a2[(i + 1) % a3] << 16) | (a2[i % a3] << 24) | (a2[(i + 2) =
a3] << 8) | a2[(i + 3) % a3];
7; i >= 0; i--) { =
// blablabla
eeeee[39]; =
39; j > 0; j--) { =
eeeee[j - 1]; =
}
c; =
// bla
0; j < 40; j++) { =
0; k < 256; k++) { =
= eeeee[j]) { =
k; =
break;
}
}
}
blablablablabla
^= dkey[i];
^= dkey[i];
}
0; i < 40; i++) { =
eeeee[i] && eeeee[i] <= 'Z') { =
(eeeee[i] - 'A' - 5 + 26) % 26 + 'A'; =
eeeee[i] && eeeee[i] <= 'z') { =
(eeeee[i] - 'a' - 7 + 26) % 26 + 'a'; =
}
printf("%c", eeeee[i]);
}
return 0;
}
LZSDS{y0u_4r3 4 m4573r_0f_cryp706r4phy}
Map_maze
⼀个⻓度为 15*15 的数组 ,数组的元素是 {⾃⼰是否为墙的枚举值、指向上、下、左、右的指针} ( 幽 默)
把构造迷宫的代码⽚段复制出来 ,IDE 批量⽂本替换 ,把它变成 int 数组并打印出来
迷宫有多解但是正确 flag 只有⼀个( 幽默)
Potato Toolkit
切到反汇编⾮图表视图,从头到尾快速粗略浏览⼀遍,找数据操作密集的位置就是主要逻辑,定位到sub_1400012E0
开头判断了a1[6]这个⽂本框为
1wesa234 |
, 后⾯读⼊ 38 字节并与这个⽂本框的⽂本循环异或(Aura是真喜欢循环异或)
注意存储的顺序与数组中是不⼀致的(估计是编译优化)
解密:
最⾼的⼭最⻓的河(赛后解出)
随便找⼀个 EXE 补全最前⾯ 16 字节的 MZ 头
开始以为考的是异常处理 ,后来发现只是魔改 Base64 + TEA ,有⼏处坑点 main 中调⽤的 sub_1400112CB(sub_14001D200) 为主要加密逻辑
sub_14001D200 较⼤的 for 循环为魔改 Base64 ,魔改点是先取三个字节的低 6 位 ,然后把三个字节 ⾼ 2 位拼接在⼀起
它下⾯调⽤的 sub_140011519(sub_14001E3F0) 第⼀个 for 循环在把 Base64 字符( 以AbC1为例)拼 接成⼩端序 u32 时调换了中间的顺序 ,从低地址向⾼地址依次是 A C b 1
第⼆个 for 循环进⾏ TEA 加密 ,32 轮后还异或了⼀个常数
它下⾯调⽤的 sub_140011113(sub_14001DF80) 在把 u32 数组拆成字节数组时 ,是按 u32 从最⾼字 节向最低字节的顺序依次 append 的 ,相当于字节序转换
解密如下
#include <stdio.h>
{0x4C, 0x5A, 0x53, 0x44, 0x53}; =
{165, 100, 159, 4, 57, 183, 166, 23, 34, 205, 38, 77, 125, 16, =
219, 133, 219, 39, 57, 66, 60, 30, 165, 34, 205, 38, 77, 125, 16, 130,
214, 55, 104, 128, 177, 249, 21, 25, 68, 24, 66, 36, 143, 120, 162, 44};
void __fastcall sub_14001E1C0(unsigned int *a)
{
int v4; // [rsp+44h] [rbp+24h]
int i; // [rsp+64h] [rbp+44h]
unsigned int v9; // [rsp+1A8h] [rbp+188h]
unsigned int v10; // [rsp+1B0h] [rbp+190h]
dword_140029DE0[4] ^ a[1]; =
v9 = dword_140029DE0[4] ^ a[0];
v4 = -957401312 + 1640531527 * 32;
for (i = 0; i < 32; ++i)
{
v4 -= 1640531527;
v9 += (dword_140029DE0[1] + (v10 >> 5)) ^ (v4 + v10) ^
+ 16 * v10);
v10 += (dword_140029DE0[3] + (v9 >> 5)) ^ (v4 + v9) ^
+ 16 * v9);
}
v10; =
v9; =
}
const char *b64alphabet =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int getIndex(char c)
{
for (int i = 0; i < 64; i++)
{
if (b64alphabet[i] == c)
{
return i;
}
}
return -1;
}
int main()
{
for (char *b = enc; b < enc + 48; b += 4)
{
char c = b[2];
b[1]; =
c; =
c = b[3];
b[0]; =
c; =
}
for (unsigned int *b = (unsigned int *)enc; b < (unsigned int *)(enc +
b += 2)
{
sub_14001E1C0(b);
}
for (char *b = enc; b < enc + 48; b += 4)
{
char c = b[2];
b[1]; =
c; =
}
char flag[36];
0; =
enc; b < enc + 48; b += 4) =
{
getIndex(b[0]); =
getIndex(b[1]); =
getIndex(b[2]); =
getIndex(b[3]); =
c1 | (msbs >> 4 << 6); =
c2 | (((msbs >> 2) & 3) << 6); =
c3 | ((msbs & 3) << 6); =
}
printf("%sn", flag);
return 0;
}
// LZSDS{how_how_how_how_how_ow_ow_ow!}
Something like coppersmith
dlp问题 ,512bit的x给了低404bit ,求解⾼位108bit
查看p-1有⼏个⼩因⼦可以利⽤ ,bsgs+ph求⼀下⾼位 ,拼起来就是完整的x
from sage.all import *
from Crypto.Cipher import AES
import hashlib
p = 63028109042655010379244017862953972881708431498171769855227678955829682905514149283089322006919537587262280117935241545095863545026918221109814907379002394
g = 37
y = 1293150376161556844462084321627758417728307246932113125521569554783424543983527961886280946944216834324374477189528743754550041489359187752209421536046860
xl = 17986330879434951085449288256517884655391850545705434564933459034981508996937405053663301303792832616366656593647019909376
enc = b'x08[x94xc1xc2xc3xb9"C^xd6Pxf9x0cxbbrrxaf&x94x8cmx02sx87x8bx1cxb3x92x81Hxe7xc6x190axcax91jxc0@(xc5Fwx95rxee'
# 512-404=108
a = pow(g, 2**404, p)
b = y*pow(g, -xl, p)
subs = [2, 385057, 727646221919, 193893885660581]
F = GF(p)
xhs = [discrete_log_lambda(F(pow(b, (p-1)//sub, p)), F(pow(a, (p-1)//sub, p)), (0, sub)) for sub in subs]
xh = crt(xhs, subs)
x = xh*2**404 + xl
} =
} =
x, p) - y}")
xh = 75264534032313167327310698296002
x = 3109629341267338542281598485842430908207399697796047162247944601790472203194018819012768066635985627456532841488248491869575854365325351247411886736433408
key = hashlib.md5(str(x).encode()).digest()
aes = AES.new(key=key, mode=AES.MODE_ECB)
flag = aes.decrypt(enc)
print(flag)
xorsa
import gmpy2
from Crypto.Util.number import *
c = 13760578729891127041098229431259961120216468948795732373975536417751222443069805775693845560005881981622202089883866395577154701229046245882282127054969114210307175116574178428823043817041956207503299220721042136515863979655578210499512044917781566303947681251248645504273995402630701480590505840473412765662
n = 14247038211821385209759067256846232227444163173099199085257790370590450749665206556163364754269182255358084948354345827898987234756662133974633117062902370811855466665351784027125333112663075085395676501121759786699720149098576433141817737564928779420725539793335830274229206316999461309927000523188222801659
hint1 = 8938538619961731399716016665470564084986243880394928918482374295814509353382364651201249532111268951793354572124324033902502588541297713297622432670722730
hint2 = 1493298155243474837320092849325750387759519643879388609208314494000605554020636706320849032906759121914762492378489852575583260177546578935320977613050647
e = 2026
p = hint1 ** hint2
q = n // p
phi = (p - 1) * (q - 1)
k = GCD(e, phi)
print(k)
d = gmpy2.invert(e // k, phi)
m = pow(c, d, n)
flag = long_to_bytes(gmpy2.iroot(m, k)[0])
print(flag)
my_site
经过测试 ,发现存在()的时候就会⾛到ssti的if⾥⾯ ,之后就写内存⻢来回显
发送过去即可得到flag
海关警察训练平台
恶意代码检测器
扫⽬录可以得到 www.zip
代码审计 ,可以发现是tp框架 ,发现这⾥存在命令执⾏
使⽤ ${} ,在⼤括号⾥⾯包含代码即可代码执⾏
发现 usort 函数没有被ban ,⽤ usort 来执⾏命令
根据php的特性 ,不使⽤引号的话能⾃⼰识别类型 ,可以⽤字符串拼接的⽅式绕过过滤
这⾥需要注意的是 ,因为没有引号 ,拼接字符的时候会warming ,然后tp就报错了 ,⽤ 警告
来忽略掉
过滤了下划线 ,⽤
getallheaders
system
传参
只需要发送⼀次 Exp
${ ,sys.tem)}
奶龙牌WAF
代码审计 ,发现这⾥⽂件名有问题
可以⽤a.php/.来绕过 ,⽤get传⼊⼀个name
后边的正则 ,使⽤PCRE回溯次数限制来绕过
print('a'*2000000+'eval($_POST[1]); ')
通过以上代码⽣成⽂件 ,然后上传
最后访问uploads/a.php
即可RCE
Golf
全角字符绕过阻⽌名单
exec ( input ())
神奇的硬币纺纱机
莫名其妙的 … …
因为0只可能赚不可能亏 ,所以前⾯⼀直在按0
Summit Potato
唉 ,出题⼈就是被 musc 给害了。
Potato.png 数据流后⾯分离出 xlsx ⽂件 ,第⼆个⼯作表按逻辑得到 Loe*n (第四个字符可以是任意Loe*n (字符) ,⽤来对 key.bin.xored 循环异或 ,根据语义和异或的规律尝试得到第四个字符为 n
https://github.com/CelestialCartographers/Loenn
再下⼀个蔚蓝 ,就可以打开xor后的地图
xlsx解压后 ,在media有⼀个图⽚
作为密码解开flag.zip压缩包
Elemental Wars
javaPcap
LilRan: Java是什么卢瑟语⾔
加密⼤致流程
cmd:base64
Method:给出 ,ECB
key->给出 ,顶真发现是bytes_to_long(cmd)
(这⾥还在java的javax.crypto.spec.SecretKeySpec上卡了很久 ,觉得是类似于NodeJs的 EVP_key,后来发现就是简单的补全截断
回显:明⽂->加密->base64->hex
基于逻辑进⾏解密
whoami
ls-alt
lsflag/
base64flag/flag.zip 5catflag/hint.txt
欢迎来到2024蜀道⼭CTF
蜀道山高校联合公益赛-土豆哥杨李航主题题目解析
前言
土豆哥简历鉴赏(大家来找茬)
简历1
简历2
土豆哥简介
、
土豆哥名场面回顾
、
附件有 3 个⽂件,⼀个带密码的 zip,⼀个 .bin ⽂件,⼀张图⽚。 可以先看图⽚,末尾附加了⼀个 zip ⽂件,将其提出来,解压后发现是 excel,将 zip 后缀改为 xlsx 后 打开。 第⼀⻚什么都没有,翻到第⼆⻚。
第⼀⻚什么都没有,翻到第⼆⻚。
⾥⾯要求输⼊ hint,然后进⾏检测,错误就会显示 Wrong! 点开其中的格⼦看⼀下,发现是 excel 公式。
红⾊的格⼦就是密⽂,只需要依次倒推回去即可。
解出来是 Loenn。
搜⼀下,发现是⼀个游戏的制图⼯具,其地图⽂件的后缀都是 bin。
⽤这个⼯具打开 bin,发现密⽂。 3kW]Y1:jRZB[
继续看 excel, 发现解压出来的 media ⽂件夹⾥⾯有—张图⽚ 。
打开 cyberchef 异或—下, 得到压缩包的密码。
解压后打开就是 flag。
原文始发于微信公众号(Urkc安全):蜀道⼭ Writeup
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论