烟99 发表于 2024-8-12 19:52

发一个数据库理软件测试安全性(率先破解成功有奖励)

本帖最后由 烟99 于 2024-8-12 20:04 编辑

本人正在开发一款新作品,为测试安全性,请大家来尝试破解。

这是一个增删、访问、管理Access的MDB数据库文件的小程序,但是软件所提到的密码是一个非对称私钥,并不是MDB文件的密码,私钥由五位大小写字母、符号、数字组成,通过公钥和一定的算法计算出的结果才是MDB文件的密码。

破解说明:MDB数据表在本程序根目录下的db文件夹,已经添加了一个MDB数据表,选中已创建的数据表,输入密码(即私钥)来访问数据表,无论成功失败都会有提示。也可以自己创建新数据表。注意:无论是预先创建的MDB还是自己创建的MDB都是空白的无内容的。

破解要求:你可以通过调试的方法逆出私钥,也可以通过MDB层面绕过数据库密码来解密数据库。破解成功后,必须在回帖中列出详细的破解步骤、用什么软件编译的、是否有壳,并将db文件夹内的MDB文件的《MainTable》数据表打开并截图,逆出私钥的,必须回答私钥是什么!

加分项:
说说db文件夹内的dblist.idx是干什么的,并且解密文件(只说用途无解密步骤无效。)

率先破解成功的坛友,将破解步骤通过回复的方式帖出,本人将奖励500CB,解密并分析出dblist.idx的再加300CB
在脱壳破解区单独开帖分析并被版主加精华的,奖励翻倍!

压缩包在文末,解压密码:52pj





爱飞的猫 发表于 2024-8-13 01:10

本帖最后由 爱飞的猫 于 2024-8-13 05:24 编辑

接着看看密码的情况:

```c
db_password_cipher_key = "4Pf79FgC8n";
ciphered_password = (char *)sub_401A88(&g_UserPassword, &db_password_cipher_key);
if ( db_password_cipher_key )
释放内存(db_password_cipher_key);
password_1 = ciphered_password;
password_1 = ciphered_password;
if ( password )
释放内存(password);
password = password_1;

// 省略...
conn_string = 文本相加(
          5,
          "Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;Data Source=",
          path_mdb_1,
          ";Jet OLEDB:DataBase Password=",
          password,
          ";Mode=Share Deny Read|Share Deny Write");
```

加密算法就得看看 `sub_401A88` 了。

先捕捉一下这个函数的输入输出方便对比:
```text
.版本 2

数据库密码 = sub_401A88 (“AZaz0”, “4Pf79FgC8n”)
检查 (数据库密码 = “514A716A200937E0598”)
```

然后就是实现:

```text
.版本 2
.支持库 dp1

.子程序 sub_401A88, 文本型
.参数 文本, 文本型
.参数 密钥, 文本型
.局部变量 工作区, 字节集
.局部变量 i, 整数型
.局部变量 密码前缀, 文本型
.局部变量 密钥_MD5, 文本型
.局部变量 密码后缀, 文本型
.局部变量 数据库密码, 文本型

工作区 = 到字节集 (文本)
.计次循环首 (取字节集长度 (工作区), i)
    工作区 = 位异或 (工作区 , 十六进制 (“10”))
.计次循环尾 ()

密码前缀 = 字节集_字节集到十六进制 (工作区)
密钥_MD5 = 到小写 (取数据摘要 (到字节集 (密钥)))
密码后缀 = 到大写 (取文本中间 (密钥_MD5, 3, 9))

数据库密码 = 密码前缀 + 密码后缀

返回 (数据库密码)
```

跑一下代码,发现逆向出来的算法是正确的。

mdb 密码破解的话,可以试着爆破(费时间),或者找一个工具。

我随便找了个价值 $30 的[号称能不到半秒的时间内破解 mdb 密码的工具](https://www.trisunsoft.com/sc/access-password-recovery/)。
工具下下来,简单处理下(破解不完美,有时间再看看怎么搞,凑合着用),得到 mdb 密码 `442678275A0937E0598`:

![](https://imgsrc.baidu.com/forum/pic/item/3801213fb80e7becb25f65c0692eb9389b506b0e.png)![](https://imgsrc.baidu.com/forum/pic/item/3ac79f3df8dcd10090c89e00348b4710b9122fbe.png)

根据算法,去掉后面的 9 个字符,然后剩下的每个字符 XOR 0x10 就能得到原始密码。

于是写一个反向获取的函数原始密码的函数:

```text
输出调试文本 (sub_401A88_rev (“442678275A0937E0598”))


.子程序 sub_401A88_rev, 文本型
.参数 输入, 文本型
.局部变量 内容, 字节集
.局部变量 i, 整数型

内容 = 字节集_十六进制到字节集 (取文本左边 (输入, 取文本长度 (输入) - 9))
.计次循环首 (取字节集长度 (内容), i)
    内容 = 位异或 (内容 , 十六进制 (“10”))
.计次循环尾 ()
返回 (到文本 (内容))
```

得到答案 `T6h7J`。

![](https://imgsrc.baidu.com/forum/pic/item/80cb39dbb6fd526693705a35ed18972bd40736b3.png)

~~因为我没装 Office,就不打开看了~~ 整了个 mdb 查看器:

![](https://imgsrc.baidu.com/forum/pic/item/21a4462309f790523c9b211f4af3d7ca7bcbd50f.png)
![](https://imgsrc.baidu.com/forum/pic/item/f7246b600c3387445a41495d170fd9f9d72aa00f.png)

---

[源码/模块](https://pan.baidu.com/s/1fyDed2_rLmLRjYaOKn-tVw?pwd=ecx6) 需要易语言 5.95

烟佬下次可以试试用[我这个工具](https://www.52pojie.cn/thread-1904733-1-1.html)处理下可执行文件,主打一个强度不高,但现有针对易语言程序的工具/脚本分析不出东西:

![](https://imgsrc.baidu.com/forum/pic/item/95eef01f3a292df51e4fca34fa315c6034a87307.png)

---

Access Password Recovery 代码看明白了。

序列号有 19 位长度。因为是 VB 写的,所以位数从 1 开始:

```text
位数 123456789A123456789
序号 TAPR-BBBB-BBEP-BBBB

0:14: 固定字符 "TAPR"
0:67:0 <= x <= 59; 分/秒?
0:89:1 <= x <= 12; 月?
A:12:1 <= x <= 31; 日?
A:34: 下述项目中的其中一个,例如 EP 表示企业版
        mov   , offset aSg ; "SG"Single License
        mov   , offset aPs ; "PS"Personal License
        mov   , offset aHm ; "HM"Home Multi-License
        mov   , offset aTm ; "TM"Team Multi-License
        mov   , offset aEp ; "EP"Enterprise?
A:67:0 <= x <= 23   ; 小时?
A:89:0 <= x <= 59   ; 分/秒?

数字/字符变化表:
'L','0', 'B','1', 'Y','2', 'Q','3', 'H','4',
'E','5',' Z','6', 'T','7', 'R','8', 'W','9'

LBYQHEZTRW
0123456789
```

一个合法的序列号:`TAPR-BBBB-BBEP-BBBB`。注册后会提示输入两次用户名确认。

注册码写出到 `%appdata%\TSS\APR\configuration.ini`:

```ini

Key=TAPR-BBBB-BBEP-BBBB
User=LCG // 爱飞的猫
```

qq465881818 发表于 2024-8-12 21:29

烟99 发表于 2024-8-12 21:34

qq465881818 发表于 2024-8-12 21:29


至少把公钥读出来吧

qq465881818 发表于 2024-8-12 21:35

烟99 发表于 2024-8-12 21:34
至少把公钥读出来吧

没难度 ,不如接点活 挣点钱:lol

烟99 发表于 2024-8-12 21:36

qq465881818 发表于 2024-8-12 21:29


绕过密码验证无用,解密并读取mdb文件才算成功

qq465881818 发表于 2024-8-12 22:34

442678275A0937E0598

烟99 发表于 2024-8-12 22:56

qq465881818 发表于 2024-8-12 22:34
442678275A0937E0598

CB不能给,mdb是解开了,但是没有分析步骤

qq465881818 发表于 2024-8-12 23:15

烟99 发表于 2024-8-12 22:56
CB不能给,mdb是解开了,但是没有分析步骤

随便吧 前10位

爱飞的猫 发表于 2024-8-13 00:06

本帖最后由 爱飞的猫 于 2024-8-13 00:07 编辑

> 说说db文件夹内的dblist.idx是干什么的,并且解密文件(只说用途无解密步骤无效。)

只看了 dbinfo 解密部分,大概过程就是解压、去掉后面 9 字符、十六进制转字节集、每个字节 `XOR 0x10` (3600 超过字节的范围啦)。

JSON 对象,储存数据库信息:
```json
{
    "dbinfo": [{
      "name": "来破解我啊",
      "dbfile": "DAT_20240812191817.mdb",
      "date": "2024/08/12 19:18:17"
    }, {
      "name": "test",
      "dbfile": "DAT_20240812225354.mdb",
      "date": "2024/08/12 22:53:54"
    }]
}
```

解密过程:
```c
.版本 2
.支持库 dp1

.子程序 解密dblist, 字节集
.参数 路径, 文本型
.参数 密钥, 文本型
.局部变量 数据, 字节集
.局部变量 文本数据, 文本型
.局部变量 字节集密钥, 字节集
.局部变量 密钥分割, 文本型
.局部变量 密钥片段, 文本型
.局部变量 输入长度, 整数型
.局部变量 输入内容, 字节集
.局部变量 i, 整数型

数据 = 读入文件 (路径)
数据 = 解压数据 (数据)
文本数据 = 到文本 (数据)
输出调试文本 (文本数据)

' 取 MD5
密钥 = 到小写 (取数据摘要 (到字节集 (密钥)))
输出调试文本 (密钥)

密钥片段 = 到大写 (取文本中间 (密钥, 3, 9))
.如果真 (密钥片段 ≠ 取文本右边 (文本数据, 9))
    输出调试文本 (“密钥不匹配”)
    返回 ({})
.如果真结束

密钥分割 = 取文本右边 (文本数据, 9)
输入长度 = 取文本长度 (文本数据)

输入内容 = 字节集_十六进制到字节集 (取文本左边 (文本数据, 输入长度 - 9)) ' 随便找了个模块,懒得写了
.计次循环首 (取字节集长度 (输入内容), i)
    ' 3600 = 0xE10 = 0x10 (mod 256)
    输入内容 = 位异或 (输入内容 , 十六进制 (“10”))
.计次循环尾 ()
返回 (输入内容)


.子程序 __启动窗口_创建完毕
.局部变量 解密结果, 字节集

解密结果 = 解密dblist (“db/dblist.idx”, “FH@Vd~3sss$1kh@^fPc.afW2P5*ar]c/”)
输出调试文本 (到文本 (解密结果))
```

用 IDA + [函数识别插件](https://www.52pojie.cn/thread-1414525-1-1.html),能比较容易看一些调用函数名称。然后就是照着伪码去死磕。

![](https://imgsrc.baidu.com/forum/pic/item/b03533fa828ba61eb123af0e0734970a314e59c5.png)

烟99 发表于 2024-8-13 00:46

爱飞的猫 发表于 2024-8-13 00:06
> 说说db文件夹内的dblist.idx是干什么的,并且解密文件(只说用途无解密步骤无效。)

只看了 dbinf ...

dblist.idx是记录mdb数据库文件个数的,易语言主程序加载mdb基本信息的时候就靠这个JSON加载
页: [1] 2 3
查看完整版本: 发一个数据库理软件测试安全性(率先破解成功有奖励)