Metasploit後滲透模塊開發

做者: 三米前有蕉皮
郵箱: root@kali-team.cn
嗶哩嗶哩: https://www.bilibili.com/video/bv1Za4y147af
博客: https://www.cnblogs.com/Kali-Team/
CC協議 <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="知識共享許可協議" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a>本做品採用<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議</a>進行許可。

前言

  • 接着上幾個視頻都是演示添加用戶的,而後忽然想起Metasploit裏面的添加用戶是調用命令行的,我就想能不能把它改成調用API的,給Metasploit提交了一點點代碼,這些都是我用過以後獲得的一些函數,因此不必定全都是對的,並且存在對某一個知識領域不是很瞭解,可能會有地方講錯,請你們指正。

結構

文件結構

external:擴展文件,好比zsh的命令行自動補全,裏面有一個source文件夾node

data:放一些exploits要用的二進制文件,字典,配置等等,通常是上傳到目標主機上執行或者在本地的一些輔助文件,裏面有一個meterpreter文件放的是留後門時用到的文件。c++

scripts:獨立腳本,能夠學習裏面的套路,自動化腳本。git

tools:開發輔助參考等等github

plugins:和其餘工具的聯動接口,rpc等等shell

modules結構

auxiliary:能夠理解打點的時候用的輔助模塊,端口掃描,指紋識別,漏洞驗證,登陸密碼爆破等等windows

encoders:編碼混淆api

exploits:漏洞利用,先按照操做系統分類,裏面再是各類應用協議分類數組

payloads:一共有三個不一樣的payload:SinglesStagersStagesruby

  1. Singles是獨立的payload,就是一個單獨個功能,好比添加一個用戶,執行一條命令,生成出來就不依賴Metasploit這個框架了,能夠理解爲shellcode;
  2. Stagers是須要依賴到Metasploit框架和目標主機創建網絡鏈接,可是依賴較少,功能也比較單一,好比彈回一個shell;
  3. Stages就是咱們經常使用的Meterpreter(Meta-Interpreter的縮寫)這個高級payload,功能強大,DLL反射

post:後滲透模塊網絡

Post Exploitation

打印信息

class.instance_variables.map{|v|v.to_s[1..-1]}
class.methods.map &:to_s
https://rapid7.github.io/metasploit-framework/api/
https://www.rubydoc.info/github/rapid7/metasploit-framework
pry調試
函數 描述
print_line 打印普通訊息
print_good 向終端輸出綠色信息,成功,好消息
print_error,print_bad 向終端輸出紅色信息,失敗,壞消息
print_warning 向終端輸出黃色信息,警告
print_status 向終端輸出綠色信息,狀態
print_blank_line 打印空行
print_line("---")
print_good("successful")
print_error("error")
print_warning("warning")
print_status("status")
print_blank_line

當前session信息

meterpreter > sysinfo 
Computer        : WIN-A18RNMNL9C2
OS              : Windows 2008 R2 (6.1 Build 7601, Service Pack 1).
Architecture    : x64
System Language : zh_CN
Domain          : KALI-TEAM
Logged On Users : 2
Meterpreter     : x86/windows
函數 描述
session.platform 獲取目標操做系統平臺,返回windows或其餘操做系統平臺等等
session.type 獲取session的類型。返回meterpreter或其餘session類型等等
session.tunnel_to_s 隧道
session.arch 獲取目標平臺架構,x86或者x64,常量(ARCH_X64,ARCH_X86)
session.info 獲取主機名和用戶名
session.run_cmd 至關於在msf控制檯敲命令
session.session_host 獲取目標鏈接通訊IP地址
session.session_port 獲取目標鏈接通訊端口
session.session_type 類型
session.payload_uuid payload的UUID,在調用API的時候要用到
session.exploit_uuid exploit的UUID,在調用API的時候要用到
session.uuid UUID,在調用API的時候要用到
session.lookup_error(5) Windows的錯誤常量
session.exploit_datastore exploit選項
print_good(session.platform.to_s)
print_good(session.type.to_s)
print_good(session.tunnel_to_s.to_s)
print_good(session.arch.to_s)
print_good(session.info.to_s)
print_good(session.session_host.to_s)
print_good(session.session_port.to_s)
print_good(session.session_type.to_s)
print_good(session.lookup_error(5).to_s)
print_good(session.exploit_datastore['payload'].to_s)

目標網絡信息

  • session.net.config.
函數 描述
interfaces 獲取網卡信息
each_interface 枚舉網卡
arp_table arp表對象
get_routes 獲取路由信息
remove_route 移除路由
netstat netstat
each_route 枚舉路由
add_route 添加路由
routes routes表
get_netstat get_netstat
get_proxy_config 獲取代理配置
get_arp_table 獲取ARP表
  • interfaces對象
[#<Rex::Post::Meterpreter::Extensions::Stdapi::Net::Interface:0x0000562efff8bbd0 @index=10, @mac_addr="\x00\f)Rr\xD0", @mac_name="Intel(R) PRO/1000 MT Network Connection", @mtu=1500, @flags=nil, @addrs=["fe80::4c6f:11ed:581f:c274", "192.168.76.132"], @netmasks=["ffff:ffff:ffff:ffff::", "255.255.255.0"], @scopes=["\n\x00\x00\x00"]>
  • arp_table對象
[#<Rex::Post::Meterpreter::Extensions::Stdapi::Net::Arp:0x00007f3d38463030 @ip_addr="224.0.0.22", @mac_addr="00:00:00:00:00:00", @interface="1">
  • get_route對象
[#<Rex::Post::Meterpreter::Extensions::Stdapi::Net::Route:0x00007f3d385a0b28 @subnet="0.0.0.0", @netmask="0.0.0.0", @gateway="192.168.76.2", @interface="10", @metric=266>
  • netstat對象
[#<Rex::Post::Meterpreter::Extensions::Stdapi::Net::Netstat:0x0000562f00520168 @local_addr="::", @remote_addr="::", @local_port=54538, @remote_port=0, @protocol="udp6", @state="", @uid=0, @inode=0, @pid_name="1344/dns.exe", @local_addr_str=":::54538", @remote_addr_str=":::*">
print_good(session.net.config.interfaces[0].mac_name.to_s)
session.net.config.each_interface do |interface|
    print_good(interface.addrs.to_s)
end
print_good(session.net.config.arp_table[0].ip_addr.to_s)
print_good(session.net.config.get_routes[0].gateway.to_s)
print_good(session.net.config.netstat[0].pid_name.to_s)
print_good(session.net.config.get_proxy_config.to_s)
session.net.config.add_route(subnet, netmask, gateway)   # Add route

核心功能

https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Transport-Control
lib/rex/post/meterpreter/client_core.rb
模塊名稱 描述
session.core.use 加載擴展插件
session.core.migrate 遷移進程
session.core.load_library 加載DLL
session.core.machine_id 機器ID
session.core.get_loaded_extension_commands('stdapi') 獲取已加載擴展命令
session.core.secure secure
session.core.transport_sleep 傳輸休眠
session.core.transport_add 添加傳輸
session.core.transport_change reverse_tcp, reverse_http, bind_tcp
session.core.set_transport_timeouts 設置傳輸超時
session.core.transport_remove 移除傳輸
session.core.transport_next 關閉當前傳輸,切換到下一個傳輸
session.core.transport_prev 關閉當前傳輸,切換到上一個傳輸
session.core.transport_list 列出傳輸
session.core.create_named_pipe_pivot 建立命名管道
session.core.use("extapi")

註冊表模塊

lib/msf/core/post/windows/registry.rb
Msf::Post::Windows::Registry
根鍵
HKEY_CLASSES_ROOT 用於存儲一些文檔類型,類,類的關聯屬性
HKEY_CURRENT_CONFIG 用戶存儲有關本地計算機系統的當前硬件配置文件信息
HKEY_CURRENT_USER 用於存儲當前用戶配置項
HKEY_PERFORMANCE_DATA 用於存儲當前用戶對計算機的配置項
HKEY_LOCAL_MACHINE 用於存儲當前用戶物理狀態
HKEY_USERS 用於存儲新用戶的默認配置項
HKEY_DYN_DATA 一個特別的根鍵

鍵操做

模塊名稱 描述
registry_hive_lookup 經過縮寫註冊根鍵
registry_createkey 建立鍵
registry_deletekey 刪除鍵
registry_enumkeys 枚舉鍵
print_good("#{registry_createkey(hkey+'X')}")
print_good("#{registry_deletekey(hkey+'X')}")
print_good(registry_enumkeys('HKEY_CURRENT_USER\\Software').to_s)

值操做

模塊名稱 描述
registry_getvaldata 獲取值數據
registry_deleteval 刪除值
registry_enumvals 枚舉值
registry_getvalinfo 獲取值信息(key,val),還返回值都類型
registry_setvaldata 設置值數據
reg_data_types = 'REG_SZ|REG_MULTI_SZ|REG_DWORD_BIG_ENDIAN|REG_DWORD|REG_BINARY|'
'REG_DWORD_LITTLE_ENDIAN|REG_NONE|REG_EXPAND_SZ|REG_LINK|REG_FULL_RESOURCE_DESCRIPTOR'

print_good(registry_enumvals('HKEY_CURRENT_USER\\Software\\TeamViewer\\').to_s)
print_good(registry_getvalinfo('HKEY_CURRENT_USER\\Software\\TeamViewer','SelectedLanguage').to_s)
print_good(registry_setvaldata('HKEY_CURRENT_USER\\Software\\TeamViewer','SelectedLanguageX', 'KT','REG_SZ').to_s)
print_good(registry_getvaldata('HKEY_CURRENT_USER\\Software\\TeamViewer','SelectedLanguage').to_s)
print_good(registry_deleteval('HKEY_CURRENT_USER\\Software\\TeamViewer','SelectedLanguageX').to_s)

Teamviewer主窗口句柄

用戶帳號管理

lib/msf/core/post/windows/accounts.rb
Msf::Post::Windows::Accounts
模塊名稱 描述
get_domain 獲取域名
delete_user 刪除用戶
resolve_sid 處理sid,e.g.('S-1-5-18')
check_dir_perms 檢查目錄權限
add_user 添加用戶
add_localgroup 添加本地組
add_group 添加域組
add_members_localgroup 添加用戶到本地組
add_members_group 添加用戶到域組
get_members_from_group 獲取域組裏面的用戶
get_members_from_localgroup 獲取本地組裏面的用戶
enum_user 枚舉用戶
enum_localgroup 枚舉本地組
enum_group 枚舉域組
net_server_enum 枚舉網絡服務
net_session_enum 枚舉網絡會話

API和錯誤常量

lib/msf/core/post/windows/error.rb
Msf::Post::Windows::Error
lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/api_constants.rb
print_good(session.railgun.const('ERROR_ACCESS_DENIED').to_s)

日誌事件

lib/rex/post/meterpreter/extensions/stdapi/sys/event_log.rb
lib/msf/core/post/windows/eventlog.rb
scripts/meterpreter/event_manager.rb
include Msf::Post::Windows::Eventlog
模塊名稱 描述
eventlog_list 列出日誌
eventlog_clear 清除日誌
  • event_manager插件

PowerShell模塊

lib/msf/core/post/windows/powershell.rb
Msf::Post::Windows::Powershell
模塊名稱 描述
read_script 讀入一個腳本
execute_script 執行腳本返回輸出內容,文本
have_powershell? 判斷是否存在powershell
get_powershell_version 獲取powershell的版本
psh_exec 執行PowerShell文本
base_script = File.read(File.join(Msf::Config.data_directory, "post", "powershell", "NTDSgrab.ps1"))
execute_script(base_script)

系統

lib/msf/core/post/windows/priv.rb
lib/rex/post/meterpreter/extensions/stdapi/sys
lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb
Msf::Post::Windows::Priv
  • 之前是有提權模塊的,可是如今所有歸到local漏洞那邊了。因此就剩下這些輔助函數了。
函數 描述
session.sys.config.sysinfo['OS'] 獲取sysinfo裏面的值
session.sys.config.getprivs 權限標識
session.sys.config.getenv 獲取環境變量
session.sys.config.is_system? 是否是系統權限
session.sys.config.steal_token 偷進程token
session.sys.config.getuid 獲取用戶名
session.sys.config.revert_to_self 返回本身的token
session.sys.config.getsid 獲取sid標示
session.sys.config.getdrivers 枚舉驅動,枚舉類型
session.sys.config.drop_token 丟棄當前token
is_admin? 判斷是否是admin
steal_current_user_token 偷當前用戶的token
is_in_admin_group? 判斷是否是在admin組
is_uac_enabled? UAC是否開啓
get_uac_level 獲取UAC等級
session.priv.getsystem getsystem
print_good(session.sys.config.sysinfo.to_s)
print_good(session.sys.config.getprivs.to_s)
print_good(session.sys.config.getenv("windir").to_s)
print_good(session.sys.config.getuid.to_s)
print_good(session.sys.config.getsid.to_s)
print_good(session.sys.config.getdrivers[0].to_s)
print_good(session.sys.config.is_system?.to_s)
print_good(is_admin?.to_s)
print_good(steal_current_user_token.to_s)
print_good(is_in_admin_group?.to_s)
print_good(is_uac_enabled?.to_s)
print_good(get_uac_level.to_s)

反射DLL

lib/msf/core/post/windows/reflective_dll_injection.rb
modules/post/windows/manage/shellcode_inject.rb
Msf::Post::Windows::ReflectiveDLLInjection
模塊名稱 描述
inject_into_process 注入shellcode到進程
inject_dll_into_process 注入dll到進程
inject_dll_data_into_process 注入反射性dll數據到進程

服務管理

lib/rex/post/meterpreter/extensions/extapi/service/service.rb
lib/msf/core/post/windows/services.rb
include Msf::Post::Windows::Services
模塊名稱 描述
each_service 枚舉服務,枚舉類型
service_list 列舉服務
service_change_startup 修改啓動方式
service_change_config 修改服務配置
service_create 建立服務
service_start 啓動服務
service_stop 中止服務
service_delete 刪除服務
service_status 服務狀態
service_restart 重啓服務
service_info 獲取服務信息
each_service do |service|
    # print_good("#{service}")
    if service[:display] == 'TeamViewer'
        print_good(service_info(service[:name]).to_s)
        print_good(service_status(service[:name]).to_s)
    end
end
# ["Boot","System","Auto","Manual","Disabled"]
service_change_startup('TeamViewer', START_TYPE_DISABLED)
service_create("TeamViewerX", { path: 'C:\\Program Files (x86)\\TeamViewer\\TeamViewer_Service.exe', display: "TEXT" })
service_start("TeamViewerX")
service_stop("TeamViewerX")
service_delete("TeamViewerX")
modules/exploits/windows/local/service_permissions.rb

用戶設置

lib/msf/core/post/windows/user_profiles.rb
Msf::Post::Windows::UserProfiles
模塊名稱 描述
grab_user_profiles 獲取用戶配置

進程模塊

lib/msf/core/post/windows/process.rb
Msf::Post::Windows::Process
函數 描述
session.sys.process.getpid 獲取當前進程pid
session.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS) 打開一個進程,返回一個進程句柄
session.sys.process.processes 枚舉全部進程信息
session.sys.process.execute 執行程序
session.sys.process.kill 殺掉一個進程
session.sys.process.each_process 枚舉類型
session.sys.process.get_processes.keep_if 枚舉類型
execute_shellcode 執行shellcode
inject_unhook 注入釋放鉤子
has_pid pid是否存在

執行shellcode

  1. 獲取當前的pid:session.sys.process.getpid
  2. 打開進程獲得進程句柄:host = session.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS)
  3. 申請內存:shell_addr = host.memory.allocate(shellcode.length)
  4. 保護當前地址:host.memory.protect(shell_addr)
  5. 向地址寫入shellcode:host.memory.write(shell_addr, shellcode)
  6. 執行shellcode:host.thread.create(shell_addr,0)

文件系統操做

include Msf::Post::File
lib/rex/post/dir.rb
lib/rex/post/file_stat.rb
lib/rex/post/file.rb
lib/rex/post/meterpreter/extensions/stdapi/fs/file_stat.rb

文件操做

  • session.fs.file.
lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb
函數 描述
separator 獲取系統目錄路徑的分隔符\
expand_path 解析環境變量形式的文件路徑'%appdata%'
rm,delete 刪除文件
new 新建文件返回一個句柄
rename,mv 重命名文件
download 下載遠程文件到本地
stat 文件信息
move,mv 移動文件
search 搜索文件
chmod 修改文件屬性
exist 文件是否存在
open 打開文件返回一個句柄
download_file 下載遠程單文件到本地
copy,cp 拷貝文件
file_local_write 寫文件到本地
upload_file 上傳單文件到遠程
write_file 寫文件到遠程
sha1 獲取文件的sha1
md5 獲取文件的md5

文件夾操做

  • session.fs.dir
lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb
函數 描述
entries,ls 列出當前文件夾裏的文件
entries_with_info 列出當前文件夾裏的文件,帶文件的詳細信息
mkdir 新建目錄
match 匹配文件
foreach 枚舉文件夾
chdir 切換到目錄,就是cd
pwd,getwd 顯示當前目錄路徑
delete,rmdir,unlink 刪除文件夾
download 遞歸下載遠程文件夾到本地
upload 遞歸上傳本地文件夾到遠程
  • 獲取文件的詳細信息
session.fs.file.stat

剪切板管理

lib/rex/post/meterpreter/extensions/extapi/clipboard/clipboard.rb
lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/clipboard.rb
include Msf::Post::Windows::ExtAPI
模塊名稱 描述
session.extapi.clipboard.set_text 設置剪切板文本
session.extapi.clipboard.get_data 獲取剪切板數據-d下載非文本數據
monitor_start 開始監控
monitor_pause 暫停監控
monitor_dump 導出監控內容
monitor_resume 從新監控
monitor_purge 清除監控
monitor_stop 中止監控

WMIC

include Msf::Post::Windows::WMIC

模塊名稱 描述
wmic_query 查詢wmic
wmic_command 執行wmic命令
wmic_user_pass_string smbexec

Runas

Msf::Post::Windows::Runas

模塊名稱 描述
shell_execute_exe 執行exe
shell_execute_psh 執行PowerShell
shell_exec 執行命令
create_process_with_logon 以登陸用戶建立進程
create_process_as_user 以指定用戶建立進程

Kiwi

Msf::Post::Windows::Kiwi

模塊名稱 描述
password_change 修改密碼
dcsync 同步域控
dcsync_ntlm 同步域控NTLM
lsa_dump_secrets 導出secrets
lsa_dump_sam 導出sam
lsa_dump_cache 導出cache
creds_all 獲取所有憑證
kerberos_ticket_list 列出kerberos票據
kerberos_ticket_use 使用kerberos票據
kerberos_ticket_purge 清除kerberos票據
golden_ticket_create 建立黃金票據
wifi_list 列出WiFi憑證

ShadowCopy

Msf::Post::Windows::ShadowCopy

模塊名稱 描述
vss_list 列出卷影備份
vss_get_ids 獲取卷影備份的id
vss_get_storage 獲取卷影備份儲存的參數
get_sc_details 列出指定id卷影備份的詳細信息
get_sc_param 獲取制定id卷影備份的參數信息
vss_get_storage_param 獲取卷影備份儲存的指定參數
vss_set_storage 設置卷影備份儲存
create_shadowcopy 建立卷影備份
start_vss 啓動卷影備份

LDAP

Msf::Post::Windows::LDAP

  • 這個我不會!下次必定!

RailGun

lib/msf/core/post/windows/railgun.rb
lib/rex/post/meterpreter/extensions/stdapi/railgun/library.rb
lib/rex/post/meterpreter/extensions/stdapi/railgun/library_function.rb
模塊名稱 描述
known_library_names 列出可用DLL
memread 讀內存
memwrite 寫內存
add_function 添加函數
add_library,add_dll 添加庫
get_library,get_dll 獲取庫,判斷存不存在
multi 執行多個函數,數組形式
const 獲取常量
lookup_error lookup_error
pointer_size 獲取指針大小,x86與x64的差異

數據類型

@@allowed_datatypes = {
    'VOID'   => ['return'],
    'BOOL'   => ['in', 'return'],
    'DWORD'  => ['in', 'return'],
    'WORD'   => ['in', 'return'],
    'BYTE'   => ['in', 'return'],
    'LPVOID' => ['in', 'return'], # sf: for specifying a memory address (e.g. VirtualAlloc/HeapAlloc/...) where we don't want to back it up with actual mem ala PBLOB
    'HANDLE' => ['in', 'return'],
    'SIZE_T' => ['in', 'return'],
    'PDWORD' => ['in', 'out', 'inout'], # todo: support for functions that return pointers to strings
    'PWCHAR' => ['in', 'out', 'inout'],
    'PCHAR'  => ['in', 'out', 'inout'],
    'PBLOB'  => ['in', 'out', 'inout'],
  }.freeze

  @@allowed_convs = ['stdcall', 'cdecl']

  @@directions = ['in', 'out', 'inout', 'return'].freeze
  • 在下面文件有詳細的轉換對應關係
lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb
VOID, BOOL, DWORD, WORD, BYTE, LPVOID, HANDLE, PDWORD, PWCHAR, PCHAR, PBLOB
  • 若是是指針數據類型的要使用:PBLOB類型,返回來的使用unpack解析,pack以後做爲參數傳進。
C語言 Railgun 描述
LPCWSTR,LPWSTR PWCHAR
DWORD DWORD
LPCSTR PCHAR
*LPVOID PBLOB 指針各類奇怪的數據類型
*DWORD,LPDWORD PDWORD 通常是一個指針地址DWORD,返回值存儲變量的地址
VOID VOID VOID返回類型
BOOL BOOL
WORD WORD 通常是常量,bits
BYTE BYTE
PSID LPVOID 指針內存
HANDLE HANDLE 句柄
#process return value
case function.return_type
  when 'LPVOID', 'HANDLE'
    if( @native == 'Q<' )
      return_hash['return'] = rec_return_value
    else
      return_hash['return'] = rec_return_value % 4294967296
    end
  when 'DWORD'
    return_hash['return'] = rec_return_value % 4294967296
  when 'WORD'
    return_hash['return'] = rec_return_value % 65536
  when 'BYTE'
    return_hash['return'] = rec_return_value % 256
  when 'BOOL'
    return_hash['return'] = (rec_return_value != 0)
  when 'VOID'
    return_hash['return'] = nil
  else
    raise "unexpected return type: #{function.return_type}"
end
  • 定義函數
lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb
  • 添加函數
Example:
   add_function("MessageBoxW",   # name
     "DWORD",                    # return value
      [                           # params
	  ["DWORD","hWnd","in"],
      ["PWCHAR","lpText","in"],
      ["PWCHAR","lpCaption","in"],
      ["DWORD","uType","in"],
  ])
  • 添加DLL庫
模塊名稱 用途 舉例
session.railgun.netapi32 用戶相關 添加用戶等等
session.railgun.util 工具函數 各類實用函數
known_library_names 已知可用DLL
https://docs.microsoft.com/en-us/previous-versions//aa383749(v=vs.85)?redirectedfrom=MSDN

添加用戶例子

  • C代碼

https://docs.microsoft.com/en-us/windows/win32/api/lmaccess/nf-lmaccess-netuseradd

NET_API_STATUS NET_API_FUNCTION NetUserAdd(
  LPCWSTR servername,
  DWORD   level,
  LPBYTE  buf,
  LPDWORD parm_err
);
  • 在文件lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_netapi32.rb添加函數。
dll.add_function('NetUserAdd', 'DWORD', [
    ["PWCHAR","servername","in"],
    ["DWORD","level","in"],
    ["PBLOB","buf","in"],
    ["PDWORD","parm_err","out"]
    ])
  • 你會發現level這個參數他是一個結構體,和上面介紹的幾種數據類型都對不上,怎麼把level傳給NetUserAdd呢?Ruby裏有一個pack能夠封裝結構體,pack就是告訴railgun在內存中怎麼解析這串東西。

https://docs.microsoft.com/en-us/windows/win32/api/Lmaccess/ns-lmaccess-user_info_1

  • 結構體
typedef struct _USER_INFO_1 {
  LPWSTR usri1_name;
  LPWSTR usri1_password;
  DWORD  usri1_password_age;
  DWORD  usri1_priv;
  LPWSTR usri1_home_dir;
  LPWSTR usri1_comment;
  DWORD  usri1_flags;
  LPWSTR usri1_script_path;
} USER_INFO_1, *PUSER_INFO_1, *LPUSER_INFO_1;
  • 上面有5個LPWSTR類型的變量,由於它是一個指針類型,在x86架構裏的指針尋址32位,用pack封裝的時候所有使用V就能夠了,V在ruby的pack中表示:小端字節順序的unsigned long (32bit 無符號整數);在x64架構裏尋址位數就不同了,因此這個結構體在內存就會不同,因此封裝的時候就要使用Q,Q在ruby的pack中表示:小端字節順序unsigned long long(64bit 無符號整數)。這個問題我用x64dbg調了一天[捂臉]。
def add_user(username, password, server_name = nil)
    addr_username = session.railgun.util.alloc_and_write_wstring(username)
    addr_password = session.railgun.util.alloc_and_write_wstring(password)
    #  Set up the USER_INFO_1 structure.
    #  https://docs.microsoft.com/en-us/windows/win32/api/Lmaccess/ns-lmaccess-user_info_1
    user_info = [
        addr_username,
        addr_password,
        0x0,
        0x1,
        0x0,
        0x0,
        client.railgun.const('UF_SCRIPT | UF_NORMAL_ACCOUNT|UF_DONT_EXPIRE_PASSWD'),
        0x0
        ].pack(client.arch == "x86" ? "VVVVVVVV" : "QQVVQQVQ")
    result = client.railgun.netapi32.NetUserAdd(server_name, 1, user_info, 4)
    client.railgun.multi([
        ["kernel32", "VirtualFree", [addr_username, 0, MEM_RELEASE]], #  addr_username
        ["kernel32", "VirtualFree", [addr_password, 0, MEM_RELEASE]], #  addr_password
        ])
    return result
end

解析返回數據

  • 上面的傳參一個解決了,解析數據可使用unpack,或者有別人在util寫好的函數

枚舉用戶

  • C代碼

https://docs.microsoft.com/en-us/windows/win32/api/lmaccess/nf-lmaccess-netuserenum

NET_API_STATUS NET_API_FUNCTION NetUserEnum(
  LPCWSTR servername,
  DWORD   level,
  DWORD   filter,
  LPBYTE  *bufptr,
  DWORD   prefmaxlen,
  LPDWORD entriesread,
  LPDWORD totalentries,
  PDWORD  resume_handle
);
  • 添加函數
dll.add_function('NetUserEnum', 'DWORD', [
    ["PWCHAR","servername","in"],
    ["DWORD","level","in"],
    ["DWORD","filter","in"],
    ["PBLOB","bufptr","out"],
    ["DWORD","prefmaxlen","in"],
    ["PDWORD","entriesread","out"],
    ["PDWORD","totalentries","out"],
    ["PDWORD","ResumeHandle","inout"],
    ])
def enum_user(server_name = nil)
    users = []
    filter = 'FILTER_NORMAL_ACCOUNT|FILTER_TEMP_DUPLICATE_ACCOUNT'
    result = client.railgun.netapi32.NetUserEnum(server_name, 0, client.railgun.const(filter), 4, 4096, 4, 4, 0)
    if (result['return'] == 0) && ((result['totalentries'] % 4294967296) != 0)
        begin
            user_info_addr = result['bufptr'].unpack1("V")
            unless user_info_addr == 0
                user_info = session.railgun.util.read_array(USER_INFO, (result['totalentries'] % 4294967296), user_info_addr)
                for member in user_info
                    users << member["usri0_name"]
                end
                return users
            end
        end
    else
        return users
    end
    ensure
    session.railgun.netapi32.NetApiBufferFree(user_info_addr)
end
  • 能夠看一下我提交的PR,上面Railgun的用法我在這個推送請求都用上了
相關文章
相關標籤/搜索