背景:一次渗透测试中,需要渗透一个C/S客户端,但存在登录加密以及使用TCP传输协议,于是使用AI进行了逆向分析,层层深入,从尝试未授权到权限绕过,最终利用数据库任意命令执行Getshell,下面分享大致思路。
开始先是一个exe文件:

查壳分析,发现是一个C#写的程序:

使用dnSpy进行分析:

这里拖入主程序,反编译只输出到1个核心源文件和1个程序集信息文件,说明大多数业务逻辑在外部DLL中

xxxHIS.DAL.ClientLink.dll— 数据访问层,中间件连接

xxxHIS.UIL.Admin.dll— UI 管理界面层

主程序主要作为启动入口

下面将xxxHIS.DAL.ClientLink.dll,xxxHIS.UIL.Admin.dll也进行反编译:

选中后导出到工程

通过AI分析:

发现其为TCP传输

加密机制:

这里是通过打开软件请求服务端,获取一个临时的Key作为加密密钥

登录过程:

这里可以注意到登录请求是通过一个请求号5009实现的,这里为后续做了一个小小的切入点

此处先由AI继续编写模拟实现获取临时key,实现加解密,否则后续无法继续测试:

核心代码:

此处是调用上述所说到的xxxLink.dll,这个dll实现了加解密,但只是内部实现,未公开,此处可以直接把这个dll复制一份进行劫持,编写代码调用这个dll里面的函数进行加解密,即此处只需要请求服务器获取到临时加密密钥即可实现数据加解密。

编译运行:

此处已实现获取临时key进行加密解密

由刚刚的登录入口请求号5009切入点,搜索关键字定位到这里:

此处疑似发现一个可以SQL执行的字段REQ_EXECSQL_SENTENCE,请求号5004

继续溯源分析在哪里被调用了:

发现此处可进行SendReqPack,第二个传参为iReqNo,即可以利用上面找到的请求号5004进行调用测试。

这里先对SendReqPack模拟进行代码实现,模拟发送数据包,同样劫持调用DLL:

写好后构造加密后的未授权测试:

Send(5004, "SELECT @@version" + S, "匿名-SQL-version");

此处发现没传账号密码直接请求被拦截了:

这里发现返回的是调用参数错误,猜测可能是没有附带授权导致的

下面开始尝试权限绕过:

此处发现了如果需要密码时传入的格式:

{0}\u0001{1}\u0001{2:d}\u0001{3:d}\u0001{4}

此处尝试通过一个存在的用户名9999,但是错误的密码:
外层格式:

{UserCode}\u0001{随便什么}\u0001{SysID}\u0001{HospID}\u0001{真正的SQL}

最终要发送的数据格式:

string outer = "9999" + S + B2S(encPwd) + S + "1" + S + "0" + S;

其中B2S是字节数组转字符串,encPwd是调用dll随意加密一个字符串,S + “1” + S + “0” + S = \u00011\u00010\u0001


成功执行SQL语句,查询到了数据库版本,并且是SQl Server

此处证明了,中间件只是按格式拆包转发,没有实际对密码校验(也可能是逻辑是只要密码能被解密即通过校验,殊不知被攻击者还原了加密流程)。外层字段(UserCode/EncPwd/SysID/……)只是做了格式要求,并没有安全校验——用错误的加密密码也一样通过,即只需要知道用户名即可任意执行SQL,并且用户名为工号,极易猜测。

尝试xp_cmdshell:

Send(5004, outer + "EXEC xp_cmdshell 'whoami'" + S, "cmdshell-whoami");


幸运的是,它这里是高权限数据库,并且直接开启了xp_cmdshell,此处成功执行了系统命令whoami