首页
社区
课程
招聘
3
[原创]DASCTF2023年7月比赛复盘-逆向部分
发表于: 2023-7-23 19:02 14166

[原创]DASCTF2023年7月比赛复盘-逆向部分

2023-7-23 19:02
14166

这个程序的控制流好像有点奇怪

这题采用了一种奇妙的干扰技巧:
在函数序言的前面插入一块代码
该代码再通过改变返回地址来改变调用链
图片描述

可以通过识别 push ebp 来确定真实的函数的位置
图片描述

编辑这些函数
设置函数起始处跳过这些插入的代码块并勾选 BP-Based Frame 可以成功 F5

func1:
图片描述
func2:
图片描述
func3:
图片描述
func4 是纯粹的比较
func5:
图片描述
其中 loc_4015AF 指向 func2 的第 13 行之后

main 函数中最后一段
图片描述

每个小函数上下断点
找到执行的顺序如下

main -> func3 -> func5 -> func2 (后半段) -> func1 -> func4

最终总结出加密算法如下:

而解密是平凡的

DASCTF{TWpnemRuSTRkVzVsWVhOMmJqZzNOREoy}

null

基于 OATPP 框架的 HTTP 服务器

根据官网的 example 可以知道每个 Controller 都是一个 C++ 类

那么先找 Controller 类的虚表
可以通过字符串名称定位
图片描述

寻找交叉引用两次
图片描述

检查函数位于 CheckHandler.sub_40617E

开头这一段是通过反转比特解密字符串
简单修补了一下

第 52 行后也修补了一下(加了一个 string 的类型)
这里是在将 string 转化成 4*10 的 int 矩阵
图片描述

第 101 行之后就是在做矩阵相乘
图片描述

综合以上可以猜测
过关需要向其发送一个 GET 请求 abcdef=$FLAG
内部算法是解矩阵方程 XQ=P

DASCTF{CI5ZCM5piv5aaC5L2V5pS26LS555qE5Y}

小王是你的好朋友
最近他们公司下发了一个程序进行逆向竞赛
此程序会和公司内网的某个服务器建立TCP连接
小王需要你帮他找到PASSWORD
此外,小王已经发现,PASSWORD并不在服务器进行判断
由于你无法访问公司内网,小王贴心地给你抓了网络包(1.pcapng)并把程序给你(c)

远程过程调用的样本

先看全局变量
有一个 48 只的全局变量被一个函数改过
前 32 只是 4 个 int64 的数组
后 16 只是单字节串
都初始化为随机数
图片描述

main 函数首先从服务器接收一个 32 只的串
传入一个以该串和刚才的随机数为参数的函数 sub_2090
然后把长度为 96 的输出再送回服务器
感觉非常有可能是在和服务器密钥交换
图片描述

sub_2090 -> sub_1f9c -> sub_1e6e 一层一层点进去可以看到这样的函数
图片描述

显然这是 128 位带模乘法

sub_1f9c 有和它类似的结构
为 128 位快速幂

再往前推断可知
func1 就是块大小为 8 的 RSA 分块加密
密钥是 32 位字串
前 16 位是 n
后 16 位是 e
图片描述

然而 128 位的 n 并不大
直接放到 factordb 解密

p=1152921504606848051
q=2152921504606847269

总结密钥交换:
服务器生成 128 位的 n 和 e 发送给客户端
客户端生成 48 字节的密钥(暂时未知加密算法)用 e 加密送给服务器

继续看 main 函数
密钥交换过后它从服务器再拿 12 字节并通过 sub_1d9a
显然这是在解密服务器的数据
不然也就不用交换密钥了

其中 sub_1c0a 是块长度 64 的 TEA 解密
图片描述

因此解密算法如下:
如果 buffer 长度小于16字节
对它使用 OTP
否则

buffer[len-16:len]
buffer[len-17:len-1]
...
buffer[0:16]
运行 TEA 解密

OTP 的密钥为 48 字串的后 16 字节
TEA 的 4 个密钥为前 32 字节

继续分析接收的 12 字节数据

main 函数将其分为 3 个整数
第一个整数为 RPC 调用号
后两个整数为参数

功能如下:

其中每段长度为 400
图片描述

因此我们只需要模拟 CLNT 的动作把 memory 转储下来分析即可

SRV says: Hello, this is the remote server.

CLNT does: read from SRV to segment 1
CLNT does: read from SRV to segment 2
SRV says: Please enter your password

CLNT does: read from stdin to segment 0
CLNT does: read from SRV to segment 8
CLNT does: read from SRV to segment 4
CLNT does: read from SRV to segment 5
CLNT does: read from SRV to segment 6
CLNT does: read from SRV to segment 7
CLNT does: exec code at segment 8
CLNT does: print segment 3
CLNT quit

图片描述
图片描述

真的是很平凡的加密

DASCTF{5rOV562J5Y5pu+5amn6Zuv2B5aSa5Liq}

你说的这个好朋友,是不是你自己?

23年7月23日于杨舍

s = [
        3279, 3264, 3324, 3288, 3363, 3345, 3528, 3453, 3498, 3627, 3708, 3675,
        3753, 3786, 3930, 3930, 4017, 4173, 4245, 4476, 4989, 4851, 5166, 5148,
        4659, 4743, 4596, 5976, 5217, 4650, 6018, 6135, 6417, 6477, 6672, 6891,
        7056, 7398, 7650, 7890]
 
for i in range(10,30,2):
    s[i+1],s[i]=s[i],s[i+1]
 
for i in range(40):
    assert(s[i]%3==0)
    s[i]//=3
 
for i in range(40):
    s[i]+=i
 
for i in range(20):
    s[10+i]^=i*(i+1)
 
for i in range(40):
    s[i]-=i*i
 
for i in range(40):
    s[i]^=0x401
 
flag=''.join(chr(b) for b in s)
print(flag)
s = [
        3279, 3264, 3324, 3288, 3363, 3345, 3528, 3453, 3498, 3627, 3708, 3675,
        3753, 3786, 3930, 3930, 4017, 4173, 4245, 4476, 4989, 4851, 5166, 5148,
        4659, 4743, 4596, 5976, 5217, 4650, 6018, 6135, 6417, 6477, 6672, 6891,
        7056, 7398, 7650, 7890]
 
for i in range(10,30,2):
    s[i+1],s[i]=s[i],s[i+1]
 
for i in range(40):
    assert(s[i]%3==0)
    s[i]//=3
 
for i in range(40):
    s[i]+=i
 
for i in range(20):
    s[10+i]^=i*(i+1)
 
for i in range(40):
    s[i]-=i*i
 
for i in range(40):
    s[i]^=0x401
 
flag=''.join(chr(b) for b in s)
print(flag)
*(_DWORD *)_abcdef = 0x9B9C9D9E;
*(_WORD *)&_abcdef[4] = 0x999A;
_abcdef[6] = 0;
bitwise_neg(_abcdef, 6);                      // bytes(~b&0xff for b in bytes.fromhex("999A9B9C9D9E")[::-1]).decode()
                                              //
                                              // abcdef
*(_QWORD *)_403 = 0xDFCCCFCBC1CE97C3LL;
*(_QWORD *)&_403[8] = 0x9A9B9B969D8D90B9LL;
*(_DWORD *)&_403[16] = 0x97D0C391;
*(_WORD *)&_403[20] = 0xC1CE;
_403[22] = 0;
bitwise_neg(_403, 22);                        // <h1>403 Forbidden</h1>
*(_QWORD *)_Wrong_flag = 0x9399DF9891908DA8LL;
*(_WORD *)&_Wrong_flag[8] = 0x989E;
_Wrong_flag[10] = 0;
bitwise_neg(_Wrong_flag, 10);                 // Wrong flag
*(_DWORD *)_abcdef = 0x9B9C9D9E;
*(_WORD *)&_abcdef[4] = 0x999A;
_abcdef[6] = 0;
bitwise_neg(_abcdef, 6);                      // bytes(~b&0xff for b in bytes.fromhex("999A9B9C9D9E")[::-1]).decode()
                                              //
                                              // abcdef
*(_QWORD *)_403 = 0xDFCCCFCBC1CE97C3LL;
*(_QWORD *)&_403[8] = 0x9A9B9B969D8D90B9LL;
*(_DWORD *)&_403[16] = 0x97D0C391;
*(_WORD *)&_403[20] = 0xC1CE;
_403[22] = 0;
bitwise_neg(_403, 22);                        // <h1>403 Forbidden</h1>
*(_QWORD *)_Wrong_flag = 0x9399DF9891908DA8LL;
*(_WORD *)&_Wrong_flag[8] = 0x989E;
_Wrong_flag[10] = 0;
bitwise_neg(_Wrong_flag, 10);                 // Wrong flag
from sage.all import matrix,ZZ
 
P = matrix(ZZ, [
    [33211, 36113, 28786, 44634, 30174, 39163, 34923, 44333, 33574, 23555],
    [35015, 42724, 34160, 49166, 35770, 45984, 39754, 51672, 38323, 27511],
    [31334, 34214, 28014, 41090, 29258, 37905, 33777, 39812, 29442, 22225],
    [30853, 35330, 30393, 41247, 30439, 39434, 31587, 46815, 35205, 20689]
])
 
Q = matrix(ZZ, [
    [23, 134, 48, 41, 41, 42, 33, 303],
    [691, 13, 45, 41, 648, 80, 15, 42],
    [56, 19, 62, 70, 23, 63, 30, 68, 17, 56],
    [92, 12, 16, 64, 313, 17, 71, 589],
    [64, 83, 71, 52, 99, 89, 76, 681, 99],
    [16, 16, 52, 430, 44, 50, 32, 50, 31],
    [20, 632, 990, 57, 79, 43, 71, 19],
    [80, 92, 93, 58, 84, 74, 81, 45, 55, 21],
    [ 1, 99, 30, 28, 561, 12, 77, 924],
    [37, 67, 60, 54, 51, 79, 38, 87, 48, 16]
])
 
X = Q.solve_left(P) # XQ = P
flag = ''
for r in X:
    for c in r:
        flag += chr(c)
print(flag)
from sage.all import matrix,ZZ
 
P = matrix(ZZ, [
    [33211, 36113, 28786, 44634, 30174, 39163, 34923, 44333, 33574, 23555],
    [35015, 42724, 34160, 49166, 35770, 45984, 39754, 51672, 38323, 27511],
    [31334, 34214, 28014, 41090, 29258, 37905, 33777, 39812, 29442, 22225],
    [30853, 35330, 30393, 41247, 30439, 39434, 31587, 46815, 35205, 20689]
])
 
Q = matrix(ZZ, [
    [23, 134, 48, 41, 41, 42, 33, 303],
    [691, 13, 45, 41, 648, 80, 15, 42],
    [56, 19, 62, 70, 23, 63, 30, 68, 17, 56],
    [92, 12, 16, 64, 313, 17, 71, 589],
    [64, 83, 71, 52, 99, 89, 76, 681, 99],
    [16, 16, 52, 430, 44, 50, 32, 50, 31],
    [20, 632, 990, 57, 79, 43, 71, 19],
    [80, 92, 93, 58, 84, 74, 81, 45, 55, 21],
    [ 1, 99, 30, 28, 561, 12, 77, 924],
    [37, 67, 60, 54, 51, 79, 38, 87, 48, 16]
])
 
X = Q.solve_left(P) # XQ = P
flag = ''
for r in X:
    for c in r:
        flag += chr(c)
print(flag)
__int128 x = a;
__int128 y = 0;
while (b != 0) {
    if (b & 1)
        y = __modti3(x + y, m);
    else
        x = __modti3(2 * x, m);
    b >>= 1;
}
return y
__int128 x = a;
__int128 y = 0;
while (b != 0) {
    if (b & 1)
        y = __modti3(x + y, m);

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2025-3-14 01:49 被狗敦子编辑 ,原因: 增加了图片,优化了语言
上传的附件:
收藏
免费 3
支持
分享
赞赏记录
参与人
雪币
留言
时间
m57
为你点赞~
2023-11-3 18:47
狗敦子
为你点赞~
2023-7-24 13:59
兔先生
为你点赞~
2023-7-24 09:25
最新回复 (2)
雪    币: 4723
活跃值: (31636)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2023-7-23 19:40
1
雪    币: 8
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
m57
3
感谢分享,很有帮助
2023-11-3 18:45
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册